Skip to content

Commit 74faa3d

Browse files
committed
JS static properties:fix multi-file references+merging
1 parent 33f3e49 commit 74faa3d

13 files changed

Lines changed: 213 additions & 278 deletions

src/compiler/binder.ts

Lines changed: 19 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2407,6 +2407,14 @@ namespace ts {
24072407
return (container.symbol && container.symbol.exports && container.symbol.exports.get(name)) || (container.locals && container.locals.get(name));
24082408
}
24092409

2410+
function reallyLookup(name: __String) {
2411+
const local = container.locals.get(name)
2412+
if (local) {
2413+
return local.exportSymbol || local;
2414+
}
2415+
return container.symbol && container.symbol.exports.get(name);
2416+
}
2417+
24102418
function bindPropertyAssignment(functionName: __String, propertyAccessExpression: PropertyAccessExpression, isPrototypeProperty: boolean) {
24112419
let targetSymbol = lookupSymbolForName(functionName);
24122420
targetSymbol = targetSymbol && targetSymbol.exportSymbol || targetSymbol;
@@ -2425,12 +2433,20 @@ namespace ts {
24252433
}
24262434
if (!isPrototypeProperty && (!targetSymbol || !(targetSymbol.flags & SymbolFlags.Namespace)) && isLegalPosition) {
24272435
// TODO: Update refactoring to understand that ES5 classes now have statics in a namespace instead
2428-
const hasExportModifier = targetSymbol && getCombinedModifierFlags(targetSymbol.valueDeclaration) & ModifierFlags.Export;
2436+
// const hasExportModifier = targetSymbol && getCombinedModifierFlags(targetSymbol.valueDeclaration) & ModifierFlags.Export;
24292437
Debug.assert(isIdentifier(propertyAccessExpression.expression));
24302438
Debug.assertEqual(propertyAccessExpression.expression.kind, SyntaxKind.Identifier);
2431-
targetSymbol = declareModuleMember(propertyAccessExpression.expression as Identifier, SymbolFlags.NamespaceModule, SymbolFlags.NamespaceModuleExcludes, hasExportModifier);
2439+
// targetSymbol = declareSymbol(symbolTable, targetSymbol.parent, propertyAccessExpression.expression as Identifier, SymbolFlags.ValueModule, SymbolFlags.ValueModuleExcludes);
2440+
2441+
const symbol = reallyLookup(functionName);
2442+
if (symbol) {
2443+
addDeclarationToSymbol(symbol, propertyAccessExpression.expression as Identifier, SymbolFlags.ValueModule | SymbolFlags.NamespaceModule);
2444+
}
2445+
else if (!targetSymbol) {
2446+
targetSymbol = declareSymbol(container.locals, undefined, propertyAccessExpression.expression as Identifier, SymbolFlags.ValueModule | SymbolFlags.NamespaceModule, SymbolFlags.ValueModuleExcludes | SymbolFlags.NamespaceModuleExcludes);
2447+
}
24322448
}
2433-
if (targetSymbol && isDeclarationOfFunctionOrClassExpression(targetSymbol)) {
2449+
if (targetSymbol && isDeclarationOfFunctionOrClassExpression(targetSymbol)) { // TODO: Probably can move inside the preceding if
24342450
targetSymbol = (targetSymbol.valueDeclaration as VariableDeclaration).initializer.symbol;
24352451
}
24362452
if (!targetSymbol || !(targetSymbol.flags & (SymbolFlags.Function | SymbolFlags.Class | SymbolFlags.NamespaceModule | SymbolFlags.ExportValue))) {

src/compiler/checker.ts

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -631,7 +631,10 @@ namespace ts {
631631
}
632632

633633
function mergeSymbol(target: Symbol, source: Symbol) {
634-
if (!(target.flags & getExcludedSymbolFlags(source.flags))) {
634+
if (!(target.flags & getExcludedSymbolFlags(source.flags)) ||
635+
source.valueDeclaration && source.valueDeclaration.kind === SyntaxKind.Identifier ||
636+
target.valueDeclaration && target.valueDeclaration.kind === SyntaxKind.Identifier) {
637+
// Javascript static-property-assignment declarations always merge, even though they are also values
635638
if (source.flags & SymbolFlags.ValueModule && target.flags & SymbolFlags.ValueModule && target.constEnumOnlyModule && !source.constEnumOnlyModule) {
636639
// reset flag when merging instantiated module into value module that has only const enums
637640
target.constEnumOnlyModule = false;

tests/baselines/reference/typeFromPropertyAssignment2.types

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
=== tests/cases/conformance/salsa/a.js ===
22
function Outer() {
3-
>Outer : { (): void; Inner: typeof I; }
3+
>Outer : typeof Outer
44

55
this.y = 2
66
>this.y = 2 : 2
@@ -12,7 +12,7 @@ function Outer() {
1212
Outer.Inner = class I {
1313
>Outer.Inner = class I { constructor() { this.x = 1 }} : typeof I
1414
>Outer.Inner : typeof I
15-
>Outer : { (): void; Inner: typeof I; }
15+
>Outer : typeof Outer
1616
>Inner : typeof I
1717
>class I { constructor() { this.x = 1 }} : typeof I
1818
>I : typeof I
@@ -28,11 +28,11 @@ Outer.Inner = class I {
2828
}
2929
/** @type {Outer} */
3030
var ok
31-
>ok : { y: number; }
31+
>ok : typeof Outer
3232

3333
ok.y
3434
>ok.y : number
35-
>ok : { y: number; }
35+
>ok : typeof Outer
3636
>y : number
3737

3838
/** @type {Outer.Inner} */
Lines changed: 15 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,25 +1,27 @@
1-
=== tests/cases/conformance/salsa/a.js ===
2-
var Common = {};
3-
>Common : Symbol(Common, Decl(a.js, 0, 3), Decl(a.js, 0, 16))
1+
=== tests/cases/conformance/salsa/def.js ===
2+
var Outer = {};
3+
>Outer : Symbol(Outer, Decl(def.js, 0, 3), Decl(a.js, 0, 0))
44

5-
Common.Outer = class {
6-
>Common : Symbol(Common, Decl(a.js, 0, 3), Decl(a.js, 0, 16))
5+
=== tests/cases/conformance/salsa/a.js ===
6+
Outer.Inner = class {
7+
>Outer : Symbol(Outer, Decl(def.js, 0, 3), Decl(a.js, 0, 0))
78

89
constructor() {
910
/** @type {number} */
1011
this.y = 12
11-
>this.y : Symbol((Anonymous class).y, Decl(a.js, 2, 19))
12-
>this : Symbol((Anonymous class), Decl(a.js, 1, 14))
13-
>y : Symbol((Anonymous class).y, Decl(a.js, 2, 19))
12+
>this.y : Symbol((Anonymous class).y, Decl(a.js, 1, 19))
13+
>this : Symbol((Anonymous class), Decl(a.js, 0, 13))
14+
>y : Symbol((Anonymous class).y, Decl(a.js, 1, 19))
1415
}
1516
}
1617

17-
/** @type {Common.Outer} */
18+
=== tests/cases/conformance/salsa/b.js ===
19+
/** @type {Outer.Inner} */
1820
var x;
19-
>x : Symbol(x, Decl(a.js, 9, 3))
21+
>x : Symbol(x, Decl(b.js, 1, 3))
2022

2123
x.y
22-
>x.y : Symbol((Anonymous class).y, Decl(a.js, 2, 19))
23-
>x : Symbol(x, Decl(a.js, 9, 3))
24-
>y : Symbol((Anonymous class).y, Decl(a.js, 2, 19))
24+
>x.y : Symbol((Anonymous class).y, Decl(a.js, 1, 19))
25+
>x : Symbol(x, Decl(b.js, 1, 3))
26+
>y : Symbol((Anonymous class).y, Decl(a.js, 1, 19))
2527

tests/baselines/reference/typeFromPropertyAssignment4.types

Lines changed: 11 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,14 @@
1-
=== tests/cases/conformance/salsa/a.js ===
2-
var Common = {};
3-
>Common : { [x: string]: any; }
1+
=== tests/cases/conformance/salsa/def.js ===
2+
var Outer = {};
3+
>Outer : { [x: string]: any; }
44
>{} : { [x: string]: any; }
55

6-
Common.Outer = class {
7-
>Common.Outer = class { constructor() { /** @type {number} */ this.y = 12 }} : typeof (Anonymous class)
8-
>Common.Outer : any
9-
>Common : { [x: string]: any; }
10-
>Outer : any
6+
=== tests/cases/conformance/salsa/a.js ===
7+
Outer.Inner = class {
8+
>Outer.Inner = class { constructor() { /** @type {number} */ this.y = 12 }} : typeof (Anonymous class)
9+
>Outer.Inner : any
10+
>Outer : { [x: string]: any; }
11+
>Inner : any
1112
>class { constructor() { /** @type {number} */ this.y = 12 }} : typeof (Anonymous class)
1213

1314
constructor() {
@@ -21,7 +22,8 @@ Common.Outer = class {
2122
}
2223
}
2324

24-
/** @type {Common.Outer} */
25+
=== tests/cases/conformance/salsa/b.js ===
26+
/** @type {Outer.Inner} */
2527
var x;
2628
>x : (Anonymous class)
2729

tests/baselines/reference/typeFromPropertyAssignment5.errors.txt

Lines changed: 0 additions & 21 deletions
This file was deleted.

tests/baselines/reference/typeFromPropertyAssignment5.symbols

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,26 @@
11
=== tests/cases/conformance/salsa/a.js ===
22
export default function MyClass() {
3-
>MyClass : Symbol(MyClass, Decl(a.js, 0, 0))
3+
>MyClass : Symbol(MyClass, Decl(a.js, 0, 0), Decl(a.js, 1, 1))
44
}
55
MyClass.bar = class C {
6-
>MyClass : Symbol(MyClass, Decl(a.js, 0, 0))
6+
>MyClass.bar : Symbol(MyClass.bar, Decl(a.js, 1, 1))
7+
>MyClass : Symbol(MyClass, Decl(a.js, 0, 0), Decl(a.js, 1, 1))
8+
>bar : Symbol(MyClass.bar, Decl(a.js, 1, 1))
79
>C : Symbol(C, Decl(a.js, 2, 13))
810
}
911
MyClass.bar
10-
>MyClass : Symbol(MyClass, Decl(a.js, 0, 0))
12+
>MyClass.bar : Symbol(MyClass.bar, Decl(a.js, 1, 1))
13+
>MyClass : Symbol(MyClass, Decl(a.js, 0, 0), Decl(a.js, 1, 1))
14+
>bar : Symbol(MyClass.bar, Decl(a.js, 1, 1))
1115

1216
=== tests/cases/conformance/salsa/b.js ===
1317
import MC from './a'
1418
>MC : Symbol(MC, Decl(b.js, 0, 6))
1519

1620
MC.bar
21+
>MC.bar : Symbol(MC.bar, Decl(a.js, 1, 1))
1722
>MC : Symbol(MC, Decl(b.js, 0, 6))
23+
>bar : Symbol(MC.bar, Decl(a.js, 1, 1))
1824

1925
/** @type {MC.bar} */
2026
var x
Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,30 +1,30 @@
11
=== tests/cases/conformance/salsa/a.js ===
22
export default function MyClass() {
3-
>MyClass : () => void
3+
>MyClass : typeof MyClass
44
}
55
MyClass.bar = class C {
66
>MyClass.bar = class C {} : typeof C
7-
>MyClass.bar : any
8-
>MyClass : any
9-
>bar : any
7+
>MyClass.bar : typeof C
8+
>MyClass : typeof MyClass
9+
>bar : typeof C
1010
>class C {} : typeof C
1111
>C : typeof C
1212
}
1313
MyClass.bar
14-
>MyClass.bar : any
15-
>MyClass : any
16-
>bar : any
14+
>MyClass.bar : typeof C
15+
>MyClass : typeof MyClass
16+
>bar : typeof C
1717

1818
=== tests/cases/conformance/salsa/b.js ===
1919
import MC from './a'
20-
>MC : () => void
20+
>MC : typeof MC
2121

2222
MC.bar
23-
>MC.bar : any
24-
>MC : () => void
25-
>bar : any
23+
>MC.bar : typeof C
24+
>MC : typeof MC
25+
>bar : typeof C
2626

2727
/** @type {MC.bar} */
2828
var x
29-
>x : any
29+
>x : C
3030

Lines changed: 24 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,27 +1,35 @@
1-
=== tests/cases/conformance/salsa/a.js ===
2-
var Outer = class { }
3-
>Outer : Symbol(Outer, Decl(a.js, 0, 3), Decl(a.js, 0, 21), Decl(a.js, 3, 1))
1+
=== tests/cases/conformance/salsa/def.js ===
2+
class Outer {}
3+
>Outer : Symbol(Outer, Decl(def.js, 0, 0), Decl(a.js, 0, 0))
44

5-
Outer.Inner = class {
6-
>Outer.Inner : Symbol(Outer.Inner, Decl(a.js, 0, 21))
7-
>Outer : Symbol(Outer, Decl(a.js, 0, 3), Decl(a.js, 0, 21), Decl(a.js, 3, 1))
8-
>Inner : Symbol(Outer.Inner, Decl(a.js, 0, 21))
5+
=== tests/cases/conformance/salsa/a.js ===
6+
Outer.Inner = class I {
7+
>Outer.Inner : Symbol(Outer.Inner, Decl(a.js, 0, 0))
8+
>Outer : Symbol(Outer, Decl(def.js, 0, 0), Decl(a.js, 0, 0))
9+
>Inner : Symbol(Outer.Inner, Decl(a.js, 0, 0))
10+
>I : Symbol(I, Decl(a.js, 0, 13))
911

1012
messages() { return [] }
11-
>messages : Symbol((Anonymous class).messages, Decl(a.js, 1, 21))
13+
>messages : Symbol(I.messages, Decl(a.js, 0, 23))
1214
}
1315
/** @type {!Outer.Inner} */
1416
Outer.i
15-
>Outer.i : Symbol(Outer.i, Decl(a.js, 3, 1))
16-
>Outer : Symbol(Outer, Decl(a.js, 0, 3), Decl(a.js, 0, 21), Decl(a.js, 3, 1))
17-
>i : Symbol(Outer.i, Decl(a.js, 3, 1))
17+
>Outer.i : Symbol(Outer.i, Decl(a.js, 2, 1))
18+
>Outer : Symbol(Outer, Decl(def.js, 0, 0), Decl(a.js, 0, 0))
19+
>i : Symbol(Outer.i, Decl(a.js, 2, 1))
1820

1921
=== tests/cases/conformance/salsa/b.js ===
2022
var msgs = Outer.i.messages()
2123
>msgs : Symbol(msgs, Decl(b.js, 0, 3))
22-
>Outer.i.messages : Symbol((Anonymous class).messages, Decl(a.js, 1, 21))
23-
>Outer.i : Symbol(Outer.i, Decl(a.js, 3, 1))
24-
>Outer : Symbol(Outer, Decl(a.js, 0, 3), Decl(a.js, 0, 21), Decl(a.js, 3, 1))
25-
>i : Symbol(Outer.i, Decl(a.js, 3, 1))
26-
>messages : Symbol((Anonymous class).messages, Decl(a.js, 1, 21))
24+
>Outer.i.messages : Symbol(I.messages, Decl(a.js, 0, 23))
25+
>Outer.i : Symbol(Outer.i, Decl(a.js, 2, 1))
26+
>Outer : Symbol(Outer, Decl(def.js, 0, 0), Decl(a.js, 0, 0))
27+
>i : Symbol(Outer.i, Decl(a.js, 2, 1))
28+
>messages : Symbol(I.messages, Decl(a.js, 0, 23))
29+
30+
/** @param {Outer.Inner} inner */
31+
function x(inner) {
32+
>x : Symbol(x, Decl(b.js, 0, 29))
33+
>inner : Symbol(inner, Decl(b.js, 3, 11))
34+
}
2735

Lines changed: 20 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,32 +1,39 @@
1-
=== tests/cases/conformance/salsa/a.js ===
2-
var Outer = class { }
3-
>Outer : typeof Outer
4-
>class { } : typeof Outer
1+
=== tests/cases/conformance/salsa/def.js ===
2+
class Outer {}
3+
>Outer : Outer
54

6-
Outer.Inner = class {
7-
>Outer.Inner = class { messages() { return [] }} : typeof (Anonymous class)
8-
>Outer.Inner : typeof (Anonymous class)
5+
=== tests/cases/conformance/salsa/a.js ===
6+
Outer.Inner = class I {
7+
>Outer.Inner = class I { messages() { return [] }} : typeof I
8+
>Outer.Inner : typeof I
99
>Outer : typeof Outer
10-
>Inner : typeof (Anonymous class)
11-
>class { messages() { return [] }} : typeof (Anonymous class)
10+
>Inner : typeof I
11+
>class I { messages() { return [] }} : typeof I
12+
>I : typeof I
1213

1314
messages() { return [] }
1415
>messages : () => any[]
1516
>[] : undefined[]
1617
}
1718
/** @type {!Outer.Inner} */
1819
Outer.i
19-
>Outer.i : (Anonymous class)
20+
>Outer.i : I
2021
>Outer : typeof Outer
21-
>i : (Anonymous class)
22+
>i : I
2223

2324
=== tests/cases/conformance/salsa/b.js ===
2425
var msgs = Outer.i.messages()
2526
>msgs : any[]
2627
>Outer.i.messages() : any[]
2728
>Outer.i.messages : () => any[]
28-
>Outer.i : (Anonymous class)
29+
>Outer.i : I
2930
>Outer : typeof Outer
30-
>i : (Anonymous class)
31+
>i : I
3132
>messages : () => any[]
3233

34+
/** @param {Outer.Inner} inner */
35+
function x(inner) {
36+
>x : (inner: I) => void
37+
>inner : I
38+
}
39+

0 commit comments

Comments
 (0)