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 c99057ad123a0ffe0645274036a38d55461dfbe9..410b45142727b7d16096d863121feb3be13781d0 100644 |
| --- a/pkg/analyzer/lib/src/generated/error_verifier.dart |
| +++ b/pkg/analyzer/lib/src/generated/error_verifier.dart |
| @@ -770,6 +770,8 @@ class ErrorVerifier extends RecursiveAstVisitor<Object> { |
| _errorReporter.reportErrorForNode( |
| StaticTypeWarningCode.INVOCATION_OF_NON_FUNCTION_EXPRESSION, |
| functionExpression); |
| + } else if (expressionType is FunctionType) { |
| + _checkTypeArguments(expressionType.element, node.typeArguments); |
| } |
| return super.visitFunctionExpressionInvocation(node); |
| } |
| @@ -943,6 +945,8 @@ class ErrorVerifier extends RecursiveAstVisitor<Object> { |
| } |
| _checkForMissingRequiredParam( |
| node.staticInvokeType, node.argumentList, methodName); |
| + _checkTypeArguments( |
| + node.methodName.staticElement, node.typeArguments, target?.staticType); |
| return super.visitMethodInvocation(node); |
| } |
| @@ -5217,13 +5221,14 @@ class ErrorVerifier extends RecursiveAstVisitor<Object> { |
| int loopThroughIndex = |
| math.min(typeNameArgList.length, boundingElts.length); |
| + bool shouldSubstitute = typeArguments.length != 0 && |
| + typeArguments.length == typeParameters.length; |
| for (int i = 0; i < loopThroughIndex; i++) { |
| TypeName argTypeName = typeNameArgList[i]; |
| DartType argType = argTypeName.type; |
| DartType boundType = boundingElts[i].bound; |
| if (argType != null && boundType != null) { |
| - if (typeArguments.length != 0 && |
| - typeArguments.length == typeParameters.length) { |
| + if (shouldSubstitute) { |
| boundType = boundType.substitute2(typeArguments, typeParameters); |
| } |
| if (!_typeSystem.isSubtypeOf(argType, boundType)) { |
| @@ -5646,6 +5651,79 @@ class ErrorVerifier extends RecursiveAstVisitor<Object> { |
| } |
| } |
| + /** |
| + * Verify that the given [typeArguments] are all within their bounds, as |
| + * defined by the given [element]. |
| + * |
| + * See [StaticTypeWarningCode.TYPE_ARGUMENT_NOT_MATCHING_BOUNDS]. |
| + */ |
| + void _checkTypeArguments(Element element, TypeArgumentList typeArguments, |
|
Jennifer Messerly
2016/04/28 17:30:02
one idea here: FunctionExpressionInvocation and Me
Brian Wilkerson
2016/04/28 20:46:11
Yes, but I was hoping to use the same method for t
|
| + [DartType targetType]) { |
| + if (element == null || typeArguments == null) { |
| + return; |
| + } |
| + void reportError( |
| + TypeName argument, DartType argumentType, DartType parameterType) { |
| + _errorReporter.reportTypeErrorForNode( |
| + StaticTypeWarningCode.TYPE_ARGUMENT_NOT_MATCHING_BOUNDS, |
| + argument, |
| + [argumentType, parameterType]); |
| + } |
| + if (element is FunctionTypedElement) { |
|
Jennifer Messerly
2016/04/28 17:30:02
Would it make sense to use the type instead of the
Brian Wilkerson
2016/04/28 20:46:11
Not sure. I'll look into that as part of the next
|
| + _checkTypeArgumentsAgainstBounds( |
| + element.typeParameters, typeArguments, targetType, reportError); |
| + } else if (element is ClassElement) { |
|
Jennifer Messerly
2016/04/28 17:30:02
is ClassElement possible here? (it looks like it's
Brian Wilkerson
2016/04/28 20:46:11
Sorry, you're seeing an incomplete thought.
It is
|
| + _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( |
| + TypeName argument, DartType argumentType, DartType parameterType)) { |
| + NodeList<TypeName> 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((TypeName typeName) => typeName.type).toList() |
| + : null; |
| + List<DartType> parameterTypes = shouldSubstitute |
| + ? typeParameters |
| + .map((TypeParameterElement element) => element.type) |
| + .toList() |
| + : null; |
| + for (int i = 0; i < maxIndex; i++) { |
| + TypeName argTypeName = typeArguments[i]; |
| + DartType argType = argTypeName.type; |
| + DartType boundType = typeParameters[i].bound; |
| + if (argType != null && boundType != null) { |
| + if (targetType is ParameterizedType) { |
| + boundType = boundType.substitute2( |
| + targetType.typeArguments, |
| + targetType.typeParameters |
| + .map((TypeParameterElement element) => element.type) |
| + .toList()); |
|
scheglov
2016/04/28 17:14:52
It looks that this expression can be extracted.
t
Brian Wilkerson
2016/04/28 20:46:11
Done
|
| + } |
| + if (shouldSubstitute) { |
| + boundType = boundType.substitute2(argumentTypes, parameterTypes); |
| + } |
| + if (!_typeSystem.isSubtypeOf(argType, boundType)) { |
| + reportError(argTypeName, argType, boundType); |
| + } |
| + } |
| + } |
| + } |
| + |
| DartType _computeReturnTypeForMethod(Expression returnExpression) { |
| // This method should never be called for generators, since generators are |
| // never allowed to contain return statements with expressions. |