From d8e2cdaeec1f1eba31b564e975c64fcb030d2cc5 Mon Sep 17 00:00:00 2001 From: Konstantin Shcheglov Date: Tue, 8 Feb 2022 19:50:36 +0000 Subject: [PATCH] Report WRONG_NUMBER_OF_TYPE_ARGUMENTS_ENUM and TYPE_ARGUMENT_NOT_MATCHING_BOUNDS for enums. Change-Id: Icac828fa09d7565974727521c27b5cd4daa7e0f4 Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/232089 Reviewed-by: Brian Wilkerson Commit-Queue: Konstantin Shcheglov --- pkg/analyzer/lib/error/error.dart | 1 + pkg/analyzer/lib/src/error/codes.g.dart | 13 +++++ .../src/error/type_arguments_verifier.dart | 49 +++++++++++++++++++ .../lib/src/generated/error_verifier.dart | 1 + pkg/analyzer/messages.yaml | 7 +++ .../test/src/diagnostics/test_all.dart | 3 ++ ...ype_argument_not_matching_bounds_test.dart | 29 +++++++++++ ...ng_number_of_type_arguments_enum_test.dart | 37 ++++++++++++++ 8 files changed, 140 insertions(+) create mode 100644 pkg/analyzer/test/src/diagnostics/wrong_number_of_type_arguments_enum_test.dart diff --git a/pkg/analyzer/lib/error/error.dart b/pkg/analyzer/lib/error/error.dart index b2341421346..c43d2d6e80c 100644 --- a/pkg/analyzer/lib/error/error.dart +++ b/pkg/analyzer/lib/error/error.dart @@ -486,6 +486,7 @@ const List errorCodeValues = [ CompileTimeErrorCode.WRONG_NUMBER_OF_TYPE_ARGUMENTS, CompileTimeErrorCode.WRONG_NUMBER_OF_TYPE_ARGUMENTS_ANONYMOUS_FUNCTION, CompileTimeErrorCode.WRONG_NUMBER_OF_TYPE_ARGUMENTS_CONSTRUCTOR, + CompileTimeErrorCode.WRONG_NUMBER_OF_TYPE_ARGUMENTS_ENUM, CompileTimeErrorCode.WRONG_NUMBER_OF_TYPE_ARGUMENTS_EXTENSION, CompileTimeErrorCode.WRONG_NUMBER_OF_TYPE_ARGUMENTS_FUNCTION, CompileTimeErrorCode.WRONG_NUMBER_OF_TYPE_ARGUMENTS_METHOD, diff --git a/pkg/analyzer/lib/src/error/codes.g.dart b/pkg/analyzer/lib/src/error/codes.g.dart index 9758ede1041..16f20e911ae 100644 --- a/pkg/analyzer/lib/src/error/codes.g.dart +++ b/pkg/analyzer/lib/src/error/codes.g.dart @@ -15893,6 +15893,19 @@ class CompileTimeErrorCode extends AnalyzerErrorCode { hasPublishedDocs: true, ); + /** + * Parameters: + * 0: the number of type parameters that were declared + * 1: the number of type arguments provided + */ + static const CompileTimeErrorCode WRONG_NUMBER_OF_TYPE_ARGUMENTS_ENUM = + CompileTimeErrorCode( + 'WRONG_NUMBER_OF_TYPE_ARGUMENTS_ENUM', + "The enum is declared with {0} type parameters, but {1} type arguments " + "were given.", + correctionMessage: "Try adjusting the number of type arguments.", + ); + /** * Parameters: * 0: the name of the extension being referenced diff --git a/pkg/analyzer/lib/src/error/type_arguments_verifier.dart b/pkg/analyzer/lib/src/error/type_arguments_verifier.dart index 1488253d7ca..db01b0bc6ef 100644 --- a/pkg/analyzer/lib/src/error/type_arguments_verifier.dart +++ b/pkg/analyzer/lib/src/error/type_arguments_verifier.dart @@ -91,6 +91,55 @@ class TypeArgumentsVerifier { } } + void checkEnumConstantDeclaration(EnumConstantDeclaration node) { + var constructorElement = node.constructorElement; + if (constructorElement == null) { + return; + } + + var enumElement = constructorElement.enclosingElement; + var typeParameters = enumElement.typeParameters; + + var typeArgumentList = node.arguments?.typeArguments; + var typeArgumentNodes = typeArgumentList?.arguments; + if (typeArgumentList != null && + typeArgumentNodes != null && + typeArgumentNodes.length != typeParameters.length) { + _errorReporter.reportErrorForNode( + CompileTimeErrorCode.WRONG_NUMBER_OF_TYPE_ARGUMENTS_ENUM, + typeArgumentList, + [typeParameters.length, typeArgumentNodes.length], + ); + } + + if (typeParameters.isEmpty) { + return; + } + + // Check that type arguments are regular-bounded. + var typeArguments = constructorElement.returnType.typeArguments; + var substitution = Substitution.fromPairs(typeParameters, typeArguments); + for (var i = 0; i < typeArguments.length; i++) { + var typeParameter = typeParameters[i]; + var typeArgument = typeArguments[i]; + + var bound = typeParameter.bound; + if (bound == null) { + continue; + } + + bound = substitution.substituteType(bound); + + if (!_typeSystem.isSubtypeOf(typeArgument, bound)) { + _errorReporter.reportErrorForNode( + CompileTimeErrorCode.TYPE_ARGUMENT_NOT_MATCHING_BOUNDS, + typeArgumentNodes?[i] ?? node.name, + [typeArgument, typeParameter.name, bound], + ); + } + } + } + void checkFunctionExpressionInvocation(FunctionExpressionInvocation node) { _checkInvocationTypeArguments( node.typeArguments?.arguments, diff --git a/pkg/analyzer/lib/src/generated/error_verifier.dart b/pkg/analyzer/lib/src/generated/error_verifier.dart index 36d3095347d..1acd7b19372 100644 --- a/pkg/analyzer/lib/src/generated/error_verifier.dart +++ b/pkg/analyzer/lib/src/generated/error_verifier.dart @@ -560,6 +560,7 @@ class ErrorVerifier extends RecursiveAstVisitor @override void visitEnumConstantDeclaration(EnumConstantDeclaration node) { _requiredParametersVerifier.visitEnumConstantDeclaration(node); + _typeArgumentsVerifier.checkEnumConstantDeclaration(node); super.visitEnumConstantDeclaration(node); } diff --git a/pkg/analyzer/messages.yaml b/pkg/analyzer/messages.yaml index 86820351401..3c90ccdc48e 100644 --- a/pkg/analyzer/messages.yaml +++ b/pkg/analyzer/messages.yaml @@ -13632,6 +13632,13 @@ CompileTimeErrorCode: } C f() => C.named(); ``` + WRONG_NUMBER_OF_TYPE_ARGUMENTS_ENUM: + problemMessage: The enum is declared with {0} type parameters, but {1} type arguments were given. + correctionMessage: Try adjusting the number of type arguments. + comment: |- + Parameters: + 0: the number of type parameters that were declared + 1: the number of type arguments provided WRONG_NUMBER_OF_TYPE_ARGUMENTS_EXTENSION: problemMessage: "The extension '{0}' is declared with {1} type parameters, but {2} type arguments were given." correctionMessage: Try adjusting the number of type arguments. diff --git a/pkg/analyzer/test/src/diagnostics/test_all.dart b/pkg/analyzer/test/src/diagnostics/test_all.dart index 3fddbedb69b..a98026b30b0 100644 --- a/pkg/analyzer/test/src/diagnostics/test_all.dart +++ b/pkg/analyzer/test/src/diagnostics/test_all.dart @@ -776,6 +776,8 @@ import 'wrong_number_of_parameters_for_operator_test.dart' as wrong_number_of_parameters_for_operator; import 'wrong_number_of_parameters_for_setter_test.dart' as wrong_number_of_parameters_for_setter; +import 'wrong_number_of_type_arguments_enum_test.dart' + as wrong_number_of_type_arguments_enum; import 'wrong_number_of_type_arguments_extension_test.dart' as wrong_number_of_type_arguments_extension; import 'wrong_number_of_type_arguments_test.dart' @@ -1306,6 +1308,7 @@ main() { void_with_type_arguments_test.main(); wrong_number_of_parameters_for_operator.main(); wrong_number_of_parameters_for_setter.main(); + wrong_number_of_type_arguments_enum.main(); wrong_number_of_type_arguments_extension.main(); wrong_number_of_type_arguments.main(); wrong_type_parameter_variance_in_superinterface.main(); 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 3149899b2c4..2aea1940b5c 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 @@ -431,6 +431,35 @@ class C extends Object with G{} class TypeArgumentNotMatchingBoundsWithNullSafetyTest extends PubPackageResolutionTest with TypeArgumentNotMatchingBoundsTestCases { + test_enum_inferred() async { + await assertErrorsInCode(''' +enum E { + v(''); + const E(T t); +} +''', [ + error(CompileTimeErrorCode.TYPE_ARGUMENT_NOT_MATCHING_BOUNDS, 26, 1), + ]); + } + + test_enum_superBounded() async { + await assertNoErrorsInCode(''' +enum E> { + v() +} +'''); + } + + test_enum_withTypeArguments() async { + await assertErrorsInCode(''' +enum E { + v() +} +''', [ + error(CompileTimeErrorCode.TYPE_ARGUMENT_NOT_MATCHING_BOUNDS, 28, 6), + ]); + } + test_extends_optIn_fromOptOut_Null() async { newFile('$testPackageLibPath/a.dart', content: r''' class A {} diff --git a/pkg/analyzer/test/src/diagnostics/wrong_number_of_type_arguments_enum_test.dart b/pkg/analyzer/test/src/diagnostics/wrong_number_of_type_arguments_enum_test.dart new file mode 100644 index 00000000000..60e12c92b14 --- /dev/null +++ b/pkg/analyzer/test/src/diagnostics/wrong_number_of_type_arguments_enum_test.dart @@ -0,0 +1,37 @@ +// Copyright (c) 2022, the Dart project authors. Please see the AUTHORS file +// 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/src/error/codes.dart'; +import 'package:test_reflective_loader/test_reflective_loader.dart'; + +import '../dart/resolution/context_collection_resolution.dart'; + +main() { + defineReflectiveSuite(() { + defineReflectiveTests(WrongNumberOfTypeArgumentsEnumTest); + }); +} + +@reflectiveTest +class WrongNumberOfTypeArgumentsEnumTest extends PubPackageResolutionTest { + test_tooFew() async { + await assertErrorsInCode(r''' +enum E { + v() +} +''', [ + error(CompileTimeErrorCode.WRONG_NUMBER_OF_TYPE_ARGUMENTS_ENUM, 18, 5), + ]); + } + + test_tooMany() async { + await assertErrorsInCode(r''' +enum E { + v() +} +''', [ + error(CompileTimeErrorCode.WRONG_NUMBER_OF_TYPE_ARGUMENTS_ENUM, 15, 10), + ]); + } +}