| 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 1c3a644d230aa3c51518fe6a85c617a7e7cfd14f..041322f071f4a3c634640f9dcfb9f15d218d9c50 100644
|
| --- a/pkg/analyzer/lib/src/generated/resolver.dart
|
| +++ b/pkg/analyzer/lib/src/generated/resolver.dart
|
| @@ -7295,6 +7295,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(
|
| + 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(
|
| + 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.
|
| @@ -8078,12 +8120,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 {
|
|
|