Skip to content

Commit d433c6e

Browse files
authored
Track late bound names in binding patterns (microsoft#26336)
1 parent d58b1f6 commit d433c6e

5 files changed

+140
-8
lines changed

src/compiler/checker.ts

Lines changed: 16 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -3552,15 +3552,10 @@ namespace ts {
35523552
anyType : getTypeOfSymbol(propertySymbol);
35533553
const saveEnclosingDeclaration = context.enclosingDeclaration;
35543554
context.enclosingDeclaration = undefined;
3555-
if (getCheckFlags(propertySymbol) & CheckFlags.Late) {
3555+
if (context.tracker.trackSymbol && getCheckFlags(propertySymbol) & CheckFlags.Late) {
35563556
const decl = first(propertySymbol.declarations);
3557-
if (context.tracker.trackSymbol && hasLateBindableName(decl)) {
3558-
// get symbol of the first identifier of the entityName
3559-
const firstIdentifier = getFirstIdentifier(decl.name.expression);
3560-
const name = resolveName(firstIdentifier, firstIdentifier.escapedText, SymbolFlags.Value | SymbolFlags.ExportValue, /*nodeNotFoundErrorMessage*/ undefined, /*nameArg*/ undefined, /*isUse*/ true);
3561-
if (name) {
3562-
context.tracker.trackSymbol(name, saveEnclosingDeclaration, SymbolFlags.Value);
3563-
}
3557+
if (hasLateBindableName(decl)) {
3558+
trackComputedName(decl.name, saveEnclosingDeclaration, context);
35643559
}
35653560
}
35663561
const propertyName = symbolToName(propertySymbol, context, SymbolFlags.Value, /*expectsIdentifier*/ true);
@@ -3770,6 +3765,9 @@ namespace ts {
37703765
function cloneBindingName(node: BindingName): BindingName {
37713766
return <BindingName>elideInitializerAndSetEmitFlags(node);
37723767
function elideInitializerAndSetEmitFlags(node: Node): Node {
3768+
if (context.tracker.trackSymbol && isComputedPropertyName(node) && isLateBindableName(node)) {
3769+
trackComputedName(node, context.enclosingDeclaration, context);
3770+
}
37733771
const visited = visitEachChild(node, elideInitializerAndSetEmitFlags, nullTransformationContext, /*nodesVisitor*/ undefined, elideInitializerAndSetEmitFlags)!;
37743772
const clone = nodeIsSynthesized(visited) ? visited : getSynthesizedClone(visited);
37753773
if (clone.kind === SyntaxKind.BindingElement) {
@@ -3780,6 +3778,16 @@ namespace ts {
37803778
}
37813779
}
37823780

3781+
function trackComputedName(node: LateBoundName, enclosingDeclaration: Node | undefined, context: NodeBuilderContext) {
3782+
if (!context.tracker.trackSymbol) return;
3783+
// get symbol of the first identifier of the entityName
3784+
const firstIdentifier = getFirstIdentifier(node.expression);
3785+
const name = resolveName(firstIdentifier, firstIdentifier.escapedText, SymbolFlags.Value | SymbolFlags.ExportValue, /*nodeNotFoundErrorMessage*/ undefined, /*nameArg*/ undefined, /*isUse*/ true);
3786+
if (name) {
3787+
context.tracker.trackSymbol(name, enclosingDeclaration, SymbolFlags.Value);
3788+
}
3789+
}
3790+
37833791
function lookupSymbolChain(symbol: Symbol, context: NodeBuilderContext, meaning: SymbolFlags, yieldModuleSymbol?: boolean) {
37843792
context.tracker.trackSymbol!(symbol, context.enclosingDeclaration, meaning); // TODO: GH#18217
37853793
// Try to get qualified name if the symbol is not a type parameter and there is an enclosing declaration.
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
//// [tests/cases/compiler/declarationEmitComputedNameCausesImportToBePainted.ts] ////
2+
3+
//// [context.ts]
4+
export const Key = Symbol();
5+
export interface Context {
6+
[Key]: string;
7+
}
8+
//// [index.ts]
9+
import { Key, Context } from "./context";
10+
11+
export const context: Context = {
12+
[Key]: 'bar',
13+
}
14+
15+
export const withContext = ({ [Key]: value }: Context) => value;
16+
17+
//// [context.js]
18+
"use strict";
19+
exports.__esModule = true;
20+
exports.Key = Symbol();
21+
//// [index.js]
22+
"use strict";
23+
exports.__esModule = true;
24+
var _a;
25+
var context_1 = require("./context");
26+
exports.context = (_a = {},
27+
_a[context_1.Key] = 'bar',
28+
_a);
29+
exports.withContext = function (_a) {
30+
var _b = context_1.Key, value = _a[_b];
31+
return value;
32+
};
33+
34+
35+
//// [context.d.ts]
36+
export declare const Key: unique symbol;
37+
export interface Context {
38+
[Key]: string;
39+
}
40+
//// [index.d.ts]
41+
import { Key, Context } from "./context";
42+
export declare const context: Context;
43+
export declare const withContext: ({ [Key]: value }: Context) => string;
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
=== tests/cases/compiler/context.ts ===
2+
export const Key = Symbol();
3+
>Key : Symbol(Key, Decl(context.ts, 0, 12))
4+
>Symbol : Symbol(Symbol, Decl(lib.es5.d.ts, --, --), Decl(lib.es2015.symbol.d.ts, --, --), Decl(lib.es2015.symbol.wellknown.d.ts, --, --))
5+
6+
export interface Context {
7+
>Context : Symbol(Context, Decl(context.ts, 0, 28))
8+
9+
[Key]: string;
10+
>[Key] : Symbol(Context[Key], Decl(context.ts, 1, 26))
11+
>Key : Symbol(Key, Decl(context.ts, 0, 12))
12+
}
13+
=== tests/cases/compiler/index.ts ===
14+
import { Key, Context } from "./context";
15+
>Key : Symbol(Key, Decl(index.ts, 0, 8))
16+
>Context : Symbol(Context, Decl(index.ts, 0, 13))
17+
18+
export const context: Context = {
19+
>context : Symbol(context, Decl(index.ts, 2, 12))
20+
>Context : Symbol(Context, Decl(index.ts, 0, 13))
21+
22+
[Key]: 'bar',
23+
>[Key] : Symbol([Key], Decl(index.ts, 2, 33))
24+
>Key : Symbol(Key, Decl(index.ts, 0, 8))
25+
}
26+
27+
export const withContext = ({ [Key]: value }: Context) => value;
28+
>withContext : Symbol(withContext, Decl(index.ts, 6, 12))
29+
>Key : Symbol(Key, Decl(index.ts, 0, 8))
30+
>value : Symbol(value, Decl(index.ts, 6, 29))
31+
>Context : Symbol(Context, Decl(index.ts, 0, 13))
32+
>value : Symbol(value, Decl(index.ts, 6, 29))
33+
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
=== tests/cases/compiler/context.ts ===
2+
export const Key = Symbol();
3+
>Key : unique symbol
4+
>Symbol() : unique symbol
5+
>Symbol : SymbolConstructor
6+
7+
export interface Context {
8+
[Key]: string;
9+
>[Key] : string
10+
>Key : unique symbol
11+
}
12+
=== tests/cases/compiler/index.ts ===
13+
import { Key, Context } from "./context";
14+
>Key : unique symbol
15+
>Context : any
16+
17+
export const context: Context = {
18+
>context : Context
19+
>{ [Key]: 'bar',} : { [Key]: string; }
20+
21+
[Key]: 'bar',
22+
>[Key] : string
23+
>Key : unique symbol
24+
>'bar' : "bar"
25+
}
26+
27+
export const withContext = ({ [Key]: value }: Context) => value;
28+
>withContext : ({ [Key]: value }: Context) => string
29+
>({ [Key]: value }: Context) => value : ({ [Key]: value }: Context) => string
30+
>Key : unique symbol
31+
>value : string
32+
>value : string
33+
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
// @declaration: true
2+
// @lib: es6
3+
// @filename: context.ts
4+
export const Key = Symbol();
5+
export interface Context {
6+
[Key]: string;
7+
}
8+
// @filename: index.ts
9+
import { Key, Context } from "./context";
10+
11+
export const context: Context = {
12+
[Key]: 'bar',
13+
}
14+
15+
export const withContext = ({ [Key]: value }: Context) => value;

0 commit comments

Comments
 (0)