Index: pkg/analyzer/lib/src/generated/error_verifier.dart |
diff --git a/pkg/analyzer/lib/src/generated/error_verifier.dart b/pkg/analyzer/lib/src/generated/error_verifier.dart |
index 346da5a6c23f5e2fcfded2096a5c41cfc90fb89c..ffef5db56d9e8e3af77f73dad77cd3321a68c279 100644 |
--- a/pkg/analyzer/lib/src/generated/error_verifier.dart |
+++ b/pkg/analyzer/lib/src/generated/error_verifier.dart |
@@ -821,7 +821,7 @@ class ErrorVerifier extends RecursiveAstVisitor<Object> { |
StaticTypeWarningCode.INVOCATION_OF_NON_FUNCTION_EXPRESSION, |
functionExpression); |
} else if (expressionType is FunctionType) { |
- _checkTypeArguments(expressionType.element, node.typeArguments); |
+ _checkTypeArguments(node); |
} |
_checkForImplicitDynamicInvoke(node); |
return super.visitFunctionExpressionInvocation(node); |
@@ -1032,8 +1032,7 @@ class ErrorVerifier extends RecursiveAstVisitor<Object> { |
} else { |
_checkForUnqualifiedReferenceToNonLocalStaticMember(methodName); |
} |
- _checkTypeArguments( |
- node.methodName.staticElement, node.typeArguments, target?.staticType); |
+ _checkTypeArguments(node); |
_checkForImplicitDynamicInvoke(node); |
return super.visitMethodInvocation(node); |
} |
@@ -6156,72 +6155,38 @@ class ErrorVerifier extends RecursiveAstVisitor<Object> { |
* |
* See [StaticTypeWarningCode.TYPE_ARGUMENT_NOT_MATCHING_BOUNDS]. |
*/ |
- void _checkTypeArguments(Element element, TypeArgumentList typeArguments, |
- [DartType targetType]) { |
- if (element == null || typeArguments == null) { |
- return; |
- } |
- void reportError(TypeAnnotation argument, DartType argumentType, |
- DartType parameterType) { |
- _errorReporter.reportTypeErrorForNode( |
- StaticTypeWarningCode.TYPE_ARGUMENT_NOT_MATCHING_BOUNDS, |
- argument, |
- [argumentType, parameterType]); |
- } |
- |
- if (element is FunctionTypedElement) { |
- _checkTypeArgumentsAgainstBounds( |
- element.typeParameters, typeArguments, targetType, reportError); |
- } else if (element is ClassElement) { |
- _checkTypeArgumentsAgainstBounds( |
- element.typeParameters, typeArguments, targetType, reportError); |
- } else if (element is ParameterElement || element is LocalVariableElement) { |
- // TODO(brianwilkerson) Implement this case |
- } else { |
- print('Unhandled element type: ${element.runtimeType}'); |
- } |
- } |
- |
- void _checkTypeArgumentsAgainstBounds( |
- List<TypeParameterElement> typeParameters, |
- TypeArgumentList typeArgumentList, |
- DartType targetType, |
- void reportError(TypeAnnotation argument, DartType argumentType, |
- DartType parameterType)) { |
- NodeList<TypeAnnotation> typeArguments = typeArgumentList.arguments; |
- int argumentsLength = typeArguments.length; |
- int maxIndex = math.min(typeParameters.length, argumentsLength); |
- |
- bool shouldSubstitute = |
- argumentsLength != 0 && argumentsLength == typeParameters.length; |
- List<DartType> argumentTypes = shouldSubstitute |
- ? typeArguments.map((TypeAnnotation type) => type.type).toList() |
- : null; |
- List<DartType> parameterTypes = shouldSubstitute |
- ? typeParameters |
- .map((TypeParameterElement element) => element.type) |
- .toList() |
- : null; |
- List<DartType> targetTypeParameterTypes = null; |
- for (int i = 0; i < maxIndex; i++) { |
- TypeAnnotation argument = typeArguments[i]; |
- DartType argType = argument.type; |
- DartType boundType = typeParameters[i].bound; |
- if (argType != null && boundType != null) { |
- if (targetType is ParameterizedType) { |
- if (targetTypeParameterTypes == null) { |
- targetTypeParameterTypes = targetType.typeParameters |
- .map((TypeParameterElement element) => element.type) |
- .toList(); |
- } |
- boundType = boundType.substitute2( |
- targetType.typeArguments, targetTypeParameterTypes); |
- } |
- if (shouldSubstitute) { |
- boundType = boundType.substitute2(argumentTypes, parameterTypes); |
- } |
- if (!_typeSystem.isSubtypeOf(argType, boundType)) { |
- reportError(argument, argType, boundType); |
+ void _checkTypeArguments(InvocationExpression node) { |
+ NodeList<TypeAnnotation> typeArgumentList = node.typeArguments?.arguments; |
+ if (typeArgumentList == null) { |
+ return; |
+ } |
+ |
+ var genericType = node.function.staticType; |
+ var instantiatedType = node.staticInvokeType; |
+ if (genericType is FunctionType && instantiatedType is FunctionType) { |
+ var fnTypeParams = |
+ TypeParameterTypeImpl.getTypes(genericType.typeFormals); |
+ var typeArgs = typeArgumentList.map((t) => t.type).toList(); |
+ |
+ for (int i = 0, len = math.min(typeArgs.length, fnTypeParams.length); |
+ i < len; |
+ i++) { |
+ // Check the `extends` clause for the type parameter, if any. |
+ // |
+ // Also substitute to handle cases like this: |
+ // |
+ // <TFrom, TTo extends TFrom> |
+ // <TFrom, TTo extends Iterable<TFrom>> |
+ // <T extends Clonable<T>> |
+ // |
+ DartType argType = typeArgs[i]; |
+ DartType bound = |
+ fnTypeParams[i].bound.substitute2(typeArgs, fnTypeParams); |
+ if (!_typeSystem.isSubtypeOf(argType, bound)) { |
+ _errorReporter.reportTypeErrorForNode( |
+ StaticTypeWarningCode.TYPE_ARGUMENT_NOT_MATCHING_BOUNDS, |
+ typeArgumentList[i], |
+ [argType, bound]); |
} |
} |
} |