Skip to content

Commit 27f9b25

Browse files
chloestefantsovaCommit Bot
authored and
Commit Bot
committed
[cfe] Report error on immediately declared abstract membrs in enums
Part of #47453 Change-Id: I376b309e019a1e18444613f14c9e8870c0f10eb6 Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/239681 Reviewed-by: Johnni Winther <[email protected]> Commit-Queue: Chloe Stefantsova <[email protected]>
1 parent aeed1fd commit 27f9b25

13 files changed

+1298
-8
lines changed

pkg/_fe_analyzer_shared/lib/src/messages/codes_generated.dart

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2781,6 +2781,14 @@ const Code<Null> codeEncoding = messageEncoding;
27812781
const MessageCode messageEncoding = const MessageCode("Encoding",
27822782
problemMessage: r"""Unable to decode bytes as UTF-8.""");
27832783

2784+
// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
2785+
const Code<Null> codeEnumAbstractMember = messageEnumAbstractMember;
2786+
2787+
// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
2788+
const MessageCode messageEnumAbstractMember = const MessageCode(
2789+
"EnumAbstractMember",
2790+
problemMessage: r"""Enums can't declare abstract members.""");
2791+
27842792
// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
27852793
const Template<
27862794
Message Function(

pkg/front_end/lib/src/fasta/kernel/hierarchy/members_node.dart

Lines changed: 14 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ import '../../messages.dart'
2727
messageDeclaredMemberConflictsWithInheritedMember,
2828
messageDeclaredMemberConflictsWithInheritedMemberCause,
2929
messageDeclaredMemberConflictsWithOverriddenMembersCause,
30+
messageEnumAbstractMember,
3031
messageInheritedMembersConflict,
3132
messageInheritedMembersConflictCause1,
3233
messageInheritedMembersConflictCause2,
@@ -2351,14 +2352,19 @@ class ClassMembersNodeBuilder {
23512352
Map<String, LocatedMessage> contextMap = <String, LocatedMessage>{};
23522353
for (ClassMember declaration in unfoldDeclarations(abstractMembers)) {
23532354
if (isNameVisibleIn(declaration.name, classBuilder.libraryBuilder)) {
2354-
String name = declaration.fullNameForErrors;
2355-
String className = declaration.classBuilder.fullNameForErrors;
2356-
String displayName =
2357-
declaration.isSetter ? "$className.$name=" : "$className.$name";
2358-
contextMap[displayName] = templateMissingImplementationCause
2359-
.withArguments(displayName)
2360-
.withLocation(
2361-
declaration.fileUri, declaration.charOffset, name.length);
2355+
if (classBuilder.isEnum && declaration.classBuilder == classBuilder) {
2356+
classBuilder.addProblem(messageEnumAbstractMember,
2357+
declaration.charOffset, declaration.name.text.length);
2358+
} else {
2359+
String name = declaration.fullNameForErrors;
2360+
String className = declaration.classBuilder.fullNameForErrors;
2361+
String displayName =
2362+
declaration.isSetter ? "$className.$name=" : "$className.$name";
2363+
contextMap[displayName] = templateMissingImplementationCause
2364+
.withArguments(displayName)
2365+
.withLocation(
2366+
declaration.fileUri, declaration.charOffset, name.length);
2367+
}
23622368
}
23632369
}
23642370
if (contextMap.isEmpty) return;

pkg/front_end/messages.status

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -214,6 +214,8 @@ DuplicatedName/example: Fail
214214
DuplicatedNamedArgument/example: Fail
215215
DuplicatedParameterName/example: Fail
216216
Encoding/analyzerCode: Fail
217+
EnumAbstractMember/analyzerCode: Fail
218+
EnumAbstractMember/example: Fail
217219
EnumConstantSameNameAsEnclosing/example: Fail
218220
EnumConstructorSuperInitializer/analyzerCode: Fail
219221
EnumConstructorSuperInitializer/example: Fail

pkg/front_end/messages.yaml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5577,3 +5577,6 @@ EnumContainsRestrictedInstanceDeclaration:
55775577

55785578
EnumImplementerContainsRestrictedInstanceDeclaration:
55795579
problemMessage: "'#name' has 'Enum' as a superinterface and can't contain non-static members with name '#name2'."
5580+
5581+
EnumAbstractMember:
5582+
problemMessage: "Enums can't declare abstract members."
Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
// Copyright (c) 2022, the Dart project authors. Please see the AUTHORS file
2+
// for details. All rights reserved. Use of this source code is governed by a
3+
// BSD-style license that can be found in the LICENSE file.
4+
5+
enum E1 {
6+
element;
7+
8+
void foo(); // Error.
9+
}
10+
11+
enum E2 {
12+
element;
13+
14+
int get foo; // Error.
15+
}
16+
17+
enum E3 {
18+
element;
19+
20+
void set foo(int val); // Error.
21+
}
22+
23+
abstract class InterfaceMethod {
24+
void foo();
25+
}
26+
27+
enum E4 implements InterfaceMethod { // Error.
28+
element
29+
}
30+
31+
abstract class InterfaceGetter {
32+
int get foo;
33+
}
34+
35+
enum E5 implements InterfaceGetter { // Error.
36+
element
37+
}
38+
39+
abstract class InterfaceSetter {
40+
void set foo(int val);
41+
}
42+
43+
enum E6 implements InterfaceSetter { // Error.
44+
element
45+
}
46+
47+
mixin MethodImplementation {
48+
void foo() {}
49+
}
50+
51+
enum E7 with MethodImplementation {
52+
element;
53+
54+
void foo(); // Ok.
55+
}
56+
57+
main() {}
Lines changed: 190 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,190 @@
1+
library /*isNonNullableByDefault*/;
2+
//
3+
// Problems in library:
4+
//
5+
// pkg/front_end/testcases/enhanced_enums/abstract_members.dart:8:8: Error: Enums can't declare abstract members.
6+
// void foo(); // Error.
7+
// ^^^
8+
//
9+
// pkg/front_end/testcases/enhanced_enums/abstract_members.dart:14:11: Error: Enums can't declare abstract members.
10+
// int get foo; // Error.
11+
// ^^^
12+
//
13+
// pkg/front_end/testcases/enhanced_enums/abstract_members.dart:20:12: Error: Enums can't declare abstract members.
14+
// void set foo(int val); // Error.
15+
// ^^^
16+
//
17+
// pkg/front_end/testcases/enhanced_enums/abstract_members.dart:27:6: Error: The non-abstract class 'E4' is missing implementations for these members:
18+
// - InterfaceMethod.foo
19+
// Try to either
20+
// - provide an implementation,
21+
// - inherit an implementation from a superclass or mixin,
22+
// - mark the class as abstract, or
23+
// - provide a 'noSuchMethod' implementation.
24+
//
25+
// enum E4 implements InterfaceMethod { // Error.
26+
// ^^
27+
// pkg/front_end/testcases/enhanced_enums/abstract_members.dart:24:8: Context: 'InterfaceMethod.foo' is defined here.
28+
// void foo();
29+
// ^^^
30+
//
31+
// pkg/front_end/testcases/enhanced_enums/abstract_members.dart:35:6: Error: The non-abstract class 'E5' is missing implementations for these members:
32+
// - InterfaceGetter.foo
33+
// Try to either
34+
// - provide an implementation,
35+
// - inherit an implementation from a superclass or mixin,
36+
// - mark the class as abstract, or
37+
// - provide a 'noSuchMethod' implementation.
38+
//
39+
// enum E5 implements InterfaceGetter { // Error.
40+
// ^^
41+
// pkg/front_end/testcases/enhanced_enums/abstract_members.dart:32:11: Context: 'InterfaceGetter.foo' is defined here.
42+
// int get foo;
43+
// ^^^
44+
//
45+
// pkg/front_end/testcases/enhanced_enums/abstract_members.dart:43:6: Error: The non-abstract class 'E6' is missing implementations for these members:
46+
// - InterfaceSetter.foo=
47+
// Try to either
48+
// - provide an implementation,
49+
// - inherit an implementation from a superclass or mixin,
50+
// - mark the class as abstract, or
51+
// - provide a 'noSuchMethod' implementation.
52+
//
53+
// enum E6 implements InterfaceSetter { // Error.
54+
// ^^
55+
// pkg/front_end/testcases/enhanced_enums/abstract_members.dart:40:12: Context: 'InterfaceSetter.foo=' is defined here.
56+
// void set foo(int val);
57+
// ^^^
58+
//
59+
import self as self;
60+
import "dart:core" as core;
61+
62+
class E1 extends core::_Enum /*isEnum*/ {
63+
static const field core::List<self::E1> values = #C4;
64+
static const field self::E1 element = #C3;
65+
const constructor •(core::int index, core::String name) → self::E1
66+
: super core::_Enum::•(index, name)
67+
;
68+
method toString() → core::String
69+
return "E1.${this.{core::_Enum::_name}{core::String}}";
70+
abstract method foo() → void;
71+
}
72+
class E2 extends core::_Enum /*isEnum*/ {
73+
static const field core::List<self::E2> values = #C6;
74+
static const field self::E2 element = #C5;
75+
const constructor •(core::int index, core::String name) → self::E2
76+
: super core::_Enum::•(index, name)
77+
;
78+
method toString() → core::String
79+
return "E2.${this.{core::_Enum::_name}{core::String}}";
80+
abstract get foo() → core::int;
81+
}
82+
class E3 extends core::_Enum /*isEnum*/ {
83+
static const field core::List<self::E3> values = #C8;
84+
static const field self::E3 element = #C7;
85+
const constructor •(core::int index, core::String name) → self::E3
86+
: super core::_Enum::•(index, name)
87+
;
88+
method toString() → core::String
89+
return "E3.${this.{core::_Enum::_name}{core::String}}";
90+
abstract set foo(core::int val) → void;
91+
}
92+
abstract class InterfaceMethod extends core::Object {
93+
synthetic constructor •() → self::InterfaceMethod
94+
: super core::Object::•()
95+
;
96+
abstract method foo() → void;
97+
}
98+
class E4 extends core::_Enum implements self::InterfaceMethod /*isEnum*/ {
99+
static const field core::List<self::E4> values = #C10;
100+
static const field self::E4 element = #C9;
101+
const constructor •(core::int index, core::String name) → self::E4
102+
: super core::_Enum::•(index, name)
103+
;
104+
method toString() → core::String
105+
return "E4.${this.{core::_Enum::_name}{core::String}}";
106+
}
107+
abstract class InterfaceGetter extends core::Object {
108+
synthetic constructor •() → self::InterfaceGetter
109+
: super core::Object::•()
110+
;
111+
abstract get foo() → core::int;
112+
}
113+
class E5 extends core::_Enum implements self::InterfaceGetter /*isEnum*/ {
114+
static const field core::List<self::E5> values = #C12;
115+
static const field self::E5 element = #C11;
116+
const constructor •(core::int index, core::String name) → self::E5
117+
: super core::_Enum::•(index, name)
118+
;
119+
method toString() → core::String
120+
return "E5.${this.{core::_Enum::_name}{core::String}}";
121+
}
122+
abstract class InterfaceSetter extends core::Object {
123+
synthetic constructor •() → self::InterfaceSetter
124+
: super core::Object::•()
125+
;
126+
abstract set foo(core::int val) → void;
127+
}
128+
class E6 extends core::_Enum implements self::InterfaceSetter /*isEnum*/ {
129+
static const field core::List<self::E6> values = #C14;
130+
static const field self::E6 element = #C13;
131+
const constructor •(core::int index, core::String name) → self::E6
132+
: super core::_Enum::•(index, name)
133+
;
134+
method toString() → core::String
135+
return "E6.${this.{core::_Enum::_name}{core::String}}";
136+
}
137+
abstract class MethodImplementation extends core::Object /*isMixinDeclaration*/ {
138+
method foo() → void {}
139+
}
140+
abstract class _E7&_Enum&MethodImplementation = core::_Enum with self::MethodImplementation /*isAnonymousMixin,hasConstConstructor*/ {
141+
const synthetic constructor •(core::int index, core::String _name) → self::_E7&_Enum&MethodImplementation
142+
: super core::_Enum::•(index, _name)
143+
;
144+
mixin-super-stub method foo() → void
145+
return super.{self::MethodImplementation::foo}();
146+
}
147+
class E7 extends self::_E7&_Enum&MethodImplementation /*isEnum*/ {
148+
static const field core::List<self::E7> values = #C16;
149+
static const field self::E7 element = #C15;
150+
const constructor •(core::int index, core::String name) → self::E7
151+
: super self::_E7&_Enum&MethodImplementation::•(index, name)
152+
;
153+
method toString() → core::String
154+
return "E7.${this.{core::_Enum::_name}{core::String}}";
155+
abstract method foo() → void;
156+
}
157+
static method main() → dynamic {}
158+
159+
constants {
160+
#C1 = 0
161+
#C2 = "element"
162+
#C3 = self::E1 {index:#C1, _name:#C2}
163+
#C4 = <self::E1>[#C3]
164+
#C5 = self::E2 {index:#C1, _name:#C2}
165+
#C6 = <self::E2>[#C5]
166+
#C7 = self::E3 {index:#C1, _name:#C2}
167+
#C8 = <self::E3>[#C7]
168+
#C9 = self::E4 {index:#C1, _name:#C2}
169+
#C10 = <self::E4>[#C9]
170+
#C11 = self::E5 {index:#C1, _name:#C2}
171+
#C12 = <self::E5>[#C11]
172+
#C13 = self::E6 {index:#C1, _name:#C2}
173+
#C14 = <self::E6>[#C13]
174+
#C15 = self::E7 {index:#C1, _name:#C2}
175+
#C16 = <self::E7>[#C15]
176+
}
177+
178+
179+
Constructor coverage from constants:
180+
org-dartlang-testcase:///abstract_members.dart:
181+
- E1. (from org-dartlang-testcase:///abstract_members.dart:5:6)
182+
- _Enum. (from org-dartlang-sdk:///sdk/lib/core/enum.dart:103:9)
183+
- Object. (from org-dartlang-sdk:///sdk/lib/core/object.dart:25:9)
184+
- E2. (from org-dartlang-testcase:///abstract_members.dart:11:6)
185+
- E3. (from org-dartlang-testcase:///abstract_members.dart:17:6)
186+
- E4. (from org-dartlang-testcase:///abstract_members.dart:27:6)
187+
- E5. (from org-dartlang-testcase:///abstract_members.dart:35:6)
188+
- E6. (from org-dartlang-testcase:///abstract_members.dart:43:6)
189+
- E7. (from org-dartlang-testcase:///abstract_members.dart:51:6)
190+
- _E7&_Enum&MethodImplementation. (from org-dartlang-testcase:///abstract_members.dart:51:6)

0 commit comments

Comments
 (0)