Fix circularity error when extending class in same JSContainer (#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.
This commit is contained in:
Nathan Shively-Sanders 2018-06-06 09:13:38 -07:00 committed by GitHub
parent 0db52da564
commit d6250c8342
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 174 additions and 5 deletions

View File

@ -12170,6 +12170,19 @@ namespace ts {
}
function getWidenedProperty(prop: Symbol, context: WideningContext | undefined): Symbol {
if (!(prop.flags & SymbolFlags.Property)) {
// Since get accessors already widen their return value there is no need to
// widen accessor based properties here.
return prop;
}
if (prop.flags & SymbolFlags.JSContainer) {
const node = prop.declarations && first(prop.declarations);
const init = getAssignedJavascriptInitializer(node);
if (init && init.kind !== SyntaxKind.ObjectLiteralExpression) {
// for JS special declarations, the only kind of initializer that will widen is object literals
return prop;
}
}
const original = getTypeOfSymbol(prop);
const propContext = context && createWideningContext(context, prop.escapedName, /*siblings*/ undefined);
const widened = getWidenedTypeWithContext(original, propContext);
@ -12190,9 +12203,7 @@ namespace ts {
function getWidenedTypeOfObjectLiteral(type: Type, context: WideningContext | undefined): Type {
const members = createSymbolTable();
for (const prop of getPropertiesOfObjectType(type)) {
// Since get accessors already widen their return value there is no need to
// widen accessor based properties here.
members.set(prop.escapedName, prop.flags & SymbolFlags.Property ? getWidenedProperty(prop, context) : prop);
members.set(prop.escapedName, getWidenedProperty(prop, context));
}
if (context) {
for (const prop of getPropertiesOfContext(context)) {
@ -15984,10 +15995,10 @@ namespace ts {
const decl = getDeclarationOfJSInitializer(node);
if (decl) {
// a JS object literal whose declaration's symbol has exports is a JS namespace
const symbol = getMergedSymbol(decl.symbol);
const symbol = getSymbolOfNode(decl);
if (symbol && hasEntries(symbol.exports)) {
propertiesTable = symbol.exports;
symbol.exports.forEach(symbol => propertiesArray.push(getMergedSymbol(symbol)));
symbol.exports.forEach(s => propertiesArray.push(getMergedSymbol(s)));
return createObjectLiteralType();
}
}

View File

@ -0,0 +1,62 @@
=== tests/cases/conformance/salsa/bug24703.js ===
var Common = {};
>Common : Symbol(Common, Decl(bug24703.js, 0, 3), Decl(bug24703.js, 0, 16))
Common.I = class {
>Common.I : Symbol(Common.I, Decl(bug24703.js, 0, 16))
>Common : Symbol(Common, Decl(bug24703.js, 0, 3), Decl(bug24703.js, 0, 16))
>I : Symbol(Common.I, Decl(bug24703.js, 0, 16))
constructor() {
this.i = 1
>this.i : Symbol(I.i, Decl(bug24703.js, 2, 19))
>this : Symbol(I, Decl(bug24703.js, 1, 10))
>i : Symbol(I.i, Decl(bug24703.js, 2, 19))
}
}
Common.O = class extends Common.I {
>Common.O : Symbol(Common.O, Decl(bug24703.js, 5, 1))
>Common : Symbol(Common, Decl(bug24703.js, 0, 3), Decl(bug24703.js, 0, 16))
>O : Symbol(Common.O, Decl(bug24703.js, 5, 1))
>Common.I : Symbol(Common.I, Decl(bug24703.js, 0, 16))
>Common : Symbol(Common, Decl(bug24703.js, 0, 3), Decl(bug24703.js, 0, 16))
>I : Symbol(Common.I, Decl(bug24703.js, 0, 16))
constructor() {
super()
>super : Symbol(I, Decl(bug24703.js, 1, 10))
this.o = 2
>this.o : Symbol(O.o, Decl(bug24703.js, 8, 15))
>this : Symbol(O, Decl(bug24703.js, 6, 10))
>o : Symbol(O.o, Decl(bug24703.js, 8, 15))
}
}
var o = new Common.O()
>o : Symbol(o, Decl(bug24703.js, 12, 3))
>Common.O : Symbol(Common.O, Decl(bug24703.js, 5, 1))
>Common : Symbol(Common, Decl(bug24703.js, 0, 3), Decl(bug24703.js, 0, 16))
>O : Symbol(Common.O, Decl(bug24703.js, 5, 1))
var i = new Common.I()
>i : Symbol(i, Decl(bug24703.js, 13, 3))
>Common.I : Symbol(Common.I, Decl(bug24703.js, 0, 16))
>Common : Symbol(Common, Decl(bug24703.js, 0, 3), Decl(bug24703.js, 0, 16))
>I : Symbol(Common.I, Decl(bug24703.js, 0, 16))
o.i
>o.i : Symbol(I.i, Decl(bug24703.js, 2, 19))
>o : Symbol(o, Decl(bug24703.js, 12, 3))
>i : Symbol(I.i, Decl(bug24703.js, 2, 19))
o.o
>o.o : Symbol(O.o, Decl(bug24703.js, 8, 15))
>o : Symbol(o, Decl(bug24703.js, 12, 3))
>o : Symbol(O.o, Decl(bug24703.js, 8, 15))
i.i
>i.i : Symbol(I.i, Decl(bug24703.js, 2, 19))
>i : Symbol(i, Decl(bug24703.js, 13, 3))
>i : Symbol(I.i, Decl(bug24703.js, 2, 19))

View File

@ -0,0 +1,74 @@
=== tests/cases/conformance/salsa/bug24703.js ===
var Common = {};
>Common : { [x: string]: any; I: typeof I; O: typeof O; }
>{} : { [x: string]: any; I: typeof I; O: typeof O; }
Common.I = class {
>Common.I = class { constructor() { this.i = 1 }} : typeof I
>Common.I : typeof I
>Common : { [x: string]: any; I: typeof I; O: typeof O; }
>I : typeof I
>class { constructor() { this.i = 1 }} : typeof I
constructor() {
this.i = 1
>this.i = 1 : 1
>this.i : number
>this : this
>i : number
>1 : 1
}
}
Common.O = class extends Common.I {
>Common.O = class extends Common.I { constructor() { super() this.o = 2 }} : typeof O
>Common.O : typeof O
>Common : { [x: string]: any; I: typeof I; O: typeof O; }
>O : typeof O
>class extends Common.I { constructor() { super() this.o = 2 }} : typeof O
>Common.I : I
>Common : { [x: string]: any; I: typeof I; O: typeof O; }
>I : typeof I
constructor() {
super()
>super() : void
>super : typeof I
this.o = 2
>this.o = 2 : 2
>this.o : number
>this : this
>o : number
>2 : 2
}
}
var o = new Common.O()
>o : O
>new Common.O() : O
>Common.O : typeof O
>Common : { [x: string]: any; I: typeof I; O: typeof O; }
>O : typeof O
var i = new Common.I()
>i : I
>new Common.I() : I
>Common.I : typeof I
>Common : { [x: string]: any; I: typeof I; O: typeof O; }
>I : typeof I
o.i
>o.i : number
>o : O
>i : number
o.o
>o.o : number
>o : O
>o : number
i.i
>i.i : number
>i : I
>i : number

View File

@ -0,0 +1,22 @@
// @noEmit: true
// @checkJs: true
// @allowJs: true
// @Filename: bug24703.js
var Common = {};
Common.I = class {
constructor() {
this.i = 1
}
}
Common.O = class extends Common.I {
constructor() {
super()
this.o = 2
}
}
var o = new Common.O()
var i = new Common.I()
o.i
o.o
i.i