Don't crash when JS class property is self-referential.

Fixes #9293
This commit is contained in:
Ryan Cavanaugh
2016-06-21 15:40:26 -07:00
parent 851a75ef5e
commit 0e3ffb5fbe
4 changed files with 66 additions and 13 deletions

View File

@@ -3147,23 +3147,29 @@ namespace ts {
if (declaration.kind === SyntaxKind.ExportAssignment) {
return links.type = checkExpression((<ExportAssignment>declaration).expression);
}
// Handle module.exports = expr
if (declaration.kind === SyntaxKind.BinaryExpression) {
return links.type = getUnionType(map(symbol.declarations, (decl: BinaryExpression) => checkExpressionCached(decl.right)));
}
if (declaration.kind === SyntaxKind.PropertyAccessExpression) {
// Declarations only exist for property access expressions for certain
// special assignment kinds
if (declaration.parent.kind === SyntaxKind.BinaryExpression) {
// Handle exports.p = expr or this.p = expr or className.prototype.method = expr
return links.type = checkExpressionCached((<BinaryExpression>declaration.parent).right);
}
}
// Handle variable, parameter or property
if (!pushTypeResolution(symbol, TypeSystemPropertyName.Type)) {
return unknownType;
}
let type = getWidenedTypeForVariableLikeDeclaration(<VariableLikeDeclaration>declaration, /*reportErrors*/ true);
let type: Type = undefined;
// Handle module.exports = expr or this.p = expr
if (declaration.kind === SyntaxKind.BinaryExpression) {
type = getUnionType(map(symbol.declarations, (decl: BinaryExpression) => checkExpressionCached(decl.right)));
}
else if (declaration.kind === SyntaxKind.PropertyAccessExpression) {
// Declarations only exist for property access expressions for certain
// special assignment kinds
if (declaration.parent.kind === SyntaxKind.BinaryExpression) {
// Handle exports.p = expr or className.prototype.method = expr
type = checkExpressionCached((<BinaryExpression>declaration.parent).right);
}
}
if (type === undefined) {
type = getWidenedTypeForVariableLikeDeclaration(<VariableLikeDeclaration>declaration, /*reportErrors*/ true);
}
if (!popTypeResolution()) {
if ((<VariableLikeDeclaration>symbol.valueDeclaration).type) {
// Variable has type annotation that circularly references the variable itself

View File

@@ -0,0 +1,17 @@
=== tests/cases/compiler/foo.js ===
export class StackOverflowTest {
>StackOverflowTest : Symbol(StackOverflowTest, Decl(foo.js, 0, 0))
constructor () {
this.testStackOverflow = this.testStackOverflow.bind(this)
>this.testStackOverflow : Symbol(StackOverflowTest.testStackOverflow, Decl(foo.js, 2, 18))
>this : Symbol(StackOverflowTest, Decl(foo.js, 0, 0))
>testStackOverflow : Symbol(StackOverflowTest.testStackOverflow, Decl(foo.js, 2, 18))
>this.testStackOverflow : Symbol(StackOverflowTest.testStackOverflow, Decl(foo.js, 2, 18))
>this : Symbol(StackOverflowTest, Decl(foo.js, 0, 0))
>testStackOverflow : Symbol(StackOverflowTest.testStackOverflow, Decl(foo.js, 2, 18))
>this : Symbol(StackOverflowTest, Decl(foo.js, 0, 0))
}
}

View File

@@ -0,0 +1,21 @@
=== tests/cases/compiler/foo.js ===
export class StackOverflowTest {
>StackOverflowTest : StackOverflowTest
constructor () {
this.testStackOverflow = this.testStackOverflow.bind(this)
>this.testStackOverflow = this.testStackOverflow.bind(this) : any
>this.testStackOverflow : any
>this : this
>testStackOverflow : any
>this.testStackOverflow.bind(this) : any
>this.testStackOverflow.bind : any
>this.testStackOverflow : any
>this : this
>testStackOverflow : any
>bind : any
>this : this
}
}

View File

@@ -0,0 +1,9 @@
// @allowJs: true
// @noEmit: true
// @filename: foo.js
export class StackOverflowTest {
constructor () {
this.testStackOverflow = this.testStackOverflow.bind(this)
}
}