| 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]);
|
| }
|
| }
|
| }
|
|
|