Skip to content

Commit 4d792f2

Browse files
committed
Merge pull request #6036 from Microsoft/structural-enums
Compare enums semi-structurally.
2 parents 5d8d09f + b04bd66 commit 4d792f2

File tree

4 files changed

+446
-0
lines changed

4 files changed

+446
-0
lines changed

src/compiler/checker.ts

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5066,6 +5066,11 @@ namespace ts {
50665066
if (source === undefinedType) return Ternary.True;
50675067
if (source === nullType && target !== undefinedType) return Ternary.True;
50685068
if (source.flags & TypeFlags.Enum && target === numberType) return Ternary.True;
5069+
if (source.flags & TypeFlags.Enum && target.flags & TypeFlags.Enum) {
5070+
if (result = enumRelatedTo(source, target)) {
5071+
return result;
5072+
}
5073+
}
50695074
if (source.flags & TypeFlags.StringLiteral && target === stringType) return Ternary.True;
50705075
if (relation === assignableRelation) {
50715076
if (isTypeAny(source)) return Ternary.True;
@@ -5780,6 +5785,27 @@ namespace ts {
57805785
}
57815786
return Ternary.False;
57825787
}
5788+
5789+
function enumRelatedTo(source: Type, target: Type) {
5790+
if (source.symbol.name !== target.symbol.name ||
5791+
source.symbol.flags & SymbolFlags.ConstEnum ||
5792+
target.symbol.flags & SymbolFlags.ConstEnum) {
5793+
return Ternary.False;
5794+
}
5795+
const targetEnumType = getTypeOfSymbol(target.symbol);
5796+
for (const property of getPropertiesOfType(getTypeOfSymbol(source.symbol))) {
5797+
if (property.flags & SymbolFlags.EnumMember) {
5798+
const targetProperty = getPropertyOfType(targetEnumType, property.name);
5799+
if (!targetProperty || !(targetProperty.flags & SymbolFlags.EnumMember)) {
5800+
reportError(Diagnostics.Property_0_is_missing_in_type_1,
5801+
property.name,
5802+
typeToString(target, /*enclosingDeclaration*/ undefined, TypeFormatFlags.UseFullyQualifiedType));
5803+
return Ternary.False;
5804+
}
5805+
}
5806+
}
5807+
return Ternary.True;
5808+
}
57835809
}
57845810

57855811
// Return true if the given type is part of a deeply nested chain of generic instantiations. We consider this to be the case
Lines changed: 129 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,129 @@
1+
tests/cases/compiler/enumAssignmentCompat3.ts(68,1): error TS2322: Type 'Abcd.E' is not assignable to type 'First.E'.
2+
Property 'd' is missing in type 'First.E'.
3+
tests/cases/compiler/enumAssignmentCompat3.ts(70,1): error TS2322: Type 'Cd.E' is not assignable to type 'First.E'.
4+
Property 'd' is missing in type 'First.E'.
5+
tests/cases/compiler/enumAssignmentCompat3.ts(71,1): error TS2322: Type 'Nope' is not assignable to type 'E'.
6+
tests/cases/compiler/enumAssignmentCompat3.ts(75,1): error TS2322: Type 'First.E' is not assignable to type 'Ab.E'.
7+
Property 'c' is missing in type 'Ab.E'.
8+
tests/cases/compiler/enumAssignmentCompat3.ts(76,1): error TS2322: Type 'First.E' is not assignable to type 'Cd.E'.
9+
Property 'a' is missing in type 'Cd.E'.
10+
tests/cases/compiler/enumAssignmentCompat3.ts(77,1): error TS2322: Type 'E' is not assignable to type 'Nope'.
11+
tests/cases/compiler/enumAssignmentCompat3.ts(82,1): error TS2322: Type 'Const.E' is not assignable to type 'First.E'.
12+
tests/cases/compiler/enumAssignmentCompat3.ts(83,1): error TS2322: Type 'First.E' is not assignable to type 'Const.E'.
13+
tests/cases/compiler/enumAssignmentCompat3.ts(86,1): error TS2322: Type 'Merged.E' is not assignable to type 'First.E'.
14+
Property 'd' is missing in type 'First.E'.
15+
16+
17+
==== tests/cases/compiler/enumAssignmentCompat3.ts (9 errors) ====
18+
namespace First {
19+
export enum E {
20+
a, b, c,
21+
}
22+
}
23+
namespace Abc {
24+
export enum E {
25+
a, b, c,
26+
}
27+
export enum Nope {
28+
a, b, c,
29+
}
30+
}
31+
namespace Abcd {
32+
export enum E {
33+
a, b, c, d,
34+
}
35+
}
36+
namespace Ab {
37+
export enum E {
38+
a, b,
39+
}
40+
}
41+
namespace Cd {
42+
export enum E {
43+
c, d,
44+
}
45+
}
46+
namespace Const {
47+
export const enum E {
48+
a, b, c,
49+
}
50+
}
51+
namespace Decl {
52+
export declare enum E {
53+
a, b, c = 3,
54+
}
55+
}
56+
namespace Merged {
57+
export enum E {
58+
a, b,
59+
}
60+
export enum E {
61+
c = 3, d,
62+
}
63+
}
64+
65+
namespace Merged2 {
66+
export enum E {
67+
a, b, c
68+
}
69+
export module E {
70+
export let d = 5;
71+
}
72+
}
73+
74+
var abc: First.E;
75+
var secondAbc: Abc.E;
76+
var secondAbcd: Abcd.E;
77+
var secondAb: Ab.E;
78+
var secondCd: Cd.E;
79+
var nope: Abc.Nope;
80+
var k: Const.E;
81+
var decl: Decl.E;
82+
var merged: Merged.E;
83+
var merged2: Merged2.E;
84+
abc = secondAbc; // ok
85+
abc = secondAbcd; // missing 'd'
86+
~~~
87+
!!! error TS2322: Type 'Abcd.E' is not assignable to type 'First.E'.
88+
!!! error TS2322: Property 'd' is missing in type 'First.E'.
89+
abc = secondAb; // ok
90+
abc = secondCd; // missing 'd'
91+
~~~
92+
!!! error TS2322: Type 'Cd.E' is not assignable to type 'First.E'.
93+
!!! error TS2322: Property 'd' is missing in type 'First.E'.
94+
abc = nope; // nope!
95+
~~~
96+
!!! error TS2322: Type 'Nope' is not assignable to type 'E'.
97+
abc = decl; // ok
98+
secondAbc = abc; // ok
99+
secondAbcd = abc; // ok
100+
secondAb = abc; // missing 'c'
101+
~~~~~~~~
102+
!!! error TS2322: Type 'First.E' is not assignable to type 'Ab.E'.
103+
!!! error TS2322: Property 'c' is missing in type 'Ab.E'.
104+
secondCd = abc; // missing 'a' and 'b'
105+
~~~~~~~~
106+
!!! error TS2322: Type 'First.E' is not assignable to type 'Cd.E'.
107+
!!! error TS2322: Property 'a' is missing in type 'Cd.E'.
108+
nope = abc; // nope!
109+
~~~~
110+
!!! error TS2322: Type 'E' is not assignable to type 'Nope'.
111+
decl = abc; // ok
112+
113+
// const is only assignable to itself
114+
k = k;
115+
abc = k; // error
116+
~~~
117+
!!! error TS2322: Type 'Const.E' is not assignable to type 'First.E'.
118+
k = abc;
119+
~
120+
!!! error TS2322: Type 'First.E' is not assignable to type 'Const.E'.
121+
122+
// merged enums compare all their members
123+
abc = merged; // missing 'd'
124+
~~~
125+
!!! error TS2322: Type 'Merged.E' is not assignable to type 'First.E'.
126+
!!! error TS2322: Property 'd' is missing in type 'First.E'.
127+
merged = abc; // ok
128+
abc = merged2; // ok
129+
merged2 = abc; // ok
Lines changed: 202 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,202 @@
1+
//// [enumAssignmentCompat3.ts]
2+
namespace First {
3+
export enum E {
4+
a, b, c,
5+
}
6+
}
7+
namespace Abc {
8+
export enum E {
9+
a, b, c,
10+
}
11+
export enum Nope {
12+
a, b, c,
13+
}
14+
}
15+
namespace Abcd {
16+
export enum E {
17+
a, b, c, d,
18+
}
19+
}
20+
namespace Ab {
21+
export enum E {
22+
a, b,
23+
}
24+
}
25+
namespace Cd {
26+
export enum E {
27+
c, d,
28+
}
29+
}
30+
namespace Const {
31+
export const enum E {
32+
a, b, c,
33+
}
34+
}
35+
namespace Decl {
36+
export declare enum E {
37+
a, b, c = 3,
38+
}
39+
}
40+
namespace Merged {
41+
export enum E {
42+
a, b,
43+
}
44+
export enum E {
45+
c = 3, d,
46+
}
47+
}
48+
49+
namespace Merged2 {
50+
export enum E {
51+
a, b, c
52+
}
53+
export module E {
54+
export let d = 5;
55+
}
56+
}
57+
58+
var abc: First.E;
59+
var secondAbc: Abc.E;
60+
var secondAbcd: Abcd.E;
61+
var secondAb: Ab.E;
62+
var secondCd: Cd.E;
63+
var nope: Abc.Nope;
64+
var k: Const.E;
65+
var decl: Decl.E;
66+
var merged: Merged.E;
67+
var merged2: Merged2.E;
68+
abc = secondAbc; // ok
69+
abc = secondAbcd; // missing 'd'
70+
abc = secondAb; // ok
71+
abc = secondCd; // missing 'd'
72+
abc = nope; // nope!
73+
abc = decl; // ok
74+
secondAbc = abc; // ok
75+
secondAbcd = abc; // ok
76+
secondAb = abc; // missing 'c'
77+
secondCd = abc; // missing 'a' and 'b'
78+
nope = abc; // nope!
79+
decl = abc; // ok
80+
81+
// const is only assignable to itself
82+
k = k;
83+
abc = k; // error
84+
k = abc;
85+
86+
// merged enums compare all their members
87+
abc = merged; // missing 'd'
88+
merged = abc; // ok
89+
abc = merged2; // ok
90+
merged2 = abc; // ok
91+
92+
//// [enumAssignmentCompat3.js]
93+
var First;
94+
(function (First) {
95+
(function (E) {
96+
E[E["a"] = 0] = "a";
97+
E[E["b"] = 1] = "b";
98+
E[E["c"] = 2] = "c";
99+
})(First.E || (First.E = {}));
100+
var E = First.E;
101+
})(First || (First = {}));
102+
var Abc;
103+
(function (Abc) {
104+
(function (E) {
105+
E[E["a"] = 0] = "a";
106+
E[E["b"] = 1] = "b";
107+
E[E["c"] = 2] = "c";
108+
})(Abc.E || (Abc.E = {}));
109+
var E = Abc.E;
110+
(function (Nope) {
111+
Nope[Nope["a"] = 0] = "a";
112+
Nope[Nope["b"] = 1] = "b";
113+
Nope[Nope["c"] = 2] = "c";
114+
})(Abc.Nope || (Abc.Nope = {}));
115+
var Nope = Abc.Nope;
116+
})(Abc || (Abc = {}));
117+
var Abcd;
118+
(function (Abcd) {
119+
(function (E) {
120+
E[E["a"] = 0] = "a";
121+
E[E["b"] = 1] = "b";
122+
E[E["c"] = 2] = "c";
123+
E[E["d"] = 3] = "d";
124+
})(Abcd.E || (Abcd.E = {}));
125+
var E = Abcd.E;
126+
})(Abcd || (Abcd = {}));
127+
var Ab;
128+
(function (Ab) {
129+
(function (E) {
130+
E[E["a"] = 0] = "a";
131+
E[E["b"] = 1] = "b";
132+
})(Ab.E || (Ab.E = {}));
133+
var E = Ab.E;
134+
})(Ab || (Ab = {}));
135+
var Cd;
136+
(function (Cd) {
137+
(function (E) {
138+
E[E["c"] = 0] = "c";
139+
E[E["d"] = 1] = "d";
140+
})(Cd.E || (Cd.E = {}));
141+
var E = Cd.E;
142+
})(Cd || (Cd = {}));
143+
var Decl;
144+
(function (Decl) {
145+
})(Decl || (Decl = {}));
146+
var Merged;
147+
(function (Merged) {
148+
(function (E) {
149+
E[E["a"] = 0] = "a";
150+
E[E["b"] = 1] = "b";
151+
})(Merged.E || (Merged.E = {}));
152+
var E = Merged.E;
153+
(function (E) {
154+
E[E["c"] = 3] = "c";
155+
E[E["d"] = 4] = "d";
156+
})(Merged.E || (Merged.E = {}));
157+
var E = Merged.E;
158+
})(Merged || (Merged = {}));
159+
var Merged2;
160+
(function (Merged2) {
161+
(function (E) {
162+
E[E["a"] = 0] = "a";
163+
E[E["b"] = 1] = "b";
164+
E[E["c"] = 2] = "c";
165+
})(Merged2.E || (Merged2.E = {}));
166+
var E = Merged2.E;
167+
var E;
168+
(function (E) {
169+
E.d = 5;
170+
})(E = Merged2.E || (Merged2.E = {}));
171+
})(Merged2 || (Merged2 = {}));
172+
var abc;
173+
var secondAbc;
174+
var secondAbcd;
175+
var secondAb;
176+
var secondCd;
177+
var nope;
178+
var k;
179+
var decl;
180+
var merged;
181+
var merged2;
182+
abc = secondAbc; // ok
183+
abc = secondAbcd; // missing 'd'
184+
abc = secondAb; // ok
185+
abc = secondCd; // missing 'd'
186+
abc = nope; // nope!
187+
abc = decl; // ok
188+
secondAbc = abc; // ok
189+
secondAbcd = abc; // ok
190+
secondAb = abc; // missing 'c'
191+
secondCd = abc; // missing 'a' and 'b'
192+
nope = abc; // nope!
193+
decl = abc; // ok
194+
// const is only assignable to itself
195+
k = k;
196+
abc = k; // error
197+
k = abc;
198+
// merged enums compare all their members
199+
abc = merged; // missing 'd'
200+
merged = abc; // ok
201+
abc = merged2; // ok
202+
merged2 = abc; // ok

0 commit comments

Comments
 (0)