Variance. Report errors on INOUT and OUT built-in identifiers when Feature.variance is enabled.

Change-Id: I4788439bea71532d2c52b715543f7deaeacdf519
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/489982
Reviewed-by: Paul Berry <paulberry@google.com>
Commit-Queue: Konstantin Shcheglov <scheglov@google.com>
Reviewed-by: Johnni Winther <johnniwinther@google.com>
This commit is contained in:
Konstantin Shcheglov
2026-03-24 13:29:17 -07:00
committed by Commit Queue
parent 99290f0c1d
commit 5ef56befcb
10 changed files with 416 additions and 28 deletions
@@ -2504,6 +2504,15 @@ class ErrorVerifier extends RecursiveAstVisitor<void>
diagnosticReporter.report(
code.withArguments(name: token.lexeme).at(token),
);
return;
}
if (_featureSet.isEnabled(Feature.variance)) {
if (token.keyword == Keyword.INOUT || token.keyword == Keyword.OUT) {
diagnosticReporter.report(
code.withArguments(name: token.lexeme).at(token),
);
}
}
}
@@ -32,4 +32,36 @@ extension Function on Object {}
[error(diag.builtInIdentifierAsExtensionName, 10, 8)],
);
}
test_inout() async {
await assertErrorsInCode(
'''
extension inout on Object {}
''',
[error(diag.builtInIdentifierAsExtensionName, 10, 5)],
);
}
test_inout_language310() async {
await assertNoErrorsInCode('''
// @dart = 3.10
extension inout on Object {}
''');
}
test_out() async {
await assertErrorsInCode(
'''
extension out on Object {}
''',
[error(diag.builtInIdentifierAsExtensionName, 10, 3)],
);
}
test_out_language310() async {
await assertNoErrorsInCode('''
// @dart = 3.10
extension out on Object {}
''');
}
}
@@ -33,4 +33,36 @@ extension type Function(int it) {}
[error(diag.builtInIdentifierAsExtensionTypeName, 15, 8)],
);
}
test_inout() async {
await assertErrorsInCode(
'''
extension type inout(int it) {}
''',
[error(diag.builtInIdentifierAsExtensionTypeName, 15, 5)],
);
}
test_inout_language310() async {
await assertNoErrorsInCode('''
// @dart = 3.10
extension type inout(int it) {}
''');
}
test_out() async {
await assertErrorsInCode(
'''
extension type out(int it) {}
''',
[error(diag.builtInIdentifierAsExtensionTypeName, 15, 3)],
);
}
test_out_language310() async {
await assertNoErrorsInCode('''
// @dart = 3.10
extension type out(int it) {}
''');
}
}
@@ -38,4 +38,48 @@ import 'dart:async' as Function;
],
);
}
test_inout() async {
await assertErrorsInCode(
'''
import 'dart:async' as inout;
''',
[
error(diag.unusedImport, 7, 12),
error(diag.builtInIdentifierAsPrefixName, 23, 5),
],
);
}
test_inout_language310() async {
await assertErrorsInCode(
'''
// @dart = 3.10
import 'dart:async' as inout;
''',
[error(diag.unusedImport, 23, 12)],
);
}
test_out() async {
await assertErrorsInCode(
'''
import 'dart:async' as out;
''',
[
error(diag.unusedImport, 7, 12),
error(diag.builtInIdentifierAsPrefixName, 23, 3),
],
);
}
test_out_language310() async {
await assertErrorsInCode(
'''
// @dart = 3.10
import 'dart:async' as out;
''',
[error(diag.unusedImport, 23, 12)],
);
}
}
@@ -33,7 +33,39 @@ class Function {}
);
}
test_enum() async {
test_class_inout() async {
await assertErrorsInCode(
'''
class inout {}
''',
[error(diag.builtInIdentifierAsTypeName, 6, 5)],
);
}
test_class_inout_language310() async {
await assertNoErrorsInCode('''
// @dart = 3.10
class inout {}
''');
}
test_class_out() async {
await assertErrorsInCode(
'''
class out {}
''',
[error(diag.builtInIdentifierAsTypeName, 6, 3)],
);
}
test_class_out_language310() async {
await assertNoErrorsInCode('''
// @dart = 3.10
class out {}
''');
}
test_enum_as() async {
await assertErrorsInCode(
'''
enum as {
@@ -44,6 +76,38 @@ enum as {
);
}
test_enum_inout() async {
await assertErrorsInCode(
'''
enum inout {v}
''',
[error(diag.builtInIdentifierAsTypeName, 5, 5)],
);
}
test_enum_inout_language310() async {
await assertNoErrorsInCode('''
// @dart = 3.10
enum inout {v}
''');
}
test_enum_out() async {
await assertErrorsInCode(
'''
enum out {v}
''',
[error(diag.builtInIdentifierAsTypeName, 5, 3)],
);
}
test_enum_out_language310() async {
await assertNoErrorsInCode('''
// @dart = 3.10
enum out {v}
''');
}
test_mixin_as() async {
await assertErrorsInCode(
'''
@@ -62,6 +126,22 @@ mixin Function {}
);
}
test_mixin_inout() async {
await assertErrorsInCode(
'''
mixin inout {}
''',
[error(diag.builtInIdentifierAsTypeName, 6, 5)],
);
}
test_mixin_inout_language310() async {
await assertNoErrorsInCode('''
// @dart = 3.10
mixin inout {}
''');
}
test_mixin_OK_on() async {
await assertNoErrorsInCode(r'''
class A {}
@@ -75,6 +155,22 @@ mixin M2 implements on {}
class B = A with on;
class C = B with M;
class D = Object with M2;
''');
}
test_mixin_out() async {
await assertErrorsInCode(
'''
mixin out {}
''',
[error(diag.builtInIdentifierAsTypeName, 6, 3)],
);
}
test_mixin_out_language310() async {
await assertNoErrorsInCode('''
// @dart = 3.10
mixin out {}
''');
}
}
@@ -34,6 +34,38 @@ class A<Function> {}
);
}
test_class_inout() async {
await assertErrorsInCode(
'''
class A<inout> {}
''',
[error(diag.builtInIdentifierAsTypeParameterName, 8, 5)],
);
}
test_class_inout_language310() async {
await assertNoErrorsInCode('''
// @dart = 3.10
class A<inout> {}
''');
}
test_class_out() async {
await assertErrorsInCode(
'''
class A<out> {}
''',
[error(diag.builtInIdentifierAsTypeParameterName, 8, 3)],
);
}
test_class_out_language310() async {
await assertNoErrorsInCode('''
// @dart = 3.10
class A<out> {}
''');
}
test_extension_as() async {
await assertErrorsInCode(
'''
@@ -43,6 +75,24 @@ extension <as> on List {}
);
}
test_extension_inout() async {
await assertErrorsInCode(
'''
extension <inout> on List {}
''',
[error(diag.builtInIdentifierAsTypeParameterName, 11, 5)],
);
}
test_extension_out() async {
await assertErrorsInCode(
'''
extension <out> on List {}
''',
[error(diag.builtInIdentifierAsTypeParameterName, 11, 3)],
);
}
test_function_as() async {
await assertErrorsInCode(
'''
@@ -51,4 +101,22 @@ void f<as>() {}
[error(diag.builtInIdentifierAsTypeParameterName, 7, 2)],
);
}
test_function_inout() async {
await assertErrorsInCode(
'''
void f<inout>() {}
''',
[error(diag.builtInIdentifierAsTypeParameterName, 7, 5)],
);
}
test_function_out() async {
await assertErrorsInCode(
'''
void f<out>() {}
''',
[error(diag.builtInIdentifierAsTypeParameterName, 7, 3)],
);
}
}
@@ -26,6 +26,46 @@ class as = A with B;
);
}
test_classTypeAlias_inout() async {
await assertErrorsInCode(
'''
class A {}
mixin B {}
class inout = A with B;
''',
[error(diag.builtInIdentifierAsTypedefName, 28, 5)],
);
}
test_classTypeAlias_inout_language310() async {
await assertNoErrorsInCode('''
// @dart = 3.10
class A {}
mixin B {}
class inout = A with B;
''');
}
test_classTypeAlias_out() async {
await assertErrorsInCode(
'''
class A {}
mixin B {}
class out = A with B;
''',
[error(diag.builtInIdentifierAsTypedefName, 28, 3)],
);
}
test_classTypeAlias_out_language310() async {
await assertNoErrorsInCode('''
// @dart = 3.10
class A {}
mixin B {}
class out = A with B;
''');
}
test_typedef_classic() async {
await assertErrorsInCode(
r'''
@@ -50,6 +90,38 @@ typedef void as();
);
}
test_typedef_classic_inout() async {
await assertErrorsInCode(
'''
typedef void inout();
''',
[error(diag.builtInIdentifierAsTypedefName, 13, 5)],
);
}
test_typedef_classic_inout_language310() async {
await assertNoErrorsInCode('''
// @dart = 3.10
typedef void inout();
''');
}
test_typedef_classic_out() async {
await assertErrorsInCode(
'''
typedef void out();
''',
[error(diag.builtInIdentifierAsTypedefName, 13, 3)],
);
}
test_typedef_classic_out_language310() async {
await assertNoErrorsInCode('''
// @dart = 3.10
typedef void out();
''');
}
test_typedef_generic_as() async {
await assertErrorsInCode(
r'''
@@ -62,6 +134,38 @@ typedef as = void Function();
);
}
test_typedef_generic_inout() async {
await assertErrorsInCode(
'''
typedef inout = void Function();
''',
[error(diag.builtInIdentifierAsTypedefName, 8, 5)],
);
}
test_typedef_generic_inout_language310() async {
await assertNoErrorsInCode('''
// @dart = 3.10
typedef inout = void Function();
''');
}
test_typedef_generic_out() async {
await assertErrorsInCode(
'''
typedef out = void Function();
''',
[error(diag.builtInIdentifierAsTypedefName, 8, 3)],
);
}
test_typedef_generic_out_language310() async {
await assertNoErrorsInCode('''
// @dart = 3.10
typedef out = void Function();
''');
}
test_typedef_interfaceType_as() async {
await assertErrorsInCode(
r'''
@@ -2,8 +2,8 @@
// 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.
// `out` and `inout` are built-in identifiers. They cannot be used as type
// names.
// `out` and `inout` are built-in identifiers.They cannot be used as names in
// declarations.
// SharedOptions=--enable-experiment=variance
@@ -18,35 +18,45 @@ class B<inout> {}
// [cfe] unspecified
class C<out, inout> {}
// ^
// [analyzer] unspecified
// ^^^
// [analyzer] COMPILE_TIME_ERROR.BUILT_IN_IDENTIFIER_IN_DECLARATION
// [cfe] unspecified
// ^
// [analyzer] unspecified
// ^^^^^
// [analyzer] COMPILE_TIME_ERROR.BUILT_IN_IDENTIFIER_IN_DECLARATION
// [cfe] unspecified
F<inout, out>() {}
//^
// [analyzer] unspecified
//^^^^^
// [analyzer] COMPILE_TIME_ERROR.BUILT_IN_IDENTIFIER_IN_DECLARATION
// [cfe] unspecified
// ^
// [analyzer] unspecified
// ^^^
// [analyzer] COMPILE_TIME_ERROR.BUILT_IN_IDENTIFIER_IN_DECLARATION
// [cfe] unspecified
mixin G<out, inout> {}
// ^
// [analyzer] unspecified
// ^^^
// [analyzer] COMPILE_TIME_ERROR.BUILT_IN_IDENTIFIER_IN_DECLARATION
// [cfe] unspecified
// ^
// [analyzer] unspecified
// ^^^^^
// [analyzer] COMPILE_TIME_ERROR.BUILT_IN_IDENTIFIER_IN_DECLARATION
// [cfe] unspecified
class I<out out> {}
// ^^^
// [analyzer] COMPILE_TIME_ERROR.BUILT_IN_IDENTIFIER_IN_DECLARATION
// [cfe] unspecified
class J<out inout> {}
// ^^^^^
// [analyzer] COMPILE_TIME_ERROR.BUILT_IN_IDENTIFIER_IN_DECLARATION
// [cfe] unspecified
typedef H<inout, out> = out Function(inout);
// ^
// [analyzer] unspecified
// ^^^^^
// [analyzer] COMPILE_TIME_ERROR.BUILT_IN_IDENTIFIER_IN_DECLARATION
// [cfe] unspecified
// ^
// [analyzer] unspecified
// ^^^
// [analyzer] COMPILE_TIME_ERROR.BUILT_IN_IDENTIFIER_IN_DECLARATION
// [cfe] unspecified
class out {}
@@ -55,7 +65,6 @@ class out {}
// [cfe] unspecified
class inout {}
// ^
// [analyzer] unspecified
// [cfe] unspecified
@@ -27,10 +27,6 @@ mixin E<in T extends E1> {}
class F<out T> = Object with D<T>;
class G<out out> {}
class H<out inout> {}
main() {
B<int, String, bool> b = B();
@@ -38,8 +34,4 @@ main() {
Expect.equals(2, c.foo(3));
F<int> f = F();
G<int> g = G();
H<int> h = H();
}
@@ -60,6 +60,8 @@ class D<in out inout in out X> {}
// [cfe] Each type parameter can have at most one variance modifier.
typedef E<out T> = T Function(T a);
// ^^^
// [analyzer] COMPILE_TIME_ERROR.BUILT_IN_IDENTIFIER_IN_DECLARATION
// ^
// [analyzer] SYNTACTIC_ERROR.EXPECTED_TOKEN
// [cfe] Expected ',' before this.