Skip to content

Commit 0e3ffb5

Browse files
committed
Don't crash when JS class property is self-referential.
Fixes microsoft#9293
1 parent 851a75e commit 0e3ffb5

File tree

4 files changed

+62
-9
lines changed

4 files changed

+62
-9
lines changed

src/compiler/checker.ts

Lines changed: 15 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -3147,23 +3147,29 @@ namespace ts {
31473147
if (declaration.kind === SyntaxKind.ExportAssignment) {
31483148
return links.type = checkExpression((<ExportAssignment>declaration).expression);
31493149
}
3150-
// Handle module.exports = expr
3150+
// Handle variable, parameter or property
3151+
if (!pushTypeResolution(symbol, TypeSystemPropertyName.Type)) {
3152+
return unknownType;
3153+
}
3154+
3155+
let type: Type = undefined;
3156+
// Handle module.exports = expr or this.p = expr
31513157
if (declaration.kind === SyntaxKind.BinaryExpression) {
3152-
return links.type = getUnionType(map(symbol.declarations, (decl: BinaryExpression) => checkExpressionCached(decl.right)));
3158+
type = getUnionType(map(symbol.declarations, (decl: BinaryExpression) => checkExpressionCached(decl.right)));
31533159
}
3154-
if (declaration.kind === SyntaxKind.PropertyAccessExpression) {
3160+
else if (declaration.kind === SyntaxKind.PropertyAccessExpression) {
31553161
// Declarations only exist for property access expressions for certain
31563162
// special assignment kinds
31573163
if (declaration.parent.kind === SyntaxKind.BinaryExpression) {
3158-
// Handle exports.p = expr or this.p = expr or className.prototype.method = expr
3159-
return links.type = checkExpressionCached((<BinaryExpression>declaration.parent).right);
3164+
// Handle exports.p = expr or className.prototype.method = expr
3165+
type = checkExpressionCached((<BinaryExpression>declaration.parent).right);
31603166
}
31613167
}
3162-
// Handle variable, parameter or property
3163-
if (!pushTypeResolution(symbol, TypeSystemPropertyName.Type)) {
3164-
return unknownType;
3168+
3169+
if (type === undefined) {
3170+
type = getWidenedTypeForVariableLikeDeclaration(<VariableLikeDeclaration>declaration, /*reportErrors*/ true);
31653171
}
3166-
let type = getWidenedTypeForVariableLikeDeclaration(<VariableLikeDeclaration>declaration, /*reportErrors*/ true);
3172+
31673173
if (!popTypeResolution()) {
31683174
if ((<VariableLikeDeclaration>symbol.valueDeclaration).type) {
31693175
// Variable has type annotation that circularly references the variable itself
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
=== tests/cases/compiler/foo.js ===
2+
3+
export class StackOverflowTest {
4+
>StackOverflowTest : Symbol(StackOverflowTest, Decl(foo.js, 0, 0))
5+
6+
constructor () {
7+
this.testStackOverflow = this.testStackOverflow.bind(this)
8+
>this.testStackOverflow : Symbol(StackOverflowTest.testStackOverflow, Decl(foo.js, 2, 18))
9+
>this : Symbol(StackOverflowTest, Decl(foo.js, 0, 0))
10+
>testStackOverflow : Symbol(StackOverflowTest.testStackOverflow, Decl(foo.js, 2, 18))
11+
>this.testStackOverflow : Symbol(StackOverflowTest.testStackOverflow, Decl(foo.js, 2, 18))
12+
>this : Symbol(StackOverflowTest, Decl(foo.js, 0, 0))
13+
>testStackOverflow : Symbol(StackOverflowTest.testStackOverflow, Decl(foo.js, 2, 18))
14+
>this : Symbol(StackOverflowTest, Decl(foo.js, 0, 0))
15+
}
16+
}
17+
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
=== tests/cases/compiler/foo.js ===
2+
3+
export class StackOverflowTest {
4+
>StackOverflowTest : StackOverflowTest
5+
6+
constructor () {
7+
this.testStackOverflow = this.testStackOverflow.bind(this)
8+
>this.testStackOverflow = this.testStackOverflow.bind(this) : any
9+
>this.testStackOverflow : any
10+
>this : this
11+
>testStackOverflow : any
12+
>this.testStackOverflow.bind(this) : any
13+
>this.testStackOverflow.bind : any
14+
>this.testStackOverflow : any
15+
>this : this
16+
>testStackOverflow : any
17+
>bind : any
18+
>this : this
19+
}
20+
}
21+
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
// @allowJs: true
2+
// @noEmit: true
3+
4+
// @filename: foo.js
5+
export class StackOverflowTest {
6+
constructor () {
7+
this.testStackOverflow = this.testStackOverflow.bind(this)
8+
}
9+
}

0 commit comments

Comments
 (0)