Skip to content

Commit a7c9c16

Browse files
committed
unify const and regular enums
1 parent 67023a8 commit a7c9c16

16 files changed

+148
-66
lines changed

src/compiler/checker.ts

Lines changed: 26 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -8953,7 +8953,7 @@ module ts {
89538953
}
89548954
var initializer = member.initializer;
89558955
if (initializer) {
8956-
autoValue = getConstantValueForEnumMemberInitializer(initializer, enumIsConst);
8956+
autoValue = getConstantValueForEnumMemberInitializer(initializer);
89578957
if (autoValue === undefined) {
89588958
if (enumIsConst) {
89598959
error(initializer, Diagnostics.In_const_enum_declarations_member_initializer_must_be_constant_expression);
@@ -8963,7 +8963,7 @@ module ts {
89638963
// If it is a constant value (not undefined), it is syntactically constrained to be a number.
89648964
// Also, we do not need to check this for ambients because there is already
89658965
// a syntax error if it is not a constant.
8966-
checkTypeAssignableTo(checkExpression(initializer), enumType, initializer, /*headMessage*/ undefined);
8966+
checkTypeAssignableTo(checkExpression(initializer), enumType, initializer, /*headMessage*/ undefined);
89678967
}
89688968
}
89698969
else if (enumIsConst) {
@@ -8988,7 +8988,7 @@ module ts {
89888988
nodeLinks.flags |= NodeCheckFlags.EnumValuesComputed;
89898989
}
89908990

8991-
function getConstantValueForEnumMemberInitializer(initializer: Expression, enumIsConst: boolean): number {
8991+
function getConstantValueForEnumMemberInitializer(initializer: Expression): number {
89928992
return evalConstant(initializer);
89938993

89948994
function evalConstant(e: Node): number {
@@ -9001,14 +9001,10 @@ module ts {
90019001
switch ((<PrefixUnaryExpression>e).operator) {
90029002
case SyntaxKind.PlusToken: return value;
90039003
case SyntaxKind.MinusToken: return -value;
9004-
case SyntaxKind.TildeToken: return enumIsConst ? ~value : undefined;
9004+
case SyntaxKind.TildeToken: return ~value;
90059005
}
90069006
return undefined;
90079007
case SyntaxKind.BinaryExpression:
9008-
if (!enumIsConst) {
9009-
return undefined;
9010-
}
9011-
90129008
var left = evalConstant((<BinaryExpression>e).left);
90139009
if (left === undefined) {
90149010
return undefined;
@@ -9034,14 +9030,10 @@ module ts {
90349030
case SyntaxKind.NumericLiteral:
90359031
return +(<LiteralExpression>e).text;
90369032
case SyntaxKind.ParenthesizedExpression:
9037-
return enumIsConst ? evalConstant((<ParenthesizedExpression>e).expression) : undefined;
9033+
return evalConstant((<ParenthesizedExpression>e).expression);
90389034
case SyntaxKind.Identifier:
90399035
case SyntaxKind.ElementAccessExpression:
90409036
case SyntaxKind.PropertyAccessExpression:
9041-
if (!enumIsConst) {
9042-
return undefined;
9043-
}
9044-
90459037
var member = initializer.parent;
90469038
var currentType = getTypeOfSymbol(getSymbolOfNode(member.parent));
90479039
var enumType: Type;
@@ -9054,19 +9046,37 @@ module ts {
90549046
propertyName = (<Identifier>e).text;
90559047
}
90569048
else {
9049+
var expression: Expression;
90579050
if (e.kind === SyntaxKind.ElementAccessExpression) {
90589051
if ((<ElementAccessExpression>e).argumentExpression === undefined ||
90599052
(<ElementAccessExpression>e).argumentExpression.kind !== SyntaxKind.StringLiteral) {
90609053
return undefined;
90619054
}
9062-
var enumType = getTypeOfNode((<ElementAccessExpression>e).expression);
9055+
expression = (<ElementAccessExpression>e).expression;
90639056
propertyName = (<LiteralExpression>(<ElementAccessExpression>e).argumentExpression).text;
90649057
}
90659058
else {
9066-
var enumType = getTypeOfNode((<PropertyAccessExpression>e).expression);
9059+
expression = (<PropertyAccessExpression>e).expression;
90679060
propertyName = (<PropertyAccessExpression>e).name.text;
90689061
}
9069-
if (enumType !== currentType) {
9062+
9063+
// expression part in ElementAccess\PropertyAccess should be either identifier or dottedName
9064+
var current = expression;
9065+
while (current) {
9066+
if (current.kind === SyntaxKind.Identifier) {
9067+
break;
9068+
}
9069+
else if (current.kind === SyntaxKind.PropertyAccessExpression) {
9070+
current = (<ElementAccessExpression>current).expression;
9071+
}
9072+
else {
9073+
return undefined;
9074+
}
9075+
}
9076+
9077+
var enumType = checkExpression(expression);
9078+
// allow references to members of other const enums
9079+
if (enumType !== currentType && !isConstEnumObjectType(enumType)) {
90709080
return undefined;
90719081
}
90729082
}

src/compiler/emitter.ts

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3694,11 +3694,13 @@ module ts {
36943694
write("[");
36953695
emitExpressionForPropertyName(node.name);
36963696
write("] = ");
3697-
if (node.initializer && !isConst(enumParent)) {
3698-
emit(node.initializer);
3697+
var constantValue = resolver.getEnumMemberValue(node);
3698+
if (constantValue !== undefined) {
3699+
write(constantValue.toString());
36993700
}
37003701
else {
3701-
write(resolver.getEnumMemberValue(node).toString());
3702+
Debug.assert(node.initializer !== undefined);
3703+
emit(node.initializer);
37023704
}
37033705
write("] = ");
37043706
emitExpressionForPropertyName(node.name);

tests/baselines/reference/collisionCodeGenEnumWithEnumMemberConflict.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,5 +8,5 @@ enum Color {
88
var Color;
99
(function (Color) {
1010
Color[Color["Color"] = 0] = "Color";
11-
Color[Color["Thing"] = Color.Color] = "Thing";
11+
Color[Color["Thing"] = 0] = "Thing";
1212
})(Color || (Color = {}));

tests/baselines/reference/collisionCodeGenModuleWithEnumMemberConflict.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,6 @@ var m1;
1212
var e;
1313
(function (e) {
1414
e[e["m1"] = 0] = "m1";
15-
e[e["m2"] = e.m1] = "m2";
15+
e[e["m2"] = 0] = "m2";
1616
})(e || (e = {}));
1717
})(m1 || (m1 = {}));

tests/baselines/reference/constEnumErrors.errors.txt

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,9 +11,11 @@ tests/cases/compiler/constEnumErrors.ts(32,5): error TS4084: 'const' enums can o
1111
tests/cases/compiler/constEnumErrors.ts(40,9): error TS4086: 'const' enum member initializer was evaluated to a non-finite value.
1212
tests/cases/compiler/constEnumErrors.ts(41,9): error TS4086: 'const' enum member initializer was evaluated to a non-finite value.
1313
tests/cases/compiler/constEnumErrors.ts(42,9): error TS4087: 'const' enum member initializer was evaluated to disallowed value 'NaN'.
14+
tests/cases/compiler/constEnumErrors.ts(47,8): error TS4083: In 'const' enum declarations member initializer must be constant expression.
15+
tests/cases/compiler/constEnumErrors.ts(50,25): error TS4084: 'const' enums can only be used in property or index access expressions or the right hand side of an import declaration or export assignment.
1416

1517

16-
==== tests/cases/compiler/constEnumErrors.ts (13 errors) ====
18+
==== tests/cases/compiler/constEnumErrors.ts (15 errors) ====
1719
const enum E {
1820
~
1921
!!! error TS2300: Duplicate identifier 'E'.
@@ -82,4 +84,15 @@ tests/cases/compiler/constEnumErrors.ts(42,9): error TS4087: 'const' enum member
8284
H = 0 / 0 // NaN
8385
~~~~~
8486
!!! error TS4087: 'const' enum member initializer was evaluated to disallowed value 'NaN'.
85-
}
87+
}
88+
89+
const enum E3 {
90+
X = 1,
91+
Y =baz().X // incorrect const enum initializer - should be identifier or property access
92+
~~~~~~~
93+
!!! error TS4083: In 'const' enum declarations member initializer must be constant expression.
94+
}
95+
96+
function baz() : typeof E3 { return undefined; }
97+
~~
98+
!!! error TS4084: 'const' enums can only be used in property or index access expressions or the right hand side of an import declaration or export assignment.

tests/baselines/reference/constEnums.js

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -149,7 +149,18 @@ function bar(e: A.B.C.E): number {
149149
case A.B.C.E.V2: return 1;
150150
case A.B.C.E.V3: return 1;
151151
}
152-
}
152+
}
153+
154+
module M1 {
155+
export const enum Enum1 { X = 100, Y = X + 1 }
156+
}
157+
158+
const enum Enum3 {
159+
Z = M1.Enum1.Y
160+
}
161+
162+
var value1 = M1.Enum1.Y;
163+
var value2 = Enum3.Z;
153164

154165
//// [constEnums.js]
155166
var A2;
@@ -221,3 +232,5 @@ function bar(e) {
221232
case 64 /* V3 */: return 1;
222233
}
223234
}
235+
var value1 = 101 /* Y */;
236+
var value2 = 101 /* Z */;

tests/baselines/reference/constEnums.types

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -554,3 +554,41 @@ function bar(e: A.B.C.E): number {
554554
>V3 : I
555555
}
556556
}
557+
558+
module M1 {
559+
>M1 : typeof M1
560+
561+
export const enum Enum1 { X = 100, Y = X + 1 }
562+
>Enum1 : Enum1
563+
>X : Enum1
564+
>Y : Enum1
565+
>X + 1 : number
566+
>X : Enum1
567+
}
568+
569+
const enum Enum3 {
570+
>Enum3 : Enum3
571+
572+
Z = M1.Enum1.Y
573+
>Z : Enum3
574+
>M1.Enum1.Y : M1.Enum1
575+
>M1.Enum1 : typeof M1.Enum1
576+
>M1 : typeof M1
577+
>Enum1 : typeof M1.Enum1
578+
>Y : M1.Enum1
579+
}
580+
581+
var value1 = M1.Enum1.Y;
582+
>value1 : M1.Enum1
583+
>M1.Enum1.Y : M1.Enum1
584+
>M1.Enum1 : typeof M1.Enum1
585+
>M1 : typeof M1
586+
>Enum1 : typeof M1.Enum1
587+
>Y : M1.Enum1
588+
589+
var value2 = Enum3.Z;
590+
>value2 : Enum3
591+
>Enum3.Z : Enum3
592+
>Enum3 : typeof Enum3
593+
>Z : Enum3
594+

tests/baselines/reference/declFileEnums.js

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -46,14 +46,14 @@ var e1;
4646
var e2;
4747
(function (e2) {
4848
e2[e2["a"] = 10] = "a";
49-
e2[e2["b"] = e2.a + 2] = "b";
49+
e2[e2["b"] = 12] = "b";
5050
e2[e2["c"] = 10] = "c";
5151
})(e2 || (e2 = {}));
5252
var e3;
5353
(function (e3) {
5454
e3[e3["a"] = 10] = "a";
5555
e3[e3["b"] = Math.PI] = "b";
56-
e3[e3["c"] = e3.a + 3] = "c";
56+
e3[e3["c"] = 13] = "c";
5757
})(e3 || (e3 = {}));
5858
var e4;
5959
(function (e4) {
@@ -80,13 +80,13 @@ declare enum e1 {
8080
}
8181
declare enum e2 {
8282
a = 10,
83-
b,
83+
b = 12,
8484
c = 10,
8585
}
8686
declare enum e3 {
8787
a = 10,
8888
b,
89-
c,
89+
c = 13,
9090
}
9191
declare enum e4 {
9292
a = 0,

tests/baselines/reference/enumBasics.js

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -108,7 +108,7 @@ var E2;
108108
var E3;
109109
(function (E3) {
110110
E3[E3["X"] = 'foo'.length] = "X";
111-
E3[E3["Y"] = 4 + 3] = "Y";
111+
E3[E3["Y"] = 7] = "Y";
112112
E3[E3["Z"] = +'foo'] = "Z";
113113
})(E3 || (E3 = {}));
114114
// Enum with constant members followed by computed members
@@ -145,7 +145,7 @@ var E8;
145145
var E9;
146146
(function (E9) {
147147
E9[E9["A"] = 0] = "A";
148-
E9[E9["B"] = E9.A] = "B";
148+
E9[E9["B"] = 0] = "B";
149149
})(E9 || (E9 = {}));
150150
// (refer to .js to validate)
151151
// Enum constant members are propagated
@@ -154,13 +154,13 @@ var doNotPropagate = [
154154
E7.A,
155155
E4.Z,
156156
E3.X,
157-
E3.Y,
157+
7 /* Y */,
158158
E3.Z
159159
];
160160
// Enum computed members are not propagated
161161
var doPropagate = [
162162
0 /* A */,
163-
E9.B,
163+
0 /* B */,
164164
0 /* B */,
165165
1 /* C */,
166166
0 /* A */,

tests/baselines/reference/enumErrors.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -53,14 +53,14 @@ var E5;
5353
var E9;
5454
(function (E9) {
5555
E9[E9["A"] = 0] = "A";
56-
E9[E9["B"] = E9.A] = "B";
56+
E9[E9["B"] = 0] = "B";
5757
})(E9 || (E9 = {}));
5858
//Enum with computed member intializer of different enum type
5959
// Bug 707850: This should be allowed
6060
var E10;
6161
(function (E10) {
6262
E10[E10["A"] = 0 /* A */] = "A";
63-
E10[E10["B"] = E9.B] = "B";
63+
E10[E10["B"] = 0 /* B */] = "B";
6464
})(E10 || (E10 = {}));
6565
// Enum with computed member intializer of other types
6666
var E11;

tests/baselines/reference/mergedDeclarations2.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ var Foo;
1717
})(Foo || (Foo = {}));
1818
var Foo;
1919
(function (Foo) {
20-
Foo[Foo["a"] = Foo.b] = "a";
20+
Foo[Foo["a"] = 0] = "a";
2121
})(Foo || (Foo = {}));
2222
var Foo;
2323
(function (Foo) {

tests/baselines/reference/mergedEnumDeclarationCodeGen.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,9 +11,9 @@ enum E {
1111
var E;
1212
(function (E) {
1313
E[E["a"] = 0] = "a";
14-
E[E["b"] = E.a] = "b";
14+
E[E["b"] = 0] = "b";
1515
})(E || (E = {}));
1616
var E;
1717
(function (E) {
18-
E[E["c"] = E.a] = "c";
18+
E[E["c"] = 0] = "c";
1919
})(E || (E = {}));

tests/baselines/reference/sourceMapValidationEnums.js.map

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

tests/baselines/reference/sourceMapValidationEnums.sourcemap.txt

Lines changed: 14 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -134,41 +134,29 @@ sourceFile:sourceMapValidationEnums.ts
134134
---
135135
>>> e2[e2["x"] = 10] = "x";
136136
1->^^^^
137-
2 > ^^^^^^^^^^^^^
138-
3 > ^^
139-
4 > ^^^^^^^
140-
5 > ^
141-
6 > ^->
137+
2 > ^^^^^^^^^^^^^^^^^^^^^^
138+
3 > ^
139+
4 > ^->
142140
1-> {
143141
>
144-
2 > x =
145-
3 > 10
146-
4 >
147-
5 >
142+
2 > x = 10
143+
3 >
148144
1->Emitted(9, 5) Source(7, 5) + SourceIndex(0) name (e2)
149-
2 >Emitted(9, 18) Source(7, 9) + SourceIndex(0) name (e2)
150-
3 >Emitted(9, 20) Source(7, 11) + SourceIndex(0) name (e2)
151-
4 >Emitted(9, 27) Source(7, 11) + SourceIndex(0) name (e2)
152-
5 >Emitted(9, 28) Source(7, 11) + SourceIndex(0) name (e2)
145+
2 >Emitted(9, 27) Source(7, 11) + SourceIndex(0) name (e2)
146+
3 >Emitted(9, 28) Source(7, 11) + SourceIndex(0) name (e2)
153147
---
154148
>>> e2[e2["y"] = 10] = "y";
155149
1->^^^^
156-
2 > ^^^^^^^^^^^^^
157-
3 > ^^
158-
4 > ^^^^^^^
159-
5 > ^
160-
6 > ^->
150+
2 > ^^^^^^^^^^^^^^^^^^^^^^
151+
3 > ^
152+
4 > ^->
161153
1->,
162154
>
163-
2 > y =
164-
3 > 10
165-
4 >
166-
5 >
155+
2 > y = 10
156+
3 >
167157
1->Emitted(10, 5) Source(8, 5) + SourceIndex(0) name (e2)
168-
2 >Emitted(10, 18) Source(8, 9) + SourceIndex(0) name (e2)
169-
3 >Emitted(10, 20) Source(8, 11) + SourceIndex(0) name (e2)
170-
4 >Emitted(10, 27) Source(8, 11) + SourceIndex(0) name (e2)
171-
5 >Emitted(10, 28) Source(8, 11) + SourceIndex(0) name (e2)
158+
2 >Emitted(10, 27) Source(8, 11) + SourceIndex(0) name (e2)
159+
3 >Emitted(10, 28) Source(8, 11) + SourceIndex(0) name (e2)
172160
---
173161
>>> e2[e2["z"] = 11] = "z";
174162
1->^^^^

0 commit comments

Comments
 (0)