@@ -170,6 +170,33 @@ class DecoratedType {
170170 }
171171 }
172172
173+ /// If this type is a function type, returns its generic formal parameters.
174+ /// Otherwise returns `null` .
175+ List <TypeParameterElement > get typeFormals {
176+ var type = this .type;
177+ if (type is FunctionType ) {
178+ return type.typeFormals;
179+ } else {
180+ return null ;
181+ }
182+ }
183+
184+ /// Converts one function type into another by substituting the given
185+ /// [argumentTypes] for the function's generic parameters.
186+ DecoratedType instantiate (List <DecoratedType > argumentTypes) {
187+ var type = this .type as FunctionType ;
188+ var typeFormals = type.typeFormals;
189+ List <DartType > undecoratedArgumentTypes = [];
190+ Map <TypeParameterElement , DecoratedType > substitution = {};
191+ for (int i = 0 ; i < argumentTypes.length; i++ ) {
192+ var argumentType = argumentTypes[i];
193+ undecoratedArgumentTypes.add (argumentType.type);
194+ substitution[typeFormals[i]] = argumentType;
195+ }
196+ return _substituteFunctionAfterFormals (
197+ type.instantiate (undecoratedArgumentTypes), substitution);
198+ }
199+
173200 /// Apply the given [substitution] to this type.
174201 ///
175202 /// [undecoratedResult] is the result of the substitution, as determined by
@@ -204,11 +231,14 @@ class DecoratedType {
204231 }
205232 return '$name $args $trailing ' ;
206233 } else if (type is FunctionType ) {
207- assert (type.typeFormals.isEmpty); // TODO(paulberry)
234+ String formals = '' ;
235+ if (type.typeFormals.isNotEmpty) {
236+ formals = '<${type .typeFormals .join (', ' )}>' ;
237+ }
208238 assert (type.namedParameterTypes.isEmpty &&
209239 namedParameters.isEmpty); // TODO(paulberry)
210240 var args = positionalParameters.map ((p) => p.toString ()).join (', ' );
211- return '$returnType Function($args )$trailing ' ;
241+ return '$returnType Function$ formals ($args )$trailing ' ;
212242 } else if (type is DynamicTypeImpl ) {
213243 return 'dynamic' ;
214244 } else {
@@ -230,21 +260,7 @@ class DecoratedType {
230260 var type = this .type;
231261 if (type is FunctionType && undecoratedResult is FunctionType ) {
232262 assert (type.typeFormals.isEmpty); // TODO(paulberry)
233- var newPositionalParameters = < DecoratedType > [];
234- for (int i = 0 ; i < positionalParameters.length; i++ ) {
235- var numRequiredParameters =
236- undecoratedResult.normalParameterTypes.length;
237- var undecoratedParameterType = i < numRequiredParameters
238- ? undecoratedResult.normalParameterTypes[i]
239- : undecoratedResult
240- .optionalParameterTypes[i - numRequiredParameters];
241- newPositionalParameters.add (positionalParameters[i]
242- ._substitute (substitution, undecoratedParameterType));
243- }
244- return DecoratedType (undecoratedResult, node,
245- returnType: returnType._substitute (
246- substitution, undecoratedResult.returnType),
247- positionalParameters: newPositionalParameters);
263+ return _substituteFunctionAfterFormals (undecoratedResult, substitution);
248264 } else if (type is InterfaceType && undecoratedResult is InterfaceType ) {
249265 List <DecoratedType > newTypeArguments = [];
250266 for (int i = 0 ; i < typeArguments.length; i++ ) {
@@ -266,6 +282,27 @@ class DecoratedType {
266282 }
267283 throw '$type .substitute($substitution )' ; // TODO(paulberry)
268284 }
285+
286+ /// Performs the logic that is common to substitution and function type
287+ /// instantiation. Namely, a decorated type is formed whose undecorated type
288+ /// is [undecoratedResult] , and whose return type, positional parameters, and
289+ /// named parameters are formed by performing the given [substitution] .
290+ DecoratedType _substituteFunctionAfterFormals (FunctionType undecoratedResult,
291+ Map <TypeParameterElement , DecoratedType > substitution) {
292+ var newPositionalParameters = < DecoratedType > [];
293+ for (int i = 0 ; i < positionalParameters.length; i++ ) {
294+ var numRequiredParameters = undecoratedResult.normalParameterTypes.length;
295+ var undecoratedParameterType = i < numRequiredParameters
296+ ? undecoratedResult.normalParameterTypes[i]
297+ : undecoratedResult.optionalParameterTypes[i - numRequiredParameters];
298+ newPositionalParameters.add (positionalParameters[i]
299+ ._substitute (substitution, undecoratedParameterType));
300+ }
301+ return DecoratedType (undecoratedResult, node,
302+ returnType:
303+ returnType._substitute (substitution, undecoratedResult.returnType),
304+ positionalParameters: newPositionalParameters);
305+ }
269306}
270307
271308/// A [DecoratedType] based on a type annotation appearing explicitly in the
0 commit comments