Skip to content

Commit

Permalink
Merge pull request #28465 from alangpierce/enforce-const-enum-access-…
Browse files Browse the repository at this point in the history
…for-isolatedmodules

Change isolatedModules to allow const enum declaration and disallow access
  • Loading branch information
RyanCavanaugh authored Feb 6, 2019
2 parents 12edac0 + 942b020 commit eed9db5
Show file tree
Hide file tree
Showing 7 changed files with 47 additions and 31 deletions.
42 changes: 25 additions & 17 deletions src/compiler/checker.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23289,22 +23289,34 @@ namespace ts {
const uninstantiatedType = checkExpressionWorker(node, checkMode, forceTuple);
const type = instantiateTypeWithSingleGenericCallSignature(node, uninstantiatedType, checkMode);
if (isConstEnumObjectType(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
const ok =
(node.parent.kind === SyntaxKind.PropertyAccessExpression && (<PropertyAccessExpression>node.parent).expression === node) ||
(node.parent.kind === SyntaxKind.ElementAccessExpression && (<ElementAccessExpression>node.parent).expression === node) ||
((node.kind === SyntaxKind.Identifier || node.kind === SyntaxKind.QualifiedName) && isInRightSideOfImportOrExportAssignment(<Identifier>node) ||
checkConstEnumAccess(node, type);
}
currentNode = saveCurrentNode;
return type;
}

function checkConstEnumAccess(node: Expression | QualifiedName, type: 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
const ok =
(node.parent.kind === SyntaxKind.PropertyAccessExpression && (<PropertyAccessExpression>node.parent).expression === node) ||
(node.parent.kind === SyntaxKind.ElementAccessExpression && (<ElementAccessExpression>node.parent).expression === node) ||
((node.kind === SyntaxKind.Identifier || node.kind === SyntaxKind.QualifiedName) && isInRightSideOfImportOrExportAssignment(<Identifier>node) ||
(node.parent.kind === SyntaxKind.TypeQuery && (<TypeQueryNode>node.parent).exprName === node));

if (!ok) {
error(node, Diagnostics.const_enums_can_only_be_used_in_property_or_index_access_expressions_or_the_right_hand_side_of_an_import_declaration_or_export_assignment_or_type_query);
if (!ok) {
error(node, Diagnostics.const_enums_can_only_be_used_in_property_or_index_access_expressions_or_the_right_hand_side_of_an_import_declaration_or_export_assignment_or_type_query);
}

if (compilerOptions.isolatedModules) {
Debug.assert(!!(type.symbol.flags & SymbolFlags.ConstEnum));
const constEnumDeclaration = type.symbol.valueDeclaration as EnumDeclaration;
if (constEnumDeclaration.flags & NodeFlags.Ambient) {
error(node, Diagnostics.Cannot_access_ambient_const_enums_when_the_isolatedModules_flag_is_provided);
}
}
currentNode = saveCurrentNode;
return type;
}

function checkParenthesizedExpression(node: ParenthesizedExpression, checkMode?: CheckMode): Type {
Expand Down Expand Up @@ -27484,11 +27496,6 @@ namespace ts {

computeEnumMemberValues(node);

const enumIsConst = isEnumConst(node);
if (compilerOptions.isolatedModules && enumIsConst && node.flags & NodeFlags.Ambient) {
error(node.name, Diagnostics.Ambient_const_enums_are_not_allowed_when_the_isolatedModules_flag_is_provided);
}

// Spec 2014 - Section 9.3:
// It isn't possible for one enum declaration to continue the automatic numbering sequence of another,
// and when an enum type has multiple declarations, only one declaration is permitted to omit a value
Expand All @@ -27499,6 +27506,7 @@ namespace ts {
const firstDeclaration = getDeclarationOfKind(enumSymbol, node.kind);
if (node === firstDeclaration) {
if (enumSymbol.declarations.length > 1) {
const enumIsConst = isEnumConst(node);
// check that const is placed\omitted on all enum declarations
forEach(enumSymbol.declarations, decl => {
if (isEnumDeclaration(decl) && isEnumConst(decl) !== enumIsConst) {
Expand Down
8 changes: 4 additions & 4 deletions src/compiler/diagnosticMessages.json
Original file line number Diff line number Diff line change
Expand Up @@ -659,10 +659,6 @@
"category": "Error",
"code": 1208
},
"Ambient const enums are not allowed when the '--isolatedModules' flag is provided.": {
"category": "Error",
"code": 1209
},
"Invalid use of '{0}'. Class definitions are automatically in strict mode.": {
"category": "Error",
"code": 1210
Expand Down Expand Up @@ -2581,6 +2577,10 @@
"category": "Error",
"code": 2747
},
"Cannot access ambient const enums when the '--isolatedModules' flag is provided.": {
"category": "Error",
"code": 2748
},

"Import declaration '{0}' is using private name '{1}'.": {
"category": "Error",
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
tests/cases/compiler/file1.ts(1,20): error TS1209: Ambient const enums are not allowed when the '--isolatedModules' flag is provided.
tests/cases/compiler/file1.ts(2,16): error TS2748: Cannot access ambient const enums when the '--isolatedModules' flag is provided.


==== tests/cases/compiler/file1.ts (1 errors) ====
declare const enum E { X = 1}
~
!!! error TS1209: Ambient const enums are not allowed when the '--isolatedModules' flag is provided.
export var y;
export var y = E.X;
~
!!! error TS2748: Cannot access ambient const enums when the '--isolatedModules' flag is provided.

5 changes: 3 additions & 2 deletions tests/baselines/reference/isolatedModulesAmbientConstEnum.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
//// [file1.ts]
declare const enum E { X = 1}
export var y;
export var y = E.X;


//// [file1.js]
export var y;
export var y = E.X;
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,9 @@ declare const enum E { X = 1}
>E : Symbol(E, Decl(file1.ts, 0, 0))
>X : Symbol(E.X, Decl(file1.ts, 0, 22))

export var y;
export var y = E.X;
>y : Symbol(y, Decl(file1.ts, 1, 10))
>E.X : Symbol(E.X, Decl(file1.ts, 0, 22))
>E : Symbol(E, Decl(file1.ts, 0, 0))
>X : Symbol(E.X, Decl(file1.ts, 0, 22))

Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,9 @@ declare const enum E { X = 1}
>X : E.X
>1 : 1

export var y;
>y : any
export var y = E.X;
>y : E
>E.X : E
>E : typeof E
>X : E

2 changes: 1 addition & 1 deletion tests/cases/compiler/isolatedModulesAmbientConstEnum.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,4 +4,4 @@
// @filename: file1.ts

declare const enum E { X = 1}
export var y;
export var y = E.X;

0 comments on commit eed9db5

Please sign in to comment.