Skip to content

Commit deba7fe

Browse files
chloestefantsovaCommit Bot
authored and
Commit Bot
committed
[cfe] Report errors on implementors of 'Enum' declaring 'values'
Part of #47453 Closes #48388 Change-Id: I87d57407e16916a78864b9ce74b9250afc39958f Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/233304 Reviewed-by: Johnni Winther <[email protected]> Commit-Queue: Chloe Stefantsova <[email protected]>
1 parent 34c0296 commit deba7fe

13 files changed

+744
-9
lines changed

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

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2835,6 +2835,31 @@ const MessageCode messageEnumFactoryRedirectsToConstructor = const MessageCode(
28352835
problemMessage:
28362836
r"""Enum factory constructors can't redirect to generative constructors.""");
28372837

2838+
// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
2839+
const Template<Message Function(String name)>
2840+
templateEnumImplementerContainsValuesDeclaration =
2841+
const Template<Message Function(String name)>(
2842+
problemMessageTemplate:
2843+
r"""'#name' has 'Enum' as a superinterface and can't contain non-static member with name 'values'.""",
2844+
withArguments: _withArgumentsEnumImplementerContainsValuesDeclaration);
2845+
2846+
// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
2847+
const Code<Message Function(String name)>
2848+
codeEnumImplementerContainsValuesDeclaration =
2849+
const Code<Message Function(String name)>(
2850+
"EnumImplementerContainsValuesDeclaration",
2851+
);
2852+
2853+
// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
2854+
Message _withArgumentsEnumImplementerContainsValuesDeclaration(String name) {
2855+
if (name.isEmpty) throw 'No name provided';
2856+
name = demangleMixinApplicationName(name);
2857+
return new Message(codeEnumImplementerContainsValuesDeclaration,
2858+
problemMessage:
2859+
"""'${name}' has 'Enum' as a superinterface and can't contain non-static member with name 'values'.""",
2860+
arguments: {'name': name});
2861+
}
2862+
28382863
// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
28392864
const Code<Null> codeEnumInClass = messageEnumInClass;
28402865

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

Lines changed: 40 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -622,25 +622,58 @@ class SourceClassBuilder extends ClassBuilderImpl
622622
// Moreover, it checks that `FutureOr` and `void` are not among the
623623
// supertypes and that `Enum` is not implemented by non-abstract classes.
624624

625-
if (!cls.isAbstract && !cls.isEnum) {
626-
bool isEnumFound = false;
625+
if (library.enableEnhancedEnumsInLibrary) {
626+
bool hasEnumSuperinterface = false;
627627
List<Supertype> interfaces =
628628
hierarchyBuilder.getNodeFromClass(cls).superclasses;
629-
for (int i = 0; !isEnumFound && i < interfaces.length; i++) {
629+
for (int i = 0; !hasEnumSuperinterface && i < interfaces.length; i++) {
630630
if (interfaces[i].classNode == enumClass) {
631-
isEnumFound = true;
631+
hasEnumSuperinterface = true;
632632
}
633633
}
634634
interfaces = hierarchyBuilder.getNodeFromClass(cls).interfaces;
635-
for (int i = 0; !isEnumFound && i < interfaces.length; i++) {
635+
for (int i = 0; !hasEnumSuperinterface && i < interfaces.length; i++) {
636636
if (interfaces[i].classNode == enumClass) {
637-
isEnumFound = true;
637+
hasEnumSuperinterface = true;
638638
}
639639
}
640-
if (isEnumFound) {
640+
if (!cls.isAbstract && !cls.isEnum && hasEnumSuperinterface) {
641641
addProblem(templateEnumSupertypeOfNonAbstractClass.withArguments(name),
642642
charOffset, noLength);
643643
}
644+
645+
if (hasEnumSuperinterface) {
646+
Builder? customValuesDeclaration =
647+
scope.lookupLocalMember("values", setter: false);
648+
if (customValuesDeclaration != null &&
649+
!customValuesDeclaration.isStatic) {
650+
// Retrieve the earliest declaration for error reporting.
651+
while (customValuesDeclaration?.next != null) {
652+
customValuesDeclaration = customValuesDeclaration?.next;
653+
}
654+
library.addProblem(
655+
templateEnumImplementerContainsValuesDeclaration
656+
.withArguments(this.name),
657+
customValuesDeclaration!.charOffset,
658+
customValuesDeclaration.fullNameForErrors.length,
659+
fileUri);
660+
}
661+
customValuesDeclaration =
662+
scope.lookupLocalMember("values", setter: true);
663+
if (customValuesDeclaration != null &&
664+
!customValuesDeclaration.isStatic) {
665+
// Retrieve the earliest declaration for error reporting.
666+
while (customValuesDeclaration?.next != null) {
667+
customValuesDeclaration = customValuesDeclaration?.next;
668+
}
669+
library.addProblem(
670+
templateEnumImplementerContainsValuesDeclaration
671+
.withArguments(this.name),
672+
customValuesDeclaration!.charOffset,
673+
customValuesDeclaration.fullNameForErrors.length,
674+
fileUri);
675+
}
676+
}
644677
}
645678

646679
void fail(NamedTypeBuilder target, Message message,

pkg/front_end/messages.status

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,6 @@
55
# Note that test/spelling: Status will have no effect. Spelling errors can
66
# always be fixed by either spelling correctly or updating the dictionary.
77

8-
EnumContainsValuesDeclaration/analyzerCode: Fail
9-
EnumContainsValuesDeclaration/example: Fail
108
AbstractClassConstructorTearOff/analyzerCode: Fail
119
AbstractClassInstantiation/example: Fail
1210
AbstractExtensionField/analyzerCode: Fail
@@ -219,6 +217,8 @@ EnumConstructorSuperInitializer/analyzerCode: Fail
219217
EnumConstructorSuperInitializer/example: Fail
220218
EnumConstructorTearoff/analyzerCode: Fail
221219
EnumConstructorTearoff/example: Fail
220+
EnumContainsValuesDeclaration/analyzerCode: Fail
221+
EnumContainsValuesDeclaration/example: Fail
222222
EnumDeclaresConstFactory/analyzerCode: Fail
223223
EnumDeclaresConstFactory/example: Fail
224224
EnumDeclaresFactory/analyzerCode: Fail
@@ -227,6 +227,8 @@ EnumEntryWithTypeArgumentsWithoutArguments/analyzerCode: Fail
227227
EnumEntryWithTypeArgumentsWithoutArguments/example: Fail
228228
EnumFactoryRedirectsToConstructor/analyzerCode: Fail
229229
EnumFactoryRedirectsToConstructor/example: Fail
230+
EnumImplementerContainsValuesDeclaration/analyzerCode: Fail
231+
EnumImplementerContainsValuesDeclaration/example: Fail
230232
EnumInstantiation/example: Fail
231233
EnumNonConstConstructor/analyzerCode: Fail
232234
EnumNonConstConstructor/example: Fail

pkg/front_end/messages.yaml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5476,3 +5476,6 @@ EnumFactoryRedirectsToConstructor:
54765476

54775477
EnumContainsValuesDeclaration:
54785478
problemMessage: "Enums can't contain declarations of members with the name 'values'."
5479+
5480+
EnumImplementerContainsValuesDeclaration:
5481+
problemMessage: "'#name' has 'Enum' as a superinterface and can't contain non-static member with name 'values'."
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
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+
mixin M1 on Enum {
6+
final int values = 42; // Error.
7+
}
8+
9+
mixin M2 on Enum {
10+
static final int values = 42; // Ok.
11+
}
12+
13+
mixin M3 on Enum {
14+
void set values(String x) {} // Error.
15+
}
16+
17+
mixin M4 on Enum {
18+
static void set values(String x) {} // Ok.
19+
}
20+
21+
mixin M5 on Enum {
22+
num get values => 0; // Error.
23+
void set values(num x) {} // Error.
24+
}
25+
26+
abstract class E1 extends Enum {
27+
int values() => 42; // Error.
28+
}
29+
30+
abstract class E2 extends Enum {
31+
static int values() => 42; // Ok.
32+
}
33+
34+
abstract class E3 extends Enum {
35+
void set values(num x) {} // Error.
36+
}
37+
38+
abstract class E4 extends Enum {
39+
static void set values(num x) {} // Ok.
40+
}
41+
42+
abstract class E5 extends Enum {
43+
num get values => 0; // Error.
44+
void set values(num x) {} // Error.
45+
}
46+
47+
main() {}
Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,91 @@
1+
library /*isNonNullableByDefault*/;
2+
//
3+
// Problems in library:
4+
//
5+
// pkg/front_end/testcases/enhanced_enums/issue48388.dart:6:13: Error: 'M1' has 'Enum' as a superinterface and can't contain non-static member with name 'values'.
6+
// final int values = 42; // Error.
7+
// ^^^^^^
8+
//
9+
// pkg/front_end/testcases/enhanced_enums/issue48388.dart:14:12: Error: 'M3' has 'Enum' as a superinterface and can't contain non-static member with name 'values'.
10+
// void set values(String x) {} // Error.
11+
// ^^^^^^
12+
//
13+
// pkg/front_end/testcases/enhanced_enums/issue48388.dart:22:11: Error: 'M5' has 'Enum' as a superinterface and can't contain non-static member with name 'values'.
14+
// num get values => 0; // Error.
15+
// ^^^^^^
16+
//
17+
// pkg/front_end/testcases/enhanced_enums/issue48388.dart:23:12: Error: 'M5' has 'Enum' as a superinterface and can't contain non-static member with name 'values'.
18+
// void set values(num x) {} // Error.
19+
// ^^^^^^
20+
//
21+
// pkg/front_end/testcases/enhanced_enums/issue48388.dart:27:7: Error: 'E1' has 'Enum' as a superinterface and can't contain non-static member with name 'values'.
22+
// int values() => 42; // Error.
23+
// ^^^^^^
24+
//
25+
// pkg/front_end/testcases/enhanced_enums/issue48388.dart:35:12: Error: 'E3' has 'Enum' as a superinterface and can't contain non-static member with name 'values'.
26+
// void set values(num x) {} // Error.
27+
// ^^^^^^
28+
//
29+
// pkg/front_end/testcases/enhanced_enums/issue48388.dart:43:11: Error: 'E5' has 'Enum' as a superinterface and can't contain non-static member with name 'values'.
30+
// num get values => 0; // Error.
31+
// ^^^^^^
32+
//
33+
// pkg/front_end/testcases/enhanced_enums/issue48388.dart:44:12: Error: 'E5' has 'Enum' as a superinterface and can't contain non-static member with name 'values'.
34+
// void set values(num x) {} // Error.
35+
// ^^^^^^
36+
//
37+
import self as self;
38+
import "dart:core" as core;
39+
40+
abstract class M1 extends core::Enum /*isMixinDeclaration*/ {
41+
final field core::int values = 42;
42+
}
43+
abstract class M2 extends core::Enum /*isMixinDeclaration*/ {
44+
static final field core::int values = 42;
45+
}
46+
abstract class M3 extends core::Enum /*isMixinDeclaration*/ {
47+
set values(core::String x) → void {}
48+
}
49+
abstract class M4 extends core::Enum /*isMixinDeclaration*/ {
50+
static set values(core::String x) → void {}
51+
}
52+
abstract class M5 extends core::Enum /*isMixinDeclaration*/ {
53+
get values() → core::num
54+
return 0;
55+
set values(core::num x) → void {}
56+
}
57+
abstract class E1 extends core::Enum {
58+
synthetic constructor •() → self::E1
59+
: super core::Enum::•()
60+
;
61+
method values() → core::int
62+
return 42;
63+
}
64+
abstract class E2 extends core::Enum {
65+
synthetic constructor •() → self::E2
66+
: super core::Enum::•()
67+
;
68+
static method values() → core::int
69+
return 42;
70+
}
71+
abstract class E3 extends core::Enum {
72+
synthetic constructor •() → self::E3
73+
: super core::Enum::•()
74+
;
75+
set values(core::num x) → void {}
76+
}
77+
abstract class E4 extends core::Enum {
78+
synthetic constructor •() → self::E4
79+
: super core::Enum::•()
80+
;
81+
static set values(core::num x) → void {}
82+
}
83+
abstract class E5 extends core::Enum {
84+
synthetic constructor •() → self::E5
85+
: super core::Enum::•()
86+
;
87+
get values() → core::num
88+
return 0;
89+
set values(core::num x) → void {}
90+
}
91+
static method main() → dynamic {}
Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,91 @@
1+
library /*isNonNullableByDefault*/;
2+
//
3+
// Problems in library:
4+
//
5+
// pkg/front_end/testcases/enhanced_enums/issue48388.dart:6:13: Error: 'M1' has 'Enum' as a superinterface and can't contain non-static member with name 'values'.
6+
// final int values = 42; // Error.
7+
// ^^^^^^
8+
//
9+
// pkg/front_end/testcases/enhanced_enums/issue48388.dart:14:12: Error: 'M3' has 'Enum' as a superinterface and can't contain non-static member with name 'values'.
10+
// void set values(String x) {} // Error.
11+
// ^^^^^^
12+
//
13+
// pkg/front_end/testcases/enhanced_enums/issue48388.dart:22:11: Error: 'M5' has 'Enum' as a superinterface and can't contain non-static member with name 'values'.
14+
// num get values => 0; // Error.
15+
// ^^^^^^
16+
//
17+
// pkg/front_end/testcases/enhanced_enums/issue48388.dart:23:12: Error: 'M5' has 'Enum' as a superinterface and can't contain non-static member with name 'values'.
18+
// void set values(num x) {} // Error.
19+
// ^^^^^^
20+
//
21+
// pkg/front_end/testcases/enhanced_enums/issue48388.dart:27:7: Error: 'E1' has 'Enum' as a superinterface and can't contain non-static member with name 'values'.
22+
// int values() => 42; // Error.
23+
// ^^^^^^
24+
//
25+
// pkg/front_end/testcases/enhanced_enums/issue48388.dart:35:12: Error: 'E3' has 'Enum' as a superinterface and can't contain non-static member with name 'values'.
26+
// void set values(num x) {} // Error.
27+
// ^^^^^^
28+
//
29+
// pkg/front_end/testcases/enhanced_enums/issue48388.dart:43:11: Error: 'E5' has 'Enum' as a superinterface and can't contain non-static member with name 'values'.
30+
// num get values => 0; // Error.
31+
// ^^^^^^
32+
//
33+
// pkg/front_end/testcases/enhanced_enums/issue48388.dart:44:12: Error: 'E5' has 'Enum' as a superinterface and can't contain non-static member with name 'values'.
34+
// void set values(num x) {} // Error.
35+
// ^^^^^^
36+
//
37+
import self as self;
38+
import "dart:core" as core;
39+
40+
abstract class M1 extends core::Enum /*isMixinDeclaration*/ {
41+
final field core::int values = 42;
42+
}
43+
abstract class M2 extends core::Enum /*isMixinDeclaration*/ {
44+
static final field core::int values = 42;
45+
}
46+
abstract class M3 extends core::Enum /*isMixinDeclaration*/ {
47+
set values(core::String x) → void {}
48+
}
49+
abstract class M4 extends core::Enum /*isMixinDeclaration*/ {
50+
static set values(core::String x) → void {}
51+
}
52+
abstract class M5 extends core::Enum /*isMixinDeclaration*/ {
53+
get values() → core::num
54+
return 0;
55+
set values(core::num x) → void {}
56+
}
57+
abstract class E1 extends core::Enum {
58+
synthetic constructor •() → self::E1
59+
: super core::Enum::•()
60+
;
61+
method values() → core::int
62+
return 42;
63+
}
64+
abstract class E2 extends core::Enum {
65+
synthetic constructor •() → self::E2
66+
: super core::Enum::•()
67+
;
68+
static method values() → core::int
69+
return 42;
70+
}
71+
abstract class E3 extends core::Enum {
72+
synthetic constructor •() → self::E3
73+
: super core::Enum::•()
74+
;
75+
set values(core::num x) → void {}
76+
}
77+
abstract class E4 extends core::Enum {
78+
synthetic constructor •() → self::E4
79+
: super core::Enum::•()
80+
;
81+
static set values(core::num x) → void {}
82+
}
83+
abstract class E5 extends core::Enum {
84+
synthetic constructor •() → self::E5
85+
: super core::Enum::•()
86+
;
87+
get values() → core::num
88+
return 0;
89+
set values(core::num x) → void {}
90+
}
91+
static method main() → dynamic {}

0 commit comments

Comments
 (0)