'const enum' iteration 0. TODO: allow and track const enums in imports, add more tests

This commit is contained in:
Vladimir Matveev
2014-10-27 23:56:07 -07:00
parent 329d6e2f13
commit 2dd9511b0a
12 changed files with 242 additions and 546 deletions

View File

@@ -6152,6 +6152,19 @@ module ts {
}
}
}
if (type.flags & (TypeFlags.ObjectType | TypeFlags.Anonymous) &&
type.symbol &&
(type.symbol.flags & SymbolFlags.Enum) &&
isConstEnumDeclaration(<EnumDeclaration>type.symbol.valueDeclaration)) {
// enum object type for const enums are only permitted in as 'left' in property access and 'object' in indexed access
var ok =
(node.parent.kind === SyntaxKind.PropertyAccess && (<PropertyAccess>node.parent).left === node) ||
(node.parent.kind === SyntaxKind.IndexedAccess && (<IndexedAccess>node.parent).object === node);
if (!ok) {
error(node, Diagnostics.const_enums_can_only_be_used_in_property_access_expressions);
}
}
return type;
}
@@ -7590,6 +7603,7 @@ module ts {
var enumType = getDeclaredTypeOfSymbol(enumSymbol);
var autoValue = 0;
var ambient = isInAmbientContext(node);
var enumIsConst = isConstEnumDeclaration(node);
forEach(node.members, member => {
if(isNumericName(member.name.text)) {
@@ -7597,16 +7611,21 @@ module ts {
}
var initializer = member.initializer;
if (initializer) {
autoValue = getConstantValueForEnumMemberInitializer(initializer);
if (autoValue === undefined && !ambient) {
// Only here do we need to check that the initializer is assignable to the enum type.
// If it is a constant value (not undefined), it is syntactically constrained to be a number.
// Also, we do not need to check this for ambients because there is already
// a syntax error if it is not a constant.
checkTypeAssignableTo(checkExpression(initializer), enumType, initializer, /*chainedMessage*/ undefined, /*terminalMessage*/ undefined);
autoValue = getConstantValueForEnumMemberInitializer(initializer, enumIsConst);
if (autoValue === undefined) {
if (enumIsConst) {
error(initializer, Diagnostics.In_const_enum_declarations_member_initializer_must_be_constant_expression);
}
else if (!ambient) {
// Only here do we need to check that the initializer is assignable to the enum type.
// If it is a constant value (not undefined), it is syntactically constrained to be a number.
// Also, we do not need to check this for ambients because there is already
// a syntax error if it is not a constant.
checkTypeAssignableTo(checkExpression(initializer), enumType, initializer, /*chainedMessage*/ undefined, /*terminalMessage*/ undefined);
}
}
}
else if (ambient) {
else if (ambient && !enumIsConst) {
autoValue = undefined;
}
@@ -7618,7 +7637,7 @@ module ts {
nodeLinks.flags |= NodeCheckFlags.EnumValuesComputed;
}
function getConstantValueForEnumMemberInitializer(initializer: Expression): number {
function getConstantValueForEnumMemberInitializer(initializer: Expression, enumIsConst: boolean): number {
return evalConstant(initializer);
function evalConstant(e: Node): number {
@@ -7631,11 +7650,11 @@ module ts {
switch ((<UnaryExpression>e).operator) {
case SyntaxKind.PlusToken: return value;
case SyntaxKind.MinusToken: return -value;
case SyntaxKind.TildeToken: return compilerOptions.propagateEnumConstants ? ~value : undefined;
case SyntaxKind.TildeToken: return enumIsConst ? ~value : undefined;
}
return undefined;
case SyntaxKind.BinaryExpression:
if (!compilerOptions.propagateEnumConstants) {
if (!enumIsConst) {
return undefined;
}
@@ -7655,14 +7674,20 @@ module ts {
case SyntaxKind.GreaterThanGreaterThanToken: return left >> right;
case SyntaxKind.GreaterThanGreaterThanGreaterThanToken: return left >>> right;
case SyntaxKind.LessThanLessThanToken: return left << right;
case SyntaxKind.AsteriskToken: return left * right;
case SyntaxKind.SlashToken: return left / right;
case SyntaxKind.PercentToken: return left % right;
case SyntaxKind.CaretToken: return left ^ right;
}
return undefined;
case SyntaxKind.NumericLiteral:
return +(<LiteralExpression>e).text;
case SyntaxKind.ParenExpression:
return enumIsConst ? evalConstant((<ParenExpression>e).expression) : undefined;
case SyntaxKind.Identifier:
case SyntaxKind.IndexedAccess:
case SyntaxKind.PropertyAccess:
if (!compilerOptions.propagateEnumConstants) {
if (!enumIsConst) {
return undefined;
}
@@ -7738,6 +7763,21 @@ module ts {
var enumSymbol = getSymbolOfNode(node);
var firstDeclaration = getDeclarationOfKind(enumSymbol, node.kind);
if (node === firstDeclaration) {
if (enumSymbol.declarations.length > 1) {
var enumIsConst = isConstEnumDeclaration(node);
// check that const is places\omitted on all enum declarations
forEach(enumSymbol.declarations, decl => {
if (decl.kind !== SyntaxKind.EnumDeclaration) {
// TODO(vladima): do we want to allow merging for const enum declarations
return;
}
if (isConstEnumDeclaration(<EnumDeclaration>decl) !== enumIsConst) {
error(decl.name, Diagnostics.Enum_declarations_must_all_be_const_or_non_const);
}
});
}
var seenEnumMissingInitialInitializer = false;
forEach(enumSymbol.declarations, declaration => {
// return true if we hit a violation of the rule, false otherwise

View File

@@ -118,11 +118,6 @@ module ts {
shortName: "w",
type: "boolean",
description: Diagnostics.Watch_input_files,
},
{
name: "propagateEnumConstants",
type: "boolean",
description: Diagnostics.Propagate_constant_values_in_enum_member_initializers
}
];

View File

@@ -353,6 +353,9 @@ module ts {
Parameter_0_of_exported_function_has_or_is_using_name_1_from_external_module_2_but_cannot_be_named: { code: 4076, category: DiagnosticCategory.Error, key: "Parameter '{0}' of exported function has or is using name '{1}' from external module {2} but cannot be named." },
Parameter_0_of_exported_function_has_or_is_using_name_1_from_private_module_2: { code: 4077, category: DiagnosticCategory.Error, key: "Parameter '{0}' of exported function has or is using name '{1}' from private module '{2}'." },
Parameter_0_of_exported_function_has_or_is_using_private_name_1: { code: 4078, category: DiagnosticCategory.Error, key: "Parameter '{0}' of exported function has or is using private name '{1}'." },
Enum_declarations_must_all_be_const_or_non_const: { code: 4079, category: DiagnosticCategory.Error, key: "Enum declarations must all be const or non-const." },
In_const_enum_declarations_member_initializer_must_be_constant_expression: { code: 4079, category: DiagnosticCategory.Error, key: "In 'const' enum declarations member initializer must be constant expression." },
const_enums_can_only_be_used_in_property_access_expressions: { code: 4079, category: DiagnosticCategory.Error, key: "'const' enums can only be used in property access expressions." },
The_current_host_does_not_support_the_0_option: { code: 5001, category: DiagnosticCategory.Error, key: "The current host does not support the '{0}' option." },
Cannot_find_the_common_subdirectory_path_for_the_input_files: { code: 5009, category: DiagnosticCategory.Error, key: "Cannot find the common subdirectory path for the input files." },
Cannot_read_file_0_Colon_1: { code: 5012, category: DiagnosticCategory.Error, key: "Cannot read file '{0}': {1}" },
@@ -372,7 +375,6 @@ module ts {
Specify_module_code_generation_Colon_commonjs_or_amd: { code: 6016, category: DiagnosticCategory.Message, key: "Specify module code generation: 'commonjs' or 'amd'" },
Print_this_message: { code: 6017, category: DiagnosticCategory.Message, key: "Print this message." },
Print_the_compiler_s_version: { code: 6019, category: DiagnosticCategory.Message, key: "Print the compiler's version." },
Propagate_constant_values_in_enum_member_initializers: { code: 6020, category: DiagnosticCategory.Message, key: "Propagate constant values in enum member initializers." },
Syntax_Colon_0: { code: 6023, category: DiagnosticCategory.Message, key: "Syntax: {0}" },
options: { code: 6024, category: DiagnosticCategory.Message, key: "options" },
file: { code: 6025, category: DiagnosticCategory.Message, key: "file" },

View File

@@ -1409,13 +1409,22 @@
"category": "Error",
"code": 4078
},
"Enum declarations must all be const or non-const.": {
"category": "Error",
"code": 4079
},
"In 'const' enum declarations member initializer must be constant expression.": {
"category": "Error",
"code": 4079
},
"'const' enums can only be used in property access expressions.": {
"category": "Error",
"code": 4079
},
"The current host does not support the '{0}' option.": {
"category": "Error",
"code": 5001
},
"Cannot find the common subdirectory path for the input files.": {
"category": "Error",
"code": 5009
@@ -1488,10 +1497,6 @@
"category": "Message",
"code": 6019
},
"Propagate constant values in enum member initializers.": {
"category": "Message",
"code": 6020
},
"Syntax: {0}": {
"category": "Message",
"code": 6023

View File

@@ -1760,6 +1760,9 @@ module ts {
}
function emitEnumDeclaration(node: EnumDeclaration) {
if (isConstEnumDeclaration(node)) {
return;
}
emitLeadingComments(node);
if (!(node.flags & NodeFlags.Export)) {
emitStart(node);
@@ -2570,6 +2573,9 @@ module ts {
if (resolver.isDeclarationVisible(node)) {
emitJsDocComments(node);
emitDeclarationFlags(node);
if (isConstEnumDeclaration(node)) {
write("const ")
}
write("enum ");
emitSourceTextOfNode(node.name);
write(" {");

View File

@@ -186,6 +186,10 @@ module ts {
return (file.flags & NodeFlags.DeclarationFile) !== 0;
}
export function isConstEnumDeclaration(node: EnumDeclaration): boolean {
return (node.flags & NodeFlags.Const) !== 0;
}
export function isPrologueDirective(node: Node): boolean {
return node.kind === SyntaxKind.ExpressionStatement && (<ExpressionStatement>node).expression.kind === SyntaxKind.StringLiteral;
}
@@ -3146,7 +3150,6 @@ module ts {
case SyntaxKind.OpenBraceToken:
case SyntaxKind.VarKeyword:
case SyntaxKind.LetKeyword:
case SyntaxKind.ConstKeyword:
case SyntaxKind.FunctionKeyword:
case SyntaxKind.IfKeyword:
case SyntaxKind.DoKeyword:
@@ -3165,6 +3168,12 @@ module ts {
case SyntaxKind.CatchKeyword:
case SyntaxKind.FinallyKeyword:
return true;
case SyntaxKind.ConstKeyword:
// const keyword can precede enum keyword when defining constant enums
// 'const enum' do not start statement.
// In ES 6 'enum' is a future reserved keyword, so it should not be used as identifier
var isConstEnum = lookAhead(() => nextToken() === SyntaxKind.EnumKeyword);
return !isConstEnum;
case SyntaxKind.InterfaceKeyword:
case SyntaxKind.ClassKeyword:
case SyntaxKind.ModuleKeyword:
@@ -3174,6 +3183,7 @@ module ts {
if (isDeclaration()) {
return false;
}
case SyntaxKind.PublicKeyword:
case SyntaxKind.PrivateKeyword:
case SyntaxKind.ProtectedKeyword:
@@ -3195,6 +3205,7 @@ module ts {
case SyntaxKind.VarKeyword:
case SyntaxKind.LetKeyword:
case SyntaxKind.ConstKeyword:
// const here should always be parsed as const declaration because of check in 'isStatement'
return parseVariableStatement(allowLetAndConstDeclarations);
case SyntaxKind.FunctionKeyword:
return parseFunctionDeclaration();
@@ -3748,6 +3759,7 @@ module ts {
}
function parseAndCheckEnumDeclaration(pos: number, flags: NodeFlags): EnumDeclaration {
var enumIsConst = flags & NodeFlags.Const;
function isIntegerLiteral(expression: Expression): boolean {
function isInteger(literalExpression: LiteralExpression): boolean {
// Allows for scientific notation since literalExpression.text was formed by
@@ -3782,22 +3794,29 @@ module ts {
node.name = parsePropertyName();
node.initializer = parseInitializer(/*inParameter*/ false);
if (inAmbientContext) {
if (node.initializer && !isIntegerLiteral(node.initializer) && errorCountBeforeEnumMember === file.syntacticErrors.length) {
grammarErrorOnNode(node.name, Diagnostics.Ambient_enum_elements_can_only_have_integer_literal_initializers);
// skip checks below for const enums - they allow arbitrary initializers as long as they can be evaluated to constant expressions.
// since all values are known in compile time - it is not necessary to check that constant enum section precedes computed enum members.
if (!enumIsConst) {
if (inAmbientContext) {
if (node.initializer && !isIntegerLiteral(node.initializer) && errorCountBeforeEnumMember === file.syntacticErrors.length) {
grammarErrorOnNode(node.name, Diagnostics.Ambient_enum_elements_can_only_have_integer_literal_initializers);
}
}
else if (node.initializer) {
inConstantEnumMemberSection = isIntegerLiteral(node.initializer);
}
else if (!inConstantEnumMemberSection && errorCountBeforeEnumMember === file.syntacticErrors.length) {
grammarErrorOnNode(node.name, Diagnostics.Enum_member_must_have_initializer);
}
}
else if (node.initializer) {
inConstantEnumMemberSection = isIntegerLiteral(node.initializer);
}
else if (!inConstantEnumMemberSection && errorCountBeforeEnumMember === file.syntacticErrors.length) {
grammarErrorOnNode(node.name, Diagnostics.Enum_member_must_have_initializer);
}
return finishNode(node);
}
var node = <EnumDeclaration>createNode(SyntaxKind.EnumDeclaration, pos);
node.flags = flags;
if (enumIsConst) {
parseExpected(SyntaxKind.ConstKeyword);
}
parseExpected(SyntaxKind.EnumKeyword);
node.name = parseIdentifier();
if (parseExpected(SyntaxKind.OpenBraceToken)) {
@@ -3953,9 +3972,17 @@ module ts {
switch (token) {
case SyntaxKind.VarKeyword:
case SyntaxKind.LetKeyword:
case SyntaxKind.ConstKeyword:
result = parseVariableStatement(/*allowLetAndConstDeclarations*/ true, pos, flags);
break;
case SyntaxKind.ConstKeyword:
var isConstEnum = lookAhead(() => nextToken() === SyntaxKind.EnumKeyword);
if (isConstEnum) {
result = parseAndCheckEnumDeclaration(pos, flags | NodeFlags.Const);
}
else {
result = parseVariableStatement(/*allowLetAndConstDeclarations*/ true, pos, flags);
}
break;
case SyntaxKind.FunctionKeyword:
result = parseFunctionDeclaration(pos, flags);
break;

View File

@@ -1095,7 +1095,6 @@ module ts {
target?: ScriptTarget;
version?: boolean;
watch?: boolean;
propagateEnumConstants?: boolean;
[option: string]: any;
}

View File

@@ -749,9 +749,6 @@ module Harness {
case 'usecasesensitivefilenames':
useCaseSensitiveFileNames = setting.value === 'true';
break;
case 'propagateenumconstants':
options.propagateEnumConstants = setting.value === 'true';
break;
case 'mapsourcefiles':
case 'maproot':
@@ -1148,7 +1145,7 @@ module Harness {
var optionRegex = /^[\/]{2}\s*@(\w+)\s*:\s*(\S*)/gm; // multiple matches on multiple lines
// List of allowed metadata names
var fileMetadataNames = ["filename", "comments", "declaration", "module", "nolib", "sourcemap", "target", "out", "outdir", "noimplicitany", "noresolve", "newline", "newlines", "emitbom", "errortruncation", "usecasesensitivefilenames", "propagateenumconstants"];
var fileMetadataNames = ["filename", "comments", "declaration", "module", "nolib", "sourcemap", "target", "out", "outdir", "noimplicitany", "noresolve", "newline", "newlines", "emitbom", "errortruncation", "usecasesensitivefilenames"];
function extractCompilerSettings(content: string): CompilerSetting[] {

View File

@@ -0,0 +1,122 @@
tests/cases/compiler/constantsInEnumMembers.ts(38,9): error TS4079: In 'const' enum declarations member initializer must be constant expression.
tests/cases/compiler/constantsInEnumMembers.ts(40,9): error TS4079: In 'const' enum declarations member initializer must be constant expression.
tests/cases/compiler/constantsInEnumMembers.ts(41,10): error TS4079: In 'const' enum declarations member initializer must be constant expression.
==== tests/cases/compiler/constantsInEnumMembers.ts (3 errors) ====
const enum Enum1 {
A0 = 100,
}
const enum Enum1 {
// correct cases
A,
B,
C = 10,
D = A + B,
E = A + 1,
F = 1 + A,
G = 1 + 1,
H = A - B,
I = A - 1,
J = 1 - A,
K = 1 - 1,
L = ~D,
M = E << B,
N = E << 1,
O = E >> B,
P = E >> 1,
Q = -D,
R = C & 5,
S = 5 & C,
T = C | D,
U = C | 1,
V = 10 | D,
W = Enum1.V,
// correct cases: reference to the enum member from different enum declaration
W1 = A0,
W2 = Enum1.A0,
W3 = Enum1["A0"],
W4 = Enum1["W"],
// illegal case
// forward reference to the element of the same enum
X = Y,
~
!!! error TS4079: In 'const' enum declarations member initializer must be constant expression.
// forward reference to the element of the same enum
Y = Enum1.Z,
~~~~~~~
!!! error TS4079: In 'const' enum declarations member initializer must be constant expression.
Y1 = Enum1["Z"],
~~~~~~~~~~
!!! error TS4079: In 'const' enum declarations member initializer must be constant expression.
Z = 100,
}
module A {
export module B {
export module C {
export const enum E {
V1 = 1,
V2 = A.B.C.E.V1 + 100
}
}
}
}
module A {
export module B {
export module C {
export const enum E {
V3 = A.B.C.E["V2"] + 200,
}
}
}
}
function foo(x: Enum1) {
switch (x) {
case Enum1.A:
case Enum1.B:
case Enum1.C:
case Enum1.D:
case Enum1.E:
case Enum1.F:
case Enum1.G:
case Enum1.H:
case Enum1.I:
case Enum1.J:
case Enum1.K:
case Enum1.L:
case Enum1.M:
case Enum1.N:
case Enum1.O:
case Enum1.P:
case Enum1.Q:
case Enum1.R:
case Enum1.S:
case Enum1.T:
case Enum1.U:
case Enum1.V:
case Enum1.W:
case Enum1.W1:
case Enum1.W2:
case Enum1.W3:
case Enum1.W4:
case Enum1.X:
case Enum1.Y:
case Enum1.Y1:
case Enum1.Z:
break;
}
}
function bar(e: A.B.C.E): number {
switch (e) {
case A.B.C.E.V1: return 1;
case A.B.C.E.V2: return 1;
case A.B.C.E.V3: return 1;
}
}

View File

@@ -1,10 +1,9 @@
//// [constantsInEnumMembers.ts]
enum Enum1 {
const enum Enum1 {
A0 = 100,
}
enum Enum1 {
const enum Enum1 {
// correct cases
A,
B,
@@ -48,7 +47,7 @@ enum Enum1 {
module A {
export module B {
export module C {
export enum E {
export const enum E {
V1 = 1,
V2 = A.B.C.E.V1 + 100
}
@@ -59,7 +58,7 @@ module A {
module A {
export module B {
export module C {
export enum E {
export const enum E {
V3 = A.B.C.E["V2"] + 200,
}
}
@@ -112,60 +111,12 @@ function bar(e: A.B.C.E): number {
}
//// [constantsInEnumMembers.js]
var Enum1;
(function (Enum1) {
Enum1[Enum1["A0"] = 100] = "A0";
})(Enum1 || (Enum1 = {}));
var Enum1;
(function (Enum1) {
// correct cases
Enum1[Enum1["A"] = 0] = "A";
Enum1[Enum1["B"] = 1] = "B";
Enum1[Enum1["C"] = 10] = "C";
Enum1[Enum1["D"] = A + B] = "D";
Enum1[Enum1["E"] = A + 1] = "E";
Enum1[Enum1["F"] = 1 + A] = "F";
Enum1[Enum1["G"] = 1 + 1] = "G";
Enum1[Enum1["H"] = A - B] = "H";
Enum1[Enum1["I"] = A - 1] = "I";
Enum1[Enum1["J"] = 1 - A] = "J";
Enum1[Enum1["K"] = 1 - 1] = "K";
Enum1[Enum1["L"] = ~D] = "L";
Enum1[Enum1["M"] = E << B] = "M";
Enum1[Enum1["N"] = E << 1] = "N";
Enum1[Enum1["O"] = E >> B] = "O";
Enum1[Enum1["P"] = E >> 1] = "P";
Enum1[Enum1["Q"] = -D] = "Q";
Enum1[Enum1["R"] = C & 5] = "R";
Enum1[Enum1["S"] = 5 & C] = "S";
Enum1[Enum1["T"] = C | D] = "T";
Enum1[Enum1["U"] = C | 1] = "U";
Enum1[Enum1["V"] = 10 | D] = "V";
Enum1[Enum1["W"] = Enum1.V] = "W";
// correct cases: reference to the enum member from different enum declaration
Enum1[Enum1["W1"] = A0] = "W1";
Enum1[Enum1["W2"] = Enum1.A0] = "W2";
Enum1[Enum1["W3"] = Enum1["A0"]] = "W3";
Enum1[Enum1["W4"] = Enum1["W"]] = "W4";
// illegal case
// forward reference to the element of the same enum
Enum1[Enum1["X"] = Enum1.Y] = "X";
// forward reference to the element of the same enum
Enum1[Enum1["Y"] = 100 /* Z */] = "Y";
Enum1[Enum1["Y1"] = Enum1["Z"]] = "Y1";
Enum1[Enum1["Z"] = 100] = "Z";
})(Enum1 || (Enum1 = {}));
var A;
(function (A) {
var B;
(function (B) {
var C;
(function (C) {
(function (E) {
E[E["V1"] = 1] = "V1";
E[E["V2"] = A.B.C.E.V1 + 100] = "V2";
})(C.E || (C.E = {}));
var E = C.E;
})(C = B.C || (B.C = {}));
})(B = A.B || (A.B = {}));
})(A || (A = {}));
@@ -175,10 +126,6 @@ var A;
(function (B) {
var C;
(function (C) {
(function (E) {
E[E["V3"] = A.B.C.E["V2"] + 200] = "V3";
})(C.E || (C.E = {}));
var E = C.E;
})(C = B.C || (B.C = {}));
})(B = A.B || (A.B = {}));
})(A || (A = {}));

View File

@@ -1,442 +0,0 @@
=== tests/cases/compiler/constantsInEnumMembers.ts ===
enum Enum1 {
>Enum1 : Enum1
A0 = 100,
>A0 : Enum1
}
enum Enum1 {
>Enum1 : Enum1
// correct cases
A,
>A : Enum1
B,
>B : Enum1
C = 10,
>C : Enum1
D = A + B,
>D : Enum1
>A + B : number
>A : Enum1
>B : Enum1
E = A + 1,
>E : Enum1
>A + 1 : number
>A : Enum1
F = 1 + A,
>F : Enum1
>1 + A : number
>A : Enum1
G = 1 + 1,
>G : Enum1
>1 + 1 : number
H = A - B,
>H : Enum1
>A - B : number
>A : Enum1
>B : Enum1
I = A - 1,
>I : Enum1
>A - 1 : number
>A : Enum1
J = 1 - A,
>J : Enum1
>1 - A : number
>A : Enum1
K = 1 - 1,
>K : Enum1
>1 - 1 : number
L = ~D,
>L : Enum1
>~D : number
>D : Enum1
M = E << B,
>M : Enum1
>E << B : number
>E : Enum1
>B : Enum1
N = E << 1,
>N : Enum1
>E << 1 : number
>E : Enum1
O = E >> B,
>O : Enum1
>E >> B : number
>E : Enum1
>B : Enum1
P = E >> 1,
>P : Enum1
>E >> 1 : number
>E : Enum1
Q = -D,
>Q : Enum1
>-D : number
>D : Enum1
R = C & 5,
>R : Enum1
>C & 5 : number
>C : Enum1
S = 5 & C,
>S : Enum1
>5 & C : number
>C : Enum1
T = C | D,
>T : Enum1
>C | D : number
>C : Enum1
>D : Enum1
U = C | 1,
>U : Enum1
>C | 1 : number
>C : Enum1
V = 10 | D,
>V : Enum1
>10 | D : number
>D : Enum1
W = Enum1.V,
>W : Enum1
>Enum1.V : Enum1
>Enum1 : typeof Enum1
>V : Enum1
// correct cases: reference to the enum member from different enum declaration
W1 = A0,
>W1 : Enum1
>A0 : Enum1
W2 = Enum1.A0,
>W2 : Enum1
>Enum1.A0 : Enum1
>Enum1 : typeof Enum1
>A0 : Enum1
W3 = Enum1["A0"],
>W3 : Enum1
>Enum1["A0"] : Enum1
>Enum1 : typeof Enum1
W4 = Enum1["W"],
>W4 : Enum1
>Enum1["W"] : Enum1
>Enum1 : typeof Enum1
// illegal case
// forward reference to the element of the same enum
X = Y,
>X : Enum1
>Y : Enum1
// forward reference to the element of the same enum
Y = Enum1.Z,
>Y : Enum1
>Enum1.Z : Enum1
>Enum1 : typeof Enum1
>Z : Enum1
Y1 = Enum1["Z"],
>Y1 : Enum1
>Enum1["Z"] : Enum1
>Enum1 : typeof Enum1
Z = 100,
>Z : Enum1
}
module A {
>A : typeof A
export module B {
>B : typeof B
export module C {
>C : typeof C
export enum E {
>E : E
V1 = 1,
>V1 : E
V2 = A.B.C.E.V1 + 100
>V2 : E
>A.B.C.E.V1 + 100 : number
>A.B.C.E.V1 : E
>A.B.C.E : typeof E
>A.B.C : typeof C
>A.B : typeof B
>A : typeof A
>B : typeof B
>C : typeof C
>E : typeof E
>V1 : E
}
}
}
}
module A {
>A : typeof A
export module B {
>B : typeof B
export module C {
>C : typeof C
export enum E {
>E : E
V3 = A.B.C.E["V2"] + 200,
>V3 : E
>A.B.C.E["V2"] + 200 : number
>A.B.C.E["V2"] : E
>A.B.C.E : typeof E
>A.B.C : typeof C
>A.B : typeof B
>A : typeof A
>B : typeof B
>C : typeof C
>E : typeof E
}
}
}
}
function foo(x: Enum1) {
>foo : (x: Enum1) => void
>x : Enum1
>Enum1 : Enum1
switch (x) {
>x : Enum1
case Enum1.A:
>Enum1.A : Enum1
>Enum1 : typeof Enum1
>A : Enum1
case Enum1.B:
>Enum1.B : Enum1
>Enum1 : typeof Enum1
>B : Enum1
case Enum1.C:
>Enum1.C : Enum1
>Enum1 : typeof Enum1
>C : Enum1
case Enum1.D:
>Enum1.D : Enum1
>Enum1 : typeof Enum1
>D : Enum1
case Enum1.E:
>Enum1.E : Enum1
>Enum1 : typeof Enum1
>E : Enum1
case Enum1.F:
>Enum1.F : Enum1
>Enum1 : typeof Enum1
>F : Enum1
case Enum1.G:
>Enum1.G : Enum1
>Enum1 : typeof Enum1
>G : Enum1
case Enum1.H:
>Enum1.H : Enum1
>Enum1 : typeof Enum1
>H : Enum1
case Enum1.I:
>Enum1.I : Enum1
>Enum1 : typeof Enum1
>I : Enum1
case Enum1.J:
>Enum1.J : Enum1
>Enum1 : typeof Enum1
>J : Enum1
case Enum1.K:
>Enum1.K : Enum1
>Enum1 : typeof Enum1
>K : Enum1
case Enum1.L:
>Enum1.L : Enum1
>Enum1 : typeof Enum1
>L : Enum1
case Enum1.M:
>Enum1.M : Enum1
>Enum1 : typeof Enum1
>M : Enum1
case Enum1.N:
>Enum1.N : Enum1
>Enum1 : typeof Enum1
>N : Enum1
case Enum1.O:
>Enum1.O : Enum1
>Enum1 : typeof Enum1
>O : Enum1
case Enum1.P:
>Enum1.P : Enum1
>Enum1 : typeof Enum1
>P : Enum1
case Enum1.Q:
>Enum1.Q : Enum1
>Enum1 : typeof Enum1
>Q : Enum1
case Enum1.R:
>Enum1.R : Enum1
>Enum1 : typeof Enum1
>R : Enum1
case Enum1.S:
>Enum1.S : Enum1
>Enum1 : typeof Enum1
>S : Enum1
case Enum1.T:
>Enum1.T : Enum1
>Enum1 : typeof Enum1
>T : Enum1
case Enum1.U:
>Enum1.U : Enum1
>Enum1 : typeof Enum1
>U : Enum1
case Enum1.V:
>Enum1.V : Enum1
>Enum1 : typeof Enum1
>V : Enum1
case Enum1.W:
>Enum1.W : Enum1
>Enum1 : typeof Enum1
>W : Enum1
case Enum1.W1:
>Enum1.W1 : Enum1
>Enum1 : typeof Enum1
>W1 : Enum1
case Enum1.W2:
>Enum1.W2 : Enum1
>Enum1 : typeof Enum1
>W2 : Enum1
case Enum1.W3:
>Enum1.W3 : Enum1
>Enum1 : typeof Enum1
>W3 : Enum1
case Enum1.W4:
>Enum1.W4 : Enum1
>Enum1 : typeof Enum1
>W4 : Enum1
case Enum1.X:
>Enum1.X : Enum1
>Enum1 : typeof Enum1
>X : Enum1
case Enum1.Y:
>Enum1.Y : Enum1
>Enum1 : typeof Enum1
>Y : Enum1
case Enum1.Y1:
>Enum1.Y1 : Enum1
>Enum1 : typeof Enum1
>Y1 : Enum1
case Enum1.Z:
>Enum1.Z : Enum1
>Enum1 : typeof Enum1
>Z : Enum1
break;
}
}
function bar(e: A.B.C.E): number {
>bar : (e: A.B.C.E) => number
>e : A.B.C.E
>A : unknown
>B : unknown
>C : unknown
>E : A.B.C.E
switch (e) {
>e : A.B.C.E
case A.B.C.E.V1: return 1;
>A.B.C.E.V1 : A.B.C.E
>A.B.C.E : typeof A.B.C.E
>A.B.C : typeof A.B.C
>A.B : typeof A.B
>A : typeof A
>B : typeof A.B
>C : typeof A.B.C
>E : typeof A.B.C.E
>V1 : A.B.C.E
case A.B.C.E.V2: return 1;
>A.B.C.E.V2 : A.B.C.E
>A.B.C.E : typeof A.B.C.E
>A.B.C : typeof A.B.C
>A.B : typeof A.B
>A : typeof A
>B : typeof A.B
>C : typeof A.B.C
>E : typeof A.B.C.E
>V2 : A.B.C.E
case A.B.C.E.V3: return 1;
>A.B.C.E.V3 : A.B.C.E
>A.B.C.E : typeof A.B.C.E
>A.B.C : typeof A.B.C
>A.B : typeof A.B
>A : typeof A
>B : typeof A.B
>C : typeof A.B.C
>E : typeof A.B.C.E
>V3 : A.B.C.E
}
}

View File

@@ -1,10 +1,8 @@
// @propagateEnumConstants: true
enum Enum1 {
const enum Enum1 {
A0 = 100,
}
enum Enum1 {
const enum Enum1 {
// correct cases
A,
B,
@@ -48,7 +46,7 @@ enum Enum1 {
module A {
export module B {
export module C {
export enum E {
export const enum E {
V1 = 1,
V2 = A.B.C.E.V1 + 100
}
@@ -59,7 +57,7 @@ module A {
module A {
export module B {
export module C {
export enum E {
export const enum E {
V3 = A.B.C.E["V2"] + 200,
}
}