Issue 45579. Report WRONG_NUMBER_OF_TYPE_ARGUMENTS and TYPE_ARGUMENT_NOT_MATCHING_BOUNDS.
Bug: https://github.com/dart-lang/sdk/issues/45579
Change-Id: I757f4d782895fb1a9c89d8238a7929e12d6a6eed
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/194000
Reviewed-by: Brian Wilkerson <brianwilkerson@google.com>
Commit-Queue: Konstantin Shcheglov <scheglov@google.com>
diff --git a/pkg/analyzer/lib/src/dart/resolver/annotation_resolver.dart b/pkg/analyzer/lib/src/dart/resolver/annotation_resolver.dart
index c82e332..efa3e86c 100644
--- a/pkg/analyzer/lib/src/dart/resolver/annotation_resolver.dart
+++ b/pkg/analyzer/lib/src/dart/resolver/annotation_resolver.dart
@@ -14,6 +14,7 @@
import 'package:analyzer/src/dart/element/element.dart';
import 'package:analyzer/src/dart/element/member.dart';
import 'package:analyzer/src/dart/element/type.dart';
+import 'package:analyzer/src/dart/element/type_algebra.dart';
import 'package:analyzer/src/dart/resolver/invocation_inference_helper.dart';
import 'package:analyzer/src/error/codes.dart';
import 'package:analyzer/src/generated/resolver.dart';
@@ -65,6 +66,7 @@
_constructorInvocation(
node,
+ classElement.name,
constructorName,
classElement.typeParameters,
constructorElement,
@@ -113,6 +115,7 @@
void _constructorInvocation(
AnnotationImpl node,
+ String typeDisplayName,
SimpleIdentifierImpl? constructorName,
List<TypeParameterElement> typeParameters,
ConstructorElement? constructorElement,
@@ -136,6 +139,18 @@
// If no type parameters, the elements are correct.
if (typeParameters.isEmpty) {
+ var typeArgumentList = node.typeArguments;
+ if (typeArgumentList != null) {
+ _errorReporter.reportErrorForNode(
+ CompileTimeErrorCode.WRONG_NUMBER_OF_TYPE_ARGUMENTS,
+ typeArgumentList,
+ [
+ typeDisplayName,
+ typeParameters.length,
+ typeArgumentList.arguments.length,
+ ],
+ );
+ }
_resolveConstructorInvocationArguments(node);
InferenceContext.setType(argumentList, constructorElement.type);
_resolver.visitArgumentList(argumentList,
@@ -174,7 +189,35 @@
typeArguments = typeArgumentList.arguments
.map((element) => element.typeOrThrow)
.toList();
+ var substitution = Substitution.fromPairs(
+ typeParameters,
+ typeArguments,
+ );
+ for (var i = 0; i < typeParameters.length; i++) {
+ var typeParameter = typeParameters[i];
+ var bound = typeParameter.bound;
+ if (bound != null) {
+ bound = substitution.substituteType(bound);
+ var typeArgument = typeArguments[i];
+ if (!_resolver.typeSystem.isSubtypeOf(typeArgument, bound)) {
+ _errorReporter.reportErrorForNode(
+ CompileTimeErrorCode.TYPE_ARGUMENT_NOT_MATCHING_BOUNDS,
+ typeArgumentList.arguments[i],
+ [typeArgument, typeParameter.name, bound],
+ );
+ }
+ }
+ }
} else {
+ _errorReporter.reportErrorForNode(
+ CompileTimeErrorCode.WRONG_NUMBER_OF_TYPE_ARGUMENTS,
+ typeArgumentList,
+ [
+ typeDisplayName,
+ typeParameters.length,
+ typeArgumentList.arguments.length,
+ ],
+ );
typeArguments = List.filled(
typeParameters.length,
DynamicTypeImpl.instance,
@@ -458,6 +501,7 @@
_constructorInvocation(
node,
+ typeAliasElement.name,
constructorName,
typeAliasElement.typeParameters,
constructorElement,
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 9d407aa..25184c2 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
@@ -471,6 +471,45 @@
''');
}
+ test_metadata_matching() async {
+ await assertNoErrorsInCode(r'''
+class A<T extends num> {
+ const A();
+}
+
+@A<int>()
+void f() {}
+''');
+ }
+
+ test_metadata_notMatching() async {
+ await assertErrorsInCode(r'''
+class A<T extends num> {
+ const A();
+}
+
+@A<String>()
+void f() {}
+''', [
+ error(CompileTimeErrorCode.TYPE_ARGUMENT_NOT_MATCHING_BOUNDS, 44, 6),
+ ]);
+ }
+
+ test_metadata_notMatching_viaTypeAlias() async {
+ await assertErrorsInCode(r'''
+class A<T> {
+ const A();
+}
+
+typedef B<T extends num> = A<T>;
+
+@B<String>()
+void f() {}
+''', [
+ error(CompileTimeErrorCode.TYPE_ARGUMENT_NOT_MATCHING_BOUNDS, 66, 6),
+ ]);
+ }
+
test_methodInvocation_genericFunctionTypeArgument_match() async {
await assertNoErrorsInCode(r'''
typedef F = void Function<T extends num>();
diff --git a/pkg/analyzer/test/src/diagnostics/wrong_number_of_type_arguments_test.dart b/pkg/analyzer/test/src/diagnostics/wrong_number_of_type_arguments_test.dart
index 29e3eee..6754881 100644
--- a/pkg/analyzer/test/src/diagnostics/wrong_number_of_type_arguments_test.dart
+++ b/pkg/analyzer/test/src/diagnostics/wrong_number_of_type_arguments_test.dart
@@ -93,6 +93,90 @@
]);
}
+ test_metadata_1of0() async {
+ await assertErrorsInCode(r'''
+class A {
+ const A();
+}
+
+@A<int>()
+void f() {}
+''', [
+ error(CompileTimeErrorCode.WRONG_NUMBER_OF_TYPE_ARGUMENTS, 28, 5),
+ ]);
+ }
+
+ test_metadata_1of0_viaTypeAlias() async {
+ await assertErrorsInCode(r'''
+class A {
+ const A();
+}
+
+typedef B = A;
+
+@B<int>()
+void f() {}
+''', [
+ error(CompileTimeErrorCode.WRONG_NUMBER_OF_TYPE_ARGUMENTS, 44, 5),
+ ]);
+ }
+
+ test_metadata_1of2() async {
+ await assertErrorsInCode(r'''
+class A<T, U> {
+ const A();
+}
+
+@A<int>()
+void f() {}
+''', [
+ error(CompileTimeErrorCode.WRONG_NUMBER_OF_TYPE_ARGUMENTS, 34, 5),
+ ]);
+ }
+
+ test_metadata_1of2_viaTypeAlias() async {
+ await assertErrorsInCode(r'''
+class A {
+ const A();
+}
+
+typedef B<T, U> = A;
+
+@B<int>()
+void f() {}
+''', [
+ error(CompileTimeErrorCode.WRONG_NUMBER_OF_TYPE_ARGUMENTS, 50, 5),
+ ]);
+ }
+
+ test_metadata_2of1() async {
+ await assertErrorsInCode(r'''
+class A<T> {
+ const A();
+}
+
+@A<int, String>()
+void f() {}
+''', [
+ error(CompileTimeErrorCode.WRONG_NUMBER_OF_TYPE_ARGUMENTS, 31, 13),
+ ]);
+ }
+
+ test_metadata_2of1_viaTypeAlias() async {
+ await assertErrorsInCode(r'''
+class A {
+ const A();
+}
+
+typedef B<T> = A;
+
+@B<int, String>()
+void f() {}
+''', [
+ error(CompileTimeErrorCode.WRONG_NUMBER_OF_TYPE_ARGUMENTS, 47, 13),
+ ]);
+ }
+
test_new_nonGeneric() async {
await assertErrorsInCode('''
class C {}