Skip to content

Commit

Permalink
Emit dynamic names for object literal types
Browse files Browse the repository at this point in the history
  • Loading branch information
rbuckton committed May 5, 2017
1 parent 64fd857 commit 57674dd
Show file tree
Hide file tree
Showing 12 changed files with 90 additions and 75 deletions.
25 changes: 19 additions & 6 deletions src/compiler/checker.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand Down Expand Up @@ -3258,6 +3255,9 @@ namespace ts {
writeKeyword(writer, SyntaxKind.ReadonlyKeyword);
writeSpace(writer);
}
if (prop.flags & SymbolFlags.Dynamic && (<TransientSymbol>prop).dynamicSource) {
writer.trackSymbol((<TransientSymbol>prop).dynamicSource, enclosingDeclaration, SymbolFlags.Value);
}
buildSymbolDisplay(prop, writer);
if (prop.flags & SymbolFlags.Optional) {
writePunctuation(writer, SyntaxKind.QuestionToken);
Expand Down Expand Up @@ -5193,7 +5193,7 @@ namespace ts {
resolveDynamicMembersOfNode(node, (<ClassLikeDeclaration | InterfaceDeclaration | TypeLiteralNode>node).members, symbolTable);
break;
case SyntaxKind.ObjectLiteralExpression:
resolveDynamicMembersOfNode(node, (<ObjectLiteralExpression>node).properties, symbolTable);
resolveDynamicMembersOfNode(node, (<ObjectLiteralExpression>node).properties, symbolTable);
break;
}
}
Expand Down Expand Up @@ -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((<ComputedPropertyName>memberDecl.name).expression)) {
const nameType = checkComputedPropertyName(<ComputedPropertyName>memberDecl.name);
if (nameType && nameType.flags & TypeFlags.StringOrNumberLiteral) {
prop = createSymbol(SymbolFlags.Property | SymbolFlags.Dynamic | member.flags, (<LiteralType>nameType).text);
prop.dynamicSource = resolveEntityName(<EntityNameExpression>(<ComputedPropertyName>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.
Expand Down Expand Up @@ -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;
}
Expand Down
11 changes: 3 additions & 8 deletions src/compiler/declarationEmitter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand Down
2 changes: 2 additions & 0 deletions src/compiler/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2610,6 +2610,7 @@ namespace ts {
trackSymbol(symbol: Symbol, enclosingDeclaration?: Node, meaning?: SymbolFlags): void;
reportInaccessibleThisError(): void;
reportIllegalExtends(): void;

}

export const enum TypeFormatFlags {
Expand Down Expand Up @@ -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 */
Expand Down
2 changes: 1 addition & 1 deletion src/compiler/utilities.ts
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@ namespace ts {
clear: () => str = "",
trackSymbol: noop,
reportInaccessibleThisError: noop,
reportIllegalExtends: noop
reportIllegalExtends: noop,
};
}

Expand Down
2 changes: 1 addition & 1 deletion src/services/utilities.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1174,7 +1174,7 @@ namespace ts {
clear: resetWriter,
trackSymbol: noop,
reportInaccessibleThisError: noop,
reportIllegalExtends: noop
reportIllegalExtends: noop,
};

function writeIndent() {
Expand Down
6 changes: 2 additions & 4 deletions tests/baselines/reference/dynamicNames.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@
//// [module.ts]
export const c0 = "a";
export const c1 = 1;
const c2 = "a";
export interface T0 {
[c0]: number;
[c1]: string;
Expand All @@ -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;
};

Expand Down Expand Up @@ -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 });
Expand Down Expand Up @@ -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]
27 changes: 12 additions & 15 deletions tests/baselines/reference/dynamicNames.symbols
Original file line number Diff line number Diff line change
Expand Up @@ -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))
Expand All @@ -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))
Expand All @@ -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))
Expand Down Expand Up @@ -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))
Expand Down
44 changes: 20 additions & 24 deletions tests/baselines/reference/dynamicNames.types
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,6 @@ export const c1 = 1;
>c1 : 1
>1 : 1

const c2 = "a";
>c2 : "a"
>"a" : "a"

export interface T0 {
>T0 : T0

Expand All @@ -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
Expand Down Expand Up @@ -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"
Expand Down Expand Up @@ -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"
Expand Down Expand Up @@ -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
Expand All @@ -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
Expand Down Expand Up @@ -329,49 +325,49 @@ 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
>t5 : N.T5
>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;
Expand Down
24 changes: 15 additions & 9 deletions tests/baselines/reference/dynamicNamesErrors.errors.txt
Original file line number Diff line number Diff line change
@@ -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;

Expand Down Expand Up @@ -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'.
!!! 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'.
}
Loading

0 comments on commit 57674dd

Please sign in to comment.