diff --git a/pkg/analyzer/lib/src/dart/resolver/extension_member_resolver.dart b/pkg/analyzer/lib/src/dart/resolver/extension_member_resolver.dart index 9c06f68801b6..13333996d027 100644 --- a/pkg/analyzer/lib/src/dart/resolver/extension_member_resolver.dart +++ b/pkg/analyzer/lib/src/dart/resolver/extension_member_resolver.dart @@ -94,12 +94,21 @@ class ExtensionMemberResolver { var receiverType = receiverExpression.staticType; var typeArgumentTypes = _inferTypeArguments(node, receiverType); - nodeImpl.typeArgumentTypes = typeArgumentTypes; - nodeImpl.extendedType = Substitution.fromPairs( + + var substitution = Substitution.fromPairs( typeParameters, typeArgumentTypes, - ).substituteType(element.extendedType); + ); + + nodeImpl.extendedType = substitution.substituteType(element.extendedType); + + _checkTypeArgumentsMatchingBounds( + typeParameters, + node.typeArguments, + typeArgumentTypes, + substitution, + ); if (!_typeSystem.isAssignableTo(receiverType, node.extendedType)) { _errorReporter.reportErrorForNode( @@ -148,6 +157,30 @@ class ExtensionMemberResolver { InferenceContext.setType(receiver, extendedForDownward); } + void _checkTypeArgumentsMatchingBounds( + List typeParameters, + TypeArgumentList typeArgumentList, + List typeArgumentTypes, + Substitution substitution, + ) { + if (typeArgumentList != null) { + for (var i = 0; i < typeArgumentTypes.length; i++) { + var argType = typeArgumentTypes[i]; + var boundType = typeParameters[i].bound; + if (boundType != null) { + boundType = substitution.substituteType(boundType); + if (!_typeSystem.isSubtypeOf(argType, boundType)) { + _errorReporter.reportTypeErrorForNode( + CompileTimeErrorCode.TYPE_ARGUMENT_NOT_MATCHING_BOUNDS, + typeArgumentList.arguments[i], + [argType, boundType], + ); + } + } + } + } + } + /// Return the most specific extension or `null` if no single one can be /// identified. _InstantiatedExtension _chooseMostSpecific( diff --git a/pkg/analyzer/lib/src/generated/error_verifier.dart b/pkg/analyzer/lib/src/generated/error_verifier.dart index 4144ae249d7e..6174f6d054e7 100644 --- a/pkg/analyzer/lib/src/generated/error_verifier.dart +++ b/pkg/analyzer/lib/src/generated/error_verifier.dart @@ -887,12 +887,11 @@ class ErrorVerifier extends RecursiveAstVisitor { @override void visitFunctionExpressionInvocation(FunctionExpressionInvocation node) { Expression functionExpression = node.function; + if (functionExpression is ExtensionOverride) { - // TODO(brianwilkerson) Update `_checkTypeArguments` to handle extension - // overrides. -// _checkTypeArguments(node); return super.visitFunctionExpressionInvocation(node); } + DartType expressionType = functionExpression.staticType; if (!_checkForNullableDereference(functionExpression) && !_checkForUseOfVoidResult(functionExpression) && diff --git a/pkg/analyzer/test/src/diagnostics/type_argument_not_matching_bounds_test.dart b/pkg/analyzer/test/src/diagnostics/type_argument_not_matching_bounds_test.dart index d32a0124b768..e1c52d5fb11e 100644 --- a/pkg/analyzer/test/src/diagnostics/type_argument_not_matching_bounds_test.dart +++ b/pkg/analyzer/test/src/diagnostics/type_argument_not_matching_bounds_test.dart @@ -2,7 +2,9 @@ // for details. All rights reserved. Use of this source code is governed by a // BSD-style license that can be found in the LICENSE file. +import 'package:analyzer/dart/analysis/features.dart'; import 'package:analyzer/src/error/codes.dart'; +import 'package:analyzer/src/generated/engine.dart' show AnalysisOptionsImpl; import 'package:test_reflective_loader/test_reflective_loader.dart'; import '../dart/resolution/driver_resolution.dart'; @@ -10,6 +12,9 @@ import '../dart/resolution/driver_resolution.dart'; main() { defineReflectiveSuite(() { defineReflectiveTests(TypeArgumentNotMatchingBoundsTest); + defineReflectiveTests( + TypeArgumentNotMatchingBoundsWithExtensionMethodsTest, + ); }); } @@ -303,3 +308,40 @@ class C extends Object with G{} ]); } } + +@reflectiveTest +class TypeArgumentNotMatchingBoundsWithExtensionMethodsTest + extends DriverResolutionTest { + @override + AnalysisOptionsImpl get analysisOptions => AnalysisOptionsImpl() + ..contextFeatures = new FeatureSet.forTesting( + sdkVersion: '2.3.0', additionalFeatures: [Feature.extension_methods]); + + test_extensionOverride_hasTypeArguments() async { + await assertErrorsInCode(r''' +extension E on int { + void foo() {} +} + +void f() { + E(0).foo(); +} +''', [ + error(CompileTimeErrorCode.TYPE_ARGUMENT_NOT_MATCHING_BOUNDS, 70, 6), + ]); + } + + test_extensionOverride_hasTypeArguments_call() async { + await assertErrorsInCode(r''' +extension E on int { + void call() {} +} + +void f() { + E(0)(); +} +''', [ + error(CompileTimeErrorCode.TYPE_ARGUMENT_NOT_MATCHING_BOUNDS, 71, 6), + ]); + } +}