Skip to content

Commit c048054

Browse files
chloestefantsovaCommit Queue
authored and
Commit Queue
committed
[cfe] Type-check new possibilities for rederectee types of Enums
With the appearance of extension types one can write programs with non-trivial subtypes of enum types, making the type checks of targets of redirection necessary, even if they are generative constructors. Closes #54010 Part of #49731 Change-Id: Ic415678c6e0579c1acf6f2542ccd90eb24b86362 Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/336886 Reviewed-by: Johnni Winther <[email protected]> Commit-Queue: Chloe Stefantsova <[email protected]>
1 parent b0a91e2 commit c048054

19 files changed

+935
-1
lines changed

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

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -797,8 +797,13 @@ class RedirectingFactoryBuilder extends SourceFactoryBuilder {
797797

798798
// Redirection to generative enum constructors is forbidden and is reported
799799
// as an error elsewhere.
800+
Builder? redirectionTargetParent = redirectionTarget.target?.parent;
801+
bool redirectingTargetParentIsEnum = redirectionTargetParent is ClassBuilder
802+
? redirectionTargetParent.isEnum
803+
: false;
800804
if (!((classBuilder?.cls.isEnum ?? false) &&
801-
(redirectionTarget.target?.isConstructor ?? false))) {
805+
(redirectionTarget.target?.isConstructor ?? false) &&
806+
redirectingTargetParentIsEnum)) {
802807
// Check whether [redirecteeType] <: [factoryType].
803808
if (!typeEnvironment.isSubtypeOf(
804809
redirecteeType,
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
// Copyright (c) 2023, 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 E {
6+
element;
7+
8+
const E();
9+
const factory E.redir() = A; // Error.
10+
}
11+
12+
class A {
13+
const A();
14+
}
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
library;
2+
//
3+
// Problems in library:
4+
//
5+
// pkg/front_end/testcases/enhanced_enums/redirecting_to_unrelated_factory.dart:9:29: Error: The constructor function type 'A Function()' isn't a subtype of 'E Function()'.
6+
// - 'A' is from 'pkg/front_end/testcases/enhanced_enums/redirecting_to_unrelated_factory.dart'.
7+
// - 'E' is from 'pkg/front_end/testcases/enhanced_enums/redirecting_to_unrelated_factory.dart'.
8+
// const factory E.redir() = A; // Error.
9+
// ^
10+
//
11+
import self as self;
12+
import "dart:core" as core;
13+
14+
class E extends core::_Enum /*isEnum*/ {
15+
static const field core::List<self::E> values = #C4;
16+
enum-element static const field self::E element = #C3;
17+
const constructor •(core::int #index, core::String #name) → self::E
18+
: super core::_Enum::•(#index, #name)
19+
;
20+
method _enumToString() → core::String
21+
return "E.${this.{core::_Enum::_name}{core::String}}";
22+
static factory redir() → self::E
23+
return invalid-expression "pkg/front_end/testcases/enhanced_enums/redirecting_to_unrelated_factory.dart:9:29: Error: The constructor function type 'A Function()' isn't a subtype of 'E Function()'.
24+
- 'A' is from 'pkg/front_end/testcases/enhanced_enums/redirecting_to_unrelated_factory.dart'.
25+
- 'E' is from 'pkg/front_end/testcases/enhanced_enums/redirecting_to_unrelated_factory.dart'.
26+
const factory E.redir() = A; // Error.
27+
^";
28+
}
29+
class A extends core::Object /*hasConstConstructor*/ {
30+
const constructor •() → self::A
31+
: super core::Object::•()
32+
;
33+
}
34+
35+
constants {
36+
#C1 = 0
37+
#C2 = "element"
38+
#C3 = self::E {index:#C1, _name:#C2}
39+
#C4 = <self::E>[#C3]
40+
}
41+
42+
43+
Constructor coverage from constants:
44+
org-dartlang-testcase:///redirecting_to_unrelated_factory.dart:
45+
- E. (from org-dartlang-testcase:///redirecting_to_unrelated_factory.dart:8:9)
46+
- _Enum. (from org-dartlang-sdk:///sdk/lib/core/enum.dart)
47+
- Object. (from org-dartlang-sdk:///sdk/lib/core/object.dart)
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
library;
2+
//
3+
// Problems in library:
4+
//
5+
// pkg/front_end/testcases/enhanced_enums/redirecting_to_unrelated_factory.dart:9:29: Error: The constructor function type 'A Function()' isn't a subtype of 'E Function()'.
6+
// - 'A' is from 'pkg/front_end/testcases/enhanced_enums/redirecting_to_unrelated_factory.dart'.
7+
// - 'E' is from 'pkg/front_end/testcases/enhanced_enums/redirecting_to_unrelated_factory.dart'.
8+
// const factory E.redir() = A; // Error.
9+
// ^
10+
//
11+
import self as self;
12+
import "dart:core" as core;
13+
14+
class E extends core::_Enum /*isEnum*/ {
15+
static const field core::List<self::E> values = #C4;
16+
enum-element static const field self::E element = #C3;
17+
const constructor •(core::int #index, core::String #name) → self::E
18+
: super core::_Enum::•(#index, #name)
19+
;
20+
method _enumToString() → core::String
21+
return "E.${this.{core::_Enum::_name}{core::String}}";
22+
static factory redir() → self::E
23+
return invalid-expression "pkg/front_end/testcases/enhanced_enums/redirecting_to_unrelated_factory.dart:9:29: Error: The constructor function type 'A Function()' isn't a subtype of 'E Function()'.
24+
- 'A' is from 'pkg/front_end/testcases/enhanced_enums/redirecting_to_unrelated_factory.dart'.
25+
- 'E' is from 'pkg/front_end/testcases/enhanced_enums/redirecting_to_unrelated_factory.dart'.
26+
const factory E.redir() = A; // Error.
27+
^";
28+
}
29+
class A extends core::Object /*hasConstConstructor*/ {
30+
const constructor •() → self::A
31+
: super core::Object::•()
32+
;
33+
}
34+
35+
constants {
36+
#C1 = 0
37+
#C2 = "element"
38+
#C3 = self::E {index:#C1, _name:#C2}
39+
#C4 = <self::E>[#C3]
40+
}
41+
42+
43+
Constructor coverage from constants:
44+
org-dartlang-testcase:///redirecting_to_unrelated_factory.dart:
45+
- E. (from org-dartlang-testcase:///redirecting_to_unrelated_factory.dart:8:9)
46+
- _Enum. (from org-dartlang-sdk:///sdk/lib/core/enum.dart)
47+
- Object. (from org-dartlang-sdk:///sdk/lib/core/object.dart)
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
enum E {
2+
element;
3+
4+
const E();
5+
const factory E.redir() = A;
6+
}
7+
8+
class A {
9+
const A();
10+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
class A {
2+
const A();
3+
}
4+
5+
enum E {
6+
element;
7+
8+
const E();
9+
const factory E.redir() = A;
10+
}
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
library;
2+
//
3+
// Problems in library:
4+
//
5+
// pkg/front_end/testcases/enhanced_enums/redirecting_to_unrelated_factory.dart:9:29: Error: The constructor function type 'A Function()' isn't a subtype of 'E Function()'.
6+
// - 'A' is from 'pkg/front_end/testcases/enhanced_enums/redirecting_to_unrelated_factory.dart'.
7+
// - 'E' is from 'pkg/front_end/testcases/enhanced_enums/redirecting_to_unrelated_factory.dart'.
8+
// const factory E.redir() = A; // Error.
9+
// ^
10+
//
11+
import self as self;
12+
import "dart:core" as core;
13+
14+
class E extends core::_Enum /*isEnum*/ {
15+
static const field core::List<self::E> values = #C4;
16+
enum-element static const field self::E element = #C3;
17+
const constructor •(core::int #index, core::String #name) → self::E
18+
: super core::_Enum::•(#index, #name)
19+
;
20+
method _enumToString() → core::String
21+
return "E.${this.{core::_Enum::_name}{core::String}}";
22+
static factory redir() → self::E
23+
return invalid-expression "pkg/front_end/testcases/enhanced_enums/redirecting_to_unrelated_factory.dart:9:29: Error: The constructor function type 'A Function()' isn't a subtype of 'E Function()'.
24+
- 'A' is from 'pkg/front_end/testcases/enhanced_enums/redirecting_to_unrelated_factory.dart'.
25+
- 'E' is from 'pkg/front_end/testcases/enhanced_enums/redirecting_to_unrelated_factory.dart'.
26+
const factory E.redir() = A; // Error.
27+
^";
28+
}
29+
class A extends core::Object /*hasConstConstructor*/ {
30+
const constructor •() → self::A
31+
: super core::Object::•()
32+
;
33+
}
34+
35+
constants {
36+
#C1 = 0
37+
#C2 = "element"
38+
#C3 = self::E {index:#C1, _name:#C2}
39+
#C4 = <self::E*>[#C3]
40+
}
41+
42+
43+
Constructor coverage from constants:
44+
org-dartlang-testcase:///redirecting_to_unrelated_factory.dart:
45+
- E. (from org-dartlang-testcase:///redirecting_to_unrelated_factory.dart:8:9)
46+
- _Enum. (from org-dartlang-sdk:///sdk/lib/core/enum.dart)
47+
- Object. (from org-dartlang-sdk:///sdk/lib/core/object.dart)
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
library;
2+
//
3+
// Problems in library:
4+
//
5+
// pkg/front_end/testcases/enhanced_enums/redirecting_to_unrelated_factory.dart:9:29: Error: The constructor function type 'A Function()' isn't a subtype of 'E Function()'.
6+
// - 'A' is from 'pkg/front_end/testcases/enhanced_enums/redirecting_to_unrelated_factory.dart'.
7+
// - 'E' is from 'pkg/front_end/testcases/enhanced_enums/redirecting_to_unrelated_factory.dart'.
8+
// const factory E.redir() = A; // Error.
9+
// ^
10+
//
11+
import self as self;
12+
import "dart:core" as core;
13+
14+
class E extends core::_Enum /*isEnum*/ {
15+
static const field core::List<self::E> values = #C4;
16+
enum-element static const field self::E element = #C3;
17+
const constructor •(core::int #index, core::String #name) → self::E
18+
: super core::_Enum::•(#index, #name)
19+
;
20+
method _enumToString() → core::String
21+
return "E.${this.{core::_Enum::_name}{core::String}}";
22+
static factory redir() → self::E
23+
return invalid-expression "pkg/front_end/testcases/enhanced_enums/redirecting_to_unrelated_factory.dart:9:29: Error: The constructor function type 'A Function()' isn't a subtype of 'E Function()'.
24+
- 'A' is from 'pkg/front_end/testcases/enhanced_enums/redirecting_to_unrelated_factory.dart'.
25+
- 'E' is from 'pkg/front_end/testcases/enhanced_enums/redirecting_to_unrelated_factory.dart'.
26+
const factory E.redir() = A; // Error.
27+
^";
28+
}
29+
class A extends core::Object /*hasConstConstructor*/ {
30+
const constructor •() → self::A
31+
: super core::Object::•()
32+
;
33+
}
34+
35+
constants {
36+
#C1 = 0
37+
#C2 = "element"
38+
#C3 = self::E {index:#C1, _name:#C2}
39+
#C4 = <self::E*>[#C3]
40+
}
41+
42+
43+
Constructor coverage from constants:
44+
org-dartlang-testcase:///redirecting_to_unrelated_factory.dart:
45+
- E. (from org-dartlang-testcase:///redirecting_to_unrelated_factory.dart:8:9)
46+
- _Enum. (from org-dartlang-sdk:///sdk/lib/core/enum.dart)
47+
- Object. (from org-dartlang-sdk:///sdk/lib/core/object.dart)
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
library;
2+
//
3+
// Problems in library:
4+
//
5+
// pkg/front_end/testcases/enhanced_enums/redirecting_to_unrelated_factory.dart:9:29: Error: The constructor function type 'A Function()' isn't a subtype of 'E Function()'.
6+
// - 'A' is from 'pkg/front_end/testcases/enhanced_enums/redirecting_to_unrelated_factory.dart'.
7+
// - 'E' is from 'pkg/front_end/testcases/enhanced_enums/redirecting_to_unrelated_factory.dart'.
8+
// const factory E.redir() = A; // Error.
9+
// ^
10+
//
11+
import self as self;
12+
import "dart:core" as core;
13+
14+
class E extends core::_Enum /*isEnum*/ {
15+
static const field core::List<self::E> values = const <self::E>[self::E::element];
16+
enum-element static const field self::E element = const self::E::•(0, "element");
17+
const constructor •(core::int #index, core::String #name) → self::E
18+
: super core::_Enum::•(#index, #name)
19+
;
20+
method _enumToString() → core::String
21+
return "E.${this.{core::_Enum::_name}{core::String}}";
22+
static factory redir() → self::E
23+
return invalid-expression "pkg/front_end/testcases/enhanced_enums/redirecting_to_unrelated_factory.dart:9:29: Error: The constructor function type 'A Function()' isn't a subtype of 'E Function()'.
24+
- 'A' is from 'pkg/front_end/testcases/enhanced_enums/redirecting_to_unrelated_factory.dart'.
25+
- 'E' is from 'pkg/front_end/testcases/enhanced_enums/redirecting_to_unrelated_factory.dart'.
26+
const factory E.redir() = A; // Error.
27+
^";
28+
}
29+
class A extends core::Object /*hasConstConstructor*/ {
30+
const constructor •() → self::A
31+
: super core::Object::•()
32+
;
33+
}
34+
35+
36+
Extra constant evaluation status:
37+
Evaluated: ListLiteral @ org-dartlang-testcase:///redirecting_to_unrelated_factory.dart:5:6 -> ListConstant(const <E*>[const E{_Enum.index: 0, _Enum._name: "element"}])
38+
Evaluated: ConstructorInvocation @ org-dartlang-testcase:///redirecting_to_unrelated_factory.dart:6:3 -> InstanceConstant(const E{_Enum.index: 0, _Enum._name: "element"})
39+
Extra constant evaluation: evaluated: 7, effectively constant: 2
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
library;
2+
//
3+
// Problems in library:
4+
//
5+
// pkg/front_end/testcases/enhanced_enums/redirecting_to_unrelated_factory.dart:9:29: Error: The constructor function type 'A Function()' isn't a subtype of 'E Function()'.
6+
// - 'A' is from 'pkg/front_end/testcases/enhanced_enums/redirecting_to_unrelated_factory.dart'.
7+
// - 'E' is from 'pkg/front_end/testcases/enhanced_enums/redirecting_to_unrelated_factory.dart'.
8+
// const factory E.redir() = A; // Error.
9+
// ^
10+
//
11+
import self as self;
12+
import "dart:core" as core;
13+
14+
class E extends core::_Enum /*isEnum*/ {
15+
static const field core::List<self::E> values = #C4;
16+
enum-element static const field self::E element = #C3;
17+
const constructor •(core::int #index, core::String #name) → self::E
18+
: super core::_Enum::•(#index, #name)
19+
;
20+
method _enumToString() → core::String
21+
return "E.${this.{core::_Enum::_name}{core::String}}";
22+
static factory redir() → self::E
23+
return invalid-expression "pkg/front_end/testcases/enhanced_enums/redirecting_to_unrelated_factory.dart:9:29: Error: The constructor function type 'A Function()' isn't a subtype of 'E Function()'.
24+
- 'A' is from 'pkg/front_end/testcases/enhanced_enums/redirecting_to_unrelated_factory.dart'.
25+
- 'E' is from 'pkg/front_end/testcases/enhanced_enums/redirecting_to_unrelated_factory.dart'.
26+
const factory E.redir() = A; // Error.
27+
^";
28+
}
29+
class A extends core::Object /*hasConstConstructor*/ {
30+
const constructor •() → self::A
31+
: super core::Object::•()
32+
;
33+
}
34+
35+
constants {
36+
#C1 = 0
37+
#C2 = "element"
38+
#C3 = self::E {index:#C1, _name:#C2}
39+
#C4 = <self::E*>[#C3]
40+
}
41+
42+
43+
Constructor coverage from constants:
44+
org-dartlang-testcase:///redirecting_to_unrelated_factory.dart:
45+
- E. (from org-dartlang-testcase:///redirecting_to_unrelated_factory.dart:8:9)
46+
- _Enum. (from org-dartlang-sdk:///sdk/lib/core/enum.dart)
47+
- Object. (from org-dartlang-sdk:///sdk/lib/core/object.dart)
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
// Copyright (c) 2023, the Dart project authors. Please see the AUTHORS file
2+
// for details. All rights reserved. Use of this source code is governed by b
3+
// BSD-style license that can be found in the LICENSE file.
4+
5+
class A1 {
6+
const A1();
7+
const factory A1.named(A1 it) = E1.named; // Error.
8+
}
9+
10+
extension type const E1(A1 it) {
11+
const E1.named(A1 it): this(it);
12+
}
13+
14+
enum A2 {
15+
element;
16+
const A2();
17+
const factory A2.named(A2 it) = E2.named; // Error.
18+
}
19+
20+
extension type const E2(A2 it) {
21+
const E2.named(A2 it): this(it);
22+
}

0 commit comments

Comments
 (0)