Skip to content

Commit 270d187

Browse files
committed
addressed CR feedback
1 parent 4aa4ea7 commit 270d187

12 files changed

+119
-75
lines changed

src/compiler/binder.ts

+11-9
Original file line numberDiff line numberDiff line change
@@ -5,25 +5,25 @@
55

66
module ts {
77

8-
export function isInstantiated(node: Node, checkConstEnums: boolean): boolean {
8+
export function isInstantiated(node: Node, treatConstEnumsAsValues: boolean): boolean {
99
// A module is uninstantiated if it contains only
1010
// 1. interface declarations
1111
if (node.kind === SyntaxKind.InterfaceDeclaration) {
1212
return false;
1313
}
1414
// 2. const enum declarations don't make module instantiated
15-
else if (checkConstEnums && node.kind === SyntaxKind.EnumDeclaration && isConstEnumDeclaration(<EnumDeclaration>node)) {
15+
else if (!treatConstEnumsAsValues && node.kind === SyntaxKind.EnumDeclaration && isConstEnumDeclaration(<EnumDeclaration>node)) {
1616
return false;
1717
}
1818
// 3. non - exported import declarations
1919
else if (node.kind === SyntaxKind.ImportDeclaration && !(node.flags & NodeFlags.Export)) {
2020
return false;
2121
}
2222
// 4. other uninstantiated module declarations.
23-
else if (node.kind === SyntaxKind.ModuleBlock && !forEachChild(node, n => isInstantiated(n, checkConstEnums))) {
23+
else if (node.kind === SyntaxKind.ModuleBlock && !forEachChild(node, n => isInstantiated(n, treatConstEnumsAsValues))) {
2424
return false;
2525
}
26-
else if (node.kind === SyntaxKind.ModuleDeclaration && !isInstantiated((<ModuleDeclaration>node).body, checkConstEnums)) {
26+
else if (node.kind === SyntaxKind.ModuleDeclaration && !isInstantiated((<ModuleDeclaration>node).body, treatConstEnumsAsValues)) {
2727
return false;
2828
}
2929
else {
@@ -252,7 +252,7 @@ module ts {
252252
if (node.name.kind === SyntaxKind.StringLiteral) {
253253
bindDeclaration(node, SymbolFlags.ValueModule, SymbolFlags.ValueModuleExcludes, /*isBlockScopeContainer*/ true);
254254
}
255-
else if (isInstantiated(node, /*checkConstEnums*/ false)) {
255+
else if (isInstantiated(node, /*treatConstEnumsAsValues*/ true)) {
256256
bindDeclaration(node, SymbolFlags.ValueModule, SymbolFlags.ValueModuleExcludes, /*isBlockScopeContainer*/ true);
257257
}
258258
else {
@@ -368,10 +368,12 @@ module ts {
368368
bindDeclaration(<Declaration>node, SymbolFlags.TypeAlias, SymbolFlags.TypeAliasExcludes, /*isBlockScopeContainer*/ false);
369369
break;
370370
case SyntaxKind.EnumDeclaration:
371-
var enumIsConst = isConstEnumDeclaration(<EnumDeclaration>node);
372-
var flags = enumIsConst ? SymbolFlags.Enum | SymbolFlags.ConstEnum : SymbolFlags.Enum;
373-
var excludes = enumIsConst ? SymbolFlags.ConstEnumExcludes : SymbolFlags.EnumExcludes;
374-
bindDeclaration(<Declaration>node, flags, excludes, /*isBlockScopeContainer*/ false);
371+
if (isConstEnumDeclaration(<EnumDeclaration>node)) {
372+
bindDeclaration(<Declaration>node, SymbolFlags.ConstEnum, SymbolFlags.ConstEnumExcludes, /*isBlockScopeContainer*/ false);
373+
}
374+
else {
375+
bindDeclaration(<Declaration>node, SymbolFlags.RegularEnum, SymbolFlags.RegularEnumExcludes, /*isBlockScopeContainer*/ false);
376+
}
375377
break;
376378
case SyntaxKind.ModuleDeclaration:
377379
bindModuleDeclaration(<ModuleDeclaration>node);

src/compiler/checker.ts

+12-21
Original file line numberDiff line numberDiff line change
@@ -186,7 +186,8 @@ module ts {
186186
if (flags & SymbolFlags.Function) result |= SymbolFlags.FunctionExcludes;
187187
if (flags & SymbolFlags.Class) result |= SymbolFlags.ClassExcludes;
188188
if (flags & SymbolFlags.Interface) result |= SymbolFlags.InterfaceExcludes;
189-
if (flags & SymbolFlags.Enum) result |= SymbolFlags.EnumExcludes;
189+
if (flags & SymbolFlags.RegularEnum) result |= SymbolFlags.RegularEnumExcludes;
190+
if (flags & SymbolFlags.ConstEnum) result |= SymbolFlags.ConstEnumExcludes;
190191
if (flags & SymbolFlags.ValueModule) result |= SymbolFlags.ValueModuleExcludes;
191192
if (flags & SymbolFlags.Method) result |= SymbolFlags.MethodExcludes;
192193
if (flags & SymbolFlags.GetAccessor) result |= SymbolFlags.GetAccessorExcludes;
@@ -5086,7 +5087,7 @@ module ts {
50865087

50875088
if (objectType === unknownType) return unknownType;
50885089

5089-
if (isConstEnumType(objectType) && node.index.kind !== SyntaxKind.StringLiteral) {
5090+
if (isConstEnumObjectType(objectType) && node.index.kind !== SyntaxKind.StringLiteral) {
50905091
error(node.index, Diagnostics.Index_expression_arguments_in_const_enums_must_be_of_type_string);
50915092
}
50925093

@@ -5966,7 +5967,7 @@ module ts {
59665967
return (type.flags & TypeFlags.Structured) !== 0;
59675968
}
59685969

5969-
function isConstEnumType(type: Type) : boolean {
5970+
function isConstEnumObjectType(type: Type) : boolean {
59705971
return type.flags & (TypeFlags.ObjectType | TypeFlags.Anonymous) && type.symbol && isConstEnumSymbol(type.symbol);
59715972
}
59725973

@@ -6199,31 +6200,21 @@ module ts {
61996200
}
62006201
}
62016202

6202-
if (isConstEnumType(type)) {
6203+
if (isConstEnumObjectType(type)) {
62036204
// enum object type for const enums are only permitted in:
62046205
// - 'left' in property access
62056206
// - 'object' in indexed access
62066207
// - target in rhs of import statement
62076208
var ok =
62086209
(node.parent.kind === SyntaxKind.PropertyAccess && (<PropertyAccess>node.parent).left === node) ||
62096210
(node.parent.kind === SyntaxKind.IndexedAccess && (<IndexedAccess>node.parent).object === node) ||
6210-
isRhsOfImportStatement(node);
6211+
((node.kind === SyntaxKind.Identifier || node.kind === SyntaxKind.QualifiedName) && isInRightSideOfImportOrExportAssignment(<EntityName>node));
62116212

62126213
if (!ok) {
6213-
error(node, Diagnostics.const_enums_can_only_be_used_in_property_access_expressions);
6214+
error(node, Diagnostics.const_enums_can_only_be_used_in_property_access_Slashindex_access_expressions_and_as_right_hand_side_in_import_declarations_Slashexport_assignments);
62146215
}
62156216
}
62166217
return type;
6217-
6218-
function isRhsOfImportStatement(n: Node): boolean {
6219-
while (n.parent) {
6220-
if (n.parent.kind === SyntaxKind.ImportDeclaration && (<ImportDeclaration>n.parent).entityName === n) {
6221-
return true;
6222-
}
6223-
n = n.parent;
6224-
}
6225-
return false;
6226-
}
62276218
}
62286219

62296220
function checkExpressionNode(node: Expression, contextualMapper: TypeMapper): Type {
@@ -6892,7 +6883,7 @@ module ts {
68926883
case SyntaxKind.InterfaceDeclaration:
68936884
return SymbolFlags.ExportType;
68946885
case SyntaxKind.ModuleDeclaration:
6895-
return (<ModuleDeclaration>d).name.kind === SyntaxKind.StringLiteral || isInstantiated(d, /*checkConstEnums*/ false)
6886+
return (<ModuleDeclaration>d).name.kind === SyntaxKind.StringLiteral || isInstantiated(d, /*treatConstEnumsAsValues*/ true)
68966887
? SymbolFlags.ExportNamespace | SymbolFlags.ExportValue
68976888
: SymbolFlags.ExportNamespace;
68986889
case SyntaxKind.ClassDeclaration:
@@ -7129,7 +7120,7 @@ module ts {
71297120
}
71307121

71317122
// Uninstantiated modules shouldnt do this check
7132-
if (node.kind === SyntaxKind.ModuleDeclaration && !isInstantiated(node, /*checkConstEnums*/ true)) {
7123+
if (node.kind === SyntaxKind.ModuleDeclaration && !isInstantiated(node, /*treatConstEnumsAsValues*/ false)) {
71337124
return;
71347125
}
71357126

@@ -8673,10 +8664,10 @@ module ts {
86738664

86748665
function getExportAssignmentName(node: SourceFile): string {
86758666
var symbol = getExportAssignmentSymbol(getSymbolOfNode(node));
8676-
return symbol && symbolIsValue(symbol) ? symbolToString(symbol): undefined;
8667+
return symbol && symbolIsValue(symbol) && !isConstEnumSymbol(symbol) ? symbolToString(symbol): undefined;
86778668
}
86788669

8679-
function isTopLevelValueImportedViaEntityName(node: ImportDeclaration): boolean {
8670+
function isTopLevelValueImportWithEntityName(node: ImportDeclaration): boolean {
86808671
if (node.parent.kind !== SyntaxKind.SourceFile || !node.entityName) {
86818672
// parent is not source file or it is not reference to internal module
86828673
return false;
@@ -8777,7 +8768,7 @@ module ts {
87778768
isReferencedImportDeclaration: isReferencedImportDeclaration,
87788769
getNodeCheckFlags: getNodeCheckFlags,
87798770
getEnumMemberValue: getEnumMemberValue,
8780-
isTopLevelValueImportedViaEntityName: isTopLevelValueImportedViaEntityName,
8771+
isTopLevelValueImportWithEntityName: isTopLevelValueImportWithEntityName,
87818772
hasSemanticErrors: hasSemanticErrors,
87828773
hasEarlyErrors: hasEarlyErrors,
87838774
isDeclarationVisible: isDeclarationVisible,

src/compiler/diagnosticInformationMap.generated.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -352,7 +352,7 @@ module ts {
352352
Exported_type_alias_0_has_or_is_using_private_name_1: { code: 4081, category: DiagnosticCategory.Error, key: "Exported type alias '{0}' has or is using private name '{1}'." },
353353
Enum_declarations_must_all_be_const_or_non_const: { code: 4082, category: DiagnosticCategory.Error, key: "Enum declarations must all be const or non-const." },
354354
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." },
355-
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." },
355+
const_enums_can_only_be_used_in_property_access_Slashindex_access_expressions_and_as_right_hand_side_in_import_declarations_Slashexport_assignments: { code: 4084, category: DiagnosticCategory.Error, key: "'const' enums can only be used in property access/index access expressions and as right hand side in import declarations/export assignments." },
356356
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'." },
357357
const_enum_member_initializer_was_evaluated_to_a_non_finite_number: { code: 4086, category: DiagnosticCategory.Error, key: "'const' enum member initializer was evaluated to a non-finite number." },
358358
const_enum_member_initializer_was_evaluated_to_NaN: { code: 4087, category: DiagnosticCategory.Error, key: "'const' enum member initializer was evaluated to NaN." },

src/compiler/diagnosticMessages.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -1409,7 +1409,7 @@
14091409
"category": "Error",
14101410
"code": 4083
14111411
},
1412-
"'const' enums can only be used in property access expressions.": {
1412+
"'const' enums can only be used in property access/index access expressions and as right hand side in import declarations/export assignments.": {
14131413
"category": "Error",
14141414
"code": 4084
14151415
},

src/compiler/emitter.ts

+2-2
Original file line numberDiff line numberDiff line change
@@ -1838,7 +1838,7 @@ module ts {
18381838
}
18391839

18401840
function emitModuleDeclaration(node: ModuleDeclaration) {
1841-
if (!isInstantiated(node, /*checkConstEnums*/ true)) {
1841+
if (!isInstantiated(node, /*treatConstEnumsAsValues*/ false)) {
18421842
return emitPinnedOrTripleSlashComments(node);
18431843
}
18441844
emitLeadingComments(node);
@@ -1890,7 +1890,7 @@ module ts {
18901890
// preserve old compiler's behavior: emit 'var' for import declaration (even if we do not consider them referenced) when
18911891
// - current file is not external module
18921892
// - import declaration is top level and target is value imported by entity name
1893-
emitImportDeclaration = !isExternalModule(currentSourceFile) && resolver.isTopLevelValueImportedViaEntityName(node);
1893+
emitImportDeclaration = !isExternalModule(currentSourceFile) && resolver.isTopLevelValueImportWithEntityName(node);
18941894
}
18951895

18961896
if (emitImportDeclaration) {

src/compiler/types.ts

+31-30
Original file line numberDiff line numberDiff line change
@@ -734,7 +734,7 @@ module ts {
734734
getExpressionNamePrefix(node: Identifier): string;
735735
getExportAssignmentName(node: SourceFile): string;
736736
isReferencedImportDeclaration(node: ImportDeclaration): boolean;
737-
isTopLevelValueImportedViaEntityName(node: ImportDeclaration): boolean;
737+
isTopLevelValueImportWithEntityName(node: ImportDeclaration): boolean;
738738
getNodeCheckFlags(node: Node): NodeCheckFlags;
739739
getEnumMemberValue(node: EnumMember): number;
740740
hasSemanticErrors(): boolean;
@@ -757,34 +757,35 @@ module ts {
757757
Function = 0x00000010, // Function
758758
Class = 0x00000020, // Class
759759
Interface = 0x00000040, // Interface
760-
Enum = 0x00000080, // Enum
761-
ValueModule = 0x00000100, // Instantiated module
762-
NamespaceModule = 0x00000200, // Uninstantiated module
763-
TypeLiteral = 0x00000400, // Type Literal
764-
ObjectLiteral = 0x00000800, // Object Literal
765-
Method = 0x00001000, // Method
766-
Constructor = 0x00002000, // Constructor
767-
GetAccessor = 0x00004000, // Get accessor
768-
SetAccessor = 0x00008000, // Set accessor
769-
CallSignature = 0x00010000, // Call signature
770-
ConstructSignature = 0x00020000, // Construct signature
771-
IndexSignature = 0x00040000, // Index signature
772-
TypeParameter = 0x00080000, // Type parameter
773-
TypeAlias = 0x00100000, // Type alias
760+
ConstEnum = 0x00000080, // Const enum
761+
RegularEnum = 0x00000100, // Enum
762+
ValueModule = 0x00000200, // Instantiated module
763+
NamespaceModule = 0x00000400, // Uninstantiated module
764+
TypeLiteral = 0x00000800, // Type Literal
765+
ObjectLiteral = 0x00001000, // Object Literal
766+
Method = 0x00002000, // Method
767+
Constructor = 0x00004000, // Constructor
768+
GetAccessor = 0x00008000, // Get accessor
769+
SetAccessor = 0x00010000, // Set accessor
770+
CallSignature = 0x00020000, // Call signature
771+
ConstructSignature = 0x00040000, // Construct signature
772+
IndexSignature = 0x00080000, // Index signature
773+
TypeParameter = 0x00100000, // Type parameter
774+
TypeAlias = 0x00200000, // Type alias
774775

775776
// Export markers (see comment in declareModuleMember in binder)
776-
ExportValue = 0x00200000, // Exported value marker
777-
ExportType = 0x00400000, // Exported type marker
778-
ExportNamespace = 0x00800000, // Exported namespace marker
779-
780-
Import = 0x01000000, // Import
781-
Instantiated = 0x02000000, // Instantiated symbol
782-
Merged = 0x04000000, // Merged symbol (created during program binding)
783-
Transient = 0x08000000, // Transient symbol (created during type check)
784-
Prototype = 0x10000000, // Prototype property (no source representation)
785-
UnionProperty = 0x20000000, // Property in union type
786-
ConstEnum = 0x40000000, // Const enum marker
787-
777+
ExportValue = 0x00400000, // Exported value marker
778+
ExportType = 0x00800000, // Exported type marker
779+
ExportNamespace = 0x01000000, // Exported namespace marker
780+
781+
Import = 0x02000000, // Import
782+
Instantiated = 0x04000000, // Instantiated symbol
783+
Merged = 0x08000000, // Merged symbol (created during program binding)
784+
Transient = 0x10000000, // Transient symbol (created during type check)
785+
Prototype = 0x20000000, // Prototype property (no source representation)
786+
UnionProperty = 0x40000000, // Property in union type
787+
788+
Enum = RegularEnum | ConstEnum,
788789
Variable = FunctionScopedVariable | BlockScopedVariable,
789790
Value = Variable | Property | EnumMember | Function | Class | Enum | ValueModule | Method | GetAccessor | SetAccessor,
790791
Type = Class | Interface | Enum | TypeLiteral | ObjectLiteral | TypeParameter | TypeAlias,
@@ -807,9 +808,9 @@ module ts {
807808
FunctionExcludes = Value & ~(Function | ValueModule),
808809
ClassExcludes = (Value | Type) & ~ValueModule,
809810
InterfaceExcludes = Type & ~Interface,
810-
EnumExcludes = (Value | Type) & ~(Enum | ValueModule),
811-
ConstEnumExcludes = (Value | Type) & ~Enum, // const enums merge only with enums
812-
ValueModuleExcludes = (Value | ConstEnum) & ~(Function | Class | Enum | ValueModule),
811+
RegularEnumExcludes = (Value | Type) & ~(RegularEnum | ValueModule), // regular enums merge only with regular enums and modules
812+
ConstEnumExcludes = (Value | Type) & ~ConstEnum, // const enums merge only with const enums
813+
ValueModuleExcludes = Value & ~(Function | Class | RegularEnum | ValueModule),
813814
NamespaceModuleExcludes = 0,
814815
MethodExcludes = Value & ~Method,
815816
GetAccessorExcludes = Value & ~SetAccessor,

src/services/breakpoints.ts

+3-3
Original file line numberDiff line numberDiff line change
@@ -178,7 +178,7 @@ module ts.BreakpointResolver {
178178

179179
case SyntaxKind.ModuleDeclaration:
180180
// span on complete module if it is instantiated
181-
if (!isInstantiated(node, /*checkConstEnums*/ true)) {
181+
if (!isInstantiated(node, /*treatConstEnumsAsValues*/ false)) {
182182
return undefined;
183183
}
184184

@@ -350,7 +350,7 @@ module ts.BreakpointResolver {
350350
function spanInBlock(block: Block): TypeScript.TextSpan {
351351
switch (block.parent.kind) {
352352
case SyntaxKind.ModuleDeclaration:
353-
if (!isInstantiated(block.parent, /*checkConstEnums*/ true)) {
353+
if (!isInstantiated(block.parent, /*treatConstEnumsAsValues*/ false)) {
354354
return undefined;
355355
}
356356

@@ -407,7 +407,7 @@ module ts.BreakpointResolver {
407407
switch (node.parent.kind) {
408408
case SyntaxKind.ModuleBlock:
409409
// If this is not instantiated module block no bp span
410-
if (!isInstantiated(node.parent.parent, /*checkConstEnums*/ true)) {
410+
if (!isInstantiated(node.parent.parent, /*treatConstEnumsAsValues*/ false)) {
411411
return undefined;
412412
}
413413

0 commit comments

Comments
 (0)