diff --git a/src/compiler/binder.ts b/src/compiler/binder.ts index 4e6a7a87afa..b2ad2151bb6 100644 --- a/src/compiler/binder.ts +++ b/src/compiler/binder.ts @@ -2298,7 +2298,7 @@ namespace ts { function isNameOfExportsOrModuleExportsAliasDeclaration(node: Node) { if (node.kind === SyntaxKind.Identifier) { - const symbol = container.locals.get((node).text); + const symbol = lookupSymbolForName((node).text); if (symbol && symbol.valueDeclaration && symbol.valueDeclaration.kind === SyntaxKind.VariableDeclaration) { const declaration = symbol.valueDeclaration as VariableDeclaration; if (declaration.initializer) { @@ -2400,8 +2400,12 @@ namespace ts { } } + function lookupSymbolForName(name: string) { + return (container.symbol && container.symbol.exports && container.symbol.exports.get(name)) || container.locals.get(name); + } + function bindPropertyAssignment(functionName: string, propertyAccessExpression: PropertyAccessExpression, isPrototypeProperty: boolean) { - let targetSymbol = container.locals.get(functionName); + let targetSymbol = lookupSymbolForName(functionName); if (targetSymbol && isDeclarationOfFunctionOrClassExpression(targetSymbol)) { targetSymbol = (targetSymbol.valueDeclaration as VariableDeclaration).initializer.symbol; diff --git a/tests/baselines/reference/inferringClassStaticMembersFromAssignments.symbols b/tests/baselines/reference/inferringClassStaticMembersFromAssignments.symbols new file mode 100644 index 00000000000..2ed29dcb72d --- /dev/null +++ b/tests/baselines/reference/inferringClassStaticMembersFromAssignments.symbols @@ -0,0 +1,130 @@ +=== tests/cases/conformance/salsa/a.js === +export class C1 { } +>C1 : Symbol(C1, Decl(a.js, 0, 0)) + +C1.staticProp = 0; +>C1.staticProp : Symbol(C1.staticProp, Decl(a.js, 0, 19)) +>C1 : Symbol(C1, Decl(a.js, 0, 0)) +>staticProp : Symbol(C1.staticProp, Decl(a.js, 0, 19)) + +export function F1() { } +>F1 : Symbol(F1, Decl(a.js, 1, 18)) + +F1.staticProp = 0; +>F1.staticProp : Symbol(F1.staticProp, Decl(a.js, 3, 24)) +>F1 : Symbol(F1, Decl(a.js, 1, 18)) +>staticProp : Symbol(F1.staticProp, Decl(a.js, 3, 24)) + +export var C2 = class { }; +>C2 : Symbol(C2, Decl(a.js, 6, 10)) + +C2.staticProp = 0; +>C2.staticProp : Symbol(C2.staticProp, Decl(a.js, 6, 26)) +>C2 : Symbol(C2, Decl(a.js, 6, 10)) +>staticProp : Symbol(C2.staticProp, Decl(a.js, 6, 26)) + +export let F2 = function () { }; +>F2 : Symbol(F2, Decl(a.js, 9, 10)) + +F2.staticProp = 0; +>F2.staticProp : Symbol(F2.staticProp, Decl(a.js, 9, 32)) +>F2 : Symbol(F2, Decl(a.js, 9, 10)) +>staticProp : Symbol(F2.staticProp, Decl(a.js, 9, 32)) + +=== tests/cases/conformance/salsa/global.js === +class C3 { } +>C3 : Symbol(C3, Decl(global.js, 0, 0)) + +C3.staticProp = 0; +>C3.staticProp : Symbol(C3.staticProp, Decl(global.js, 0, 12)) +>C3 : Symbol(C3, Decl(global.js, 0, 0)) +>staticProp : Symbol(C3.staticProp, Decl(global.js, 0, 12)) + +function F3() { } +>F3 : Symbol(F3, Decl(global.js, 1, 18)) + +F3.staticProp = 0; +>F3.staticProp : Symbol(F3.staticProp, Decl(global.js, 3, 17)) +>F3 : Symbol(F3, Decl(global.js, 1, 18)) +>staticProp : Symbol(F3.staticProp, Decl(global.js, 3, 17)) + +var C4 = class { }; +>C4 : Symbol(C4, Decl(global.js, 6, 3)) + +C4.staticProp = 0; +>C4.staticProp : Symbol(C4.staticProp, Decl(global.js, 6, 19)) +>C4 : Symbol(C4, Decl(global.js, 6, 3)) +>staticProp : Symbol(C4.staticProp, Decl(global.js, 6, 19)) + +let F4 = function () { }; +>F4 : Symbol(F4, Decl(global.js, 9, 3)) + +F4.staticProp = 0; +>F4.staticProp : Symbol(F4.staticProp, Decl(global.js, 9, 25)) +>F4 : Symbol(F4, Decl(global.js, 9, 3)) +>staticProp : Symbol(F4.staticProp, Decl(global.js, 9, 25)) + +=== tests/cases/conformance/salsa/b.ts === +import * as a from "./a"; +>a : Symbol(a, Decl(b.ts, 0, 6)) + +var n: number; +>n : Symbol(n, Decl(b.ts, 1, 3), Decl(b.ts, 3, 3), Decl(b.ts, 4, 3), Decl(b.ts, 5, 3), Decl(b.ts, 6, 3), Decl(b.ts, 9, 3), Decl(b.ts, 10, 3), Decl(b.ts, 11, 3), Decl(b.ts, 12, 3)) + +var n = a.C1.staticProp; +>n : Symbol(n, Decl(b.ts, 1, 3), Decl(b.ts, 3, 3), Decl(b.ts, 4, 3), Decl(b.ts, 5, 3), Decl(b.ts, 6, 3), Decl(b.ts, 9, 3), Decl(b.ts, 10, 3), Decl(b.ts, 11, 3), Decl(b.ts, 12, 3)) +>a.C1.staticProp : Symbol(a.C1.staticProp, Decl(a.js, 0, 19)) +>a.C1 : Symbol(a.C1, Decl(a.js, 0, 0)) +>a : Symbol(a, Decl(b.ts, 0, 6)) +>C1 : Symbol(a.C1, Decl(a.js, 0, 0)) +>staticProp : Symbol(a.C1.staticProp, Decl(a.js, 0, 19)) + +var n = a.C2.staticProp; +>n : Symbol(n, Decl(b.ts, 1, 3), Decl(b.ts, 3, 3), Decl(b.ts, 4, 3), Decl(b.ts, 5, 3), Decl(b.ts, 6, 3), Decl(b.ts, 9, 3), Decl(b.ts, 10, 3), Decl(b.ts, 11, 3), Decl(b.ts, 12, 3)) +>a.C2.staticProp : Symbol(C2.staticProp, Decl(a.js, 6, 26)) +>a.C2 : Symbol(a.C2, Decl(a.js, 6, 10)) +>a : Symbol(a, Decl(b.ts, 0, 6)) +>C2 : Symbol(a.C2, Decl(a.js, 6, 10)) +>staticProp : Symbol(C2.staticProp, Decl(a.js, 6, 26)) + +var n = a.F1.staticProp; +>n : Symbol(n, Decl(b.ts, 1, 3), Decl(b.ts, 3, 3), Decl(b.ts, 4, 3), Decl(b.ts, 5, 3), Decl(b.ts, 6, 3), Decl(b.ts, 9, 3), Decl(b.ts, 10, 3), Decl(b.ts, 11, 3), Decl(b.ts, 12, 3)) +>a.F1.staticProp : Symbol(a.F1.staticProp, Decl(a.js, 3, 24)) +>a.F1 : Symbol(a.F1, Decl(a.js, 1, 18)) +>a : Symbol(a, Decl(b.ts, 0, 6)) +>F1 : Symbol(a.F1, Decl(a.js, 1, 18)) +>staticProp : Symbol(a.F1.staticProp, Decl(a.js, 3, 24)) + +var n = a.F2.staticProp; +>n : Symbol(n, Decl(b.ts, 1, 3), Decl(b.ts, 3, 3), Decl(b.ts, 4, 3), Decl(b.ts, 5, 3), Decl(b.ts, 6, 3), Decl(b.ts, 9, 3), Decl(b.ts, 10, 3), Decl(b.ts, 11, 3), Decl(b.ts, 12, 3)) +>a.F2.staticProp : Symbol(F2.staticProp, Decl(a.js, 9, 32)) +>a.F2 : Symbol(a.F2, Decl(a.js, 9, 10)) +>a : Symbol(a, Decl(b.ts, 0, 6)) +>F2 : Symbol(a.F2, Decl(a.js, 9, 10)) +>staticProp : Symbol(F2.staticProp, Decl(a.js, 9, 32)) + + +var n = C3.staticProp; +>n : Symbol(n, Decl(b.ts, 1, 3), Decl(b.ts, 3, 3), Decl(b.ts, 4, 3), Decl(b.ts, 5, 3), Decl(b.ts, 6, 3), Decl(b.ts, 9, 3), Decl(b.ts, 10, 3), Decl(b.ts, 11, 3), Decl(b.ts, 12, 3)) +>C3.staticProp : Symbol(C3.staticProp, Decl(global.js, 0, 12)) +>C3 : Symbol(C3, Decl(global.js, 0, 0)) +>staticProp : Symbol(C3.staticProp, Decl(global.js, 0, 12)) + +var n = C4.staticProp; +>n : Symbol(n, Decl(b.ts, 1, 3), Decl(b.ts, 3, 3), Decl(b.ts, 4, 3), Decl(b.ts, 5, 3), Decl(b.ts, 6, 3), Decl(b.ts, 9, 3), Decl(b.ts, 10, 3), Decl(b.ts, 11, 3), Decl(b.ts, 12, 3)) +>C4.staticProp : Symbol(C4.staticProp, Decl(global.js, 6, 19)) +>C4 : Symbol(C4, Decl(global.js, 6, 3)) +>staticProp : Symbol(C4.staticProp, Decl(global.js, 6, 19)) + +var n = F3.staticProp; +>n : Symbol(n, Decl(b.ts, 1, 3), Decl(b.ts, 3, 3), Decl(b.ts, 4, 3), Decl(b.ts, 5, 3), Decl(b.ts, 6, 3), Decl(b.ts, 9, 3), Decl(b.ts, 10, 3), Decl(b.ts, 11, 3), Decl(b.ts, 12, 3)) +>F3.staticProp : Symbol(F3.staticProp, Decl(global.js, 3, 17)) +>F3 : Symbol(F3, Decl(global.js, 1, 18)) +>staticProp : Symbol(F3.staticProp, Decl(global.js, 3, 17)) + +var n = F4.staticProp; +>n : Symbol(n, Decl(b.ts, 1, 3), Decl(b.ts, 3, 3), Decl(b.ts, 4, 3), Decl(b.ts, 5, 3), Decl(b.ts, 6, 3), Decl(b.ts, 9, 3), Decl(b.ts, 10, 3), Decl(b.ts, 11, 3), Decl(b.ts, 12, 3)) +>F4.staticProp : Symbol(F4.staticProp, Decl(global.js, 9, 25)) +>F4 : Symbol(F4, Decl(global.js, 9, 3)) +>staticProp : Symbol(F4.staticProp, Decl(global.js, 9, 25)) + diff --git a/tests/baselines/reference/inferringClassStaticMembersFromAssignments.types b/tests/baselines/reference/inferringClassStaticMembersFromAssignments.types new file mode 100644 index 00000000000..69dff49724b --- /dev/null +++ b/tests/baselines/reference/inferringClassStaticMembersFromAssignments.types @@ -0,0 +1,150 @@ +=== tests/cases/conformance/salsa/a.js === +export class C1 { } +>C1 : C1 + +C1.staticProp = 0; +>C1.staticProp = 0 : 0 +>C1.staticProp : number +>C1 : typeof C1 +>staticProp : number +>0 : 0 + +export function F1() { } +>F1 : { (): void; staticProp: number; } + +F1.staticProp = 0; +>F1.staticProp = 0 : 0 +>F1.staticProp : number +>F1 : { (): void; staticProp: number; } +>staticProp : number +>0 : 0 + +export var C2 = class { }; +>C2 : typeof C2 +>class { } : typeof C2 + +C2.staticProp = 0; +>C2.staticProp = 0 : 0 +>C2.staticProp : number +>C2 : typeof C2 +>staticProp : number +>0 : 0 + +export let F2 = function () { }; +>F2 : { (): void; staticProp: number; } +>function () { } : { (): void; staticProp: number; } + +F2.staticProp = 0; +>F2.staticProp = 0 : 0 +>F2.staticProp : number +>F2 : { (): void; staticProp: number; } +>staticProp : number +>0 : 0 + +=== tests/cases/conformance/salsa/global.js === +class C3 { } +>C3 : C3 + +C3.staticProp = 0; +>C3.staticProp = 0 : 0 +>C3.staticProp : number +>C3 : typeof C3 +>staticProp : number +>0 : 0 + +function F3() { } +>F3 : { (): void; staticProp: number; } + +F3.staticProp = 0; +>F3.staticProp = 0 : 0 +>F3.staticProp : number +>F3 : { (): void; staticProp: number; } +>staticProp : number +>0 : 0 + +var C4 = class { }; +>C4 : typeof C4 +>class { } : typeof C4 + +C4.staticProp = 0; +>C4.staticProp = 0 : 0 +>C4.staticProp : number +>C4 : typeof C4 +>staticProp : number +>0 : 0 + +let F4 = function () { }; +>F4 : { (): void; staticProp: number; } +>function () { } : { (): void; staticProp: number; } + +F4.staticProp = 0; +>F4.staticProp = 0 : 0 +>F4.staticProp : number +>F4 : { (): void; staticProp: number; } +>staticProp : number +>0 : 0 + +=== tests/cases/conformance/salsa/b.ts === +import * as a from "./a"; +>a : typeof a + +var n: number; +>n : number + +var n = a.C1.staticProp; +>n : number +>a.C1.staticProp : number +>a.C1 : typeof a.C1 +>a : typeof a +>C1 : typeof a.C1 +>staticProp : number + +var n = a.C2.staticProp; +>n : number +>a.C2.staticProp : number +>a.C2 : typeof C2 +>a : typeof a +>C2 : typeof C2 +>staticProp : number + +var n = a.F1.staticProp; +>n : number +>a.F1.staticProp : number +>a.F1 : { (): void; staticProp: number; } +>a : typeof a +>F1 : { (): void; staticProp: number; } +>staticProp : number + +var n = a.F2.staticProp; +>n : number +>a.F2.staticProp : number +>a.F2 : { (): void; staticProp: number; } +>a : typeof a +>F2 : { (): void; staticProp: number; } +>staticProp : number + + +var n = C3.staticProp; +>n : number +>C3.staticProp : number +>C3 : typeof C3 +>staticProp : number + +var n = C4.staticProp; +>n : number +>C4.staticProp : number +>C4 : typeof C4 +>staticProp : number + +var n = F3.staticProp; +>n : number +>F3.staticProp : number +>F3 : { (): void; staticProp: number; } +>staticProp : number + +var n = F4.staticProp; +>n : number +>F4.staticProp : number +>F4 : { (): void; staticProp: number; } +>staticProp : number + diff --git a/tests/cases/conformance/salsa/inferringClassStaticMembersFromAssignments.ts b/tests/cases/conformance/salsa/inferringClassStaticMembersFromAssignments.ts new file mode 100644 index 00000000000..7ed3a81dcfe --- /dev/null +++ b/tests/cases/conformance/salsa/inferringClassStaticMembersFromAssignments.ts @@ -0,0 +1,43 @@ +// @noEmit: true +// @allowJs: true + +// @filename: a.js +export class C1 { } +C1.staticProp = 0; + +export function F1() { } +F1.staticProp = 0; + +export var C2 = class { }; +C2.staticProp = 0; + +export let F2 = function () { }; +F2.staticProp = 0; + +//@filename: global.js +class C3 { } +C3.staticProp = 0; + +function F3() { } +F3.staticProp = 0; + +var C4 = class { }; +C4.staticProp = 0; + +let F4 = function () { }; +F4.staticProp = 0; + +// @filename: b.ts +import * as a from "./a"; +var n: number; + +var n = a.C1.staticProp; +var n = a.C2.staticProp; +var n = a.F1.staticProp; +var n = a.F2.staticProp; + + +var n = C3.staticProp; +var n = C4.staticProp; +var n = F3.staticProp; +var n = F4.staticProp; \ No newline at end of file