New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Allow dynamic names in types #15473

Merged
merged 65 commits into from Nov 16, 2017
Commits
Jump to file or symbol
Failed to load files and symbols.
+1,316 −30
Diff settings

Always

Just for now

View

Large diffs are not rendered by default.

Oops, something went wrong.
@@ -452,19 +452,6 @@ namespace ts {
return emitTypePredicate(<TypePredicateNode>type);
}
function writeEntityName(entityName: EntityName | Expression) {
if (entityName.kind === SyntaxKind.Identifier) {
writeTextOfNode(currentText, entityName);
}
else {
const left = entityName.kind === SyntaxKind.QualifiedName ? (<QualifiedName>entityName).left : (<PropertyAccessExpression>entityName).expression;
const right = entityName.kind === SyntaxKind.QualifiedName ? (<QualifiedName>entityName).right : (<PropertyAccessExpression>entityName).name;
writeEntityName(left);
write(".");
writeTextOfNode(currentText, right);
}
}
function emitEntityName(entityName: EntityNameOrEntityNameExpression) {
const visibilityResult = resolver.isEntityNameVisible(entityName,
// Aliases can be written asynchronously so use correct enclosing declaration
@@ -584,6 +571,19 @@ namespace ts {
}
}
function writeEntityName(entityName: EntityName | Expression) {
if (entityName.kind === SyntaxKind.Identifier) {
writeTextOfNode(currentText, entityName);
}
else {
const left = entityName.kind === SyntaxKind.QualifiedName ? (<QualifiedName>entityName).left : (<PropertyAccessExpression>entityName).expression;
const right = entityName.kind === SyntaxKind.QualifiedName ? (<QualifiedName>entityName).right : (<PropertyAccessExpression>entityName).name;
writeEntityName(left);
write(".");
writeTextOfNode(currentText, right);
}
}
function emitSourceFile(node: SourceFile) {
currentText = node.text;
currentLineMap = getLineStarts(node);
@@ -1202,7 +1202,7 @@ namespace ts {
}
function emitPropertyDeclaration(node: Declaration) {
if (hasDynamicName(node)) {
if (hasDynamicName(node) && !resolver.isLiteralDynamicName(<ComputedPropertyName>node.name)) {
return;
}
@@ -1221,10 +1221,17 @@ namespace ts {
emitBindingPattern(<BindingPattern>node.name);
}
else {
// If this node is a computed name, it can only be a symbol, because we've already skipped
// it if it's not a well known symbol. In that case, the text of the name will be exactly
// what we want, namely the name expression enclosed in brackets.
writeTextOfNode(currentText, node.name);
if (isDynamicName(node.name)) {
// If this node has a dynamic name, it can only be an identifier or property access because
// we've already skipped it otherwise.
emitDynamicName(<EntityNameExpression>(<ComputedPropertyName>node.name).expression);
}
else {
// If this node is a computed name, it can only be a symbol, because we've already skipped
// it if it's not a well known symbol. In that case, the text of the name will be exactly
// what we want, namely the name expression enclosed in brackets.
writeTextOfNode(currentText, node.name);
}
// If optional property emit ? but in the case of parameterProperty declaration with "?" indicating optional parameter for the constructor
// we don't want to emit property declaration with "?"
if ((node.kind === SyntaxKind.PropertyDeclaration || node.kind === SyntaxKind.PropertySignature ||
@@ -1287,6 +1294,19 @@ namespace ts {
} : undefined;
}
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);
}
}
function emitBindingPattern(bindingPattern: BindingPattern) {
// Only select non-omitted expression from the bindingPattern's elements.
// We have to do this to avoid emitting trailing commas.
@@ -2123,6 +2123,10 @@
"category": "Error",
"code": 2710
},
"Subsequent property declarations must have the same type. Property '{0}' must be of type '{1}', but here has type '{2}'.": {
"category": "Error",
"code": 2711
},
"Import declaration '{0}' is using private name '{1}'.": {
"category": "Error",
View
@@ -2721,6 +2721,7 @@ namespace ts {
isTopLevelValueImportEqualsWithEntityName(node: ImportEqualsDeclaration): boolean;
getNodeCheckFlags(node: Node): NodeCheckFlags;
isDeclarationVisible(node: Declaration): boolean;
isLiteralDynamicName(node: ComputedPropertyName): boolean;
collectLinkedAliases(node: Identifier): Node[];
isImplementationOfOverload(node: FunctionLikeDeclaration): boolean;
isRequiredInitializedParameter(node: ParameterDeclaration): boolean;
@@ -2775,6 +2776,7 @@ namespace ts {
ExportStar = 1 << 25, // Export * declaration
Optional = 1 << 26, // Optional property
Transient = 1 << 27, // Transient symbol (created during type check)
Dynamic = 1 << 28, // Dynamically resolved symbol from computed property
Enum = RegularEnum | ConstEnum,
Variable = FunctionScopedVariable | BlockScopedVariable,
@@ -2869,6 +2871,8 @@ namespace ts {
isDeclarationWithCollidingName?: boolean; // True if symbol is block scoped redeclaration
bindingElement?: BindingElement; // Binding element associated with property symbol
exportsSomeValue?: boolean; // True if module exports some value (not just types)
dynamicMembers?: SymbolTable; // Dynamic members with literal names resolved during check
resolvedMembers?: SymbolTable;
}
/* @internal */
@@ -68,6 +68,9 @@ namespace ts {
transformers: {
before: [replaceUndefinedWithVoid0],
after: [replaceIdentifiersNamedOldNameWithNewName]
},
compilerOptions: {
newLine: ts.NewLineKind.CarriageReturnLineFeed
}
}).outputText;
});
@@ -0,0 +1,142 @@
//// [tests/cases/compiler/dynamicNames.ts] ////
//// [module.ts]
export const c0 = "a";
export const c1 = 1;
export interface T0 {
[c0]: number;
[c1]: string;
}
export declare class T1 implements T2 {
[c0]: number;
[c1]: string;
}
export declare class T2 extends T1 {
}
export declare type T3 = {
[c0]: number;
[c1]: string;
};
//// [main.ts]
import { c0, c1, T0, T1, T2, T3 } from "./module";
import * as M from "./module";
namespace N {
export const c2 = "a";
export const c3 = 1;
export interface T4 {
[N.c2]: number;
[N.c3]: string;
}
export declare class T5 implements T4 {
[N.c2]: number;
[N.c3]: string;
}
export declare class T6 extends T5 {
}
export declare type T7 = {
[N.c2]: number;
[N.c3]: string;
};
}
const c4 = "a";
const c5 = 1;
interface T8 {
[c4]: number;
[c5]: string;
}
declare class T9 implements T8 {
[c4]: number;
[c5]: string;
}
declare class T10 extends T9 {
}
declare type T11 = {
[c4]: number;
[c5]: string;
};
interface T12 {
a: number;
1: string;
}
declare class T13 implements T2 {
a: number;
1: string;
}
declare class T14 extends T13 {
}
declare type T15 = {
a: number;
1: string;
};
let t0: T0;
let t1: T1;
let t2: T2;
let t3: T3;
let t0_1: M.T0;
let t1_1: M.T1;
let t2_1: M.T2;
let t3_1: M.T3;
let t4: N.T4;
let t5: N.T5;
let t6: N.T6;
let t7: N.T7;
let t8: T8;
let t9: T9;
let t10: T10;
let t11: T11;
let t12: T12;
let t13: T13;
let t14: T14;
let t15: T15;
// assignability
t0 = t1, t0 = t2, t0 = t3, t1 = t0, t1 = t2, t1 = t3, t2 = t0, t2 = t1, t2 = t3, t3 = t0, t3 = t1, t3 = t2;
t4 = t5, t4 = t6, t4 = t7, t5 = t4, t5 = t6, t5 = t7, t6 = t4, t6 = t5, t6 = t7, t7 = t4, t7 = t5, t7 = t6;
t0 = t12, t0 = t13, t0 = t14, t0 = t15, t12 = t0, t13 = t0, t14 = t0, t15 = t0;
//// [module.js]
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.c0 = "a";
exports.c1 = 1;
//// [main.js]
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
var N;
(function (N) {
N.c2 = "a";
N.c3 = 1;
})(N || (N = {}));
const c4 = "a";
const c5 = 1;
let t0;
let t1;
let t2;
let t3;
let t0_1;
let t1_1;
let t2_1;
let t3_1;
let t4;
let t5;
let t6;
let t7;
let t8;
let t9;
let t10;
let t11;
let t12;
let t13;
let t14;
let t15;
// assignability
t0 = t1, t0 = t2, t0 = t3, t1 = t0, t1 = t2, t1 = t3, t2 = t0, t2 = t1, t2 = t3, t3 = t0, t3 = t1, t3 = t2;
t4 = t5, t4 = t6, t4 = t7, t5 = t4, t5 = t6, t5 = t7, t6 = t4, t6 = t5, t6 = t7, t7 = t4, t7 = t5, t7 = t6;
t0 = t12, t0 = t13, t0 = t14, t0 = t15, t12 = t0, t13 = t0, t14 = t0, t15 = t0;
Oops, something went wrong.
ProTip! Use n and p to navigate between commits in a pull request.