Chromium Code Reviews| 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) { |
|
Jennifer Messerly
2017/01/24 03:09:16
rewrote this to simplify
in general -- when we st
|
| + 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]); |
| } |
| } |
| } |