const enums, iteration 1: const enums can be used in imports, const enums can be merged only with const enums.

This commit is contained in:
Vladimir Matveev 2014-10-29 00:17:16 -07:00
parent 6f4ea86227
commit e949eda583
16 changed files with 703 additions and 233 deletions

View File

@ -5,21 +5,25 @@
module ts {
export function isInstantiated(node: Node): boolean {
export function isInstantiated(node: Node, checkConstEnums: boolean): boolean {
// A module is uninstantiated if it contains only
// 1. interface declarations
if (node.kind === SyntaxKind.InterfaceDeclaration) {
return false;
}
// 2. non - exported import declarations
// 2. const enum declarations don't make module instantiated
else if (checkConstEnums && node.kind === SyntaxKind.EnumDeclaration && isConstEnumDeclaration(<EnumDeclaration>node)) {
return false;
}
// 3. non - exported import declarations
else if (node.kind === SyntaxKind.ImportDeclaration && !(node.flags & NodeFlags.Export)) {
return false;
}
// 3. other uninstantiated module declarations.
else if (node.kind === SyntaxKind.ModuleBlock && !forEachChild(node, isInstantiated)) {
// 4. other uninstantiated module declarations.
else if (node.kind === SyntaxKind.ModuleBlock && !forEachChild(node, n => isInstantiated(n, checkConstEnums))) {
return false;
}
else if (node.kind === SyntaxKind.ModuleDeclaration && !isInstantiated((<ModuleDeclaration>node).body)) {
else if (node.kind === SyntaxKind.ModuleDeclaration && !isInstantiated((<ModuleDeclaration>node).body, checkConstEnums)) {
return false;
}
else {
@ -248,7 +252,7 @@ module ts {
if (node.name.kind === SyntaxKind.StringLiteral) {
bindDeclaration(node, SymbolFlags.ValueModule, SymbolFlags.ValueModuleExcludes, /*isBlockScopeContainer*/ true);
}
else if (isInstantiated(node)) {
else if (isInstantiated(node, /*checkConstEnums*/ false)) {
bindDeclaration(node, SymbolFlags.ValueModule, SymbolFlags.ValueModuleExcludes, /*isBlockScopeContainer*/ true);
}
else {
@ -364,7 +368,10 @@ module ts {
bindDeclaration(<Declaration>node, SymbolFlags.TypeAlias, SymbolFlags.TypeAliasExcludes, /*isBlockScopeContainer*/ false);
break;
case SyntaxKind.EnumDeclaration:
bindDeclaration(<Declaration>node, SymbolFlags.Enum, SymbolFlags.EnumExcludes, /*isBlockScopeContainer*/ false);
var enumIsConst = isConstEnumDeclaration(<EnumDeclaration>node);
var flags = enumIsConst ? SymbolFlags.Enum | SymbolFlags.ConstEnum : SymbolFlags.Enum;
var excludes = enumIsConst ? SymbolFlags.ConstEnumExcludes : SymbolFlags.EnumExcludes;
bindDeclaration(<Declaration>node, flags, excludes, /*isBlockScopeContainer*/ false);
break;
case SyntaxKind.ModuleDeclaration:
bindModuleDeclaration(<ModuleDeclaration>node);

View File

@ -4431,8 +4431,8 @@ module ts {
if (symbol.flags & SymbolFlags.Import) {
// Mark the import as referenced so that we emit it in the final .js file.
// exception: identifiers that appear in type queries
getSymbolLinks(symbol).referenced = !isInTypeQuery(node);
// exception: identifiers that appear in type queries, const enums
getSymbolLinks(symbol).referenced = !isInTypeQuery(node) && !isConstEnumSymbol(resolveImport(symbol));
}
checkCollisionWithCapturedSuperVariable(node, node);
@ -5086,6 +5086,10 @@ module ts {
if (objectType === unknownType) return unknownType;
if (isConstEnumType(objectType) && node.index.kind !== SyntaxKind.StringLiteral) {
error(node.index, Diagnostics.Index_expression_arguments_in_const_enums_must_be_of_type_string);
}
// TypeScript 1.0 spec (April 2014): 4.10 Property Access
// - If IndexExpr is a string literal or a numeric literal and ObjExpr's apparent type has a property with the name
// given by that literal(converted to its string representation in the case of a numeric literal), the property access is of the type of that property.
@ -5962,6 +5966,14 @@ module ts {
return (type.flags & TypeFlags.Structured) !== 0;
}
function isConstEnumType(type: Type) : boolean {
return type.flags & (TypeFlags.ObjectType | TypeFlags.Anonymous) && type.symbol && isConstEnumSymbol(type.symbol);
}
function isConstEnumSymbol(symbol: Symbol): boolean {
return (symbol.flags & SymbolFlags.ConstEnum) !== 0;
}
function checkInstanceOfExpression(node: BinaryExpression, leftType: Type, rightType: Type): Type {
// TypeScript 1.0 spec (April 2014): 4.15.4
// The instanceof operator requires the left operand to be of type Any, an object type, or a type parameter type,
@ -6187,19 +6199,31 @@ 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
if (isConstEnumType(type)) {
// enum object type for const enums are only permitted in:
// - 'left' in property access
// - 'object' in indexed access
// - target in rhs of import statement
var ok =
(node.parent.kind === SyntaxKind.PropertyAccess && (<PropertyAccess>node.parent).left === node) ||
(node.parent.kind === SyntaxKind.IndexedAccess && (<IndexedAccess>node.parent).object === node);
(node.parent.kind === SyntaxKind.IndexedAccess && (<IndexedAccess>node.parent).object === node) ||
isRhsOfImportStatement(node);
if (!ok) {
error(node, Diagnostics.const_enums_can_only_be_used_in_property_access_expressions);
}
}
return type;
function isRhsOfImportStatement(n: Node): boolean {
while (n.parent) {
if (n.parent.kind === SyntaxKind.ImportDeclaration && (<ImportDeclaration>n.parent).entityName === n) {
return true;
}
n = n.parent;
}
return false;
}
}
function checkExpressionNode(node: Expression, contextualMapper: TypeMapper): Type {
@ -6868,7 +6892,7 @@ module ts {
case SyntaxKind.InterfaceDeclaration:
return SymbolFlags.ExportType;
case SyntaxKind.ModuleDeclaration:
return (<ModuleDeclaration>d).name.kind === SyntaxKind.StringLiteral || isInstantiated(d)
return (<ModuleDeclaration>d).name.kind === SyntaxKind.StringLiteral || isInstantiated(d, /*checkConstEnums*/ false)
? SymbolFlags.ExportNamespace | SymbolFlags.ExportValue
: SymbolFlags.ExportNamespace;
case SyntaxKind.ClassDeclaration:
@ -7105,7 +7129,7 @@ module ts {
}
// Uninstantiated modules shouldnt do this check
if (node.kind === SyntaxKind.ModuleDeclaration && !isInstantiated(node)) {
if (node.kind === SyntaxKind.ModuleDeclaration && !isInstantiated(node, /*checkConstEnums*/ true)) {
return;
}
@ -7707,14 +7731,9 @@ module ts {
switch ((<BinaryExpression>e).operator) {
case SyntaxKind.BarToken: return left | right;
case SyntaxKind.AmpersandToken: return left & right;
case SyntaxKind.PlusToken: return left + right;
case SyntaxKind.MinusToken: return left - right;
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;
@ -7803,13 +7822,8 @@ module ts {
if (node === firstDeclaration) {
if (enumSymbol.declarations.length > 1) {
var enumIsConst = isConstEnumDeclaration(node);
// check that const is places\omitted on all enum declarations
// check that const is placed\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);
}
@ -8655,7 +8669,7 @@ module ts {
}
var symbol = getSymbolOfNode(node);
var target = resolveImport(symbol);
return target !== unknownSymbol && ((target.flags & SymbolFlags.Value) !== 0);
return target !== unknownSymbol && ((target.flags & SymbolFlags.Value) !== 0) && !isConstEnumSymbol(target);
}
function hasSemanticErrors() {
@ -8676,7 +8690,8 @@ module ts {
// As a consequence this might cause emitting extra.
if (node.flags & NodeFlags.Export) {
var target = resolveImport(symbol);
if (target !== unknownSymbol && target.flags & SymbolFlags.Value) {
// importing const enum does not cause import to be referenced
if (target !== unknownSymbol && target.flags & SymbolFlags.Value && !isConstEnumSymbol(target)) {
return true;
}
}

View File

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

View File

@ -353,6 +353,7 @@ module ts {
Enum_declarations_must_all_be_const_or_non_const: { code: 4082, category: DiagnosticCategory.Error, key: "Enum declarations must all be const or non-const." },
In_const_enum_declarations_member_initializer_must_be_constant_expression: { code: 4083, 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: 4084, category: DiagnosticCategory.Error, key: "'const' enums can only be used in property access expressions." },
Index_expression_arguments_in_const_enums_must_be_of_type_string: { code: 4085, category: DiagnosticCategory.Error, key: "Index expression arguments in 'const' enums must be of type 'string'." },
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}" },

View File

@ -1412,7 +1412,11 @@
"'const' enums can only be used in property access expressions.": {
"category": "Error",
"code": 4084
},
},
"Index expression arguments in 'const' enums must be of type 'string'.": {
"category": "Error",
"code": 4085
},
"The current host does not support the '{0}' option.": {
"category": "Error",
"code": 5001

View File

@ -1760,7 +1760,8 @@ module ts {
}
function emitEnumDeclaration(node: EnumDeclaration) {
if (isConstEnumDeclaration(node)) {
// const enums are completely erased during compilation.
if (isConstEnumDeclaration(node) && !compilerOptions.preserveConstEnums) {
return;
}
emitLeadingComments(node);
@ -1837,7 +1838,7 @@ module ts {
}
function emitModuleDeclaration(node: ModuleDeclaration) {
if (!isInstantiated(node)) {
if (!isInstantiated(node, /*checkConstEnums*/ true)) {
return emitPinnedOrTripleSlashComments(node);
}
emitLeadingComments(node);

View File

@ -783,6 +783,7 @@ module ts {
Transient = 0x08000000, // Transient symbol (created during type check)
Prototype = 0x10000000, // Prototype property (no source representation)
UnionProperty = 0x20000000, // Property in union type
ConstEnum = 0x40000000, // Const enum marker
Variable = FunctionScopedVariable | BlockScopedVariable,
Value = Variable | Property | EnumMember | Function | Class | Enum | ValueModule | Method | GetAccessor | SetAccessor,
@ -807,7 +808,8 @@ module ts {
ClassExcludes = (Value | Type) & ~ValueModule,
InterfaceExcludes = Type & ~Interface,
EnumExcludes = (Value | Type) & ~(Enum | ValueModule),
ValueModuleExcludes = Value & ~(Function | Class | Enum | ValueModule),
ConstEnumExcludes = (Value | Type) & ~Enum, // const enums merge only with enums
ValueModuleExcludes = (Value | ConstEnum) & ~(Function | Class | Enum | ValueModule),
NamespaceModuleExcludes = 0,
MethodExcludes = Value & ~Method,
GetAccessorExcludes = Value & ~SetAccessor,
@ -1076,6 +1078,7 @@ module ts {
target?: ScriptTarget;
version?: boolean;
watch?: boolean;
preserveConstEnums?: boolean;
[option: string]: string | number | boolean;
}

View File

@ -178,7 +178,7 @@ module ts.BreakpointResolver {
case SyntaxKind.ModuleDeclaration:
// span on complete module if it is instantiated
if (!isInstantiated(node)) {
if (!isInstantiated(node, /*checkConstEnums*/ true)) {
return undefined;
}
@ -350,7 +350,7 @@ module ts.BreakpointResolver {
function spanInBlock(block: Block): TypeScript.TextSpan {
switch (block.parent.kind) {
case SyntaxKind.ModuleDeclaration:
if (!isInstantiated(block.parent)) {
if (!isInstantiated(block.parent, /*checkConstEnums*/ true)) {
return undefined;
}
@ -407,7 +407,7 @@ module ts.BreakpointResolver {
switch (node.parent.kind) {
case SyntaxKind.ModuleBlock:
// If this is not instantiated module block no bp span
if (!isInstantiated(node.parent.parent)) {
if (!isInstantiated(node.parent.parent, /*checkConstEnums*/ true)) {
return undefined;
}

View File

@ -4549,7 +4549,7 @@ module ts {
if ((<ModuleDeclaration>node).name.kind === SyntaxKind.StringLiteral) {
return SemanticMeaning.Namespace | SemanticMeaning.Value;
}
else if (isInstantiated(node)) {
else if (isInstantiated(node, /*checkConstEnums*/ true)) {
return SemanticMeaning.Namespace | SemanticMeaning.Value;
}
else {
@ -4826,7 +4826,7 @@ module ts {
*/
function hasValueSideModule(symbol: Symbol): boolean {
return forEach(symbol.declarations, declaration => {
return declaration.kind === SyntaxKind.ModuleDeclaration && isInstantiated(declaration);
return declaration.kind === SyntaxKind.ModuleDeclaration && isInstantiated(declaration, /*checkConstEnums*/ true);
});
}
}

View File

@ -0,0 +1,65 @@
tests/cases/compiler/constEnumErrors.ts(1,12): error TS2300: Duplicate identifier 'E'.
tests/cases/compiler/constEnumErrors.ts(5,8): error TS2300: Duplicate identifier 'E'.
tests/cases/compiler/constEnumErrors.ts(12,9): error TS4083: In 'const' enum declarations member initializer must be constant expression.
tests/cases/compiler/constEnumErrors.ts(14,9): error TS4083: In 'const' enum declarations member initializer must be constant expression.
tests/cases/compiler/constEnumErrors.ts(15,10): error TS4083: In 'const' enum declarations member initializer must be constant expression.
tests/cases/compiler/constEnumErrors.ts(22,13): error TS4085: Index expression arguments in 'const' enums must be of type 'string'.
tests/cases/compiler/constEnumErrors.ts(24,13): error TS4085: Index expression arguments in 'const' enums must be of type 'string'.
tests/cases/compiler/constEnumErrors.ts(26,9): error TS4084: 'const' enums can only be used in property access expressions.
tests/cases/compiler/constEnumErrors.ts(27,10): error TS4084: 'const' enums can only be used in property access expressions.
tests/cases/compiler/constEnumErrors.ts(32,5): error TS4084: 'const' enums can only be used in property access expressions.
==== tests/cases/compiler/constEnumErrors.ts (10 errors) ====
const enum E {
~
!!! error TS2300: Duplicate identifier 'E'.
A
}
module E {
~
!!! error TS2300: Duplicate identifier 'E'.
var x = 1;
}
const enum E1 {
// illegal case
// forward reference to the element of the same enum
X = Y,
~
!!! error TS4083: In 'const' enum declarations member initializer must be constant expression.
// forward reference to the element of the same enum
Y = E1.Z,
~~~~
!!! error TS4083: In 'const' enum declarations member initializer must be constant expression.
Y1 = E1["Z"]
~~~~~~~
!!! error TS4083: In 'const' enum declarations member initializer must be constant expression.
}
const enum E2 {
A
}
var y0 = E2[1]
~
!!! error TS4085: Index expression arguments in 'const' enums must be of type 'string'.
var name = "A";
var y1 = E2[name];
~~~~
!!! error TS4085: Index expression arguments in 'const' enums must be of type 'string'.
var x = E2;
~~
!!! error TS4084: 'const' enums can only be used in property access expressions.
var y = [E2];
~~
!!! error TS4084: 'const' enums can only be used in property access expressions.
function foo(t: any): void {
}
foo(E2);
~~
!!! error TS4084: 'const' enums can only be used in property access expressions.

View File

@ -0,0 +1,47 @@
//// [constEnumErrors.ts]
const enum E {
A
}
module E {
var x = 1;
}
const enum E1 {
// illegal case
// forward reference to the element of the same enum
X = Y,
// forward reference to the element of the same enum
Y = E1.Z,
Y1 = E1["Z"]
}
const enum E2 {
A
}
var y0 = E2[1]
var name = "A";
var y1 = E2[name];
var x = E2;
var y = [E2];
function foo(t: any): void {
}
foo(E2);
//// [constEnumErrors.js]
var E;
(function (E) {
var x = 1;
})(E || (E = {}));
var y0 = E2[1];
var name = "A";
var y1 = E2[name];
var x = E2;
var y = [E2];
function foo(t) {
}
foo(E2);

View File

@ -1,4 +1,4 @@
//// [constantsInEnumMembers.ts]
//// [constEnums.ts]
const enum Enum1 {
A0 = 100,
}
@ -8,14 +8,14 @@ const enum Enum1 {
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,
D = A | B,
E = A | 1,
F = 1 | A,
G = (1 & 1),
H = ~(A | B),
I = A >>> 1,
J = 1 & A,
K = ~(1 | 5),
L = ~D,
M = E << B,
N = E << 1,
@ -34,13 +34,6 @@ const enum Enum1 {
W2 = Enum1.A0,
W3 = Enum1["A0"],
W4 = Enum1["W"],
// illegal case
// forward reference to the element of the same enum
X = Y,
// forward reference to the element of the same enum
Y = Enum1.Z,
Y1 = Enum1["Z"],
Z = 100,
}
@ -49,7 +42,7 @@ module A {
export module C {
export const enum E {
V1 = 1,
V2 = A.B.C.E.V1 + 100
V2 = A.B.C.E.V1 | 100
}
}
}
@ -59,12 +52,21 @@ module A {
export module B {
export module C {
export const enum E {
V3 = A.B.C.E["V2"] + 200,
V3 = A.B.C.E["V2"] & 200,
}
}
}
}
import I = A.B.C.E;
function foo0(e: I): void {
if (e === I.V1) {
}
else if (e === I.V2) {
}
}
function foo(x: Enum1) {
switch (x) {
case Enum1.A:
@ -94,10 +96,6 @@ function foo(x: Enum1) {
case Enum1.W2:
case Enum1.W3:
case Enum1.W4:
case Enum1.X:
case Enum1.Y:
case Enum1.Y1:
case Enum1.Z:
break;
}
}
@ -110,25 +108,13 @@ function bar(e: A.B.C.E): number {
}
}
//// [constantsInEnumMembers.js]
var A;
(function (A) {
var B;
(function (B) {
var C;
(function (C) {
})(C = B.C || (B.C = {}));
})(B = A.B || (A.B = {}));
})(A || (A = {}));
var A;
(function (A) {
var B;
(function (B) {
var C;
(function (C) {
})(C = B.C || (B.C = {}));
})(B = A.B || (A.B = {}));
})(A || (A = {}));
//// [constEnums.js]
function foo0(e) {
if (e === 1 /* V1 */) {
}
else if (e === 101 /* V2 */) {
}
}
function foo(x) {
switch (x) {
case 0 /* A */:
@ -137,11 +123,11 @@ function foo(x) {
case 1 /* D */:
case 1 /* E */:
case 1 /* F */:
case 2 /* G */:
case -1 /* H */:
case -1 /* I */:
case 1 /* J */:
case 0 /* K */:
case 1 /* G */:
case -2 /* H */:
case 0 /* I */:
case 0 /* J */:
case -6 /* K */:
case -2 /* L */:
case 2 /* M */:
case 2 /* N */:
@ -158,10 +144,6 @@ function foo(x) {
case 100 /* W2 */:
case 100 /* W3 */:
case 11 /* W4 */:
case Enum1.X:
case Enum1.Y:
case Enum1.Y1:
case 100 /* Z */:
break;
}
}
@ -171,7 +153,7 @@ function bar(e) {
return 1;
case 101 /* V2 */:
return 1;
case 301 /* V3 */:
case 64 /* V3 */:
return 1;
}
}

View File

@ -0,0 +1,433 @@
=== tests/cases/compiler/constEnums.ts ===
const enum Enum1 {
>Enum1 : Enum1
A0 = 100,
>A0 : Enum1
}
const 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
>1 & 1 : number
H = ~(A | B),
>H : Enum1
>~(A | B) : number
>(A | B) : number
>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 | 5),
>K : Enum1
>~(1 | 5) : number
>(1 | 5) : number
>1 | 5 : 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
}
module A {
>A : typeof A
export module B {
>B : typeof B
export module C {
>C : typeof C
export const 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 const 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
}
}
}
}
import I = A.B.C.E;
>I : typeof I
>A : typeof A
>B : typeof A.B
>C : typeof A.B.C
>E : I
function foo0(e: I): void {
>foo0 : (e: I) => void
>e : I
>I : I
if (e === I.V1) {
>e === I.V1 : boolean
>e : I
>I.V1 : I
>I : typeof I
>V1 : I
}
else if (e === I.V2) {
>e === I.V2 : boolean
>e : I
>I.V2 : I
>I : typeof I
>V2 : I
}
}
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
break;
}
}
function bar(e: A.B.C.E): number {
>bar : (e: I) => number
>e : I
>A : unknown
>B : unknown
>C : unknown
>E : I
switch (e) {
>e : I
case A.B.C.E.V1: return 1;
>A.B.C.E.V1 : I
>A.B.C.E : typeof I
>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 I
>V1 : I
case A.B.C.E.V2: return 1;
>A.B.C.E.V2 : I
>A.B.C.E : typeof I
>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 I
>V2 : I
case A.B.C.E.V3: return 1;
>A.B.C.E.V3 : I
>A.B.C.E : typeof I
>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 I
>V3 : I
}
}

View File

@ -1,122 +0,0 @@
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

@ -0,0 +1,32 @@
const enum E {
A
}
module E {
var x = 1;
}
const enum E1 {
// illegal case
// forward reference to the element of the same enum
X = Y,
// forward reference to the element of the same enum
Y = E1.Z,
Y1 = E1["Z"]
}
const enum E2 {
A
}
var y0 = E2[1]
var name = "A";
var y1 = E2[name];
var x = E2;
var y = [E2];
function foo(t: any): void {
}
foo(E2);

View File

@ -7,14 +7,14 @@ const enum Enum1 {
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,
D = A | B,
E = A | 1,
F = 1 | A,
G = (1 & 1),
H = ~(A | B),
I = A >>> 1,
J = 1 & A,
K = ~(1 | 5),
L = ~D,
M = E << B,
N = E << 1,
@ -33,13 +33,6 @@ const enum Enum1 {
W2 = Enum1.A0,
W3 = Enum1["A0"],
W4 = Enum1["W"],
// illegal case
// forward reference to the element of the same enum
X = Y,
// forward reference to the element of the same enum
Y = Enum1.Z,
Y1 = Enum1["Z"],
Z = 100,
}
@ -48,7 +41,7 @@ module A {
export module C {
export const enum E {
V1 = 1,
V2 = A.B.C.E.V1 + 100
V2 = A.B.C.E.V1 | 100
}
}
}
@ -58,12 +51,21 @@ module A {
export module B {
export module C {
export const enum E {
V3 = A.B.C.E["V2"] + 200,
V3 = A.B.C.E["V2"] & 200,
}
}
}
}
import I = A.B.C.E;
function foo0(e: I): void {
if (e === I.V1) {
}
else if (e === I.V2) {
}
}
function foo(x: Enum1) {
switch (x) {
case Enum1.A:
@ -93,10 +95,6 @@ function foo(x: Enum1) {
case Enum1.W2:
case Enum1.W3:
case Enum1.W4:
case Enum1.X:
case Enum1.Y:
case Enum1.Y1:
case Enum1.Z:
break;
}
}