Index: pkg/analyzer/lib/src/generated/resolver.dart |
diff --git a/pkg/analyzer/lib/src/generated/resolver.dart b/pkg/analyzer/lib/src/generated/resolver.dart |
index ecfe2049c611843dc861a4ce6229e8b30173263d..e1b5f67a212c02451485c19ffad4e26ed6efa18b 100644 |
--- a/pkg/analyzer/lib/src/generated/resolver.dart |
+++ b/pkg/analyzer/lib/src/generated/resolver.dart |
@@ -7293,6 +7293,48 @@ class ResolverVisitor extends ScopedVisitor { |
} |
/** |
+ * Given a downward inference type [fnType], and the declared |
+ * [typeParameterList] for a function expression, determines if we can enable |
+ * downward inference and if so, returns the function type to use for |
+ * inference. |
+ * |
+ * This will return null if inference is not possible. This happens when |
+ * there is no way we can find a subtype of the function type, given the |
+ * provided type parameter list. |
+ */ |
+ FunctionType matchFunctionTypeParameters( |
Jennifer Messerly
2016/02/08 21:54:27
I feel like there's got to be a better way to fact
|
+ TypeParameterList typeParameterList, FunctionType fnType) { |
+ if (typeParameterList == null) { |
+ if (fnType.typeFormals.isEmpty) { |
+ return fnType; |
+ } |
+ |
+ // A non-generic function cannot be a subtype of a generic one. |
+ return null; |
+ } |
+ |
+ NodeList<TypeParameter> typeParameters = typeParameterList.typeParameters; |
+ if (fnType.typeFormals.isEmpty) { |
+ // TODO(jmesserly): this is a legal subtype. We don't currently infer |
+ // here, but we could. This is similar to |
+ // StrongTypeSystemImpl.inferFunctionTypeInstantiation, but we don't |
+ // have the FunctionType yet for the current node, so it's not quite |
+ // straightforward to apply. |
+ return null; |
+ } |
+ |
+ if (fnType.typeFormals.length != typeParameters.length) { |
+ // A subtype cannot have different number of type formals. |
+ return null; |
+ } |
+ |
+ // Same number of type formals. Instantiate the function type so its |
+ // parameter and return type are in terms of the surrounding context. |
+ return fnType.instantiate( |
Jennifer Messerly
2016/02/08 21:54:27
This is a case like:
// declare generic funct
|
+ typeParameters.map((t) => t.name.staticElement.type).toList()); |
+ } |
+ |
+ /** |
* If it is appropriate to do so, override the current type of the static and propagated elements |
* associated with the given expression with the given type. Generally speaking, it is appropriate |
* if the given type is more specific than the current type. |
@@ -8076,12 +8118,16 @@ class ResolverVisitor extends ScopedVisitor { |
try { |
DartType functionType = InferenceContext.getType(node); |
if (functionType is FunctionType) { |
- _inferFormalParameterList(node.parameters, functionType); |
- DartType returnType = _computeReturnOrYieldType( |
- functionType.returnType, |
- _enclosingFunction.isGenerator, |
- _enclosingFunction.isAsynchronous); |
- InferenceContext.setType(node.body, returnType); |
+ functionType = |
+ matchFunctionTypeParameters(node.typeParameters, functionType); |
+ if (functionType is FunctionType) { |
+ _inferFormalParameterList(node.parameters, functionType); |
+ DartType returnType = _computeReturnOrYieldType( |
+ functionType.returnType, |
+ _enclosingFunction.isGenerator, |
+ _enclosingFunction.isAsynchronous); |
+ InferenceContext.setType(node.body, returnType); |
+ } |
} |
super.visitFunctionExpression(node); |
} finally { |