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 | 24 ++++++++++++------- .../jsFileClassSelfReferencedProperty.symbols | 17 +++++++++++++ .../jsFileClassSelfReferencedProperty.types | 21 ++++++++++++++++ .../jsFileClassSelfReferencedProperty.ts | 9 +++++++ 4 files changed, 62 insertions(+), 9 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 ac8a47a991379..054983f0d979d 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 + // Handle variable, parameter or property + if (!pushTypeResolution(symbol, TypeSystemPropertyName.Type)) { + return unknownType; + } + + let type: Type = undefined; + // Handle module.exports = expr or this.p = expr if (declaration.kind === SyntaxKind.BinaryExpression) { - return links.type = getUnionType(map(symbol.declarations, (decl: BinaryExpression) => checkExpressionCached(decl.right))); + type = getUnionType(map(symbol.declarations, (decl: BinaryExpression) => checkExpressionCached(decl.right))); } - if (declaration.kind === SyntaxKind.PropertyAccessExpression) { + 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 this.p = expr or className.prototype.method = expr - return links.type = checkExpressionCached((declaration.parent).right); + // Handle exports.p = expr or className.prototype.method = expr + type = checkExpressionCached((declaration.parent).right); } } - // Handle variable, parameter or property - if (!pushTypeResolution(symbol, TypeSystemPropertyName.Type)) { - return unknownType; + + if (type === undefined) { + type = getWidenedTypeForVariableLikeDeclaration(declaration, /*reportErrors*/ true); } - let 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 0000000000000..2d9626897bfd5 --- /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 0000000000000..44344ac147204 --- /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 0000000000000..8d6cecdb2003b --- /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 281ce4277337f..0000000000000 --- 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 ae60fdfa47728..0000000000000 --- 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 c5a067ede4dd2..0000000000000 --- 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 793a7a78ba71e..0000000000000 --- 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 d7d6eb6930028..0000000000000 --- 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 1ceb1bcd1464c..0000000000000 --- 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 d7d6eb6930028..0000000000000 --- 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 1ceb1bcd1464c..0000000000000 --- 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 054983f0d979d..570f15f5ebd0e 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