Skip to content

Commit

Permalink
Report TYPE_ARGUMENT_NOT_MATCHING_BOUNDS for extension overrides.
Browse files Browse the repository at this point in the history
R=brianwilkerson@google.com

Change-Id: I1ad9c98707dbdb8b03c8b5bd014e9c174d365bcc
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/112860
Reviewed-by: Brian Wilkerson <brianwilkerson@google.com>
Commit-Queue: Konstantin Shcheglov <scheglov@google.com>
  • Loading branch information
scheglov authored and commit-bot@chromium.org committed Aug 13, 2019
1 parent 974bee0 commit cd46a39
Show file tree
Hide file tree
Showing 3 changed files with 80 additions and 6 deletions.
39 changes: 36 additions & 3 deletions pkg/analyzer/lib/src/dart/resolver/extension_member_resolver.dart
Original file line number Diff line number Diff line change
Expand Up @@ -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(
Expand Down Expand Up @@ -148,6 +157,30 @@ class ExtensionMemberResolver {
InferenceContext.setType(receiver, extendedForDownward);
}

void _checkTypeArgumentsMatchingBounds(
List<TypeParameterElement> typeParameters,
TypeArgumentList typeArgumentList,
List<DartType> 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(
Expand Down
5 changes: 2 additions & 3 deletions pkg/analyzer/lib/src/generated/error_verifier.dart
Original file line number Diff line number Diff line change
Expand Up @@ -887,12 +887,11 @@ class ErrorVerifier extends RecursiveAstVisitor<void> {
@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) &&
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,19 @@
// 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';

main() {
defineReflectiveSuite(() {
defineReflectiveTests(TypeArgumentNotMatchingBoundsTest);
defineReflectiveTests(
TypeArgumentNotMatchingBoundsWithExtensionMethodsTest,
);
});
}

Expand Down Expand Up @@ -303,3 +308,40 @@ class C extends Object with G<B>{}
]);
}
}

@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<T extends num> on int {
void foo() {}
}
void f() {
E<String>(0).foo();
}
''', [
error(CompileTimeErrorCode.TYPE_ARGUMENT_NOT_MATCHING_BOUNDS, 70, 6),
]);
}

test_extensionOverride_hasTypeArguments_call() async {
await assertErrorsInCode(r'''
extension E<T extends num> on int {
void call() {}
}
void f() {
E<String>(0)();
}
''', [
error(CompileTimeErrorCode.TYPE_ARGUMENT_NOT_MATCHING_BOUNDS, 71, 6),
]);
}
}

0 comments on commit cd46a39

Please sign in to comment.