Skip to content

Commit cd46a39

Browse files
scheglovcommit-bot@chromium.org
authored andcommitted
Report TYPE_ARGUMENT_NOT_MATCHING_BOUNDS for extension overrides.
[email protected] Change-Id: I1ad9c98707dbdb8b03c8b5bd014e9c174d365bcc Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/112860 Reviewed-by: Brian Wilkerson <[email protected]> Commit-Queue: Konstantin Shcheglov <[email protected]>
1 parent 974bee0 commit cd46a39

File tree

3 files changed

+80
-6
lines changed

3 files changed

+80
-6
lines changed

pkg/analyzer/lib/src/dart/resolver/extension_member_resolver.dart

Lines changed: 36 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -94,12 +94,21 @@ class ExtensionMemberResolver {
9494
var receiverType = receiverExpression.staticType;
9595

9696
var typeArgumentTypes = _inferTypeArguments(node, receiverType);
97-
9897
nodeImpl.typeArgumentTypes = typeArgumentTypes;
99-
nodeImpl.extendedType = Substitution.fromPairs(
98+
99+
var substitution = Substitution.fromPairs(
100100
typeParameters,
101101
typeArgumentTypes,
102-
).substituteType(element.extendedType);
102+
);
103+
104+
nodeImpl.extendedType = substitution.substituteType(element.extendedType);
105+
106+
_checkTypeArgumentsMatchingBounds(
107+
typeParameters,
108+
node.typeArguments,
109+
typeArgumentTypes,
110+
substitution,
111+
);
103112

104113
if (!_typeSystem.isAssignableTo(receiverType, node.extendedType)) {
105114
_errorReporter.reportErrorForNode(
@@ -148,6 +157,30 @@ class ExtensionMemberResolver {
148157
InferenceContext.setType(receiver, extendedForDownward);
149158
}
150159

160+
void _checkTypeArgumentsMatchingBounds(
161+
List<TypeParameterElement> typeParameters,
162+
TypeArgumentList typeArgumentList,
163+
List<DartType> typeArgumentTypes,
164+
Substitution substitution,
165+
) {
166+
if (typeArgumentList != null) {
167+
for (var i = 0; i < typeArgumentTypes.length; i++) {
168+
var argType = typeArgumentTypes[i];
169+
var boundType = typeParameters[i].bound;
170+
if (boundType != null) {
171+
boundType = substitution.substituteType(boundType);
172+
if (!_typeSystem.isSubtypeOf(argType, boundType)) {
173+
_errorReporter.reportTypeErrorForNode(
174+
CompileTimeErrorCode.TYPE_ARGUMENT_NOT_MATCHING_BOUNDS,
175+
typeArgumentList.arguments[i],
176+
[argType, boundType],
177+
);
178+
}
179+
}
180+
}
181+
}
182+
}
183+
151184
/// Return the most specific extension or `null` if no single one can be
152185
/// identified.
153186
_InstantiatedExtension _chooseMostSpecific(

pkg/analyzer/lib/src/generated/error_verifier.dart

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -887,12 +887,11 @@ class ErrorVerifier extends RecursiveAstVisitor<void> {
887887
@override
888888
void visitFunctionExpressionInvocation(FunctionExpressionInvocation node) {
889889
Expression functionExpression = node.function;
890+
890891
if (functionExpression is ExtensionOverride) {
891-
// TODO(brianwilkerson) Update `_checkTypeArguments` to handle extension
892-
// overrides.
893-
// _checkTypeArguments(node);
894892
return super.visitFunctionExpressionInvocation(node);
895893
}
894+
896895
DartType expressionType = functionExpression.staticType;
897896
if (!_checkForNullableDereference(functionExpression) &&
898897
!_checkForUseOfVoidResult(functionExpression) &&

pkg/analyzer/test/src/diagnostics/type_argument_not_matching_bounds_test.dart

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,14 +2,19 @@
22
// for details. All rights reserved. Use of this source code is governed by a
33
// BSD-style license that can be found in the LICENSE file.
44

5+
import 'package:analyzer/dart/analysis/features.dart';
56
import 'package:analyzer/src/error/codes.dart';
7+
import 'package:analyzer/src/generated/engine.dart' show AnalysisOptionsImpl;
68
import 'package:test_reflective_loader/test_reflective_loader.dart';
79

810
import '../dart/resolution/driver_resolution.dart';
911

1012
main() {
1113
defineReflectiveSuite(() {
1214
defineReflectiveTests(TypeArgumentNotMatchingBoundsTest);
15+
defineReflectiveTests(
16+
TypeArgumentNotMatchingBoundsWithExtensionMethodsTest,
17+
);
1318
});
1419
}
1520

@@ -303,3 +308,40 @@ class C extends Object with G<B>{}
303308
]);
304309
}
305310
}
311+
312+
@reflectiveTest
313+
class TypeArgumentNotMatchingBoundsWithExtensionMethodsTest
314+
extends DriverResolutionTest {
315+
@override
316+
AnalysisOptionsImpl get analysisOptions => AnalysisOptionsImpl()
317+
..contextFeatures = new FeatureSet.forTesting(
318+
sdkVersion: '2.3.0', additionalFeatures: [Feature.extension_methods]);
319+
320+
test_extensionOverride_hasTypeArguments() async {
321+
await assertErrorsInCode(r'''
322+
extension E<T extends num> on int {
323+
void foo() {}
324+
}
325+
326+
void f() {
327+
E<String>(0).foo();
328+
}
329+
''', [
330+
error(CompileTimeErrorCode.TYPE_ARGUMENT_NOT_MATCHING_BOUNDS, 70, 6),
331+
]);
332+
}
333+
334+
test_extensionOverride_hasTypeArguments_call() async {
335+
await assertErrorsInCode(r'''
336+
extension E<T extends num> on int {
337+
void call() {}
338+
}
339+
340+
void f() {
341+
E<String>(0)();
342+
}
343+
''', [
344+
error(CompileTimeErrorCode.TYPE_ARGUMENT_NOT_MATCHING_BOUNDS, 71, 6),
345+
]);
346+
}
347+
}

0 commit comments

Comments
 (0)