Skip to content

Commit c5b5090

Browse files
jensjohaCommit Queue
authored andcommitted
[CFE] Fix crash when enum has duplicate constructors
Change-Id: I5ee6ef32431eda38c63a3eb3f3ded6b74e2c79df Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/396800 Reviewed-by: Johnni Winther <[email protected]> Commit-Queue: Jens Johansen <[email protected]>
1 parent 17b9bf2 commit c5b5090

8 files changed

+186
-1
lines changed

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

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -161,9 +161,11 @@ class SourceEnumBuilder extends SourceClassBuilder {
161161
super.buildScopes(coreLibrary);
162162
_createSynthesizedMembers(coreLibrary);
163163

164+
// Include duplicates to install the formals on all constructors to avoid a
165+
// crash later.
164166
Iterator<MemberBuilder> iterator =
165167
nameSpace.filteredConstructorNameIterator(
166-
includeDuplicates: false, includeAugmentations: true);
168+
includeDuplicates: true, includeAugmentations: true);
167169
while (iterator.moveNext()) {
168170
MemberBuilder member = iterator.current;
169171
if (member is DeclaredSourceConstructorBuilder) {
@@ -612,6 +614,11 @@ class SourceEnumBuilder extends SourceClassBuilder {
612614
constructorName = constructorName == "new" ? "" : constructorName;
613615
MemberBuilder? constructorBuilder =
614616
nameSpace.lookupConstructor(constructorName);
617+
// TODO(CFE Team): Should there be a conversion to an invalid expression
618+
// instead? That's what happens on classes.
619+
while (constructorBuilder?.next != null) {
620+
constructorBuilder = constructorBuilder?.next as MemberBuilder;
621+
}
615622

616623
ArgumentsImpl arguments;
617624
List<Expression> enumSyntheticArguments = <Expression>[
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
// Copyright (c) 2024, 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 Foo {
6+
a, b;
7+
8+
const Foo();
9+
const Foo();
10+
}
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
library;
2+
//
3+
// Problems in library:
4+
//
5+
// pkg/front_end/testcases/regress/duplicate_enum_constructor.dart:9:9: Error: 'Foo' is already declared in this scope.
6+
// const Foo();
7+
// ^^^
8+
// pkg/front_end/testcases/regress/duplicate_enum_constructor.dart:8:9: Context: Previous declaration of 'Foo'.
9+
// const Foo();
10+
// ^^^
11+
//
12+
import self as self;
13+
import "dart:core" as core;
14+
15+
class Foo extends core::_Enum /*isEnum*/ {
16+
static const field core::List<self::Foo> values = #C7;
17+
enum-element static const field self::Foo a = #C3;
18+
enum-element static const field self::Foo b = #C6;
19+
const constructor •(core::int #index, core::String #name) → self::Foo
20+
: super core::_Enum::•(#index, #name)
21+
;
22+
method _enumToString() → core::String
23+
return "Foo.${this.{core::_Enum::_name}{core::String}}";
24+
}
25+
26+
constants {
27+
#C1 = 0
28+
#C2 = "a"
29+
#C3 = self::Foo {index:#C1, _name:#C2}
30+
#C4 = 1
31+
#C5 = "b"
32+
#C6 = self::Foo {index:#C4, _name:#C5}
33+
#C7 = <self::Foo>[#C3, #C6]
34+
}
35+
36+
37+
Constructor coverage from constants:
38+
org-dartlang-testcase:///duplicate_enum_constructor.dart:
39+
- Foo. (from org-dartlang-testcase:///duplicate_enum_constructor.dart:8:9)
40+
- _Enum. (from org-dartlang-sdk:///sdk/lib/core/enum.dart)
41+
- Object. (from org-dartlang-sdk:///sdk/lib/core/object.dart)
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
library;
2+
//
3+
// Problems in library:
4+
//
5+
// pkg/front_end/testcases/regress/duplicate_enum_constructor.dart:9:9: Error: 'Foo' is already declared in this scope.
6+
// const Foo();
7+
// ^^^
8+
// pkg/front_end/testcases/regress/duplicate_enum_constructor.dart:8:9: Context: Previous declaration of 'Foo'.
9+
// const Foo();
10+
// ^^^
11+
//
12+
import self as self;
13+
import "dart:core" as core;
14+
15+
class Foo extends core::_Enum /*isEnum*/ {
16+
static const field core::List<self::Foo> values = #C7;
17+
enum-element static const field self::Foo a = #C3;
18+
enum-element static const field self::Foo b = #C6;
19+
const constructor •(core::int #index, core::String #name) → self::Foo
20+
: super core::_Enum::•(#index, #name)
21+
;
22+
method _enumToString() → core::String
23+
return "Foo.${this.{core::_Enum::_name}{core::String}}";
24+
}
25+
26+
constants {
27+
#C1 = 0
28+
#C2 = "a"
29+
#C3 = self::Foo {index:#C1, _name:#C2}
30+
#C4 = 1
31+
#C5 = "b"
32+
#C6 = self::Foo {index:#C4, _name:#C5}
33+
#C7 = <self::Foo>[#C3, #C6]
34+
}
35+
36+
37+
Constructor coverage from constants:
38+
org-dartlang-testcase:///duplicate_enum_constructor.dart:
39+
- Foo. (from org-dartlang-testcase:///duplicate_enum_constructor.dart:8:9)
40+
- _Enum. (from org-dartlang-sdk:///sdk/lib/core/enum.dart)
41+
- Object. (from org-dartlang-sdk:///sdk/lib/core/object.dart)
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
library;
2+
//
3+
// Problems in library:
4+
//
5+
// pkg/front_end/testcases/regress/duplicate_enum_constructor.dart:9:9: Error: 'Foo' is already declared in this scope.
6+
// const Foo();
7+
// ^^^
8+
// pkg/front_end/testcases/regress/duplicate_enum_constructor.dart:8:9: Context: Previous declaration of 'Foo'.
9+
// const Foo();
10+
// ^^^
11+
//
12+
import self as self;
13+
import "dart:core" as core;
14+
15+
class Foo extends core::_Enum /*isEnum*/ {
16+
static const field core::List<self::Foo> values = const <self::Foo>[self::Foo::a, self::Foo::b];
17+
enum-element static const field self::Foo a = const self::Foo::•(0, "a");
18+
enum-element static const field self::Foo b = const self::Foo::•(1, "b");
19+
const constructor •(core::int #index, core::String #name) → self::Foo
20+
: super core::_Enum::•(#index, #name)
21+
;
22+
method _enumToString() → core::String
23+
return "Foo.${this.{core::_Enum::_name}{core::String}}";
24+
}
25+
26+
27+
Extra constant evaluation status:
28+
Evaluated: ListLiteral @ org-dartlang-testcase:///duplicate_enum_constructor.dart:5:6 -> ListConstant(const <Foo>[const Foo{_Enum.index: 0, _Enum._name: "a"}, const Foo{_Enum.index: 1, _Enum._name: "b"}])
29+
Evaluated: ConstructorInvocation @ org-dartlang-testcase:///duplicate_enum_constructor.dart:6:3 -> InstanceConstant(const Foo{_Enum.index: 0, _Enum._name: "a"})
30+
Evaluated: ConstructorInvocation @ org-dartlang-testcase:///duplicate_enum_constructor.dart:6:6 -> InstanceConstant(const Foo{_Enum.index: 1, _Enum._name: "b"})
31+
Extra constant evaluation: evaluated: 8, effectively constant: 3
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
library;
2+
//
3+
// Problems in library:
4+
//
5+
// pkg/front_end/testcases/regress/duplicate_enum_constructor.dart:9:9: Error: 'Foo' is already declared in this scope.
6+
// const Foo();
7+
// ^^^
8+
// pkg/front_end/testcases/regress/duplicate_enum_constructor.dart:8:9: Context: Previous declaration of 'Foo'.
9+
// const Foo();
10+
// ^^^
11+
//
12+
import self as self;
13+
import "dart:core" as core;
14+
15+
class Foo extends core::_Enum /*isEnum*/ {
16+
static const field core::List<self::Foo> values = #C7;
17+
enum-element static const field self::Foo a = #C3;
18+
enum-element static const field self::Foo b = #C6;
19+
const constructor •(core::int #index, core::String #name) → self::Foo
20+
: super core::_Enum::•(#index, #name)
21+
;
22+
method _enumToString() → core::String
23+
return "Foo.${this.{core::_Enum::_name}{core::String}}";
24+
}
25+
26+
constants {
27+
#C1 = 0
28+
#C2 = "a"
29+
#C3 = self::Foo {index:#C1, _name:#C2}
30+
#C4 = 1
31+
#C5 = "b"
32+
#C6 = self::Foo {index:#C4, _name:#C5}
33+
#C7 = <self::Foo>[#C3, #C6]
34+
}
35+
36+
37+
Constructor coverage from constants:
38+
org-dartlang-testcase:///duplicate_enum_constructor.dart:
39+
- Foo. (from org-dartlang-testcase:///duplicate_enum_constructor.dart:8:9)
40+
- _Enum. (from org-dartlang-sdk:///sdk/lib/core/enum.dart)
41+
- Object. (from org-dartlang-sdk:///sdk/lib/core/object.dart)
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
enum Foo {
2+
a,
3+
b;
4+
5+
const Foo();
6+
const Foo();
7+
}
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
enum Foo {
2+
a,
3+
b;
4+
5+
const Foo();
6+
const Foo();
7+
}

0 commit comments

Comments
 (0)