Skip to content

Commit eb3d490

Browse files
chloestefantsovaCommit Bot
authored and
Commit Bot
committed
[cfe] Add basic support for intertfaces implemented by enums
Part of #47453 Closes #48140 Change-Id: I6f45fa869a0cf64ae041e0768a0129a989e6d903 Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/228161 Reviewed-by: Johnni Winther <[email protected]> Commit-Queue: Chloe Stefantsova <[email protected]>
1 parent 763f35a commit eb3d490

12 files changed

+782
-4
lines changed

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

+16-1
Original file line numberDiff line numberDiff line change
@@ -2363,7 +2363,7 @@ class OutlineBuilder extends StackListenerImpl {
23632363
const FixedNullableList<EnumConstantInfo>().pop(stack, elementsCount);
23642364
int endCharOffset = popCharOffset();
23652365
int startCharOffset = popCharOffset();
2366-
pop() as List<TypeBuilder>?; // interfaces.
2366+
List<TypeBuilder>? interfaces = pop() as List<TypeBuilder>?;
23672367
MixinApplicationBuilder? mixinBuilder = pop() as MixinApplicationBuilder?;
23682368
List<TypeVariableBuilder>? typeVariables =
23692369
pop() as List<TypeVariableBuilder>?;
@@ -2373,11 +2373,26 @@ class OutlineBuilder extends StackListenerImpl {
23732373
checkEmpty(startCharOffset);
23742374

23752375
if (name is! ParserRecovery) {
2376+
if (interfaces != null) {
2377+
for (TypeBuilder interface in interfaces) {
2378+
if (interface.nullabilityBuilder.build(libraryBuilder) ==
2379+
Nullability.nullable) {
2380+
libraryBuilder.addProblem(
2381+
templateNullableInterfaceError
2382+
.withArguments(interface.fullNameForErrors),
2383+
interface.charOffset ?? startCharOffset,
2384+
(name as String).length,
2385+
uri);
2386+
}
2387+
}
2388+
}
2389+
23762390
libraryBuilder.addEnum(
23772391
metadata,
23782392
name as String,
23792393
typeVariables,
23802394
mixinBuilder,
2395+
interfaces,
23812396
enumConstantInfos,
23822397
startCharOffset,
23832398
charOffset,

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

+6-3
Original file line numberDiff line numberDiff line change
@@ -93,14 +93,15 @@ class SourceEnumBuilder extends SourceClassBuilder {
9393
List<MetadataBuilder>? metadata,
9494
String name,
9595
List<TypeVariableBuilder>? typeVariables,
96+
TypeBuilder supertypeBuilder,
97+
List<TypeBuilder>? interfaceBuilders,
9698
Scope scope,
9799
ConstructorScope constructors,
98100
Class cls,
99101
this.enumConstantInfos,
100102
this.intType,
101103
this.listType,
102104
this.objectType,
103-
TypeBuilder supertypeBuilder,
104105
this.stringType,
105106
SourceLibraryBuilder parent,
106107
int startCharOffset,
@@ -113,7 +114,7 @@ class SourceEnumBuilder extends SourceClassBuilder {
113114
name,
114115
typeVariables,
115116
supertypeBuilder,
116-
/* interfaces = */ null,
117+
interfaceBuilders,
117118
/* onTypes = */ null,
118119
scope,
119120
constructors,
@@ -130,6 +131,7 @@ class SourceEnumBuilder extends SourceClassBuilder {
130131
String name,
131132
List<TypeVariableBuilder>? typeVariables,
132133
TypeBuilder? supertypeBuilder,
134+
List<TypeBuilder>? interfaceBuilders,
133135
List<EnumConstantInfo?>? enumConstantInfos,
134136
SourceLibraryBuilder parent,
135137
int startCharOffset,
@@ -408,6 +410,8 @@ class SourceEnumBuilder extends SourceClassBuilder {
408410
metadata,
409411
name,
410412
typeVariables,
413+
supertypeBuilder,
414+
interfaceBuilders,
411415
new Scope(
412416
local: members,
413417
setters: setters,
@@ -420,7 +424,6 @@ class SourceEnumBuilder extends SourceClassBuilder {
420424
intType,
421425
listType,
422426
objectType,
423-
supertypeBuilder,
424427
stringType,
425428
parent,
426429
startCharOffsetComputed,

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

+2
Original file line numberDiff line numberDiff line change
@@ -2794,6 +2794,7 @@ class SourceLibraryBuilder extends LibraryBuilderImpl {
27942794
String name,
27952795
List<TypeVariableBuilder>? typeVariables,
27962796
TypeBuilder? supertypeBuilder,
2797+
List<TypeBuilder>? interfaceBuilders,
27972798
List<EnumConstantInfo?>? enumConstantInfos,
27982799
int startCharOffset,
27992800
int charOffset,
@@ -2818,6 +2819,7 @@ class SourceLibraryBuilder extends LibraryBuilderImpl {
28182819
applyMixins(supertypeBuilder, startCharOffset, charOffset,
28192820
charEndOffset, name, /* isMixinDeclaration = */ false,
28202821
typeVariables: typeVariables, isMacro: false, isEnumMixin: true),
2822+
interfaceBuilders,
28212823
enumConstantInfos,
28222824
this,
28232825
startCharOffset,
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
// Copyright (c) 2021, 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+
abstract class I {
6+
void foo();
7+
}
8+
9+
enum E1 implements I { // Ok.
10+
one,
11+
two;
12+
13+
void foo() {}
14+
}
15+
16+
enum E2 implements I { // Error.
17+
one,
18+
two
19+
}
20+
21+
enum E3 implements I? { // Error.
22+
one,
23+
two;
24+
25+
void foo() {}
26+
}
27+
28+
enum E4 {
29+
one,
30+
two;
31+
32+
void foo() {}
33+
}
34+
35+
bar(I i) {}
36+
37+
test(E1 e1, E2 e2, E3 e3, E4 e4) {
38+
bar(e1); // Ok.
39+
bar(e2); // Ok.
40+
bar(e3); // Ok.
41+
bar(e4); // Error.
42+
}
43+
44+
main() {}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,121 @@
1+
library /*isNonNullableByDefault*/;
2+
//
3+
// Problems in library:
4+
//
5+
// pkg/front_end/testcases/enhanced_enums/simple_interfaces.dart:21:20: Error: Can't implement 'I' because it's marked with '?'.
6+
// enum E3 implements I? { // Error.
7+
// ^^
8+
//
9+
// pkg/front_end/testcases/enhanced_enums/simple_interfaces.dart:16:6: Error: The non-abstract class 'E2' is missing implementations for these members:
10+
// - I.foo
11+
// Try to either
12+
// - provide an implementation,
13+
// - inherit an implementation from a superclass or mixin,
14+
// - mark the class as abstract, or
15+
// - provide a 'noSuchMethod' implementation.
16+
//
17+
// enum E2 implements I { // Error.
18+
// ^^
19+
// pkg/front_end/testcases/enhanced_enums/simple_interfaces.dart:6:8: Context: 'I.foo' is defined here.
20+
// void foo();
21+
// ^^^
22+
//
23+
// pkg/front_end/testcases/enhanced_enums/simple_interfaces.dart:41:7: Error: The argument type 'E4' can't be assigned to the parameter type 'I'.
24+
// - 'E4' is from 'pkg/front_end/testcases/enhanced_enums/simple_interfaces.dart'.
25+
// - 'I' is from 'pkg/front_end/testcases/enhanced_enums/simple_interfaces.dart'.
26+
// bar(e4); // Error.
27+
// ^
28+
//
29+
import self as self;
30+
import "dart:core" as core;
31+
32+
abstract class I extends core::Object {
33+
synthetic constructor •() → self::I
34+
: super core::Object::•()
35+
;
36+
abstract method foo() → void;
37+
}
38+
class E1 extends core::_Enum implements self::I /*isEnum*/ {
39+
static const field core::List<self::E1> values = #C7;
40+
static const field self::E1 one = #C3;
41+
static const field self::E1 two = #C6;
42+
const constructor •(core::int index, core::String name) → self::E1
43+
: super core::_Enum::•(index, name)
44+
;
45+
method toString() → core::String
46+
return "E1.${this.{core::_Enum::_name}{core::String}}";
47+
method foo() → void {}
48+
}
49+
class E2 extends core::_Enum implements self::I /*isEnum*/ {
50+
static const field core::List<self::E2> values = #C10;
51+
static const field self::E2 one = #C8;
52+
static const field self::E2 two = #C9;
53+
const constructor •(core::int index, core::String name) → self::E2
54+
: super core::_Enum::•(index, name)
55+
;
56+
method toString() → core::String
57+
return "E2.${this.{core::_Enum::_name}{core::String}}";
58+
}
59+
class E3 extends core::_Enum implements self::I /*isEnum*/ {
60+
static const field core::List<self::E3> values = #C13;
61+
static const field self::E3 one = #C11;
62+
static const field self::E3 two = #C12;
63+
const constructor •(core::int index, core::String name) → self::E3
64+
: super core::_Enum::•(index, name)
65+
;
66+
method toString() → core::String
67+
return "E3.${this.{core::_Enum::_name}{core::String}}";
68+
method foo() → void {}
69+
}
70+
class E4 extends core::_Enum /*isEnum*/ {
71+
static const field core::List<self::E4> values = #C16;
72+
static const field self::E4 one = #C14;
73+
static const field self::E4 two = #C15;
74+
const constructor •(core::int index, core::String name) → self::E4
75+
: super core::_Enum::•(index, name)
76+
;
77+
method toString() → core::String
78+
return "E4.${this.{core::_Enum::_name}{core::String}}";
79+
method foo() → void {}
80+
}
81+
static method bar(self::I i) → dynamic {}
82+
static method test(self::E1 e1, self::E2 e2, self::E3 e3, self::E4 e4) → dynamic {
83+
self::bar(e1);
84+
self::bar(e2);
85+
self::bar(e3);
86+
self::bar(invalid-expression "pkg/front_end/testcases/enhanced_enums/simple_interfaces.dart:41:7: Error: The argument type 'E4' can't be assigned to the parameter type 'I'.
87+
- 'E4' is from 'pkg/front_end/testcases/enhanced_enums/simple_interfaces.dart'.
88+
- 'I' is from 'pkg/front_end/testcases/enhanced_enums/simple_interfaces.dart'.
89+
bar(e4); // Error.
90+
^" in e4 as{TypeError,ForNonNullableByDefault} self::I);
91+
}
92+
static method main() → dynamic {}
93+
94+
constants {
95+
#C1 = 0
96+
#C2 = "one"
97+
#C3 = self::E1 {index:#C1, _name:#C2}
98+
#C4 = 1
99+
#C5 = "two"
100+
#C6 = self::E1 {index:#C4, _name:#C5}
101+
#C7 = <self::E1>[#C3, #C6]
102+
#C8 = self::E2 {index:#C1, _name:#C2}
103+
#C9 = self::E2 {index:#C4, _name:#C5}
104+
#C10 = <self::E2>[#C8, #C9]
105+
#C11 = self::E3 {index:#C1, _name:#C2}
106+
#C12 = self::E3 {index:#C4, _name:#C5}
107+
#C13 = <self::E3>[#C11, #C12]
108+
#C14 = self::E4 {index:#C1, _name:#C2}
109+
#C15 = self::E4 {index:#C4, _name:#C5}
110+
#C16 = <self::E4>[#C14, #C15]
111+
}
112+
113+
114+
Constructor coverage from constants:
115+
org-dartlang-testcase:///simple_interfaces.dart:
116+
- E1. (from org-dartlang-testcase:///simple_interfaces.dart:9:6)
117+
- _Enum. (from org-dartlang-sdk:///sdk/lib/core/enum.dart:76:9)
118+
- Object. (from org-dartlang-sdk:///sdk/lib/core/object.dart:25:9)
119+
- E2. (from org-dartlang-testcase:///simple_interfaces.dart:16:6)
120+
- E3. (from org-dartlang-testcase:///simple_interfaces.dart:21:6)
121+
- E4. (from org-dartlang-testcase:///simple_interfaces.dart:28:6)
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,121 @@
1+
library /*isNonNullableByDefault*/;
2+
//
3+
// Problems in library:
4+
//
5+
// pkg/front_end/testcases/enhanced_enums/simple_interfaces.dart:21:20: Error: Can't implement 'I' because it's marked with '?'.
6+
// enum E3 implements I? { // Error.
7+
// ^^
8+
//
9+
// pkg/front_end/testcases/enhanced_enums/simple_interfaces.dart:16:6: Error: The non-abstract class 'E2' is missing implementations for these members:
10+
// - I.foo
11+
// Try to either
12+
// - provide an implementation,
13+
// - inherit an implementation from a superclass or mixin,
14+
// - mark the class as abstract, or
15+
// - provide a 'noSuchMethod' implementation.
16+
//
17+
// enum E2 implements I { // Error.
18+
// ^^
19+
// pkg/front_end/testcases/enhanced_enums/simple_interfaces.dart:6:8: Context: 'I.foo' is defined here.
20+
// void foo();
21+
// ^^^
22+
//
23+
// pkg/front_end/testcases/enhanced_enums/simple_interfaces.dart:41:7: Error: The argument type 'E4' can't be assigned to the parameter type 'I'.
24+
// - 'E4' is from 'pkg/front_end/testcases/enhanced_enums/simple_interfaces.dart'.
25+
// - 'I' is from 'pkg/front_end/testcases/enhanced_enums/simple_interfaces.dart'.
26+
// bar(e4); // Error.
27+
// ^
28+
//
29+
import self as self;
30+
import "dart:core" as core;
31+
32+
abstract class I extends core::Object {
33+
synthetic constructor •() → self::I
34+
: super core::Object::•()
35+
;
36+
abstract method foo() → void;
37+
}
38+
class E1 extends core::_Enum implements self::I /*isEnum*/ {
39+
static const field core::List<self::E1> values = #C7;
40+
static const field self::E1 one = #C3;
41+
static const field self::E1 two = #C6;
42+
const constructor •(core::int index, core::String name) → self::E1
43+
: super core::_Enum::•(index, name)
44+
;
45+
method toString() → core::String
46+
return "E1.${this.{core::_Enum::_name}{core::String}}";
47+
method foo() → void {}
48+
}
49+
class E2 extends core::_Enum implements self::I /*isEnum*/ {
50+
static const field core::List<self::E2> values = #C10;
51+
static const field self::E2 one = #C8;
52+
static const field self::E2 two = #C9;
53+
const constructor •(core::int index, core::String name) → self::E2
54+
: super core::_Enum::•(index, name)
55+
;
56+
method toString() → core::String
57+
return "E2.${this.{core::_Enum::_name}{core::String}}";
58+
}
59+
class E3 extends core::_Enum implements self::I /*isEnum*/ {
60+
static const field core::List<self::E3> values = #C13;
61+
static const field self::E3 one = #C11;
62+
static const field self::E3 two = #C12;
63+
const constructor •(core::int index, core::String name) → self::E3
64+
: super core::_Enum::•(index, name)
65+
;
66+
method toString() → core::String
67+
return "E3.${this.{core::_Enum::_name}{core::String}}";
68+
method foo() → void {}
69+
}
70+
class E4 extends core::_Enum /*isEnum*/ {
71+
static const field core::List<self::E4> values = #C16;
72+
static const field self::E4 one = #C14;
73+
static const field self::E4 two = #C15;
74+
const constructor •(core::int index, core::String name) → self::E4
75+
: super core::_Enum::•(index, name)
76+
;
77+
method toString() → core::String
78+
return "E4.${this.{core::_Enum::_name}{core::String}}";
79+
method foo() → void {}
80+
}
81+
static method bar(self::I i) → dynamic {}
82+
static method test(self::E1 e1, self::E2 e2, self::E3 e3, self::E4 e4) → dynamic {
83+
self::bar(e1);
84+
self::bar(e2);
85+
self::bar(e3);
86+
self::bar(invalid-expression "pkg/front_end/testcases/enhanced_enums/simple_interfaces.dart:41:7: Error: The argument type 'E4' can't be assigned to the parameter type 'I'.
87+
- 'E4' is from 'pkg/front_end/testcases/enhanced_enums/simple_interfaces.dart'.
88+
- 'I' is from 'pkg/front_end/testcases/enhanced_enums/simple_interfaces.dart'.
89+
bar(e4); // Error.
90+
^" in e4 as{TypeError,ForNonNullableByDefault} self::I);
91+
}
92+
static method main() → dynamic {}
93+
94+
constants {
95+
#C1 = 0
96+
#C2 = "one"
97+
#C3 = self::E1 {index:#C1, _name:#C2}
98+
#C4 = 1
99+
#C5 = "two"
100+
#C6 = self::E1 {index:#C4, _name:#C5}
101+
#C7 = <self::E1>[#C3, #C6]
102+
#C8 = self::E2 {index:#C1, _name:#C2}
103+
#C9 = self::E2 {index:#C4, _name:#C5}
104+
#C10 = <self::E2>[#C8, #C9]
105+
#C11 = self::E3 {index:#C1, _name:#C2}
106+
#C12 = self::E3 {index:#C4, _name:#C5}
107+
#C13 = <self::E3>[#C11, #C12]
108+
#C14 = self::E4 {index:#C1, _name:#C2}
109+
#C15 = self::E4 {index:#C4, _name:#C5}
110+
#C16 = <self::E4>[#C14, #C15]
111+
}
112+
113+
114+
Constructor coverage from constants:
115+
org-dartlang-testcase:///simple_interfaces.dart:
116+
- E1. (from org-dartlang-testcase:///simple_interfaces.dart:9:6)
117+
- _Enum. (from org-dartlang-sdk:///sdk/lib/core/enum.dart:76:9)
118+
- Object. (from org-dartlang-sdk:///sdk/lib/core/object.dart:25:9)
119+
- E2. (from org-dartlang-testcase:///simple_interfaces.dart:16:6)
120+
- E3. (from org-dartlang-testcase:///simple_interfaces.dart:21:6)
121+
- E4. (from org-dartlang-testcase:///simple_interfaces.dart:28:6)

0 commit comments

Comments
 (0)