Version 2.15.0-23.0.dev
Merge commit 'f5a3bce734ac8b77e94c255899d65997c4677ace' into 'dev'
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 4f6512f..944c834 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 9fad340..92573bd 100644
--- a/pkg/analyzer/lib/src/generated/resolver.dart
+++ b/pkg/analyzer/lib/src/generated/resolver.dart
@@ -2008,17 +2008,6 @@
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 c339039..c484dd0 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 @@
}
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 @@
}
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 @@
}
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 @@
}
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 5d66e3c..eaf482e 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 @@
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 eceff88..e898f39 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 @@
_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 71dc58a..1d02cb5 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 @@
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 @@
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 21d767b..c4497b1 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 @@
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 9d91421..b6a6ed9 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 @@
templateInternalProblemUnfinishedTypeVariable,
templateTypeArgumentsOnTypeVariable;
+import '../scope.dart';
import '../source/source_library_builder.dart';
import '../util/helpers.dart';
@@ -200,9 +201,9 @@
DeclarationBuilder? classOrExtensionBuilder,
MemberBuilder? memberBuilder,
CoreTypes coreTypes,
- List<DelayedActionPerformer> delayedActionPerformers) {
+ List<DelayedActionPerformer> 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 5ffcb20..8bb7538 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 @@
List<DelayedActionPerformer> delayedActionPerformers,
List<SynthesizedFunctionNode> 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 4ed49c9..5c4ebef3 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 @@
@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 5bdcbaa..a64606e 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 @@
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 @@
List<DelayedActionPerformer> delayedActionPerformers,
List<SynthesizedFunctionNode> 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 @@
});
}
+ Scope computeTypeParameterScope(Scope parent) {
+ if (typeVariables == null) return parent;
+ Map<String, Builder> local = <String, Builder>{};
+ for (TypeVariableBuilder variable in typeVariables!) {
+ local[variable.name] = variable;
+ }
+ return new Scope(
+ local: local,
+ parent: parent,
+ debugName: "type parameter",
+ isModifiable: false);
+ }
+
Map<Procedure, Member>? _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 0000000..ecbb4a2
--- /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<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 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<foo>();
+// ^^^
+// [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 0000000..d411e2f
--- /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<T, @Annotation(T) U> {}
+// ^
+// [analyzer] COMPILE_TIME_ERROR.CONST_WITH_NON_CONSTANT_ARGUMENT
+// [cfe] Type variables can't be used in static members.
+
+void function<T, @Annotation(T) U>() {}
+// ^
+// [analyzer] COMPILE_TIME_ERROR.CONST_WITH_NON_CONSTANT_ARGUMENT
+// [cfe] Type variables can't be used as constants.
+
+extension Extension<T, @Annotation(T) U> on Map<T, U> {}
+// ^
+// [analyzer] COMPILE_TIME_ERROR.CONST_WITH_NON_CONSTANT_ARGUMENT
+// [cfe] Type variables can't be used in static members.
+
+class C {
+ void method<T, @Annotation(T) U>() {}
+ // ^
+ // [analyzer] COMPILE_TIME_ERROR.CONST_WITH_NON_CONSTANT_ARGUMENT
+ // [cfe] Type variables can't be used as constants.
+}
+
+mixin Mixin<T, @Annotation(T) U> {}
+// ^
+// [analyzer] COMPILE_TIME_ERROR.CONST_WITH_NON_CONSTANT_ARGUMENT
+// [cfe] Type variables can't be used in static members.
+
+typedef void Typedef1<T, @Annotation(T) U>(T t, U u);
+// ^
+// [analyzer] COMPILE_TIME_ERROR.CONST_WITH_NON_CONSTANT_ARGUMENT
+// [cfe] Type variables can't be used as constants.
+
+typedef Typedef2<T, @Annotation(T) U> = 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 0000000..ecbb4a2
--- /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<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 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<foo>();
+// ^^^
+// [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 0000000..d411e2f
--- /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<T, @Annotation(T) U> {}
+// ^
+// [analyzer] COMPILE_TIME_ERROR.CONST_WITH_NON_CONSTANT_ARGUMENT
+// [cfe] Type variables can't be used in static members.
+
+void function<T, @Annotation(T) U>() {}
+// ^
+// [analyzer] COMPILE_TIME_ERROR.CONST_WITH_NON_CONSTANT_ARGUMENT
+// [cfe] Type variables can't be used as constants.
+
+extension Extension<T, @Annotation(T) U> on Map<T, U> {}
+// ^
+// [analyzer] COMPILE_TIME_ERROR.CONST_WITH_NON_CONSTANT_ARGUMENT
+// [cfe] Type variables can't be used in static members.
+
+class C {
+ void method<T, @Annotation(T) U>() {}
+ // ^
+ // [analyzer] COMPILE_TIME_ERROR.CONST_WITH_NON_CONSTANT_ARGUMENT
+ // [cfe] Type variables can't be used as constants.
+}
+
+mixin Mixin<T, @Annotation(T) U> {}
+// ^
+// [analyzer] COMPILE_TIME_ERROR.CONST_WITH_NON_CONSTANT_ARGUMENT
+// [cfe] Type variables can't be used in static members.
+
+typedef void Typedef1<T, @Annotation(T) U>(T t, U u);
+// ^
+// [analyzer] COMPILE_TIME_ERROR.CONST_WITH_NON_CONSTANT_ARGUMENT
+// [cfe] Type variables can't be used as constants.
+
+typedef Typedef2<T, @Annotation(T) U> = 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 8848d41..0596b39 100644
--- a/tests/lib/mirrors/metadata_scope_test.dart
+++ b/tests/lib/mirrors/metadata_scope_test.dart
@@ -15,8 +15,10 @@
// 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 0ecaeb1..fec9be7 100644
--- a/tests/lib_2/mirrors/metadata_scope_test.dart
+++ b/tests/lib_2/mirrors/metadata_scope_test.dart
@@ -17,8 +17,10 @@
// 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/tools/VERSION b/tools/VERSION
index b02aaac..f5bacd2 100644
--- a/tools/VERSION
+++ b/tools/VERSION
@@ -27,5 +27,5 @@
MAJOR 2
MINOR 15
PATCH 0
-PRERELEASE 22
+PRERELEASE 23
PRERELEASE_PATCH 0
\ No newline at end of file