From 0e3ffb5fbe1e8be5732e71441f5e3fba7bb89213 Mon Sep 17 00:00:00 2001 From: Ryan Cavanaugh Date: Tue, 21 Jun 2016 15:40:26 -0700 Subject: [PATCH 1/3] Don't crash when JS class property is self-referential. Fixes #9293 --- src/compiler/checker.ts | 32 +++++++++++-------- .../jsFileClassSelfReferencedProperty.symbols | 17 ++++++++++ .../jsFileClassSelfReferencedProperty.types | 21 ++++++++++++ .../jsFileClassSelfReferencedProperty.ts | 9 ++++++ 4 files changed, 66 insertions(+), 13 deletions(-) create mode 100644 tests/baselines/reference/jsFileClassSelfReferencedProperty.symbols create mode 100644 tests/baselines/reference/jsFileClassSelfReferencedProperty.types create mode 100644 tests/cases/compiler/jsFileClassSelfReferencedProperty.ts diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index ac8a47a9913..054983f0d97 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -3147,23 +3147,29 @@ namespace ts { if (declaration.kind === SyntaxKind.ExportAssignment) { return links.type = checkExpression((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((declaration.parent).right); - } - } // Handle variable, parameter or property if (!pushTypeResolution(symbol, TypeSystemPropertyName.Type)) { return unknownType; } - let type = getWidenedTypeForVariableLikeDeclaration(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((declaration.parent).right); + } + } + + if (type === undefined) { + type = getWidenedTypeForVariableLikeDeclaration(declaration, /*reportErrors*/ true); + } + if (!popTypeResolution()) { if ((symbol.valueDeclaration).type) { // Variable has type annotation that circularly references the variable itself diff --git a/tests/baselines/reference/jsFileClassSelfReferencedProperty.symbols b/tests/baselines/reference/jsFileClassSelfReferencedProperty.symbols new file mode 100644 index 00000000000..2d9626897bf --- /dev/null +++ b/tests/baselines/reference/jsFileClassSelfReferencedProperty.symbols @@ -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)) + } +} + diff --git a/tests/baselines/reference/jsFileClassSelfReferencedProperty.types b/tests/baselines/reference/jsFileClassSelfReferencedProperty.types new file mode 100644 index 00000000000..44344ac1472 --- /dev/null +++ b/tests/baselines/reference/jsFileClassSelfReferencedProperty.types @@ -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 + } +} + diff --git a/tests/cases/compiler/jsFileClassSelfReferencedProperty.ts b/tests/cases/compiler/jsFileClassSelfReferencedProperty.ts new file mode 100644 index 00000000000..8d6cecdb200 --- /dev/null +++ b/tests/cases/compiler/jsFileClassSelfReferencedProperty.ts @@ -0,0 +1,9 @@ +// @allowJs: true +// @noEmit: true + +// @filename: foo.js +export class StackOverflowTest { + constructor () { + this.testStackOverflow = this.testStackOverflow.bind(this) + } +} From c4f8fb2bc2e7176c0f5a3a07e590f06881661cf6 Mon Sep 17 00:00:00 2001 From: Ryan Cavanaugh Date: Tue, 21 Jun 2016 15:40:38 -0700 Subject: [PATCH 2/3] Remove stale baselines --- .../constDeclarations-useBeforeDefinition2.symbols | 9 --------- .../constDeclarations-useBeforeDefinition2.types | 10 ---------- .../letDeclarations-useBeforeDefinition2.symbols | 9 --------- .../letDeclarations-useBeforeDefinition2.types | 10 ---------- ...n compiler-options input is empty object.errors.txt | 6 ------ ...rror when compiler-options input is empty object.js | 2 -- ...n compiler-options input is empty string.errors.txt | 6 ------ ...rror when compiler-options input is empty string.js | 2 -- 8 files changed, 54 deletions(-) delete mode 100644 tests/baselines/reference/constDeclarations-useBeforeDefinition2.symbols delete mode 100644 tests/baselines/reference/constDeclarations-useBeforeDefinition2.types delete mode 100644 tests/baselines/reference/letDeclarations-useBeforeDefinition2.symbols delete mode 100644 tests/baselines/reference/letDeclarations-useBeforeDefinition2.types delete mode 100644 tests/baselines/reference/transpile/Report an error when compiler-options input is empty object.errors.txt delete mode 100644 tests/baselines/reference/transpile/Report an error when compiler-options input is empty object.js delete mode 100644 tests/baselines/reference/transpile/Report an error when compiler-options input is empty string.errors.txt delete mode 100644 tests/baselines/reference/transpile/Report an error when compiler-options input is empty string.js diff --git a/tests/baselines/reference/constDeclarations-useBeforeDefinition2.symbols b/tests/baselines/reference/constDeclarations-useBeforeDefinition2.symbols deleted file mode 100644 index 281ce427733..00000000000 --- a/tests/baselines/reference/constDeclarations-useBeforeDefinition2.symbols +++ /dev/null @@ -1,9 +0,0 @@ -=== tests/cases/compiler/file1.ts === - -c; ->c : Symbol(c, Decl(file2.ts, 0, 5)) - -=== tests/cases/compiler/file2.ts === -const c = 0; ->c : Symbol(c, Decl(file2.ts, 0, 5)) - diff --git a/tests/baselines/reference/constDeclarations-useBeforeDefinition2.types b/tests/baselines/reference/constDeclarations-useBeforeDefinition2.types deleted file mode 100644 index ae60fdfa477..00000000000 --- a/tests/baselines/reference/constDeclarations-useBeforeDefinition2.types +++ /dev/null @@ -1,10 +0,0 @@ -=== tests/cases/compiler/file1.ts === - -c; ->c : number - -=== tests/cases/compiler/file2.ts === -const c = 0; ->c : number ->0 : number - diff --git a/tests/baselines/reference/letDeclarations-useBeforeDefinition2.symbols b/tests/baselines/reference/letDeclarations-useBeforeDefinition2.symbols deleted file mode 100644 index c5a067ede4d..00000000000 --- a/tests/baselines/reference/letDeclarations-useBeforeDefinition2.symbols +++ /dev/null @@ -1,9 +0,0 @@ -=== tests/cases/compiler/file1.ts === - -l; ->l : Symbol(l, Decl(file2.ts, 0, 5)) - -=== tests/cases/compiler/file2.ts === -const l = 0; ->l : Symbol(l, Decl(file2.ts, 0, 5)) - diff --git a/tests/baselines/reference/letDeclarations-useBeforeDefinition2.types b/tests/baselines/reference/letDeclarations-useBeforeDefinition2.types deleted file mode 100644 index 793a7a78ba7..00000000000 --- a/tests/baselines/reference/letDeclarations-useBeforeDefinition2.types +++ /dev/null @@ -1,10 +0,0 @@ -=== tests/cases/compiler/file1.ts === - -l; ->l : number - -=== tests/cases/compiler/file2.ts === -const l = 0; ->l : number ->0 : number - diff --git a/tests/baselines/reference/transpile/Report an error when compiler-options input is empty object.errors.txt b/tests/baselines/reference/transpile/Report an error when compiler-options input is empty object.errors.txt deleted file mode 100644 index d7d6eb69300..00000000000 --- a/tests/baselines/reference/transpile/Report an error when compiler-options input is empty object.errors.txt +++ /dev/null @@ -1,6 +0,0 @@ -error TS6046: Argument for '--module' option must be: 'none', 'commonjs', 'amd', 'system', 'umd', 'es6', 'es2015' - - -!!! error TS6046: Argument for '--module' option must be: 'none', 'commonjs', 'amd', 'system', 'umd', 'es6', 'es2015' -==== file.ts (0 errors) ==== - \ No newline at end of file diff --git a/tests/baselines/reference/transpile/Report an error when compiler-options input is empty object.js b/tests/baselines/reference/transpile/Report an error when compiler-options input is empty object.js deleted file mode 100644 index 1ceb1bcd146..00000000000 --- a/tests/baselines/reference/transpile/Report an error when compiler-options input is empty object.js +++ /dev/null @@ -1,2 +0,0 @@ -"use strict"; -//# sourceMappingURL=file.js.map \ No newline at end of file diff --git a/tests/baselines/reference/transpile/Report an error when compiler-options input is empty string.errors.txt b/tests/baselines/reference/transpile/Report an error when compiler-options input is empty string.errors.txt deleted file mode 100644 index d7d6eb69300..00000000000 --- a/tests/baselines/reference/transpile/Report an error when compiler-options input is empty string.errors.txt +++ /dev/null @@ -1,6 +0,0 @@ -error TS6046: Argument for '--module' option must be: 'none', 'commonjs', 'amd', 'system', 'umd', 'es6', 'es2015' - - -!!! error TS6046: Argument for '--module' option must be: 'none', 'commonjs', 'amd', 'system', 'umd', 'es6', 'es2015' -==== file.ts (0 errors) ==== - \ No newline at end of file diff --git a/tests/baselines/reference/transpile/Report an error when compiler-options input is empty string.js b/tests/baselines/reference/transpile/Report an error when compiler-options input is empty string.js deleted file mode 100644 index 1ceb1bcd146..00000000000 --- a/tests/baselines/reference/transpile/Report an error when compiler-options input is empty string.js +++ /dev/null @@ -1,2 +0,0 @@ -"use strict"; -//# sourceMappingURL=file.js.map \ No newline at end of file From 66c30931a9524fa22594f4c6e1309c5aac62121d Mon Sep 17 00:00:00 2001 From: Ryan Cavanaugh Date: Tue, 21 Jun 2016 16:13:11 -0700 Subject: [PATCH 3/3] Lint --- src/compiler/checker.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 054983f0d97..570f15f5ebd 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -3169,7 +3169,7 @@ namespace ts { if (type === undefined) { type = getWidenedTypeForVariableLikeDeclaration(declaration, /*reportErrors*/ true); } - + if (!popTypeResolution()) { if ((symbol.valueDeclaration).type) { // Variable has type annotation that circularly references the variable itself