Skip to content

Commit def9a76

Browse files
chloestefantsovaCommit Bot
authored and
Commit Bot
committed
[cfe] Report errors on indirect implementation of Enum
Part of #47453 Change-Id: I00fc3ca00713b1181eb0179312d3eb68cfeae334 Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/228648 Reviewed-by: Johnni Winther <johnniwinther@google.com> Commit-Queue: Chloe Stefantsova <cstefantsova@google.com>
1 parent 5b83864 commit def9a76

16 files changed

+671
-36
lines changed

pkg/front_end/lib/src/fasta/kernel/kernel_target.dart

+15-1
Original file line numberDiff line numberDiff line change
@@ -137,6 +137,14 @@ class KernelTarget extends TargetImplementation {
137137
/* charOffset = */ null,
138138
instanceTypeVariableAccess: InstanceTypeVariableAccessState.Unexpected);
139139

140+
final NamedTypeBuilder enumType = new NamedTypeBuilder(
141+
"Enum",
142+
const NullabilityBuilder.omitted(),
143+
/* arguments = */ null,
144+
/* fileUri = */ null,
145+
/* charOffset = */ null,
146+
instanceTypeVariableAccess: InstanceTypeVariableAccessState.Unexpected);
147+
140148
final bool excludeSource = !CompilerContext.current.options.embedSourceText;
141149

142150
final Map<String, String>? environmentDefines =
@@ -406,6 +414,7 @@ class KernelTarget extends TargetImplementation {
406414
link(new List<Library>.from(loader.libraries), nameRoot: nameRoot);
407415
computeCoreTypes();
408416
loader.buildClassHierarchy(sourceClassBuilders, objectClassBuilder);
417+
loader.checkSupertypes(sourceClassBuilders, enumClass);
409418
// TODO(johnniwinther): Enable this when supported in the isolate-based
410419
// macro executor.
411420
/*if (macroApplications != null) {
@@ -416,7 +425,6 @@ class KernelTarget extends TargetImplementation {
416425
loader.computeShowHideElements();
417426
loader.installTypedefTearOffs();
418427
loader.performTopLevelInference(sourceClassBuilders);
419-
loader.checkSupertypes(sourceClassBuilders);
420428
loader.checkOverrides(sourceClassBuilders);
421429
loader.checkAbstractMembers(sourceClassBuilders);
422430
loader.addNoSuchMethodForwarders(sourceClassBuilders);
@@ -648,6 +656,10 @@ class KernelTarget extends TargetImplementation {
648656

649657
Class get objectClass => objectClassBuilder.cls;
650658

659+
ClassBuilder get enumClassBuilder => enumType.declaration as ClassBuilder;
660+
661+
Class get enumClass => enumClassBuilder.cls;
662+
651663
/// If [builder] doesn't have a constructors, install the defaults.
652664
void installDefaultConstructor(SourceClassBuilder builder) {
653665
assert(!builder.isMixinApplication);
@@ -976,6 +988,8 @@ class KernelTarget extends TargetImplementation {
976988
nullType.bind(nullClassBuilder..isNullClass = true);
977989
bottomType.bind(loader.coreLibrary
978990
.lookupLocalMember("Never", required: true) as TypeDeclarationBuilder);
991+
enumType.bind(loader.coreLibrary.lookupLocalMember("Enum", required: true)
992+
as TypeDeclarationBuilder);
979993
}
980994

981995
void computeCoreTypes() {

pkg/front_end/lib/src/fasta/source/source_class_builder.dart

+25-2
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@ import '../builder/void_type_declaration_builder.dart';
4040
import '../dill/dill_member_builder.dart';
4141
import '../fasta_codes.dart';
4242
import '../kernel/combined_member_signature.dart';
43+
import '../kernel/hierarchy/hierarchy_builder.dart';
4344
import '../kernel/kernel_helper.dart';
4445
import '../kernel/kernel_target.dart' show KernelTarget;
4546
import '../kernel/redirecting_factory_body.dart'
@@ -621,12 +622,34 @@ class SourceClassBuilder extends ClassBuilderImpl
621622
}
622623
}
623624

624-
void checkSupertypes(CoreTypes coreTypes) {
625+
void checkSupertypes(CoreTypes coreTypes,
626+
ClassHierarchyBuilder hierarchyBuilder, Class enumClass) {
625627
// This method determines whether the class (that's being built) its super
626628
// class appears both in 'extends' and 'implements' clauses and whether any
627629
// interface appears multiple times in the 'implements' clause.
628630
// Moreover, it checks that `FutureOr` and `void` are not among the
629-
// supertypes.
631+
// supertypes and that `Enum` is not implemented by non-abstract classes.
632+
633+
if (!cls.isAbstract && !cls.isEnum) {
634+
bool isEnumFound = false;
635+
List<Supertype> interfaces =
636+
hierarchyBuilder.getNodeFromClass(cls).superclasses;
637+
for (int i = 0; !isEnumFound && i < interfaces.length; i++) {
638+
if (interfaces[i].classNode == enumClass) {
639+
isEnumFound = true;
640+
}
641+
}
642+
interfaces = hierarchyBuilder.getNodeFromClass(cls).interfaces;
643+
for (int i = 0; !isEnumFound && i < interfaces.length; i++) {
644+
if (interfaces[i].classNode == enumClass) {
645+
isEnumFound = true;
646+
}
647+
}
648+
if (isEnumFound) {
649+
addProblem(templateEnumSupertypeOfNonAbstractClass.withArguments(name),
650+
charOffset, noLength);
651+
}
652+
}
630653

631654
void fail(NamedTypeBuilder target, Message message,
632655
TypeAliasBuilder? aliasBuilder) {

pkg/front_end/lib/src/fasta/source/source_loader.dart

+5-12
Original file line numberDiff line numberDiff line change
@@ -1713,20 +1713,12 @@ severity: $severity
17131713
bool checkEnumSupertypeIsDenylisted(SourceClassBuilder cls) {
17141714
if (!cls.library.enableEnhancedEnumsInLibrary) {
17151715
cls.addProblem(
1716-
templateExperimentNotEnabled.withArguments('enhanced-enums',
1717-
cls.library.enableEnhancedEnumsVersionInLibrary.toText()),
1716+
templateEnumSupertypeOfNonAbstractClass.withArguments(cls.name),
17181717
cls.charOffset,
17191718
noLength);
17201719
return true;
1721-
} else {
1722-
if (!cls.isAbstract) {
1723-
cls.addProblem(
1724-
templateEnumSupertypeOfNonAbstractClass.withArguments(cls.name),
1725-
cls.charOffset,
1726-
noLength);
1727-
}
1728-
return false;
17291720
}
1721+
return false;
17301722
}
17311723

17321724
void checkClassSupertypes(
@@ -1925,10 +1917,11 @@ severity: $severity
19251917
ticker.logMs("Computed core types");
19261918
}
19271919

1928-
void checkSupertypes(List<SourceClassBuilder> sourceClasses) {
1920+
void checkSupertypes(
1921+
List<SourceClassBuilder> sourceClasses, Class enumClass) {
19291922
for (SourceClassBuilder builder in sourceClasses) {
19301923
if (builder.library.loader == this && !builder.isPatch) {
1931-
builder.checkSupertypes(coreTypes);
1924+
builder.checkSupertypes(coreTypes, hierarchyBuilder, enumClass);
19321925
}
19331926
}
19341927
ticker.logMs("Checked supertypes");

pkg/front_end/testcases/enhanced_enums/enum_as_supertype_error.dart

+16
Original file line numberDiff line numberDiff line change
@@ -10,4 +10,20 @@ class B implements Enum { // Error.
1010
int get foo => index;
1111
}
1212

13+
abstract class EnumInterface implements Enum {}
14+
15+
class EnumClass extends EnumInterface { // Error.
16+
int get index => 0;
17+
}
18+
19+
abstract class AbstractEnumClass extends EnumInterface {}
20+
21+
class EnumClass2 extends AbstractEnumClass {} // Error.
22+
23+
mixin EnumMixin on Enum {}
24+
25+
abstract class AbstractEnumClass2 with EnumMixin {}
26+
27+
class EnumClass3 extends AbstractEnumClass2 {} // Error.
28+
1329
main() {}

pkg/front_end/testcases/enhanced_enums/enum_as_supertype_error.dart.strong.expect

+92
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,18 @@ library /*isNonNullableByDefault*/;
1010
// class B implements Enum { // Error.
1111
// ^
1212
//
13+
// pkg/front_end/testcases/enhanced_enums/enum_as_supertype_error.dart:15:7: Error: Non-abstract class 'EnumClass' has 'Enum' as a superinterface.
14+
// class EnumClass extends EnumInterface { // Error.
15+
// ^
16+
//
17+
// pkg/front_end/testcases/enhanced_enums/enum_as_supertype_error.dart:21:7: Error: Non-abstract class 'EnumClass2' has 'Enum' as a superinterface.
18+
// class EnumClass2 extends AbstractEnumClass {} // Error.
19+
// ^
20+
//
21+
// pkg/front_end/testcases/enhanced_enums/enum_as_supertype_error.dart:27:7: Error: Non-abstract class 'EnumClass3' has 'Enum' as a superinterface.
22+
// class EnumClass3 extends AbstractEnumClass2 {} // Error.
23+
// ^
24+
//
1325
// pkg/front_end/testcases/enhanced_enums/enum_as_supertype_error.dart:5:7: Error: The non-abstract class 'A' is missing implementations for these members:
1426
// - Enum.index
1527
// Try to either
@@ -38,6 +50,41 @@ library /*isNonNullableByDefault*/;
3850
// int get index;
3951
// ^^^^^
4052
//
53+
// pkg/front_end/testcases/enhanced_enums/enum_as_supertype_error.dart:21:7: Error: The non-abstract class 'EnumClass2' is missing implementations for these members:
54+
// - Enum.index
55+
// Try to either
56+
// - provide an implementation,
57+
// - inherit an implementation from a superclass or mixin,
58+
// - mark the class as abstract, or
59+
// - provide a 'noSuchMethod' implementation.
60+
//
61+
// class EnumClass2 extends AbstractEnumClass {} // Error.
62+
// ^^^^^^^^^^
63+
// sdk/lib/core/enum.dart:22:11: Context: 'Enum.index' is defined here.
64+
// int get index;
65+
// ^^^^^
66+
//
67+
// pkg/front_end/testcases/enhanced_enums/enum_as_supertype_error.dart:27:7: Error: The non-abstract class 'EnumClass3' is missing implementations for these members:
68+
// - Enum.index
69+
// Try to either
70+
// - provide an implementation,
71+
// - inherit an implementation from a superclass or mixin,
72+
// - mark the class as abstract, or
73+
// - provide a 'noSuchMethod' implementation.
74+
//
75+
// class EnumClass3 extends AbstractEnumClass2 {} // Error.
76+
// ^^^^^^^^^^
77+
// sdk/lib/core/enum.dart:22:11: Context: 'Enum.index' is defined here.
78+
// int get index;
79+
// ^^^^^
80+
//
81+
// pkg/front_end/testcases/enhanced_enums/enum_as_supertype_error.dart:25:16: Error: 'Object' doesn't implement 'Enum' so it can't be used with 'EnumMixin'.
82+
// - 'Object' is from 'dart:core'.
83+
// - 'Enum' is from 'dart:core'.
84+
// - 'EnumMixin' is from 'pkg/front_end/testcases/enhanced_enums/enum_as_supertype_error.dart'.
85+
// abstract class AbstractEnumClass2 with EnumMixin {}
86+
// ^
87+
//
4188
import self as self;
4289
import "dart:core" as core;
4390

@@ -59,6 +106,51 @@ class B extends core::Object implements core::Enum {
59106
no-such-method-forwarder get /* from org-dartlang-sdk:///sdk/lib/core/enum.dart */ _name() → core::String
60107
return this.{core::Object::noSuchMethod}(new core::_InvocationMirror::_withType(#C1, 1, #C2, #C3, core::Map::unmodifiable<core::Symbol*, dynamic>(#C4))){(core::Invocation) → dynamic} as{TypeError,ForDynamic,ForNonNullableByDefault} core::String;
61108
}
109+
abstract class EnumInterface extends core::Object implements core::Enum {
110+
synthetic constructor •() → self::EnumInterface
111+
: super core::Object::•()
112+
;
113+
}
114+
class EnumClass extends self::EnumInterface {
115+
synthetic constructor •() → self::EnumClass
116+
: super self::EnumInterface::•()
117+
;
118+
get index() → core::int
119+
return 0;
120+
no-such-method-forwarder get /* from org-dartlang-sdk:///sdk/lib/core/enum.dart */ _name() → core::String
121+
return this.{core::Object::noSuchMethod}(new core::_InvocationMirror::_withType(#C1, 1, #C2, #C3, core::Map::unmodifiable<core::Symbol*, dynamic>(#C4))){(core::Invocation) → dynamic} as{TypeError,ForDynamic,ForNonNullableByDefault} core::String;
122+
}
123+
abstract class AbstractEnumClass extends self::EnumInterface {
124+
synthetic constructor •() → self::AbstractEnumClass
125+
: super self::EnumInterface::•()
126+
;
127+
}
128+
class EnumClass2 extends self::AbstractEnumClass {
129+
synthetic constructor •() → self::EnumClass2
130+
: super self::AbstractEnumClass::•()
131+
;
132+
no-such-method-forwarder get /* from org-dartlang-sdk:///sdk/lib/core/enum.dart */ _name() → core::String
133+
return this.{core::Object::noSuchMethod}(new core::_InvocationMirror::_withType(#C1, 1, #C2, #C3, core::Map::unmodifiable<core::Symbol*, dynamic>(#C4))){(core::Invocation) → dynamic} as{TypeError,ForDynamic,ForNonNullableByDefault} core::String;
134+
}
135+
abstract class EnumMixin extends core::Enum /*isMixinDeclaration*/ {
136+
}
137+
abstract class _AbstractEnumClass2&Object&EnumMixin = core::Object with self::EnumMixin /*isAnonymousMixin,hasConstConstructor*/ {
138+
const synthetic constructor •() → self::_AbstractEnumClass2&Object&EnumMixin
139+
: super core::Object::•()
140+
;
141+
}
142+
abstract class AbstractEnumClass2 extends self::_AbstractEnumClass2&Object&EnumMixin {
143+
synthetic constructor •() → self::AbstractEnumClass2
144+
: super self::_AbstractEnumClass2&Object&EnumMixin::•()
145+
;
146+
}
147+
class EnumClass3 extends self::AbstractEnumClass2 {
148+
synthetic constructor •() → self::EnumClass3
149+
: super self::AbstractEnumClass2::•()
150+
;
151+
no-such-method-forwarder get /* from org-dartlang-sdk:///sdk/lib/core/enum.dart */ _name() → core::String
152+
return this.{core::Object::noSuchMethod}(new core::_InvocationMirror::_withType(#C1, 1, #C2, #C3, core::Map::unmodifiable<core::Symbol*, dynamic>(#C4))){(core::Invocation) → dynamic} as{TypeError,ForDynamic,ForNonNullableByDefault} core::String;
153+
}
62154
static method main() → dynamic {}
63155

64156
constants {

pkg/front_end/testcases/enhanced_enums/enum_as_supertype_error.dart.strong.transformed.expect

+92
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,18 @@ library /*isNonNullableByDefault*/;
1010
// class B implements Enum { // Error.
1111
// ^
1212
//
13+
// pkg/front_end/testcases/enhanced_enums/enum_as_supertype_error.dart:15:7: Error: Non-abstract class 'EnumClass' has 'Enum' as a superinterface.
14+
// class EnumClass extends EnumInterface { // Error.
15+
// ^
16+
//
17+
// pkg/front_end/testcases/enhanced_enums/enum_as_supertype_error.dart:21:7: Error: Non-abstract class 'EnumClass2' has 'Enum' as a superinterface.
18+
// class EnumClass2 extends AbstractEnumClass {} // Error.
19+
// ^
20+
//
21+
// pkg/front_end/testcases/enhanced_enums/enum_as_supertype_error.dart:27:7: Error: Non-abstract class 'EnumClass3' has 'Enum' as a superinterface.
22+
// class EnumClass3 extends AbstractEnumClass2 {} // Error.
23+
// ^
24+
//
1325
// pkg/front_end/testcases/enhanced_enums/enum_as_supertype_error.dart:5:7: Error: The non-abstract class 'A' is missing implementations for these members:
1426
// - Enum.index
1527
// Try to either
@@ -38,6 +50,41 @@ library /*isNonNullableByDefault*/;
3850
// int get index;
3951
// ^^^^^
4052
//
53+
// pkg/front_end/testcases/enhanced_enums/enum_as_supertype_error.dart:21:7: Error: The non-abstract class 'EnumClass2' is missing implementations for these members:
54+
// - Enum.index
55+
// Try to either
56+
// - provide an implementation,
57+
// - inherit an implementation from a superclass or mixin,
58+
// - mark the class as abstract, or
59+
// - provide a 'noSuchMethod' implementation.
60+
//
61+
// class EnumClass2 extends AbstractEnumClass {} // Error.
62+
// ^^^^^^^^^^
63+
// sdk/lib/core/enum.dart:22:11: Context: 'Enum.index' is defined here.
64+
// int get index;
65+
// ^^^^^
66+
//
67+
// pkg/front_end/testcases/enhanced_enums/enum_as_supertype_error.dart:27:7: Error: The non-abstract class 'EnumClass3' is missing implementations for these members:
68+
// - Enum.index
69+
// Try to either
70+
// - provide an implementation,
71+
// - inherit an implementation from a superclass or mixin,
72+
// - mark the class as abstract, or
73+
// - provide a 'noSuchMethod' implementation.
74+
//
75+
// class EnumClass3 extends AbstractEnumClass2 {} // Error.
76+
// ^^^^^^^^^^
77+
// sdk/lib/core/enum.dart:22:11: Context: 'Enum.index' is defined here.
78+
// int get index;
79+
// ^^^^^
80+
//
81+
// pkg/front_end/testcases/enhanced_enums/enum_as_supertype_error.dart:25:16: Error: 'Object' doesn't implement 'Enum' so it can't be used with 'EnumMixin'.
82+
// - 'Object' is from 'dart:core'.
83+
// - 'Enum' is from 'dart:core'.
84+
// - 'EnumMixin' is from 'pkg/front_end/testcases/enhanced_enums/enum_as_supertype_error.dart'.
85+
// abstract class AbstractEnumClass2 with EnumMixin {}
86+
// ^
87+
//
4188
import self as self;
4289
import "dart:core" as core;
4390

@@ -59,6 +106,51 @@ class B extends core::Object implements core::Enum {
59106
no-such-method-forwarder get /* from org-dartlang-sdk:///sdk/lib/core/enum.dart */ _name() → core::String
60107
return this.{core::Object::noSuchMethod}(new core::_InvocationMirror::_withType(#C1, 1, #C2, #C3, core::Map::unmodifiable<core::Symbol*, dynamic>(#C4))){(core::Invocation) → dynamic} as{TypeError,ForDynamic,ForNonNullableByDefault} core::String;
61108
}
109+
abstract class EnumInterface extends core::Object implements core::Enum {
110+
synthetic constructor •() → self::EnumInterface
111+
: super core::Object::•()
112+
;
113+
}
114+
class EnumClass extends self::EnumInterface {
115+
synthetic constructor •() → self::EnumClass
116+
: super self::EnumInterface::•()
117+
;
118+
get index() → core::int
119+
return 0;
120+
no-such-method-forwarder get /* from org-dartlang-sdk:///sdk/lib/core/enum.dart */ _name() → core::String
121+
return this.{core::Object::noSuchMethod}(new core::_InvocationMirror::_withType(#C1, 1, #C2, #C3, core::Map::unmodifiable<core::Symbol*, dynamic>(#C4))){(core::Invocation) → dynamic} as{TypeError,ForDynamic,ForNonNullableByDefault} core::String;
122+
}
123+
abstract class AbstractEnumClass extends self::EnumInterface {
124+
synthetic constructor •() → self::AbstractEnumClass
125+
: super self::EnumInterface::•()
126+
;
127+
}
128+
class EnumClass2 extends self::AbstractEnumClass {
129+
synthetic constructor •() → self::EnumClass2
130+
: super self::AbstractEnumClass::•()
131+
;
132+
no-such-method-forwarder get /* from org-dartlang-sdk:///sdk/lib/core/enum.dart */ _name() → core::String
133+
return this.{core::Object::noSuchMethod}(new core::_InvocationMirror::_withType(#C1, 1, #C2, #C3, core::Map::unmodifiable<core::Symbol*, dynamic>(#C4))){(core::Invocation) → dynamic} as{TypeError,ForDynamic,ForNonNullableByDefault} core::String;
134+
}
135+
abstract class EnumMixin extends core::Enum /*isMixinDeclaration*/ {
136+
}
137+
abstract class _AbstractEnumClass2&Object&EnumMixin extends core::Object implements self::EnumMixin /*isAnonymousMixin,isEliminatedMixin,hasConstConstructor*/ {
138+
const synthetic constructor •() → self::_AbstractEnumClass2&Object&EnumMixin
139+
: super core::Object::•()
140+
;
141+
}
142+
abstract class AbstractEnumClass2 extends self::_AbstractEnumClass2&Object&EnumMixin {
143+
synthetic constructor •() → self::AbstractEnumClass2
144+
: super self::_AbstractEnumClass2&Object&EnumMixin::•()
145+
;
146+
}
147+
class EnumClass3 extends self::AbstractEnumClass2 {
148+
synthetic constructor •() → self::EnumClass3
149+
: super self::AbstractEnumClass2::•()
150+
;
151+
no-such-method-forwarder get /* from org-dartlang-sdk:///sdk/lib/core/enum.dart */ _name() → core::String
152+
return this.{core::Object::noSuchMethod}(new core::_InvocationMirror::_withType(#C1, 1, #C2, #C3, core::Map::unmodifiable<core::Symbol*, dynamic>(#C4))){(core::Invocation) → dynamic} as{TypeError,ForDynamic,ForNonNullableByDefault} core::String;
153+
}
62154
static method main() → dynamic {}
63155

64156
constants {

0 commit comments

Comments
 (0)