Skip to content

Commit 0ee2b0f

Browse files
[cfe] Adjust redirecting initializers of enum constructors
Part of #47453 Change-Id: I46a96c8c6ab4d54186ad612e3c7586cc92781d87 Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/225729 Reviewed-by: Johnni Winther <[email protected]>
1 parent ae69916 commit 0ee2b0f

11 files changed

+522
-1
lines changed

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

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1760,6 +1760,37 @@ class BodyBuilder extends ScopeListener<JumpTarget>
17601760
constructor.initializers.add(buildInvalidInitializer(buildProblem(
17611761
fasta.messageConstructorNotSync, body!.fileOffset, noLength)));
17621762
}
1763+
if (libraryBuilder.enableEnhancedEnumsInLibrary &&
1764+
classBuilder is SourceEnumBuilder &&
1765+
constructor.initializers.isNotEmpty &&
1766+
constructor.initializers.last is RedirectingInitializer) {
1767+
RedirectingInitializer redirectingInitializer =
1768+
constructor.initializers.last as RedirectingInitializer;
1769+
redirectingInitializer.arguments.positional.insertAll(0, [
1770+
new VariableGet(constructor.function.positionalParameters[0])
1771+
..parent = redirectingInitializer.arguments,
1772+
new VariableGet(constructor.function.positionalParameters[1])
1773+
..parent = redirectingInitializer.arguments
1774+
]);
1775+
1776+
LocatedMessage? message = checkArgumentsForFunction(
1777+
redirectingInitializer.target.function,
1778+
redirectingInitializer.arguments,
1779+
builder.charOffset, const <TypeParameter>[]);
1780+
if (message != null) {
1781+
Initializer invalidInitializer = buildInvalidInitializer(
1782+
buildUnresolvedError(
1783+
forest.createNullLiteral(redirectingInitializer.fileOffset),
1784+
constructorNameForDiagnostics(builder.name, isSuper: false),
1785+
redirectingInitializer.arguments,
1786+
redirectingInitializer.fileOffset,
1787+
isSuper: false,
1788+
message: message,
1789+
kind: UnresolvedKind.Constructor));
1790+
constructor.initializers.removeLast();
1791+
constructor.initializers.add(invalidInitializer..parent = constructor);
1792+
}
1793+
}
17631794
if (needsImplicitSuperInitializer) {
17641795
/// >If no superinitializer is provided, an implicit superinitializer
17651796
/// >of the form super() is added at the end of k’s initializer list,

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

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4576,7 +4576,14 @@ class ThisAccessGenerator extends Generator {
45764576
// The check of the arguments is done later for super initializers if the
45774577
// 'super-parameters' language feature is enabled. In that case the
45784578
// additional parameters can be added at a later stage.
4579-
if (!(isSuper && _helper.libraryBuilder.enableSuperParametersInLibrary)) {
4579+
bool isPotentialSuperParametersReceiver =
4580+
isSuper && _helper.libraryBuilder.enableSuperParametersInLibrary;
4581+
// Additional arguments are added to the redirecting initializer of an
4582+
// enum constructor, so the check is performed later.
4583+
bool isEnumConstructorRedirectingInitializer =
4584+
constructor.enclosingClass.isEnum;
4585+
if (!isPotentialSuperParametersReceiver &&
4586+
!isEnumConstructorRedirectingInitializer) {
45804587
message = _helper.checkArgumentsForFunction(
45814588
constructor.function, arguments, offset, <TypeParameter>[]);
45824589
}
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
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+
enum E1 {
6+
one(1),
7+
two.named(2);
8+
9+
final int foo;
10+
11+
const E1(this.foo);
12+
const E1.named(int value) : this(value); // Ok.
13+
}
14+
15+
enum E2 {
16+
one(1),
17+
two.named(2);
18+
19+
final int foo;
20+
21+
const E2(this.foo);
22+
const E2.named(int value) : this(value, value); // Error.
23+
}
24+
25+
main() {}
Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
library /*isNonNullableByDefault*/;
2+
//
3+
// Problems in library:
4+
//
5+
// pkg/front_end/testcases/enhanced_enums/redirecting_initializers.dart:22:35: Error: Too many positional arguments: 3 allowed, but 4 found.
6+
// Try removing the extra positional arguments.
7+
// const E2.named(int value) : this(value, value); // Error.
8+
// ^
9+
//
10+
// pkg/front_end/testcases/enhanced_enums/redirecting_initializers.dart:22:9: Error: Final field 'foo' is not initialized by this constructor.
11+
// Try to initialize the field using an initializing formal or a field initializer.
12+
// const E2.named(int value) : this(value, value); // Error.
13+
// ^^^^^
14+
// pkg/front_end/testcases/enhanced_enums/redirecting_initializers.dart:19:13: Context: 'foo' is defined here.
15+
// final int foo;
16+
// ^^^
17+
//
18+
import self as self;
19+
import "dart:core" as core;
20+
21+
class E1 extends core::_Enum /*isEnum*/ {
22+
static const field core::List<self::E1> values = #C8;
23+
static const field self::E1 one = #C4;
24+
static const field self::E1 two = #C7;
25+
final field core::int foo;
26+
const constructor •(core::int index, core::String name, core::int foo) → self::E1
27+
: self::E1::foo = foo, super core::_Enum::•(index, name)
28+
;
29+
const constructor named(core::int index, core::String name, core::int value) → self::E1
30+
: this self::E1::•(index, name, value)
31+
;
32+
method toString() → core::String
33+
return "E1.${this.{core::_Enum::_name}{core::String}}";
34+
}
35+
class E2 extends core::_Enum /*isEnum*/ {
36+
static const field core::List<self::E2> values = invalid-expression "pkg/front_end/testcases/enhanced_enums/redirecting_initializers.dart:22:35: Error: Too many positional arguments: 3 allowed, but 4 found.
37+
Try removing the extra positional arguments.
38+
const E2.named(int value) : this(value, value); // Error.
39+
^";
40+
static const field self::E2 one = #C9;
41+
static const field self::E2 two = invalid-expression "pkg/front_end/testcases/enhanced_enums/redirecting_initializers.dart:22:35: Error: Too many positional arguments: 3 allowed, but 4 found.
42+
Try removing the extra positional arguments.
43+
const E2.named(int value) : this(value, value); // Error.
44+
^";
45+
final field core::int foo;
46+
const constructor •(core::int index, core::String name, core::int foo) → self::E2
47+
: self::E2::foo = foo, super core::_Enum::•(index, name)
48+
;
49+
const constructor named(core::int index, core::String name, core::int value) → self::E2
50+
: self::E2::foo = null, final dynamic #t1 = invalid-expression "pkg/front_end/testcases/enhanced_enums/redirecting_initializers.dart:22:35: Error: Too many positional arguments: 3 allowed, but 4 found.
51+
Try removing the extra positional arguments.
52+
const E2.named(int value) : this(value, value); // Error.
53+
^"
54+
;
55+
method toString() → core::String
56+
return "E2.${this.{core::_Enum::_name}{core::String}}";
57+
}
58+
static method main() → dynamic {}
59+
60+
constants {
61+
#C1 = 1
62+
#C2 = 0
63+
#C3 = "one"
64+
#C4 = self::E1 {foo:#C1, index:#C2, _name:#C3}
65+
#C5 = 2
66+
#C6 = "two"
67+
#C7 = self::E1 {foo:#C5, index:#C1, _name:#C6}
68+
#C8 = <self::E1>[#C4, #C7]
69+
#C9 = self::E2 {foo:#C1, index:#C2, _name:#C3}
70+
}
71+
72+
73+
Constructor coverage from constants:
74+
org-dartlang-testcase:///redirecting_initializers.dart:
75+
- E1. (from org-dartlang-testcase:///redirecting_initializers.dart:11:9)
76+
- _Enum. (from org-dartlang-sdk:///sdk/lib/core/enum.dart:76:9)
77+
- Object. (from org-dartlang-sdk:///sdk/lib/core/object.dart:25:9)
78+
- E1.named (from org-dartlang-testcase:///redirecting_initializers.dart:12:9)
79+
- E2. (from org-dartlang-testcase:///redirecting_initializers.dart:21:9)
80+
- E2.named (from org-dartlang-testcase:///redirecting_initializers.dart:22:9)
Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
library /*isNonNullableByDefault*/;
2+
//
3+
// Problems in library:
4+
//
5+
// pkg/front_end/testcases/enhanced_enums/redirecting_initializers.dart:22:35: Error: Too many positional arguments: 3 allowed, but 4 found.
6+
// Try removing the extra positional arguments.
7+
// const E2.named(int value) : this(value, value); // Error.
8+
// ^
9+
//
10+
// pkg/front_end/testcases/enhanced_enums/redirecting_initializers.dart:22:9: Error: Final field 'foo' is not initialized by this constructor.
11+
// Try to initialize the field using an initializing formal or a field initializer.
12+
// const E2.named(int value) : this(value, value); // Error.
13+
// ^^^^^
14+
// pkg/front_end/testcases/enhanced_enums/redirecting_initializers.dart:19:13: Context: 'foo' is defined here.
15+
// final int foo;
16+
// ^^^
17+
//
18+
import self as self;
19+
import "dart:core" as core;
20+
21+
class E1 extends core::_Enum /*isEnum*/ {
22+
static const field core::List<self::E1> values = #C8;
23+
static const field self::E1 one = #C4;
24+
static const field self::E1 two = #C7;
25+
final field core::int foo;
26+
const constructor •(core::int index, core::String name, core::int foo) → self::E1
27+
: self::E1::foo = foo, super core::_Enum::•(index, name)
28+
;
29+
const constructor named(core::int index, core::String name, core::int value) → self::E1
30+
: this self::E1::•(index, name, value)
31+
;
32+
method toString() → core::String
33+
return "E1.${this.{core::_Enum::_name}{core::String}}";
34+
}
35+
class E2 extends core::_Enum /*isEnum*/ {
36+
static const field core::List<self::E2> values = invalid-expression "pkg/front_end/testcases/enhanced_enums/redirecting_initializers.dart:22:35: Error: Too many positional arguments: 3 allowed, but 4 found.
37+
Try removing the extra positional arguments.
38+
const E2.named(int value) : this(value, value); // Error.
39+
^";
40+
static const field self::E2 one = #C9;
41+
static const field self::E2 two = invalid-expression "pkg/front_end/testcases/enhanced_enums/redirecting_initializers.dart:22:35: Error: Too many positional arguments: 3 allowed, but 4 found.
42+
Try removing the extra positional arguments.
43+
const E2.named(int value) : this(value, value); // Error.
44+
^";
45+
final field core::int foo;
46+
const constructor •(core::int index, core::String name, core::int foo) → self::E2
47+
: self::E2::foo = foo, super core::_Enum::•(index, name)
48+
;
49+
const constructor named(core::int index, core::String name, core::int value) → self::E2
50+
: self::E2::foo = null, final dynamic #t1 = invalid-expression "pkg/front_end/testcases/enhanced_enums/redirecting_initializers.dart:22:35: Error: Too many positional arguments: 3 allowed, but 4 found.
51+
Try removing the extra positional arguments.
52+
const E2.named(int value) : this(value, value); // Error.
53+
^"
54+
;
55+
method toString() → core::String
56+
return "E2.${this.{core::_Enum::_name}{core::String}}";
57+
}
58+
static method main() → dynamic {}
59+
60+
constants {
61+
#C1 = 1
62+
#C2 = 0
63+
#C3 = "one"
64+
#C4 = self::E1 {foo:#C1, index:#C2, _name:#C3}
65+
#C5 = 2
66+
#C6 = "two"
67+
#C7 = self::E1 {foo:#C5, index:#C1, _name:#C6}
68+
#C8 = <self::E1>[#C4, #C7]
69+
#C9 = self::E2 {foo:#C1, index:#C2, _name:#C3}
70+
}
71+
72+
73+
Constructor coverage from constants:
74+
org-dartlang-testcase:///redirecting_initializers.dart:
75+
- E1. (from org-dartlang-testcase:///redirecting_initializers.dart:11:9)
76+
- _Enum. (from org-dartlang-sdk:///sdk/lib/core/enum.dart:76:9)
77+
- Object. (from org-dartlang-sdk:///sdk/lib/core/object.dart:25:9)
78+
- E1.named (from org-dartlang-testcase:///redirecting_initializers.dart:12:9)
79+
- E2. (from org-dartlang-testcase:///redirecting_initializers.dart:21:9)
80+
- E2.named (from org-dartlang-testcase:///redirecting_initializers.dart:22:9)
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
enum E1 { one(1), two.named(2); final int foo; const E1(this.foo); const E1.named(int value) : this(value); }
2+
enum E2 { one(1), two.named(2); final int foo; const E2(this.foo); const E2.named(int value) : this(value, value); }
3+
main() {}
Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
library /*isNonNullableByDefault*/;
2+
//
3+
// Problems in library:
4+
//
5+
// pkg/front_end/testcases/enhanced_enums/redirecting_initializers.dart:22:35: Error: Too many positional arguments: 3 allowed, but 4 found.
6+
// Try removing the extra positional arguments.
7+
// const E2.named(int value) : this(value, value); // Error.
8+
// ^
9+
//
10+
// pkg/front_end/testcases/enhanced_enums/redirecting_initializers.dart:22:9: Error: Final field 'foo' is not initialized by this constructor.
11+
// Try to initialize the field using an initializing formal or a field initializer.
12+
// const E2.named(int value) : this(value, value); // Error.
13+
// ^^^^^
14+
// pkg/front_end/testcases/enhanced_enums/redirecting_initializers.dart:19:13: Context: 'foo' is defined here.
15+
// final int foo;
16+
// ^^^
17+
//
18+
import self as self;
19+
import "dart:core" as core;
20+
21+
class E1 extends core::_Enum /*isEnum*/ {
22+
static const field core::List<self::E1> values = #C8;
23+
static const field self::E1 one = #C4;
24+
static const field self::E1 two = #C7;
25+
final field core::int foo;
26+
const constructor •(core::int index, core::String name, core::int foo) → self::E1
27+
: self::E1::foo = foo, super core::_Enum::•(index, name)
28+
;
29+
const constructor named(core::int index, core::String name, core::int value) → self::E1
30+
: this self::E1::•(index, name, value)
31+
;
32+
method toString() → core::String
33+
return "E1.${this.{core::_Enum::_name}{core::String}}";
34+
}
35+
class E2 extends core::_Enum /*isEnum*/ {
36+
static const field core::List<self::E2> values = invalid-expression "pkg/front_end/testcases/enhanced_enums/redirecting_initializers.dart:22:35: Error: Too many positional arguments: 3 allowed, but 4 found.
37+
Try removing the extra positional arguments.
38+
const E2.named(int value) : this(value, value); // Error.
39+
^";
40+
static const field self::E2 one = #C9;
41+
static const field self::E2 two = invalid-expression "pkg/front_end/testcases/enhanced_enums/redirecting_initializers.dart:22:35: Error: Too many positional arguments: 3 allowed, but 4 found.
42+
Try removing the extra positional arguments.
43+
const E2.named(int value) : this(value, value); // Error.
44+
^";
45+
final field core::int foo;
46+
const constructor •(core::int index, core::String name, core::int foo) → self::E2
47+
: self::E2::foo = foo, super core::_Enum::•(index, name)
48+
;
49+
const constructor named(core::int index, core::String name, core::int value) → self::E2
50+
: self::E2::foo = null, final dynamic #t1 = invalid-expression "pkg/front_end/testcases/enhanced_enums/redirecting_initializers.dart:22:35: Error: Too many positional arguments: 3 allowed, but 4 found.
51+
Try removing the extra positional arguments.
52+
const E2.named(int value) : this(value, value); // Error.
53+
^"
54+
;
55+
method toString() → core::String
56+
return "E2.${this.{core::_Enum::_name}{core::String}}";
57+
}
58+
static method main() → dynamic {}
59+
60+
constants {
61+
#C1 = 1
62+
#C2 = 0
63+
#C3 = "one"
64+
#C4 = self::E1 {foo:#C1, index:#C2, _name:#C3}
65+
#C5 = 2
66+
#C6 = "two"
67+
#C7 = self::E1 {foo:#C5, index:#C1, _name:#C6}
68+
#C8 = <self::E1*>[#C4, #C7]
69+
#C9 = self::E2 {foo:#C1, index:#C2, _name:#C3}
70+
}
71+
72+
73+
Constructor coverage from constants:
74+
org-dartlang-testcase:///redirecting_initializers.dart:
75+
- E1. (from org-dartlang-testcase:///redirecting_initializers.dart:11:9)
76+
- _Enum. (from org-dartlang-sdk:///sdk/lib/core/enum.dart:76:9)
77+
- Object. (from org-dartlang-sdk:///sdk/lib/core/object.dart:25:9)
78+
- E1.named (from org-dartlang-testcase:///redirecting_initializers.dart:12:9)
79+
- E2. (from org-dartlang-testcase:///redirecting_initializers.dart:21:9)
80+
- E2.named (from org-dartlang-testcase:///redirecting_initializers.dart:22:9)

0 commit comments

Comments
 (0)