From 9fac99e6922912916c92689483babd38854d8d1f Mon Sep 17 00:00:00 2001 From: Nathan Shively-Sanders Date: Wed, 8 Jun 2016 14:23:42 -0700 Subject: [PATCH 1/3] Add test case The test passes in 1.8 and fails in master. --- .../inferParameterWithMethodCallInitializer.ts | 12 ++++++++++++ 1 file changed, 12 insertions(+) create mode 100644 tests/cases/compiler/inferParameterWithMethodCallInitializer.ts diff --git a/tests/cases/compiler/inferParameterWithMethodCallInitializer.ts b/tests/cases/compiler/inferParameterWithMethodCallInitializer.ts new file mode 100644 index 00000000000..ba38c7cb909 --- /dev/null +++ b/tests/cases/compiler/inferParameterWithMethodCallInitializer.ts @@ -0,0 +1,12 @@ +// @noImplicitAny: true +function getNumber(): number { + return 1; +} +class Example { + getNumber(): number { + return 1; + } + doSomething(a = this.getNumber()): typeof a { + return a; + } +} From 0c64b0c24e1d6c22f86e784afaafe144ba4b91e0 Mon Sep 17 00:00:00 2001 From: Nathan Shively-Sanders Date: Thu, 9 Jun 2016 12:29:13 -0700 Subject: [PATCH 2/3] this in parameter initializers resolves to class Accept baselines now that the test passes. --- src/compiler/checker.ts | 2 +- ...inferParameterWithMethodCallInitializer.js | 30 +++++++++++++++++++ ...ParameterWithMethodCallInitializer.symbols | 27 +++++++++++++++++ ...erParameterWithMethodCallInitializer.types | 30 +++++++++++++++++++ 4 files changed, 88 insertions(+), 1 deletion(-) create mode 100644 tests/baselines/reference/inferParameterWithMethodCallInitializer.js create mode 100644 tests/baselines/reference/inferParameterWithMethodCallInitializer.symbols create mode 100644 tests/baselines/reference/inferParameterWithMethodCallInitializer.types diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 650bc488b0e..ba866c867e9 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -8392,7 +8392,7 @@ namespace ts { if (needToCaptureLexicalThis) { captureLexicalThis(node, container); } - if (isFunctionLike(container)) { + if (isFunctionLike(container) && !isInParameterInitializerBeforeContainingFunction(node)) { // If this is a function in a JS file, it might be a class method. Check if it's the RHS // of a x.prototype.y = function [name]() { .... } if (container.kind === SyntaxKind.FunctionExpression && diff --git a/tests/baselines/reference/inferParameterWithMethodCallInitializer.js b/tests/baselines/reference/inferParameterWithMethodCallInitializer.js new file mode 100644 index 00000000000..6a5400ca19a --- /dev/null +++ b/tests/baselines/reference/inferParameterWithMethodCallInitializer.js @@ -0,0 +1,30 @@ +//// [inferParameterWithMethodCallInitializer.ts] +function getNumber(): number { + return 1; +} +class Example { + getNumber(): number { + return 1; + } + doSomething(a = this.getNumber()): typeof a { + return a; + } +} + + +//// [inferParameterWithMethodCallInitializer.js] +function getNumber() { + return 1; +} +var Example = (function () { + function Example() { + } + Example.prototype.getNumber = function () { + return 1; + }; + Example.prototype.doSomething = function (a) { + if (a === void 0) { a = this.getNumber(); } + return a; + }; + return Example; +}()); diff --git a/tests/baselines/reference/inferParameterWithMethodCallInitializer.symbols b/tests/baselines/reference/inferParameterWithMethodCallInitializer.symbols new file mode 100644 index 00000000000..e4318fe1ead --- /dev/null +++ b/tests/baselines/reference/inferParameterWithMethodCallInitializer.symbols @@ -0,0 +1,27 @@ +=== tests/cases/compiler/inferParameterWithMethodCallInitializer.ts === +function getNumber(): number { +>getNumber : Symbol(getNumber, Decl(inferParameterWithMethodCallInitializer.ts, 0, 0)) + + return 1; +} +class Example { +>Example : Symbol(Example, Decl(inferParameterWithMethodCallInitializer.ts, 2, 1)) + + getNumber(): number { +>getNumber : Symbol(Example.getNumber, Decl(inferParameterWithMethodCallInitializer.ts, 3, 15)) + + return 1; + } + doSomething(a = this.getNumber()): typeof a { +>doSomething : Symbol(Example.doSomething, Decl(inferParameterWithMethodCallInitializer.ts, 6, 5)) +>a : Symbol(a, Decl(inferParameterWithMethodCallInitializer.ts, 7, 16)) +>this.getNumber : Symbol(Example.getNumber, Decl(inferParameterWithMethodCallInitializer.ts, 3, 15)) +>this : Symbol(Example, Decl(inferParameterWithMethodCallInitializer.ts, 2, 1)) +>getNumber : Symbol(Example.getNumber, Decl(inferParameterWithMethodCallInitializer.ts, 3, 15)) +>a : Symbol(a, Decl(inferParameterWithMethodCallInitializer.ts, 7, 16)) + + return a; +>a : Symbol(a, Decl(inferParameterWithMethodCallInitializer.ts, 7, 16)) + } +} + diff --git a/tests/baselines/reference/inferParameterWithMethodCallInitializer.types b/tests/baselines/reference/inferParameterWithMethodCallInitializer.types new file mode 100644 index 00000000000..53c58e201b7 --- /dev/null +++ b/tests/baselines/reference/inferParameterWithMethodCallInitializer.types @@ -0,0 +1,30 @@ +=== tests/cases/compiler/inferParameterWithMethodCallInitializer.ts === +function getNumber(): number { +>getNumber : () => number + + return 1; +>1 : number +} +class Example { +>Example : Example + + getNumber(): number { +>getNumber : () => number + + return 1; +>1 : number + } + doSomething(a = this.getNumber()): typeof a { +>doSomething : (a?: number) => number +>a : number +>this.getNumber() : number +>this.getNumber : () => number +>this : this +>getNumber : () => number +>a : number + + return a; +>a : number + } +} + From e307295fb95633e457cdcf5e30b544fa9d7d0b15 Mon Sep 17 00:00:00 2001 From: Nathan Shively-Sanders Date: Thu, 9 Jun 2016 15:20:51 -0700 Subject: [PATCH 3/3] Resolve function-this in parameter initialisers when explicitly provided --- src/compiler/checker.ts | 13 +++++++- ...inferParameterWithMethodCallInitializer.js | 21 +++++++++++++ ...ParameterWithMethodCallInitializer.symbols | 28 +++++++++++++++++ ...erParameterWithMethodCallInitializer.types | 30 +++++++++++++++++++ ...inferParameterWithMethodCallInitializer.ts | 8 +++++ 5 files changed, 99 insertions(+), 1 deletion(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index ba866c867e9..3842c05debf 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -8392,7 +8392,10 @@ namespace ts { if (needToCaptureLexicalThis) { captureLexicalThis(node, container); } - if (isFunctionLike(container) && !isInParameterInitializerBeforeContainingFunction(node)) { + if (isFunctionLike(container) && + (!isInParameterInitializerBeforeContainingFunction(node) || getFunctionLikeThisParameter(container))) { + // Note: a parameter initializer should refer to class-this unless function-this is explicitly annotated. + // If this is a function in a JS file, it might be a class method. Check if it's the RHS // of a x.prototype.y = function [name]() { .... } if (container.kind === SyntaxKind.FunctionExpression && @@ -18473,6 +18476,14 @@ namespace ts { } } + function getFunctionLikeThisParameter(func: FunctionLikeDeclaration) { + if (func.parameters.length && + func.parameters[0].name.kind === SyntaxKind.Identifier && + (func.parameters[0].name).originalKeywordKind === SyntaxKind.ThisKeyword) { + return func.parameters[0]; + } + } + function checkGrammarForNonSymbolComputedProperty(node: DeclarationName, message: DiagnosticMessage) { if (isDynamicName(node)) { return grammarErrorOnNode(node, message); diff --git a/tests/baselines/reference/inferParameterWithMethodCallInitializer.js b/tests/baselines/reference/inferParameterWithMethodCallInitializer.js index 6a5400ca19a..5b33f78f766 100644 --- a/tests/baselines/reference/inferParameterWithMethodCallInitializer.js +++ b/tests/baselines/reference/inferParameterWithMethodCallInitializer.js @@ -10,6 +10,14 @@ class Example { return a; } } +function weird(this: Example, a = this.getNumber()) { + return a; +} +class Weird { + doSomething(this: Example, a = this.getNumber()) { + return a; + } +} //// [inferParameterWithMethodCallInitializer.js] @@ -28,3 +36,16 @@ var Example = (function () { }; return Example; }()); +function weird(a) { + if (a === void 0) { a = this.getNumber(); } + return a; +} +var Weird = (function () { + function Weird() { + } + Weird.prototype.doSomething = function (a) { + if (a === void 0) { a = this.getNumber(); } + return a; + }; + return Weird; +}()); diff --git a/tests/baselines/reference/inferParameterWithMethodCallInitializer.symbols b/tests/baselines/reference/inferParameterWithMethodCallInitializer.symbols index e4318fe1ead..e0734a4b39b 100644 --- a/tests/baselines/reference/inferParameterWithMethodCallInitializer.symbols +++ b/tests/baselines/reference/inferParameterWithMethodCallInitializer.symbols @@ -24,4 +24,32 @@ class Example { >a : Symbol(a, Decl(inferParameterWithMethodCallInitializer.ts, 7, 16)) } } +function weird(this: Example, a = this.getNumber()) { +>weird : Symbol(weird, Decl(inferParameterWithMethodCallInitializer.ts, 10, 1)) +>this : Symbol(this, Decl(inferParameterWithMethodCallInitializer.ts, 11, 15)) +>Example : Symbol(Example, Decl(inferParameterWithMethodCallInitializer.ts, 2, 1)) +>a : Symbol(a, Decl(inferParameterWithMethodCallInitializer.ts, 11, 29)) +>this.getNumber : Symbol(Example.getNumber, Decl(inferParameterWithMethodCallInitializer.ts, 3, 15)) +>this : Symbol(Example, Decl(inferParameterWithMethodCallInitializer.ts, 2, 1)) +>getNumber : Symbol(Example.getNumber, Decl(inferParameterWithMethodCallInitializer.ts, 3, 15)) + + return a; +>a : Symbol(a, Decl(inferParameterWithMethodCallInitializer.ts, 11, 29)) +} +class Weird { +>Weird : Symbol(Weird, Decl(inferParameterWithMethodCallInitializer.ts, 13, 1)) + + doSomething(this: Example, a = this.getNumber()) { +>doSomething : Symbol(Weird.doSomething, Decl(inferParameterWithMethodCallInitializer.ts, 14, 13)) +>this : Symbol(this, Decl(inferParameterWithMethodCallInitializer.ts, 15, 16)) +>Example : Symbol(Example, Decl(inferParameterWithMethodCallInitializer.ts, 2, 1)) +>a : Symbol(a, Decl(inferParameterWithMethodCallInitializer.ts, 15, 30)) +>this.getNumber : Symbol(Example.getNumber, Decl(inferParameterWithMethodCallInitializer.ts, 3, 15)) +>this : Symbol(Example, Decl(inferParameterWithMethodCallInitializer.ts, 2, 1)) +>getNumber : Symbol(Example.getNumber, Decl(inferParameterWithMethodCallInitializer.ts, 3, 15)) + + return a; +>a : Symbol(a, Decl(inferParameterWithMethodCallInitializer.ts, 15, 30)) + } +} diff --git a/tests/baselines/reference/inferParameterWithMethodCallInitializer.types b/tests/baselines/reference/inferParameterWithMethodCallInitializer.types index 53c58e201b7..9aeccb2b2e0 100644 --- a/tests/baselines/reference/inferParameterWithMethodCallInitializer.types +++ b/tests/baselines/reference/inferParameterWithMethodCallInitializer.types @@ -27,4 +27,34 @@ class Example { >a : number } } +function weird(this: Example, a = this.getNumber()) { +>weird : (this: Example, a?: number) => number +>this : Example +>Example : Example +>a : number +>this.getNumber() : number +>this.getNumber : () => number +>this : Example +>getNumber : () => number + + return a; +>a : number +} +class Weird { +>Weird : Weird + + doSomething(this: Example, a = this.getNumber()) { +>doSomething : (this: Example, a?: number) => number +>this : Example +>Example : Example +>a : number +>this.getNumber() : number +>this.getNumber : () => number +>this : Example +>getNumber : () => number + + return a; +>a : number + } +} diff --git a/tests/cases/compiler/inferParameterWithMethodCallInitializer.ts b/tests/cases/compiler/inferParameterWithMethodCallInitializer.ts index ba38c7cb909..392709ccdf6 100644 --- a/tests/cases/compiler/inferParameterWithMethodCallInitializer.ts +++ b/tests/cases/compiler/inferParameterWithMethodCallInitializer.ts @@ -10,3 +10,11 @@ class Example { return a; } } +function weird(this: Example, a = this.getNumber()) { + return a; +} +class Weird { + doSomething(this: Example, a = this.getNumber()) { + return a; + } +}