Track late bound names in binding patterns (#26336)

This commit is contained in:
Wesley Wigham 2018-08-17 16:30:01 -07:00 committed by GitHub
parent d58b1f664b
commit d433c6ed05
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 140 additions and 8 deletions

View File

@ -3552,15 +3552,10 @@ namespace ts {
anyType : getTypeOfSymbol(propertySymbol);
const saveEnclosingDeclaration = context.enclosingDeclaration;
context.enclosingDeclaration = undefined;
if (getCheckFlags(propertySymbol) & CheckFlags.Late) {
if (context.tracker.trackSymbol && getCheckFlags(propertySymbol) & CheckFlags.Late) {
const decl = first(propertySymbol.declarations);
if (context.tracker.trackSymbol && hasLateBindableName(decl)) {
// get symbol of the first identifier of the entityName
const firstIdentifier = getFirstIdentifier(decl.name.expression);
const name = resolveName(firstIdentifier, firstIdentifier.escapedText, SymbolFlags.Value | SymbolFlags.ExportValue, /*nodeNotFoundErrorMessage*/ undefined, /*nameArg*/ undefined, /*isUse*/ true);
if (name) {
context.tracker.trackSymbol(name, saveEnclosingDeclaration, SymbolFlags.Value);
}
if (hasLateBindableName(decl)) {
trackComputedName(decl.name, saveEnclosingDeclaration, context);
}
}
const propertyName = symbolToName(propertySymbol, context, SymbolFlags.Value, /*expectsIdentifier*/ true);
@ -3770,6 +3765,9 @@ namespace ts {
function cloneBindingName(node: BindingName): BindingName {
return <BindingName>elideInitializerAndSetEmitFlags(node);
function elideInitializerAndSetEmitFlags(node: Node): Node {
if (context.tracker.trackSymbol && isComputedPropertyName(node) && isLateBindableName(node)) {
trackComputedName(node, context.enclosingDeclaration, context);
}
const visited = visitEachChild(node, elideInitializerAndSetEmitFlags, nullTransformationContext, /*nodesVisitor*/ undefined, elideInitializerAndSetEmitFlags)!;
const clone = nodeIsSynthesized(visited) ? visited : getSynthesizedClone(visited);
if (clone.kind === SyntaxKind.BindingElement) {
@ -3780,6 +3778,16 @@ namespace ts {
}
}
function trackComputedName(node: LateBoundName, enclosingDeclaration: Node | undefined, context: NodeBuilderContext) {
if (!context.tracker.trackSymbol) return;
// get symbol of the first identifier of the entityName
const firstIdentifier = getFirstIdentifier(node.expression);
const name = resolveName(firstIdentifier, firstIdentifier.escapedText, SymbolFlags.Value | SymbolFlags.ExportValue, /*nodeNotFoundErrorMessage*/ undefined, /*nameArg*/ undefined, /*isUse*/ true);
if (name) {
context.tracker.trackSymbol(name, enclosingDeclaration, SymbolFlags.Value);
}
}
function lookupSymbolChain(symbol: Symbol, context: NodeBuilderContext, meaning: SymbolFlags, yieldModuleSymbol?: boolean) {
context.tracker.trackSymbol!(symbol, context.enclosingDeclaration, meaning); // TODO: GH#18217
// Try to get qualified name if the symbol is not a type parameter and there is an enclosing declaration.

View File

@ -0,0 +1,43 @@
//// [tests/cases/compiler/declarationEmitComputedNameCausesImportToBePainted.ts] ////
//// [context.ts]
export const Key = Symbol();
export interface Context {
[Key]: string;
}
//// [index.ts]
import { Key, Context } from "./context";
export const context: Context = {
[Key]: 'bar',
}
export const withContext = ({ [Key]: value }: Context) => value;
//// [context.js]
"use strict";
exports.__esModule = true;
exports.Key = Symbol();
//// [index.js]
"use strict";
exports.__esModule = true;
var _a;
var context_1 = require("./context");
exports.context = (_a = {},
_a[context_1.Key] = 'bar',
_a);
exports.withContext = function (_a) {
var _b = context_1.Key, value = _a[_b];
return value;
};
//// [context.d.ts]
export declare const Key: unique symbol;
export interface Context {
[Key]: string;
}
//// [index.d.ts]
import { Key, Context } from "./context";
export declare const context: Context;
export declare const withContext: ({ [Key]: value }: Context) => string;

View File

@ -0,0 +1,33 @@
=== tests/cases/compiler/context.ts ===
export const Key = Symbol();
>Key : Symbol(Key, Decl(context.ts, 0, 12))
>Symbol : Symbol(Symbol, Decl(lib.es5.d.ts, --, --), Decl(lib.es2015.symbol.d.ts, --, --), Decl(lib.es2015.symbol.wellknown.d.ts, --, --))
export interface Context {
>Context : Symbol(Context, Decl(context.ts, 0, 28))
[Key]: string;
>[Key] : Symbol(Context[Key], Decl(context.ts, 1, 26))
>Key : Symbol(Key, Decl(context.ts, 0, 12))
}
=== tests/cases/compiler/index.ts ===
import { Key, Context } from "./context";
>Key : Symbol(Key, Decl(index.ts, 0, 8))
>Context : Symbol(Context, Decl(index.ts, 0, 13))
export const context: Context = {
>context : Symbol(context, Decl(index.ts, 2, 12))
>Context : Symbol(Context, Decl(index.ts, 0, 13))
[Key]: 'bar',
>[Key] : Symbol([Key], Decl(index.ts, 2, 33))
>Key : Symbol(Key, Decl(index.ts, 0, 8))
}
export const withContext = ({ [Key]: value }: Context) => value;
>withContext : Symbol(withContext, Decl(index.ts, 6, 12))
>Key : Symbol(Key, Decl(index.ts, 0, 8))
>value : Symbol(value, Decl(index.ts, 6, 29))
>Context : Symbol(Context, Decl(index.ts, 0, 13))
>value : Symbol(value, Decl(index.ts, 6, 29))

View File

@ -0,0 +1,33 @@
=== tests/cases/compiler/context.ts ===
export const Key = Symbol();
>Key : unique symbol
>Symbol() : unique symbol
>Symbol : SymbolConstructor
export interface Context {
[Key]: string;
>[Key] : string
>Key : unique symbol
}
=== tests/cases/compiler/index.ts ===
import { Key, Context } from "./context";
>Key : unique symbol
>Context : any
export const context: Context = {
>context : Context
>{ [Key]: 'bar',} : { [Key]: string; }
[Key]: 'bar',
>[Key] : string
>Key : unique symbol
>'bar' : "bar"
}
export const withContext = ({ [Key]: value }: Context) => value;
>withContext : ({ [Key]: value }: Context) => string
>({ [Key]: value }: Context) => value : ({ [Key]: value }: Context) => string
>Key : unique symbol
>value : string
>value : string

View File

@ -0,0 +1,15 @@
// @declaration: true
// @lib: es6
// @filename: context.ts
export const Key = Symbol();
export interface Context {
[Key]: string;
}
// @filename: index.ts
import { Key, Context } from "./context";
export const context: Context = {
[Key]: 'bar',
}
export const withContext = ({ [Key]: value }: Context) => value;