diff --git a/CHANGELOG.md b/CHANGELOG.md index 4f6512f46df..944c8345ba3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,26 @@ +## 2.15.0 + +### Language + +- Annotations on type parameters of classes can no longer refer to class members + without a prefix. For example, this used to be permitted: + + ```dart + class C<@Annotation(foo) T> { + static void foo() {} + } + ``` + + Now, the reference must be qualified with the class name, i.e.: + + ```dart + class C<@Annotation(C.foo) T> { + static void foo() {} + } + ``` + + This brings the implementation behavior in line with the spec. + ## 2.14.0 ### Language diff --git a/pkg/analyzer/lib/src/generated/resolver.dart b/pkg/analyzer/lib/src/generated/resolver.dart index 9fad340990d..92573bd1903 100644 --- a/pkg/analyzer/lib/src/generated/resolver.dart +++ b/pkg/analyzer/lib/src/generated/resolver.dart @@ -2007,17 +2007,6 @@ class ResolverVisitor extends ResolverBase with ErrorDetectionHelpers { @override void visitTypeName(TypeName node) {} - @override - void visitTypeParameter(TypeParameter node) { - var previousThisType = _thisType; - try { - _setupThisType(); - super.visitTypeParameter(node); - } finally { - _thisType = previousThisType; - } - } - @override void visitVariableDeclaration(VariableDeclaration node) { _variableDeclarationResolver.resolve(node as VariableDeclarationImpl); diff --git a/pkg/analyzer/test/src/diagnostics/undefined_identifier_test.dart b/pkg/analyzer/test/src/diagnostics/undefined_identifier_test.dart index c339039bf98..c484dd0c2d8 100644 --- a/pkg/analyzer/test/src/diagnostics/undefined_identifier_test.dart +++ b/pkg/analyzer/test/src/diagnostics/undefined_identifier_test.dart @@ -43,61 +43,6 @@ void f(int value) { } mixin UndefinedIdentifierTestCases on PubPackageResolutionTest { - test_annotation_favors_scope_resolution_over_this_resolution_class() async { - // If an annotation on a class type parameter cannot be resolved using the - // normal scope resolution mechanism, it is resolved via implicit `this`. - // Note: this behavior doesn't match the spec so we may change it - see - // https://github.com/dart-lang/language/issues/1790 - await assertNoErrorsInCode(''' -class C<@Annotation.function(foo) @Annotation.type(B) T> { - static void foo() {} - static void B() {} -} -class B {} -class Annotation { - const Annotation.function(void Function() f); - const Annotation.type(Type t); -} -'''); - } - - test_annotation_favors_scope_resolution_over_this_resolution_extension() async { - // If an annotation on an extension type parameter cannot be resolved using - // the normal scope resolution mechanism, it is resolved via implicit - // `this`. Note: this behavior doesn't match the spec so we may change it - - // see https://github.com/dart-lang/language/issues/1790 - await assertNoErrorsInCode(''' -extension E<@Annotation.function(foo) @Annotation.type(B) T> on C {} -class C { - static void foo() {} - static void B() {} -} -class B {} -class Annotation { - const Annotation.function(void Function() f); - const Annotation.type(Type t); -} -'''); - } - - test_annotation_favors_scope_resolution_over_this_resolution_mixin() async { - // If an annotation on a mixin type parameter cannot be resolved using the - // normal scope resolution mechanism, it is resolved via implicit `this`. - // Note: this behavior doesn't match the spec so we may change it - see - // https://github.com/dart-lang/language/issues/1790 - await assertNoErrorsInCode(''' -mixin M<@Annotation.function(foo) @Annotation.type(B) T> { - static void foo() {} - static void B() {} -} -class B {} -class Annotation { - const Annotation.function(void Function() f); - const Annotation.type(Type t); -} -'''); - } - test_annotation_references_static_method_in_class() async { await assertErrorsInCode(''' @Annotation(foo) @@ -114,18 +59,19 @@ class Annotation { } test_annotation_references_static_method_in_class_from_type_parameter() async { - // It is allowed for an annotation of a class type parameter to refer to - // a method in a class (note: this doesn't match the spec but we currently - // test it to make sure we match CFE behavior - see - // https://github.com/dart-lang/language/issues/1790) - await assertNoErrorsInCode(''' + // It not is allowed for an annotation of a class type parameter to refer to + // a method in a class. + await assertErrorsInCode(''' class C<@Annotation(foo) T> { static void foo() {} } class Annotation { const Annotation(dynamic d); } -'''); +''', [ + error(CompileTimeErrorCode.UNDEFINED_IDENTIFIER, 20, 3), + error(CompileTimeErrorCode.CONST_WITH_NON_CONSTANT_ARGUMENT, 20, 3), + ]); } test_annotation_references_static_method_in_extension() async { @@ -144,18 +90,19 @@ class Annotation { } test_annotation_references_static_method_in_extension_from_type_parameter() async { - // It is allowed for an annotation of a mixin type parameter to refer to - // a method in a class (note: this doesn't match the spec but we currently - // test it to make sure we match CFE behavior - see - // https://github.com/dart-lang/language/issues/1790) - await assertNoErrorsInCode(''' + // It is not allowed for an annotation of an extension type parameter to + // refer to a method in a class. + await assertErrorsInCode(''' extension E<@Annotation(foo) T> on T { static void foo() {} } class Annotation { const Annotation(dynamic d); } -'''); +''', [ + error(CompileTimeErrorCode.CONST_WITH_NON_CONSTANT_ARGUMENT, 24, 3), + error(CompileTimeErrorCode.UNDEFINED_IDENTIFIER, 24, 3), + ]); } test_annotation_references_static_method_in_mixin() async { @@ -174,18 +121,80 @@ class Annotation { } test_annotation_references_static_method_in_mixin_from_type_parameter() async { - // It is allowed for an annotation of a mixin type parameter to refer to - // a method in a class (note: this doesn't match the spec but we currently - // test it to make sure we match CFE behavior - see - // https://github.com/dart-lang/language/issues/1790) - await assertNoErrorsInCode(''' + // It is not allowed for an annotation of a mixin type parameter to refer to + // a method in a class. + await assertErrorsInCode(''' mixin M<@Annotation(foo) T> { static void foo() {} } class Annotation { const Annotation(dynamic d); } -'''); +''', [ + error(CompileTimeErrorCode.UNDEFINED_IDENTIFIER, 20, 3), + error(CompileTimeErrorCode.CONST_WITH_NON_CONSTANT_ARGUMENT, 20, 3), + ]); + } + + test_annotation_uses_scope_resolution_class() async { + // If an annotation on a class type parameter cannot be resolved using the + // normal scope resolution mechanism, it is not resolved via implicit + // `this`. + await assertErrorsInCode(''' +class C<@Annotation.function(foo) @Annotation.type(B) T> { + static void foo() {} + static void B() {} +} +class B {} +class Annotation { + const Annotation.function(void Function() f); + const Annotation.type(Type t); +} +''', [ + error(CompileTimeErrorCode.UNDEFINED_IDENTIFIER, 29, 3), + error(CompileTimeErrorCode.CONST_WITH_NON_CONSTANT_ARGUMENT, 29, 3), + ]); + } + + test_annotation_uses_scope_resolution_extension() async { + // If an annotation on an extension type parameter cannot be resolved using + // the normal scope resolution mechanism, it is not resolved via implicit + // `this`. + await assertErrorsInCode(''' +extension E<@Annotation.function(foo) @Annotation.type(B) T> on C {} +class C { + static void foo() {} + static void B() {} +} +class B {} +class Annotation { + const Annotation.function(void Function() f); + const Annotation.type(Type t); +} +''', [ + error(CompileTimeErrorCode.CONST_WITH_NON_CONSTANT_ARGUMENT, 33, 3), + error(CompileTimeErrorCode.UNDEFINED_IDENTIFIER, 33, 3), + ]); + } + + test_annotation_uses_scope_resolution_mixin() async { + // If an annotation on a mixin type parameter cannot be resolved using the + // normal scope resolution mechanism, it is not resolved via implicit + // `this`. + await assertErrorsInCode(''' +mixin M<@Annotation.function(foo) @Annotation.type(B) T> { + static void foo() {} + static void B() {} +} +class B {} +class Annotation { + const Annotation.function(void Function() f); + const Annotation.type(Type t); +} +''', [ + error(CompileTimeErrorCode.UNDEFINED_IDENTIFIER, 29, 3), + error(CompileTimeErrorCode.CONST_WITH_NON_CONSTANT_ARGUMENT, 29, 3), + ]); } @failingTest diff --git a/pkg/front_end/lib/src/fasta/builder/class_builder.dart b/pkg/front_end/lib/src/fasta/builder/class_builder.dart index 5d66e3c13fe..eaf482ead21 100644 --- a/pkg/front_end/lib/src/fasta/builder/class_builder.dart +++ b/pkg/front_end/lib/src/fasta/builder/class_builder.dart @@ -354,12 +354,12 @@ abstract class ClassBuilderImpl extends DeclarationBuilderImpl delayedActionPerformers, synthesizedFunctionNodes); } - MetadataBuilder.buildAnnotations( - isPatch ? origin.cls : cls, metadata, library, this, null, fileUri); + MetadataBuilder.buildAnnotations(isPatch ? origin.cls : cls, metadata, + library, this, null, fileUri, library.scope); if (typeVariables != null) { for (int i = 0; i < typeVariables!.length; i++) { - typeVariables![i].buildOutlineExpressions( - library, this, null, coreTypes, delayedActionPerformers); + typeVariables![i].buildOutlineExpressions(library, this, null, + coreTypes, delayedActionPerformers, scope.parent!); } } diff --git a/pkg/front_end/lib/src/fasta/builder/field_builder.dart b/pkg/front_end/lib/src/fasta/builder/field_builder.dart index eceff880dd2..e898f399e27 100644 --- a/pkg/front_end/lib/src/fasta/builder/field_builder.dart +++ b/pkg/front_end/lib/src/fasta/builder/field_builder.dart @@ -400,8 +400,8 @@ class SourceFieldBuilder extends MemberBuilderImpl implements FieldBuilder { _fieldEncoding.completeSignature(coreTypes); for (Annotatable annotatable in _fieldEncoding.annotatables) { - MetadataBuilder.buildAnnotations( - annotatable, metadata, library, classBuilder, this, fileUri); + MetadataBuilder.buildAnnotations(annotatable, metadata, library, + classBuilder, this, fileUri, classBuilder?.scope ?? library.scope); } // For modular compilation we need to include initializers of all const diff --git a/pkg/front_end/lib/src/fasta/builder/function_builder.dart b/pkg/front_end/lib/src/fasta/builder/function_builder.dart index 71dc58a3e15..1d02cb5d946 100644 --- a/pkg/front_end/lib/src/fasta/builder/function_builder.dart +++ b/pkg/front_end/lib/src/fasta/builder/function_builder.dart @@ -486,8 +486,9 @@ abstract class FunctionBuilderImpl extends MemberBuilderImpl isClassMember || isExtensionMember ? parent as DeclarationBuilder : null; - MetadataBuilder.buildAnnotations( - member, metadata, library, classOrExtensionBuilder, this, fileUri); + Scope parentScope = classOrExtensionBuilder?.scope ?? library.scope; + MetadataBuilder.buildAnnotations(member, metadata, library, + classOrExtensionBuilder, this, fileUri, parentScope); if (typeVariables != null) { for (int i = 0; i < typeVariables!.length; i++) { typeVariables![i].buildOutlineExpressions( @@ -495,7 +496,8 @@ abstract class FunctionBuilderImpl extends MemberBuilderImpl classOrExtensionBuilder, this, coreTypes, - delayedActionPerformers); + delayedActionPerformers, + computeTypeParameterScope(parentScope)); } } diff --git a/pkg/front_end/lib/src/fasta/builder/metadata_builder.dart b/pkg/front_end/lib/src/fasta/builder/metadata_builder.dart index 21d767b4ccd..c4497b1bb85 100644 --- a/pkg/front_end/lib/src/fasta/builder/metadata_builder.dart +++ b/pkg/front_end/lib/src/fasta/builder/metadata_builder.dart @@ -30,14 +30,8 @@ class MetadataBuilder { SourceLibraryBuilder library, DeclarationBuilder? classOrExtensionBuilder, MemberBuilder? member, - Uri fileUri) { + Uri fileUri, Scope scope) { if (metadata == null) return; - Scope scope = parent is Library || - parent is Class || - parent is Extension || - classOrExtensionBuilder == null - ? library.scope - : classOrExtensionBuilder.scope; BodyBuilder bodyBuilder = library.loader .createBodyBuilderForOutlineExpression(library, classOrExtensionBuilder, member ?? classOrExtensionBuilder ?? library, scope, fileUri); diff --git a/pkg/front_end/lib/src/fasta/builder/type_variable_builder.dart b/pkg/front_end/lib/src/fasta/builder/type_variable_builder.dart index 9d91421a3b9..b6a6ed974cc 100644 --- a/pkg/front_end/lib/src/fasta/builder/type_variable_builder.dart +++ b/pkg/front_end/lib/src/fasta/builder/type_variable_builder.dart @@ -13,6 +13,7 @@ import '../fasta_codes.dart' templateInternalProblemUnfinishedTypeVariable, templateTypeArgumentsOnTypeVariable; +import '../scope.dart'; import '../source/source_library_builder.dart'; import '../util/helpers.dart'; @@ -200,9 +201,9 @@ class TypeVariableBuilder extends TypeDeclarationBuilderImpl { DeclarationBuilder? classOrExtensionBuilder, MemberBuilder? memberBuilder, CoreTypes coreTypes, - List delayedActionPerformers) { + List delayedActionPerformers, Scope scope) { MetadataBuilder.buildAnnotations(parameter, metadata, libraryBuilder, - classOrExtensionBuilder, memberBuilder, fileUri!); + classOrExtensionBuilder, memberBuilder, fileUri!, scope); } @override diff --git a/pkg/front_end/lib/src/fasta/source/source_extension_builder.dart b/pkg/front_end/lib/src/fasta/source/source_extension_builder.dart index 5ffcb206648..8bb753874fb 100644 --- a/pkg/front_end/lib/src/fasta/source/source_extension_builder.dart +++ b/pkg/front_end/lib/src/fasta/source/source_extension_builder.dart @@ -278,11 +278,11 @@ class SourceExtensionBuilder extends ExtensionBuilderImpl { List delayedActionPerformers, List synthesizedFunctionNodes) { MetadataBuilder.buildAnnotations(isPatch ? origin.extension : extension, - metadata, library, this, null, fileUri); + metadata, library, this, null, fileUri, library.scope); if (typeParameters != null) { for (int i = 0; i < typeParameters!.length; i++) { - typeParameters![i].buildOutlineExpressions( - library, this, null, coreTypes, delayedActionPerformers); + typeParameters![i].buildOutlineExpressions(library, this, null, + coreTypes, delayedActionPerformers, scope.parent!); } } diff --git a/pkg/front_end/lib/src/fasta/source/source_library_builder.dart b/pkg/front_end/lib/src/fasta/source/source_library_builder.dart index 4ed49c90b2e..5c4ebef3f87 100644 --- a/pkg/front_end/lib/src/fasta/source/source_library_builder.dart +++ b/pkg/front_end/lib/src/fasta/source/source_library_builder.dart @@ -2648,7 +2648,7 @@ class SourceLibraryBuilder extends LibraryBuilderImpl { @override void buildOutlineExpressions() { MetadataBuilder.buildAnnotations( - library, metadata, this, null, null, fileUri); + library, metadata, this, null, null, fileUri, scope); } /// Builds the core AST structures for [declaration] needed for the outline. diff --git a/pkg/front_end/lib/src/fasta/source/source_type_alias_builder.dart b/pkg/front_end/lib/src/fasta/source/source_type_alias_builder.dart index 5bdcbaab84d..a64606ef539 100644 --- a/pkg/front_end/lib/src/fasta/source/source_type_alias_builder.dart +++ b/pkg/front_end/lib/src/fasta/source/source_type_alias_builder.dart @@ -18,7 +18,9 @@ import '../fasta_codes.dart' show noLength, templateCyclicTypedef, templateTypeArgumentMismatch; import '../problems.dart' show unhandled; +import '../scope.dart'; +import '../builder/builder.dart'; import '../builder/class_builder.dart'; import '../builder/fixed_type_builder.dart'; import '../builder/formal_parameter_builder.dart'; @@ -256,11 +258,16 @@ class SourceTypeAliasBuilder extends TypeAliasBuilderImpl { List delayedActionPerformers, List synthesizedFunctionNodes) { MetadataBuilder.buildAnnotations( - typedef, metadata, library, null, null, fileUri); + typedef, metadata, library, null, null, fileUri, library.scope); if (typeVariables != null) { for (int i = 0; i < typeVariables!.length; i++) { typeVariables![i].buildOutlineExpressions( - library, null, null, coreTypes, delayedActionPerformers); + library, + null, + null, + coreTypes, + delayedActionPerformers, + computeTypeParameterScope(library.scope)); } } _tearOffDependencies?.forEach((Procedure tearOff, Member target) { @@ -273,6 +280,19 @@ class SourceTypeAliasBuilder extends TypeAliasBuilderImpl { }); } + Scope computeTypeParameterScope(Scope parent) { + if (typeVariables == null) return parent; + Map local = {}; + for (TypeVariableBuilder variable in typeVariables!) { + local[variable.name] = variable; + } + return new Scope( + local: local, + parent: parent, + debugName: "type parameter", + isModifiable: false); + } + Map? _tearOffDependencies; void buildTypedefTearOffs( diff --git a/tests/language/metadata/type_parameter_scope_inner_test.dart b/tests/language/metadata/type_parameter_scope_inner_test.dart new file mode 100644 index 00000000000..ecbb4a231b5 --- /dev/null +++ b/tests/language/metadata/type_parameter_scope_inner_test.dart @@ -0,0 +1,66 @@ +// Copyright (c) 2021, 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. + +// Test that metadata on a type parameter cannot refer to declarations in an +// inner scope. See https://github.com/dart-lang/language/issues/1790. + +class Annotation { + const Annotation(dynamic d); +} + +class Class<@Annotation(foo) T> { +// ^^^ +// [analyzer] COMPILE_TIME_ERROR.CONST_WITH_NON_CONSTANT_ARGUMENT +// [analyzer] COMPILE_TIME_ERROR.UNDEFINED_IDENTIFIER +// [cfe] Getter not found: 'foo'. + static void foo() {} +} + +void function<@Annotation(foo) T>(dynamic foo) { +// ^^^ +// [analyzer] COMPILE_TIME_ERROR.CONST_WITH_NON_CONSTANT_ARGUMENT +// [analyzer] COMPILE_TIME_ERROR.UNDEFINED_IDENTIFIER +// [cfe] Getter not found: 'foo'. + dynamic foo; +} + +extension Extension<@Annotation(foo) T> on Class { +// ^^^ +// [analyzer] COMPILE_TIME_ERROR.CONST_WITH_NON_CONSTANT_ARGUMENT +// [analyzer] COMPILE_TIME_ERROR.UNDEFINED_IDENTIFIER +// [cfe] Getter not found: 'foo'. + static void foo() {} + + void extensionMethod<@Annotation(foo) T, @Annotation(bar) U>() {} + // ^^^ + // [analyzer] COMPILE_TIME_ERROR.CONST_WITH_NON_CONSTANT_ARGUMENT + // [analyzer] COMPILE_TIME_ERROR.UNDEFINED_IDENTIFIER + // [cfe] Getter not found: 'bar'. +} + +class C { + void method<@Annotation(foo) T, @Annotation(bar) U>(dynamic foo) { + // ^^^ + // [analyzer] COMPILE_TIME_ERROR.CONST_WITH_NON_CONSTANT_ARGUMENT + // [analyzer] COMPILE_TIME_ERROR.UNDEFINED_IDENTIFIER + // [cfe] Getter not found: 'foo'. + dynamic foo; + } + + static void bar() {} +} + +mixin Mixin<@Annotation(foo) T> { +// ^^^ +// [analyzer] COMPILE_TIME_ERROR.CONST_WITH_NON_CONSTANT_ARGUMENT +// [analyzer] COMPILE_TIME_ERROR.UNDEFINED_IDENTIFIER +// [cfe] Getter not found: 'foo'. + static void foo() {} +} + +typedef Typedef<@Annotation(foo) T> = void Function(); +// ^^^ +// [analyzer] COMPILE_TIME_ERROR.CONST_WITH_NON_CONSTANT_ARGUMENT +// [analyzer] COMPILE_TIME_ERROR.UNDEFINED_IDENTIFIER +// [cfe] Getter not found: 'foo'. diff --git a/tests/language/metadata/type_parameter_scope_other_test.dart b/tests/language/metadata/type_parameter_scope_other_test.dart new file mode 100644 index 00000000000..d411e2f40a4 --- /dev/null +++ b/tests/language/metadata/type_parameter_scope_other_test.dart @@ -0,0 +1,51 @@ +// Copyright (c) 2021, 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. + +// Test that identifiers in type parameter metadata can refer to other type +// parameters in the same declaration; they are in scope and take precedence +// over top level declarations, even if this leads to compile errors. + +/// Top level declaration of T; nothing should resolve to this. +void T() {} + +class Annotation { + const Annotation(dynamic d); +} + +class Class {} +// ^ +// [analyzer] COMPILE_TIME_ERROR.CONST_WITH_NON_CONSTANT_ARGUMENT +// [cfe] Type variables can't be used in static members. + +void function() {} +// ^ +// [analyzer] COMPILE_TIME_ERROR.CONST_WITH_NON_CONSTANT_ARGUMENT +// [cfe] Type variables can't be used as constants. + +extension Extension on Map {} +// ^ +// [analyzer] COMPILE_TIME_ERROR.CONST_WITH_NON_CONSTANT_ARGUMENT +// [cfe] Type variables can't be used in static members. + +class C { + void method() {} + // ^ + // [analyzer] COMPILE_TIME_ERROR.CONST_WITH_NON_CONSTANT_ARGUMENT + // [cfe] Type variables can't be used as constants. +} + +mixin Mixin {} +// ^ +// [analyzer] COMPILE_TIME_ERROR.CONST_WITH_NON_CONSTANT_ARGUMENT +// [cfe] Type variables can't be used in static members. + +typedef void Typedef1(T t, U u); +// ^ +// [analyzer] COMPILE_TIME_ERROR.CONST_WITH_NON_CONSTANT_ARGUMENT +// [cfe] Type variables can't be used as constants. + +typedef Typedef2 = void Function(T t, U u); +// ^ +// [analyzer] COMPILE_TIME_ERROR.CONST_WITH_NON_CONSTANT_ARGUMENT +// [cfe] Type variables can't be used as constants. diff --git a/tests/language_2/metadata/type_parameter_scope_inner_test.dart b/tests/language_2/metadata/type_parameter_scope_inner_test.dart new file mode 100644 index 00000000000..ecbb4a231b5 --- /dev/null +++ b/tests/language_2/metadata/type_parameter_scope_inner_test.dart @@ -0,0 +1,66 @@ +// Copyright (c) 2021, 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. + +// Test that metadata on a type parameter cannot refer to declarations in an +// inner scope. See https://github.com/dart-lang/language/issues/1790. + +class Annotation { + const Annotation(dynamic d); +} + +class Class<@Annotation(foo) T> { +// ^^^ +// [analyzer] COMPILE_TIME_ERROR.CONST_WITH_NON_CONSTANT_ARGUMENT +// [analyzer] COMPILE_TIME_ERROR.UNDEFINED_IDENTIFIER +// [cfe] Getter not found: 'foo'. + static void foo() {} +} + +void function<@Annotation(foo) T>(dynamic foo) { +// ^^^ +// [analyzer] COMPILE_TIME_ERROR.CONST_WITH_NON_CONSTANT_ARGUMENT +// [analyzer] COMPILE_TIME_ERROR.UNDEFINED_IDENTIFIER +// [cfe] Getter not found: 'foo'. + dynamic foo; +} + +extension Extension<@Annotation(foo) T> on Class { +// ^^^ +// [analyzer] COMPILE_TIME_ERROR.CONST_WITH_NON_CONSTANT_ARGUMENT +// [analyzer] COMPILE_TIME_ERROR.UNDEFINED_IDENTIFIER +// [cfe] Getter not found: 'foo'. + static void foo() {} + + void extensionMethod<@Annotation(foo) T, @Annotation(bar) U>() {} + // ^^^ + // [analyzer] COMPILE_TIME_ERROR.CONST_WITH_NON_CONSTANT_ARGUMENT + // [analyzer] COMPILE_TIME_ERROR.UNDEFINED_IDENTIFIER + // [cfe] Getter not found: 'bar'. +} + +class C { + void method<@Annotation(foo) T, @Annotation(bar) U>(dynamic foo) { + // ^^^ + // [analyzer] COMPILE_TIME_ERROR.CONST_WITH_NON_CONSTANT_ARGUMENT + // [analyzer] COMPILE_TIME_ERROR.UNDEFINED_IDENTIFIER + // [cfe] Getter not found: 'foo'. + dynamic foo; + } + + static void bar() {} +} + +mixin Mixin<@Annotation(foo) T> { +// ^^^ +// [analyzer] COMPILE_TIME_ERROR.CONST_WITH_NON_CONSTANT_ARGUMENT +// [analyzer] COMPILE_TIME_ERROR.UNDEFINED_IDENTIFIER +// [cfe] Getter not found: 'foo'. + static void foo() {} +} + +typedef Typedef<@Annotation(foo) T> = void Function(); +// ^^^ +// [analyzer] COMPILE_TIME_ERROR.CONST_WITH_NON_CONSTANT_ARGUMENT +// [analyzer] COMPILE_TIME_ERROR.UNDEFINED_IDENTIFIER +// [cfe] Getter not found: 'foo'. diff --git a/tests/language_2/metadata/type_parameter_scope_other_test.dart b/tests/language_2/metadata/type_parameter_scope_other_test.dart new file mode 100644 index 00000000000..d411e2f40a4 --- /dev/null +++ b/tests/language_2/metadata/type_parameter_scope_other_test.dart @@ -0,0 +1,51 @@ +// Copyright (c) 2021, 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. + +// Test that identifiers in type parameter metadata can refer to other type +// parameters in the same declaration; they are in scope and take precedence +// over top level declarations, even if this leads to compile errors. + +/// Top level declaration of T; nothing should resolve to this. +void T() {} + +class Annotation { + const Annotation(dynamic d); +} + +class Class {} +// ^ +// [analyzer] COMPILE_TIME_ERROR.CONST_WITH_NON_CONSTANT_ARGUMENT +// [cfe] Type variables can't be used in static members. + +void function() {} +// ^ +// [analyzer] COMPILE_TIME_ERROR.CONST_WITH_NON_CONSTANT_ARGUMENT +// [cfe] Type variables can't be used as constants. + +extension Extension on Map {} +// ^ +// [analyzer] COMPILE_TIME_ERROR.CONST_WITH_NON_CONSTANT_ARGUMENT +// [cfe] Type variables can't be used in static members. + +class C { + void method() {} + // ^ + // [analyzer] COMPILE_TIME_ERROR.CONST_WITH_NON_CONSTANT_ARGUMENT + // [cfe] Type variables can't be used as constants. +} + +mixin Mixin {} +// ^ +// [analyzer] COMPILE_TIME_ERROR.CONST_WITH_NON_CONSTANT_ARGUMENT +// [cfe] Type variables can't be used in static members. + +typedef void Typedef1(T t, U u); +// ^ +// [analyzer] COMPILE_TIME_ERROR.CONST_WITH_NON_CONSTANT_ARGUMENT +// [cfe] Type variables can't be used as constants. + +typedef Typedef2 = void Function(T t, U u); +// ^ +// [analyzer] COMPILE_TIME_ERROR.CONST_WITH_NON_CONSTANT_ARGUMENT +// [cfe] Type variables can't be used as constants. diff --git a/tests/lib/mirrors/metadata_scope_test.dart b/tests/lib/mirrors/metadata_scope_test.dart index 8848d41d336..0596b39aba8 100644 --- a/tests/lib/mirrors/metadata_scope_test.dart +++ b/tests/lib/mirrors/metadata_scope_test.dart @@ -15,8 +15,10 @@ class Annotation { // Note there is no compile-time constant 'foo' in scope. In particular, A.foo // is not in scope here. -@Annotation(foo) // //# 01: compile-time error -class A<@Annotation(foo) T> { +@Annotation(foo) //# 01: compile-time error +class A< + @Annotation(foo) //# 02: compile-time error + T> { @Annotation(foo) static foo() {} diff --git a/tests/lib_2/mirrors/metadata_scope_test.dart b/tests/lib_2/mirrors/metadata_scope_test.dart index 0ecaeb19427..fec9be72936 100644 --- a/tests/lib_2/mirrors/metadata_scope_test.dart +++ b/tests/lib_2/mirrors/metadata_scope_test.dart @@ -17,8 +17,10 @@ class Annotation { // Note there is no compile-time constant 'foo' in scope. In particular, A.foo // is not in scope here. -@Annotation(foo) // //# 01: compile-time error -class A<@Annotation(foo) T> { +@Annotation(foo) //# 01: compile-time error +class A< + @Annotation(foo) //# 02: compile-time error + T> { @Annotation(foo) static foo() {}