Skip to content

Commit d6250c8

Browse files
authored
Fix circularity error when extending class in same JSContainer (microsoft#24710)
Do this by not widening properties of an object literal that are 1. JS initialisers 2. and not an object literal These properties have types that will never widen, so the compiler shouldn't ask for the types earlier than it strictly needs to.
1 parent 0db52da commit d6250c8

4 files changed

Lines changed: 174 additions & 5 deletions

File tree

src/compiler/checker.ts

Lines changed: 16 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -12170,6 +12170,19 @@ namespace ts {
1217012170
}
1217112171

1217212172
function getWidenedProperty(prop: Symbol, context: WideningContext | undefined): Symbol {
12173+
if (!(prop.flags & SymbolFlags.Property)) {
12174+
// Since get accessors already widen their return value there is no need to
12175+
// widen accessor based properties here.
12176+
return prop;
12177+
}
12178+
if (prop.flags & SymbolFlags.JSContainer) {
12179+
const node = prop.declarations && first(prop.declarations);
12180+
const init = getAssignedJavascriptInitializer(node);
12181+
if (init && init.kind !== SyntaxKind.ObjectLiteralExpression) {
12182+
// for JS special declarations, the only kind of initializer that will widen is object literals
12183+
return prop;
12184+
}
12185+
}
1217312186
const original = getTypeOfSymbol(prop);
1217412187
const propContext = context && createWideningContext(context, prop.escapedName, /*siblings*/ undefined);
1217512188
const widened = getWidenedTypeWithContext(original, propContext);
@@ -12190,9 +12203,7 @@ namespace ts {
1219012203
function getWidenedTypeOfObjectLiteral(type: Type, context: WideningContext | undefined): Type {
1219112204
const members = createSymbolTable();
1219212205
for (const prop of getPropertiesOfObjectType(type)) {
12193-
// Since get accessors already widen their return value there is no need to
12194-
// widen accessor based properties here.
12195-
members.set(prop.escapedName, prop.flags & SymbolFlags.Property ? getWidenedProperty(prop, context) : prop);
12206+
members.set(prop.escapedName, getWidenedProperty(prop, context));
1219612207
}
1219712208
if (context) {
1219812209
for (const prop of getPropertiesOfContext(context)) {
@@ -15984,10 +15995,10 @@ namespace ts {
1598415995
const decl = getDeclarationOfJSInitializer(node);
1598515996
if (decl) {
1598615997
// a JS object literal whose declaration's symbol has exports is a JS namespace
15987-
const symbol = getMergedSymbol(decl.symbol);
15998+
const symbol = getSymbolOfNode(decl);
1598815999
if (symbol && hasEntries(symbol.exports)) {
1598916000
propertiesTable = symbol.exports;
15990-
symbol.exports.forEach(symbol => propertiesArray.push(getMergedSymbol(symbol)));
16001+
symbol.exports.forEach(s => propertiesArray.push(getMergedSymbol(s)));
1599116002
return createObjectLiteralType();
1599216003
}
1599316004
}
Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
=== tests/cases/conformance/salsa/bug24703.js ===
2+
var Common = {};
3+
>Common : Symbol(Common, Decl(bug24703.js, 0, 3), Decl(bug24703.js, 0, 16))
4+
5+
Common.I = class {
6+
>Common.I : Symbol(Common.I, Decl(bug24703.js, 0, 16))
7+
>Common : Symbol(Common, Decl(bug24703.js, 0, 3), Decl(bug24703.js, 0, 16))
8+
>I : Symbol(Common.I, Decl(bug24703.js, 0, 16))
9+
10+
constructor() {
11+
this.i = 1
12+
>this.i : Symbol(I.i, Decl(bug24703.js, 2, 19))
13+
>this : Symbol(I, Decl(bug24703.js, 1, 10))
14+
>i : Symbol(I.i, Decl(bug24703.js, 2, 19))
15+
}
16+
}
17+
Common.O = class extends Common.I {
18+
>Common.O : Symbol(Common.O, Decl(bug24703.js, 5, 1))
19+
>Common : Symbol(Common, Decl(bug24703.js, 0, 3), Decl(bug24703.js, 0, 16))
20+
>O : Symbol(Common.O, Decl(bug24703.js, 5, 1))
21+
>Common.I : Symbol(Common.I, Decl(bug24703.js, 0, 16))
22+
>Common : Symbol(Common, Decl(bug24703.js, 0, 3), Decl(bug24703.js, 0, 16))
23+
>I : Symbol(Common.I, Decl(bug24703.js, 0, 16))
24+
25+
constructor() {
26+
super()
27+
>super : Symbol(I, Decl(bug24703.js, 1, 10))
28+
29+
this.o = 2
30+
>this.o : Symbol(O.o, Decl(bug24703.js, 8, 15))
31+
>this : Symbol(O, Decl(bug24703.js, 6, 10))
32+
>o : Symbol(O.o, Decl(bug24703.js, 8, 15))
33+
}
34+
}
35+
var o = new Common.O()
36+
>o : Symbol(o, Decl(bug24703.js, 12, 3))
37+
>Common.O : Symbol(Common.O, Decl(bug24703.js, 5, 1))
38+
>Common : Symbol(Common, Decl(bug24703.js, 0, 3), Decl(bug24703.js, 0, 16))
39+
>O : Symbol(Common.O, Decl(bug24703.js, 5, 1))
40+
41+
var i = new Common.I()
42+
>i : Symbol(i, Decl(bug24703.js, 13, 3))
43+
>Common.I : Symbol(Common.I, Decl(bug24703.js, 0, 16))
44+
>Common : Symbol(Common, Decl(bug24703.js, 0, 3), Decl(bug24703.js, 0, 16))
45+
>I : Symbol(Common.I, Decl(bug24703.js, 0, 16))
46+
47+
o.i
48+
>o.i : Symbol(I.i, Decl(bug24703.js, 2, 19))
49+
>o : Symbol(o, Decl(bug24703.js, 12, 3))
50+
>i : Symbol(I.i, Decl(bug24703.js, 2, 19))
51+
52+
o.o
53+
>o.o : Symbol(O.o, Decl(bug24703.js, 8, 15))
54+
>o : Symbol(o, Decl(bug24703.js, 12, 3))
55+
>o : Symbol(O.o, Decl(bug24703.js, 8, 15))
56+
57+
i.i
58+
>i.i : Symbol(I.i, Decl(bug24703.js, 2, 19))
59+
>i : Symbol(i, Decl(bug24703.js, 13, 3))
60+
>i : Symbol(I.i, Decl(bug24703.js, 2, 19))
61+
62+
Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
=== tests/cases/conformance/salsa/bug24703.js ===
2+
var Common = {};
3+
>Common : { [x: string]: any; I: typeof I; O: typeof O; }
4+
>{} : { [x: string]: any; I: typeof I; O: typeof O; }
5+
6+
Common.I = class {
7+
>Common.I = class { constructor() { this.i = 1 }} : typeof I
8+
>Common.I : typeof I
9+
>Common : { [x: string]: any; I: typeof I; O: typeof O; }
10+
>I : typeof I
11+
>class { constructor() { this.i = 1 }} : typeof I
12+
13+
constructor() {
14+
this.i = 1
15+
>this.i = 1 : 1
16+
>this.i : number
17+
>this : this
18+
>i : number
19+
>1 : 1
20+
}
21+
}
22+
Common.O = class extends Common.I {
23+
>Common.O = class extends Common.I { constructor() { super() this.o = 2 }} : typeof O
24+
>Common.O : typeof O
25+
>Common : { [x: string]: any; I: typeof I; O: typeof O; }
26+
>O : typeof O
27+
>class extends Common.I { constructor() { super() this.o = 2 }} : typeof O
28+
>Common.I : I
29+
>Common : { [x: string]: any; I: typeof I; O: typeof O; }
30+
>I : typeof I
31+
32+
constructor() {
33+
super()
34+
>super() : void
35+
>super : typeof I
36+
37+
this.o = 2
38+
>this.o = 2 : 2
39+
>this.o : number
40+
>this : this
41+
>o : number
42+
>2 : 2
43+
}
44+
}
45+
var o = new Common.O()
46+
>o : O
47+
>new Common.O() : O
48+
>Common.O : typeof O
49+
>Common : { [x: string]: any; I: typeof I; O: typeof O; }
50+
>O : typeof O
51+
52+
var i = new Common.I()
53+
>i : I
54+
>new Common.I() : I
55+
>Common.I : typeof I
56+
>Common : { [x: string]: any; I: typeof I; O: typeof O; }
57+
>I : typeof I
58+
59+
o.i
60+
>o.i : number
61+
>o : O
62+
>i : number
63+
64+
o.o
65+
>o.o : number
66+
>o : O
67+
>o : number
68+
69+
i.i
70+
>i.i : number
71+
>i : I
72+
>i : number
73+
74+
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
// @noEmit: true
2+
// @checkJs: true
3+
// @allowJs: true
4+
// @Filename: bug24703.js
5+
var Common = {};
6+
Common.I = class {
7+
constructor() {
8+
this.i = 1
9+
}
10+
}
11+
Common.O = class extends Common.I {
12+
constructor() {
13+
super()
14+
this.o = 2
15+
}
16+
}
17+
var o = new Common.O()
18+
var i = new Common.I()
19+
o.i
20+
o.o
21+
i.i
22+

0 commit comments

Comments
 (0)