diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 4491804c56d68..0b42dd1b3cf7b 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -2897,9 +2897,6 @@ namespace ts { } function getNameOfSymbol(symbol: Symbol): string { - if (symbol.flags & SymbolFlags.Dynamic) { - return `"${escapeString(unescapeIdentifier(symbol.name))}"`; - } if (symbol.declarations && symbol.declarations.length) { const declaration = symbol.declarations[0]; if (declaration.name) { @@ -3258,6 +3255,9 @@ namespace ts { writeKeyword(writer, SyntaxKind.ReadonlyKeyword); writeSpace(writer); } + if (prop.flags & SymbolFlags.Dynamic && (prop).dynamicSource) { + writer.trackSymbol((prop).dynamicSource, enclosingDeclaration, SymbolFlags.Value); + } buildSymbolDisplay(prop, writer); if (prop.flags & SymbolFlags.Optional) { writePunctuation(writer, SyntaxKind.QuestionToken); @@ -5193,7 +5193,7 @@ namespace ts { resolveDynamicMembersOfNode(node, (node).members, symbolTable); break; case SyntaxKind.ObjectLiteralExpression: - resolveDynamicMembersOfNode(node, (node).properties, symbolTable); + resolveDynamicMembersOfNode(node, (node).properties, symbolTable); break; } } @@ -13191,7 +13191,20 @@ namespace ts { } typeFlags |= type.flags; - const prop = createSymbol(SymbolFlags.Property | member.flags, member.name); + + let prop: TransientSymbol; + if (hasDynamicName(memberDecl) && isEntityNameExpression((memberDecl.name).expression)) { + const nameType = checkComputedPropertyName(memberDecl.name); + if (nameType && nameType.flags & TypeFlags.StringOrNumberLiteral) { + prop = createSymbol(SymbolFlags.Property | SymbolFlags.Dynamic | member.flags, (nameType).text); + prop.dynamicSource = resolveEntityName((memberDecl.name).expression, SymbolFlags.Value); + } + } + + if (!prop) { + prop = createSymbol(SymbolFlags.Property | member.flags, member.name); + } + if (inDestructuringPattern) { // If object literal is an assignment pattern and if the assignment pattern specifies a default value // for the property, make the property optional. @@ -13259,7 +13272,7 @@ namespace ts { checkNodeDeferred(memberDecl); } - if (hasDynamicName(memberDecl)) { + if (hasDynamicName(memberDecl) && !(member && member.flags & SymbolFlags.Dynamic)) { if (isNumericName(memberDecl.name)) { hasComputedNumberProperty = true; } diff --git a/src/compiler/declarationEmitter.ts b/src/compiler/declarationEmitter.ts index ec123a7488d97..e4fb1cf976065 100644 --- a/src/compiler/declarationEmitter.ts +++ b/src/compiler/declarationEmitter.ts @@ -1297,14 +1297,9 @@ namespace ts { function emitDynamicName(entityName: EntityNameExpression) { writer.getSymbolAccessibilityDiagnostic = getVariableDeclarationTypeVisibilityError; const visibilityResult = resolver.isEntityNameVisible(entityName, enclosingDeclaration); - if (visibilityResult.accessibility !== SymbolAccessibility.Accessible) { - resolver.writeTypeOfExpression(entityName, enclosingDeclaration, TypeFormatFlags.None, writer); - } - else { - handleSymbolAccessibilityError(visibilityResult); - recordTypeReferenceDirectivesIfNecessary(resolver.getTypeReferenceDirectivesForEntityName(entityName)); - writeTextOfNode(currentText, node.name); - } + handleSymbolAccessibilityError(visibilityResult); + recordTypeReferenceDirectivesIfNecessary(resolver.getTypeReferenceDirectivesForEntityName(entityName)); + writeTextOfNode(currentText, node.name); } function emitBindingPattern(bindingPattern: BindingPattern) { diff --git a/src/compiler/types.ts b/src/compiler/types.ts index f9fe5a849ce36..d8a4cdc651bb5 100644 --- a/src/compiler/types.ts +++ b/src/compiler/types.ts @@ -2610,6 +2610,7 @@ namespace ts { trackSymbol(symbol: Symbol, enclosingDeclaration?: Node, meaning?: SymbolFlags): void; reportInaccessibleThisError(): void; reportIllegalExtends(): void; + } export const enum TypeFormatFlags { @@ -2880,6 +2881,7 @@ namespace ts { exportsSomeValue?: boolean; // True if module exports some value (not just types) dynamicMembers?: SymbolTable; // Dynamic members with literal names resolved during check resolvedMembers?: SymbolTable; + dynamicSource?: Symbol; } /* @internal */ diff --git a/src/compiler/utilities.ts b/src/compiler/utilities.ts index 5314bdacb436e..f1ee91acd82c8 100644 --- a/src/compiler/utilities.ts +++ b/src/compiler/utilities.ts @@ -68,7 +68,7 @@ namespace ts { clear: () => str = "", trackSymbol: noop, reportInaccessibleThisError: noop, - reportIllegalExtends: noop + reportIllegalExtends: noop, }; } diff --git a/src/services/utilities.ts b/src/services/utilities.ts index e884b342feff1..43b67b0dd5fe8 100644 --- a/src/services/utilities.ts +++ b/src/services/utilities.ts @@ -1174,7 +1174,7 @@ namespace ts { clear: resetWriter, trackSymbol: noop, reportInaccessibleThisError: noop, - reportIllegalExtends: noop + reportIllegalExtends: noop, }; function writeIndent() { diff --git a/tests/baselines/reference/dynamicNames.js b/tests/baselines/reference/dynamicNames.js index 173c02b444821..e4a661d6d3f02 100644 --- a/tests/baselines/reference/dynamicNames.js +++ b/tests/baselines/reference/dynamicNames.js @@ -3,7 +3,6 @@ //// [module.ts] export const c0 = "a"; export const c1 = 1; -const c2 = "a"; export interface T0 { [c0]: number; [c1]: string; @@ -15,7 +14,7 @@ export declare class T1 implements T2 { export declare class T2 extends T1 { } export declare type T3 = { - [c2]: number; + [c0]: number; [c1]: string; }; @@ -107,7 +106,6 @@ t0 = t12, t0 = t13, t0 = t14, t0 = t15, t12 = t0, t13 = t0, t14 = t0, t15 = t0; Object.defineProperty(exports, "__esModule", { value: true }); exports.c0 = "a"; exports.c1 = 1; -const c2 = "a"; //// [main.js] "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); @@ -158,7 +156,7 @@ export declare class T1 implements T2 { export declare class T2 extends T1 { } export declare type T3 = { - "a": number; + [c0]: number; [c1]: string; }; //// [main.d.ts] diff --git a/tests/baselines/reference/dynamicNames.symbols b/tests/baselines/reference/dynamicNames.symbols index 12dd6576b740c..1663172d125bd 100644 --- a/tests/baselines/reference/dynamicNames.symbols +++ b/tests/baselines/reference/dynamicNames.symbols @@ -5,11 +5,8 @@ export const c0 = "a"; export const c1 = 1; >c1 : Symbol(c1, Decl(module.ts, 1, 12)) -const c2 = "a"; ->c2 : Symbol(c2, Decl(module.ts, 2, 5)) - export interface T0 { ->T0 : Symbol(T0, Decl(module.ts, 2, 15)) +>T0 : Symbol(T0, Decl(module.ts, 1, 20)) [c0]: number; >c0 : Symbol(c0, Decl(module.ts, 0, 12)) @@ -18,8 +15,8 @@ export interface T0 { >c1 : Symbol(c1, Decl(module.ts, 1, 12)) } export declare class T1 implements T2 { ->T1 : Symbol(T1, Decl(module.ts, 6, 1)) ->T2 : Symbol(T2, Decl(module.ts, 10, 1)) +>T1 : Symbol(T1, Decl(module.ts, 5, 1)) +>T2 : Symbol(T2, Decl(module.ts, 9, 1)) [c0]: number; >c0 : Symbol(c0, Decl(module.ts, 0, 12)) @@ -28,14 +25,14 @@ export declare class T1 implements T2 { >c1 : Symbol(c1, Decl(module.ts, 1, 12)) } export declare class T2 extends T1 { ->T2 : Symbol(T2, Decl(module.ts, 10, 1)) ->T1 : Symbol(T1, Decl(module.ts, 6, 1)) +>T2 : Symbol(T2, Decl(module.ts, 9, 1)) +>T1 : Symbol(T1, Decl(module.ts, 5, 1)) } export declare type T3 = { ->T3 : Symbol(T3, Decl(module.ts, 12, 1)) +>T3 : Symbol(T3, Decl(module.ts, 11, 1)) - [c2]: number; ->c2 : Symbol(c2, Decl(module.ts, 2, 5)) + [c0]: number; +>c0 : Symbol(c0, Decl(module.ts, 0, 12)) [c1]: string; >c1 : Symbol(c1, Decl(module.ts, 1, 12)) @@ -199,22 +196,22 @@ let t3: T3; let t0_1: M.T0; >t0_1 : Symbol(t0_1, Decl(main.ts, 60, 3)) >M : Symbol(M, Decl(main.ts, 1, 6)) ->T0 : Symbol(T0, Decl(module.ts, 2, 15)) +>T0 : Symbol(T0, Decl(module.ts, 1, 20)) let t1_1: M.T1; >t1_1 : Symbol(t1_1, Decl(main.ts, 61, 3)) >M : Symbol(M, Decl(main.ts, 1, 6)) ->T1 : Symbol(T1, Decl(module.ts, 6, 1)) +>T1 : Symbol(T1, Decl(module.ts, 5, 1)) let t2_1: M.T2; >t2_1 : Symbol(t2_1, Decl(main.ts, 62, 3)) >M : Symbol(M, Decl(main.ts, 1, 6)) ->T2 : Symbol(T2, Decl(module.ts, 10, 1)) +>T2 : Symbol(T2, Decl(module.ts, 9, 1)) let t3_1: M.T3; >t3_1 : Symbol(t3_1, Decl(main.ts, 63, 3)) >M : Symbol(M, Decl(main.ts, 1, 6)) ->T3 : Symbol(T3, Decl(module.ts, 12, 1)) +>T3 : Symbol(T3, Decl(module.ts, 11, 1)) let t4: N.T4; >t4 : Symbol(t4, Decl(main.ts, 64, 3)) diff --git a/tests/baselines/reference/dynamicNames.types b/tests/baselines/reference/dynamicNames.types index f9391d417c441..6a6ce65416ff4 100644 --- a/tests/baselines/reference/dynamicNames.types +++ b/tests/baselines/reference/dynamicNames.types @@ -7,10 +7,6 @@ export const c1 = 1; >c1 : 1 >1 : 1 -const c2 = "a"; ->c2 : "a" ->"a" : "a" - export interface T0 { >T0 : T0 @@ -37,8 +33,8 @@ export declare class T2 extends T1 { export declare type T3 = { >T3 : T3 - [c2]: number; ->c2 : "a" + [c0]: number; +>c0 : "a" [c1]: string; >c1 : 1 @@ -100,7 +96,7 @@ namespace N { >T5 : T5 } export declare type T7 = { ->T7 : { "a": number; "1": string; } +>T7 : { [N.c2]: number; [N.c3]: string; } [N.c2]: number; >N.c2 : "a" @@ -147,7 +143,7 @@ declare class T10 extends T9 { >T9 : T9 } declare type T11 = { ->T11 : { "a": number; "1": string; } +>T11 : { [c4]: number; [c5]: string; } [c4]: number; >c4 : "a" @@ -239,9 +235,9 @@ let t6: N.T6; >T6 : N.T6 let t7: N.T7; ->t7 : { "a": number; "1": string; } +>t7 : { [N.c2]: number; [N.c3]: string; } >N : any ->T7 : { "a": number; "1": string; } +>T7 : { [N.c2]: number; [N.c3]: string; } let t8: T8; >t8 : T8 @@ -256,8 +252,8 @@ let t10: T10; >T10 : T10 let t11: T11; ->t11 : { "a": number; "1": string; } ->T11 : { "a": number; "1": string; } +>t11 : { [c4]: number; [c5]: string; } +>T11 : { [c4]: number; [c5]: string; } let t12: T12; >t12 : T12 @@ -329,13 +325,13 @@ t4 = t5, t4 = t6, t4 = t7, t5 = t4, t5 = t6, t5 = t7, t6 = t4, t6 = t5, t6 = t7, >t4 = t5, t4 = t6, t4 = t7, t5 = t4, t5 = t6, t5 = t7, t6 = t4, t6 = t5, t6 = t7, t7 = t4, t7 = t5, t7 = t6 : N.T6 >t4 = t5, t4 = t6, t4 = t7, t5 = t4, t5 = t6, t5 = t7, t6 = t4, t6 = t5, t6 = t7, t7 = t4, t7 = t5 : N.T5 >t4 = t5, t4 = t6, t4 = t7, t5 = t4, t5 = t6, t5 = t7, t6 = t4, t6 = t5, t6 = t7, t7 = t4 : N.T4 ->t4 = t5, t4 = t6, t4 = t7, t5 = t4, t5 = t6, t5 = t7, t6 = t4, t6 = t5, t6 = t7 : { "a": number; "1": string; } +>t4 = t5, t4 = t6, t4 = t7, t5 = t4, t5 = t6, t5 = t7, t6 = t4, t6 = t5, t6 = t7 : { [N.c2]: number; [N.c3]: string; } >t4 = t5, t4 = t6, t4 = t7, t5 = t4, t5 = t6, t5 = t7, t6 = t4, t6 = t5 : N.T5 >t4 = t5, t4 = t6, t4 = t7, t5 = t4, t5 = t6, t5 = t7, t6 = t4 : N.T4 ->t4 = t5, t4 = t6, t4 = t7, t5 = t4, t5 = t6, t5 = t7 : { "a": number; "1": string; } +>t4 = t5, t4 = t6, t4 = t7, t5 = t4, t5 = t6, t5 = t7 : { [N.c2]: number; [N.c3]: string; } >t4 = t5, t4 = t6, t4 = t7, t5 = t4, t5 = t6 : N.T6 >t4 = t5, t4 = t6, t4 = t7, t5 = t4 : N.T4 ->t4 = t5, t4 = t6, t4 = t7 : { "a": number; "1": string; } +>t4 = t5, t4 = t6, t4 = t7 : { [N.c2]: number; [N.c3]: string; } >t4 = t5, t4 = t6 : N.T6 >t4 = t5 : N.T5 >t4 : N.T4 @@ -343,35 +339,35 @@ t4 = t5, t4 = t6, t4 = t7, t5 = t4, t5 = t6, t5 = t7, t6 = t4, t6 = t5, t6 = t7, >t4 = t6 : N.T6 >t4 : N.T4 >t6 : N.T6 ->t4 = t7 : { "a": number; "1": string; } +>t4 = t7 : { [N.c2]: number; [N.c3]: string; } >t4 : N.T4 ->t7 : { "a": number; "1": string; } +>t7 : { [N.c2]: number; [N.c3]: string; } >t5 = t4 : N.T4 >t5 : N.T5 >t4 : N.T4 >t5 = t6 : N.T6 >t5 : N.T5 >t6 : N.T6 ->t5 = t7 : { "a": number; "1": string; } +>t5 = t7 : { [N.c2]: number; [N.c3]: string; } >t5 : N.T5 ->t7 : { "a": number; "1": string; } +>t7 : { [N.c2]: number; [N.c3]: string; } >t6 = t4 : N.T4 >t6 : N.T6 >t4 : N.T4 >t6 = t5 : N.T5 >t6 : N.T6 >t5 : N.T5 ->t6 = t7 : { "a": number; "1": string; } +>t6 = t7 : { [N.c2]: number; [N.c3]: string; } >t6 : N.T6 ->t7 : { "a": number; "1": string; } +>t7 : { [N.c2]: number; [N.c3]: string; } >t7 = t4 : N.T4 ->t7 : { "a": number; "1": string; } +>t7 : { [N.c2]: number; [N.c3]: string; } >t4 : N.T4 >t7 = t5 : N.T5 ->t7 : { "a": number; "1": string; } +>t7 : { [N.c2]: number; [N.c3]: string; } >t5 : N.T5 >t7 = t6 : N.T6 ->t7 : { "a": number; "1": string; } +>t7 : { [N.c2]: number; [N.c3]: string; } >t6 : N.T6 t0 = t12, t0 = t13, t0 = t14, t0 = t15, t12 = t0, t13 = t0, t14 = t0, t15 = t0; diff --git a/tests/baselines/reference/dynamicNamesErrors.errors.txt b/tests/baselines/reference/dynamicNamesErrors.errors.txt index 90e33b02736eb..124f9746757db 100644 --- a/tests/baselines/reference/dynamicNamesErrors.errors.txt +++ b/tests/baselines/reference/dynamicNamesErrors.errors.txt @@ -1,15 +1,16 @@ tests/cases/compiler/dynamicNamesErrors.ts(5,5): error TS2300: Duplicate identifier '1'. tests/cases/compiler/dynamicNamesErrors.ts(6,5): error TS2300: Duplicate identifier '1'. tests/cases/compiler/dynamicNamesErrors.ts(19,5): error TS2711: Subsequent property declarations must have the same type. Property '[c1]' must be of type 'number', but here has type 'string'. -tests/cases/compiler/dynamicNamesErrors.ts(25,1): error TS2322: Type 'T2' is not assignable to type 'T1'. - Types of property '"1"' are incompatible. +tests/cases/compiler/dynamicNamesErrors.ts(24,1): error TS2322: Type 'T2' is not assignable to type 'T1'. + Types of property '[c0]' are incompatible. Type 'string' is not assignable to type 'number'. -tests/cases/compiler/dynamicNamesErrors.ts(26,1): error TS2322: Type 'T1' is not assignable to type 'T2'. - Types of property '"1"' are incompatible. +tests/cases/compiler/dynamicNamesErrors.ts(25,1): error TS2322: Type 'T1' is not assignable to type 'T2'. + Types of property '[c0]' are incompatible. Type 'number' is not assignable to type 'string'. +tests/cases/compiler/dynamicNamesErrors.ts(28,6): error TS4033: Property '[c0]' of exported interface has or is using private name 'c0'. -==== tests/cases/compiler/dynamicNamesErrors.ts (5 errors) ==== +==== tests/cases/compiler/dynamicNamesErrors.ts (6 errors) ==== const c0 = "1"; const c1 = 1; @@ -37,16 +38,21 @@ tests/cases/compiler/dynamicNamesErrors.ts(26,1): error TS2322: Type 'T1' is not !!! error TS2711: Subsequent property declarations must have the same type. Property '[c1]' must be of type 'number', but here has type 'string'. } - let t1: T1; let t2: T2; t1 = t2; ~~ !!! error TS2322: Type 'T2' is not assignable to type 'T1'. -!!! error TS2322: Types of property '"1"' are incompatible. +!!! error TS2322: Types of property '[c0]' are incompatible. !!! error TS2322: Type 'string' is not assignable to type 'number'. t2 = t1; ~~ !!! error TS2322: Type 'T1' is not assignable to type 'T2'. -!!! error TS2322: Types of property '"1"' are incompatible. -!!! error TS2322: Type 'number' is not assignable to type 'string'. \ No newline at end of file +!!! error TS2322: Types of property '[c0]' are incompatible. +!!! error TS2322: Type 'number' is not assignable to type 'string'. + + export interface T4 { + [c0]: number; + ~~ +!!! error TS4033: Property '[c0]' of exported interface has or is using private name 'c0'. + } \ No newline at end of file diff --git a/tests/baselines/reference/dynamicNamesErrors.js b/tests/baselines/reference/dynamicNamesErrors.js index 186ae8870d7ab..ec4fb8114cbf2 100644 --- a/tests/baselines/reference/dynamicNamesErrors.js +++ b/tests/baselines/reference/dynamicNamesErrors.js @@ -20,13 +20,18 @@ interface T3 { [c1]: string; } - let t1: T1; let t2: T2; t1 = t2; -t2 = t1; +t2 = t1; + +export interface T4 { + [c0]: number; +} //// [dynamicNamesErrors.js] +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); const c0 = "1"; const c1 = 1; let t1; diff --git a/tests/cases/compiler/dynamicNames.ts b/tests/cases/compiler/dynamicNames.ts index 473d5bc3a8d23..6330a7b304421 100644 --- a/tests/cases/compiler/dynamicNames.ts +++ b/tests/cases/compiler/dynamicNames.ts @@ -4,7 +4,6 @@ // @filename: module.ts export const c0 = "a"; export const c1 = 1; -const c2 = "a"; export interface T0 { [c0]: number; [c1]: string; @@ -16,7 +15,7 @@ export declare class T1 implements T2 { export declare class T2 extends T1 { } export declare type T3 = { - [c2]: number; + [c0]: number; [c1]: string; }; diff --git a/tests/cases/compiler/dynamicNamesErrors.ts b/tests/cases/compiler/dynamicNamesErrors.ts index c819619a58193..cb8377677327a 100644 --- a/tests/cases/compiler/dynamicNamesErrors.ts +++ b/tests/cases/compiler/dynamicNamesErrors.ts @@ -1,5 +1,6 @@ // @target: esnext - +// @module: commonjs +// @declaration: true const c0 = "1"; const c1 = 1; @@ -21,8 +22,11 @@ interface T3 { [c1]: string; } - let t1: T1; let t2: T2; t1 = t2; -t2 = t1; \ No newline at end of file +t2 = t1; + +export interface T4 { + [c0]: number; +} \ No newline at end of file