From b0f4ad73b03f540a21fa4ef2451fc966d0be5b2a Mon Sep 17 00:00:00 2001 From: Ryan Cavanaugh Date: Mon, 24 Apr 2023 09:03:29 -0700 Subject: [PATCH 1/2] Ignore self-calls when collecting the return type of a function --- src/compiler/checker.ts | 6 ++ ...WithoutReturnTypeAnnotationInference.types | 12 +-- .../functionImplementations.errors.txt | 6 +- .../reference/functionImplementations.types | 18 ++--- ...mplicitAnyFromCircularInference.errors.txt | 8 +- .../implicitAnyFromCircularInference.types | 14 ++-- ...cursiveGenericSignatureInstantiation.types | 6 +- .../simpleRecursionWithBaseCase.errors.txt | 47 +++++++++++ .../reference/simpleRecursionWithBaseCase.js | 63 +++++++++++++++ .../simpleRecursionWithBaseCase.symbols | 58 +++++++++++++ .../simpleRecursionWithBaseCase.types | 81 +++++++++++++++++++ tests/baselines/reference/witness.errors.txt | 10 ++- tests/baselines/reference/witness.types | 24 +++--- .../compiler/simpleRecursionWithBaseCase.ts | 31 +++++++ 14 files changed, 338 insertions(+), 46 deletions(-) create mode 100644 tests/baselines/reference/simpleRecursionWithBaseCase.errors.txt create mode 100644 tests/baselines/reference/simpleRecursionWithBaseCase.js create mode 100644 tests/baselines/reference/simpleRecursionWithBaseCase.symbols create mode 100644 tests/baselines/reference/simpleRecursionWithBaseCase.types create mode 100644 tests/cases/compiler/simpleRecursionWithBaseCase.ts diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 4b32f7459cfef..044f220e34351 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -35614,6 +35614,12 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { forEachReturnStatement(func.body as Block, returnStatement => { const expr = returnStatement.expression; if (expr) { + // Bare calls to this same function don't contribute to inference + if (expr.kind === SyntaxKind.CallExpression && checkExpressionCached((expr as CallExpression).expression).symbol === func.symbol) { + hasReturnOfTypeNever = true; + return; + } + let type = checkExpressionCached(expr, checkMode && checkMode & ~CheckMode.SkipGenericFunctions); if (functionFlags & FunctionFlags.Async) { // From within an async function you can return either a non-promise value or a promise. Any diff --git a/tests/baselines/reference/callSignatureWithoutReturnTypeAnnotationInference.types b/tests/baselines/reference/callSignatureWithoutReturnTypeAnnotationInference.types index d07126c148ef5..cff38b11b2591 100644 --- a/tests/baselines/reference/callSignatureWithoutReturnTypeAnnotationInference.types +++ b/tests/baselines/reference/callSignatureWithoutReturnTypeAnnotationInference.types @@ -31,16 +31,16 @@ var r2 = foo2(1); >1 : 1 function foo3() { ->foo3 : () => any +>foo3 : () => never return foo3(); ->foo3() : any ->foo3 : () => any +>foo3() : never +>foo3 : () => never } var r3 = foo3(); ->r3 : any ->foo3() : any ->foo3 : () => any +>r3 : never +>foo3() : never +>foo3 : () => never function foo4(x: T) { >foo4 : (x: T) => T diff --git a/tests/baselines/reference/functionImplementations.errors.txt b/tests/baselines/reference/functionImplementations.errors.txt index e289bd7e40039..a63cdd8234c28 100644 --- a/tests/baselines/reference/functionImplementations.errors.txt +++ b/tests/baselines/reference/functionImplementations.errors.txt @@ -1,7 +1,8 @@ +tests/cases/conformance/functions/functionImplementations.ts(85,5): error TS2403: Subsequent variable declarations must have the same type. Variable 'a' must be of type 'any', but here has type 'Base'. tests/cases/conformance/functions/functionImplementations.ts(90,1): error TS2839: This condition will always return 'false' since JavaScript compares objects by reference, not value. -==== tests/cases/conformance/functions/functionImplementations.ts (1 errors) ==== +==== tests/cases/conformance/functions/functionImplementations.ts (2 errors) ==== // FunctionExpression with no return type annotation and no return statement returns void var v: void = function () { } (); @@ -87,6 +88,9 @@ tests/cases/conformance/functions/functionImplementations.ts(90,1): error TS2839 // FunctionExpression with no return type annotation with multiple return statements with one a recursive call var a = function f() { + ~ +!!! error TS2403: Subsequent variable declarations must have the same type. Variable 'a' must be of type 'any', but here has type 'Base'. +!!! related TS6203 tests/cases/conformance/functions/functionImplementations.ts:5:5: 'a' was also declared here. return new Base(); return new Derived(); return f(); // ? } (); diff --git a/tests/baselines/reference/functionImplementations.types b/tests/baselines/reference/functionImplementations.types index 66cafa8d610ae..fe4d2b7199976 100644 --- a/tests/baselines/reference/functionImplementations.types +++ b/tests/baselines/reference/functionImplementations.types @@ -17,12 +17,12 @@ var a: any = function f() { }; var a: any = function f() { >a : any ->function f() { return f();} : () => any ->f : () => any +>function f() { return f();} : () => never +>f : () => never return f(); ->f() : any ->f : () => any +>f() : never +>f : () => never }; @@ -205,17 +205,17 @@ var b = function () { // FunctionExpression with no return type annotation with multiple return statements with one a recursive call var a = function f() { >a : any ->function f() { return new Base(); return new Derived(); return f(); // ?} () : any ->function f() { return new Base(); return new Derived(); return f(); // ?} : () => any ->f : () => any +>function f() { return new Base(); return new Derived(); return f(); // ?} () : Base +>function f() { return new Base(); return new Derived(); return f(); // ?} : () => Base +>f : () => Base return new Base(); return new Derived(); return f(); // ? >new Base() : Base >Base : typeof Base >new Derived() : Derived >Derived : typeof Derived ->f() : any ->f : () => any +>f() : Base +>f : () => Base } (); diff --git a/tests/baselines/reference/implicitAnyFromCircularInference.errors.txt b/tests/baselines/reference/implicitAnyFromCircularInference.errors.txt index 18693df2f5f76..6b6be4da96fad 100644 --- a/tests/baselines/reference/implicitAnyFromCircularInference.errors.txt +++ b/tests/baselines/reference/implicitAnyFromCircularInference.errors.txt @@ -2,15 +2,13 @@ tests/cases/compiler/implicitAnyFromCircularInference.ts(2,5): error TS2502: 'a' tests/cases/compiler/implicitAnyFromCircularInference.ts(5,5): error TS2502: 'b' is referenced directly or indirectly in its own type annotation. tests/cases/compiler/implicitAnyFromCircularInference.ts(6,5): error TS2502: 'c' is referenced directly or indirectly in its own type annotation. tests/cases/compiler/implicitAnyFromCircularInference.ts(9,5): error TS2502: 'd' is referenced directly or indirectly in its own type annotation. -tests/cases/compiler/implicitAnyFromCircularInference.ts(14,10): error TS7023: 'g' implicitly has return type 'any' because it does not have a return type annotation and is referenced directly or indirectly in one of its return expressions. -tests/cases/compiler/implicitAnyFromCircularInference.ts(17,5): error TS7023: 'f1' implicitly has return type 'any' because it does not have a return type annotation and is referenced directly or indirectly in one of its return expressions. tests/cases/compiler/implicitAnyFromCircularInference.ts(22,5): error TS7023: 'f2' implicitly has return type 'any' because it does not have a return type annotation and is referenced directly or indirectly in one of its return expressions. tests/cases/compiler/implicitAnyFromCircularInference.ts(25,10): error TS7023: 'h' implicitly has return type 'any' because it does not have a return type annotation and is referenced directly or indirectly in one of its return expressions. tests/cases/compiler/implicitAnyFromCircularInference.ts(27,14): error TS7023: 'foo' implicitly has return type 'any' because it does not have a return type annotation and is referenced directly or indirectly in one of its return expressions. tests/cases/compiler/implicitAnyFromCircularInference.ts(44,9): error TS7023: 'x' implicitly has return type 'any' because it does not have a return type annotation and is referenced directly or indirectly in one of its return expressions. -==== tests/cases/compiler/implicitAnyFromCircularInference.ts (10 errors) ==== +==== tests/cases/compiler/implicitAnyFromCircularInference.ts (8 errors) ==== // Error expected var a: typeof a; ~ @@ -33,13 +31,9 @@ tests/cases/compiler/implicitAnyFromCircularInference.ts(44,9): error TS7023: 'x // Error expected function g() { return g(); } - ~ -!!! error TS7023: 'g' implicitly has return type 'any' because it does not have a return type annotation and is referenced directly or indirectly in one of its return expressions. // Error expected var f1 = function () { - ~~ -!!! error TS7023: 'f1' implicitly has return type 'any' because it does not have a return type annotation and is referenced directly or indirectly in one of its return expressions. return f1(); }; diff --git a/tests/baselines/reference/implicitAnyFromCircularInference.types b/tests/baselines/reference/implicitAnyFromCircularInference.types index 906307b0725d5..0e8960432fb40 100644 --- a/tests/baselines/reference/implicitAnyFromCircularInference.types +++ b/tests/baselines/reference/implicitAnyFromCircularInference.types @@ -24,18 +24,18 @@ function f() { return f; } // Error expected function g() { return g(); } ->g : () => any ->g() : any ->g : () => any +>g : () => never +>g() : never +>g : () => never // Error expected var f1 = function () { ->f1 : () => any ->function () { return f1();} : () => any +>f1 : () => never +>function () { return f1();} : () => never return f1(); ->f1() : any ->f1 : () => any +>f1() : never +>f1 : () => never }; diff --git a/tests/baselines/reference/recursiveGenericSignatureInstantiation.types b/tests/baselines/reference/recursiveGenericSignatureInstantiation.types index 88e9782fdaf51..70f6229bbe0ad 100644 --- a/tests/baselines/reference/recursiveGenericSignatureInstantiation.types +++ b/tests/baselines/reference/recursiveGenericSignatureInstantiation.types @@ -1,11 +1,11 @@ === tests/cases/compiler/recursiveGenericSignatureInstantiation.ts === function f6(x: T) { ->f6 : (x: T) => any +>f6 : (x: T) => never >x : T return f6(x); ->f6(x) : any ->f6 : (x: T) => any +>f6(x) : never +>f6 : (x: T) => never >x : T } diff --git a/tests/baselines/reference/simpleRecursionWithBaseCase.errors.txt b/tests/baselines/reference/simpleRecursionWithBaseCase.errors.txt new file mode 100644 index 0000000000000..44b9d8530321e --- /dev/null +++ b/tests/baselines/reference/simpleRecursionWithBaseCase.errors.txt @@ -0,0 +1,47 @@ +tests/cases/compiler/simpleRecursionWithBaseCase.ts(8,21): error TS2554: Expected 1 arguments, but got 0. +tests/cases/compiler/simpleRecursionWithBaseCase.ts(13,20): error TS2554: Expected 1 arguments, but got 0. +tests/cases/compiler/simpleRecursionWithBaseCase.ts(19,20): error TS2345: Argument of type 'string' is not assignable to parameter of type 'number'. +tests/cases/compiler/simpleRecursionWithBaseCase.ts(27,16): error TS2304: Cannot find name 'notfoundsymbol'. + + +==== tests/cases/compiler/simpleRecursionWithBaseCase.ts (4 errors) ==== + function fn1(n: number) { + if (n === 0) { + return 3; + } else { + return fn1(n - 1); + } + } + const num: number = fn1(); + ~~~~~ +!!! error TS2554: Expected 1 arguments, but got 0. +!!! related TS6210 tests/cases/compiler/simpleRecursionWithBaseCase.ts:1:14: An argument for 'n' was not provided. + + function fn2(n: number) { + return fn2(n); + } + const nev: never = fn2(); + ~~~~~ +!!! error TS2554: Expected 1 arguments, but got 0. +!!! related TS6210 tests/cases/compiler/simpleRecursionWithBaseCase.ts:10:14: An argument for 'n' was not provided. + + function fn3(n: number) { + if (n === 0) { + return 3; + } else { + return fn1("hello world"); + ~~~~~~~~~~~~~ +!!! error TS2345: Argument of type 'string' is not assignable to parameter of type 'number'. + } + } + + function fn4(n: number) { + if (n === 0) { + return 3; + } else { + return notfoundsymbol("hello world"); + ~~~~~~~~~~~~~~ +!!! error TS2304: Cannot find name 'notfoundsymbol'. + } + } + \ No newline at end of file diff --git a/tests/baselines/reference/simpleRecursionWithBaseCase.js b/tests/baselines/reference/simpleRecursionWithBaseCase.js new file mode 100644 index 0000000000000..757eb87de7cc6 --- /dev/null +++ b/tests/baselines/reference/simpleRecursionWithBaseCase.js @@ -0,0 +1,63 @@ +//// [simpleRecursionWithBaseCase.ts] +function fn1(n: number) { + if (n === 0) { + return 3; + } else { + return fn1(n - 1); + } +} +const num: number = fn1(); + +function fn2(n: number) { + return fn2(n); +} +const nev: never = fn2(); + +function fn3(n: number) { + if (n === 0) { + return 3; + } else { + return fn1("hello world"); + } +} + +function fn4(n: number) { + if (n === 0) { + return 3; + } else { + return notfoundsymbol("hello world"); + } +} + + +//// [simpleRecursionWithBaseCase.js] +"use strict"; +function fn1(n) { + if (n === 0) { + return 3; + } + else { + return fn1(n - 1); + } +} +var num = fn1(); +function fn2(n) { + return fn2(n); +} +var nev = fn2(); +function fn3(n) { + if (n === 0) { + return 3; + } + else { + return fn1("hello world"); + } +} +function fn4(n) { + if (n === 0) { + return 3; + } + else { + return notfoundsymbol("hello world"); + } +} diff --git a/tests/baselines/reference/simpleRecursionWithBaseCase.symbols b/tests/baselines/reference/simpleRecursionWithBaseCase.symbols new file mode 100644 index 0000000000000..42a85c0123625 --- /dev/null +++ b/tests/baselines/reference/simpleRecursionWithBaseCase.symbols @@ -0,0 +1,58 @@ +=== tests/cases/compiler/simpleRecursionWithBaseCase.ts === +function fn1(n: number) { +>fn1 : Symbol(fn1, Decl(simpleRecursionWithBaseCase.ts, 0, 0)) +>n : Symbol(n, Decl(simpleRecursionWithBaseCase.ts, 0, 13)) + + if (n === 0) { +>n : Symbol(n, Decl(simpleRecursionWithBaseCase.ts, 0, 13)) + + return 3; + } else { + return fn1(n - 1); +>fn1 : Symbol(fn1, Decl(simpleRecursionWithBaseCase.ts, 0, 0)) +>n : Symbol(n, Decl(simpleRecursionWithBaseCase.ts, 0, 13)) + } +} +const num: number = fn1(); +>num : Symbol(num, Decl(simpleRecursionWithBaseCase.ts, 7, 5)) +>fn1 : Symbol(fn1, Decl(simpleRecursionWithBaseCase.ts, 0, 0)) + +function fn2(n: number) { +>fn2 : Symbol(fn2, Decl(simpleRecursionWithBaseCase.ts, 7, 26)) +>n : Symbol(n, Decl(simpleRecursionWithBaseCase.ts, 9, 13)) + + return fn2(n); +>fn2 : Symbol(fn2, Decl(simpleRecursionWithBaseCase.ts, 7, 26)) +>n : Symbol(n, Decl(simpleRecursionWithBaseCase.ts, 9, 13)) +} +const nev: never = fn2(); +>nev : Symbol(nev, Decl(simpleRecursionWithBaseCase.ts, 12, 5)) +>fn2 : Symbol(fn2, Decl(simpleRecursionWithBaseCase.ts, 7, 26)) + +function fn3(n: number) { +>fn3 : Symbol(fn3, Decl(simpleRecursionWithBaseCase.ts, 12, 25)) +>n : Symbol(n, Decl(simpleRecursionWithBaseCase.ts, 14, 13)) + + if (n === 0) { +>n : Symbol(n, Decl(simpleRecursionWithBaseCase.ts, 14, 13)) + + return 3; + } else { + return fn1("hello world"); +>fn1 : Symbol(fn1, Decl(simpleRecursionWithBaseCase.ts, 0, 0)) + } +} + +function fn4(n: number) { +>fn4 : Symbol(fn4, Decl(simpleRecursionWithBaseCase.ts, 20, 1)) +>n : Symbol(n, Decl(simpleRecursionWithBaseCase.ts, 22, 13)) + + if (n === 0) { +>n : Symbol(n, Decl(simpleRecursionWithBaseCase.ts, 22, 13)) + + return 3; + } else { + return notfoundsymbol("hello world"); + } +} + diff --git a/tests/baselines/reference/simpleRecursionWithBaseCase.types b/tests/baselines/reference/simpleRecursionWithBaseCase.types new file mode 100644 index 0000000000000..6abfb17b1a3e8 --- /dev/null +++ b/tests/baselines/reference/simpleRecursionWithBaseCase.types @@ -0,0 +1,81 @@ +=== tests/cases/compiler/simpleRecursionWithBaseCase.ts === +function fn1(n: number) { +>fn1 : (n: number) => number +>n : number + + if (n === 0) { +>n === 0 : boolean +>n : number +>0 : 0 + + return 3; +>3 : 3 + + } else { + return fn1(n - 1); +>fn1(n - 1) : number +>fn1 : (n: number) => number +>n - 1 : number +>n : number +>1 : 1 + } +} +const num: number = fn1(); +>num : number +>fn1() : number +>fn1 : (n: number) => number + +function fn2(n: number) { +>fn2 : (n: number) => never +>n : number + + return fn2(n); +>fn2(n) : never +>fn2 : (n: number) => never +>n : number +} +const nev: never = fn2(); +>nev : never +>fn2() : never +>fn2 : (n: number) => never + +function fn3(n: number) { +>fn3 : (n: number) => number +>n : number + + if (n === 0) { +>n === 0 : boolean +>n : number +>0 : 0 + + return 3; +>3 : 3 + + } else { + return fn1("hello world"); +>fn1("hello world") : number +>fn1 : (n: number) => number +>"hello world" : "hello world" + } +} + +function fn4(n: number) { +>fn4 : (n: number) => any +>n : number + + if (n === 0) { +>n === 0 : boolean +>n : number +>0 : 0 + + return 3; +>3 : 3 + + } else { + return notfoundsymbol("hello world"); +>notfoundsymbol("hello world") : any +>notfoundsymbol : any +>"hello world" : "hello world" + } +} + diff --git a/tests/baselines/reference/witness.errors.txt b/tests/baselines/reference/witness.errors.txt index c005239eb9606..809908d22ab5e 100644 --- a/tests/baselines/reference/witness.errors.txt +++ b/tests/baselines/reference/witness.errors.txt @@ -1,5 +1,6 @@ tests/cases/conformance/types/witness/witness.ts(4,21): error TS2372: Parameter 'pInit' cannot reference itself. tests/cases/conformance/types/witness/witness.ts(8,14): error TS2729: Property 'x' is used before its initialization. +tests/cases/conformance/types/witness/witness.ts(20,5): error TS2403: Subsequent variable declarations must have the same type. Variable 'a' must be of type 'any', but here has type 'never'. tests/cases/conformance/types/witness/witness.ts(28,12): error TS2695: Left side of comma operator is unused and has no side effects. tests/cases/conformance/types/witness/witness.ts(29,5): error TS2403: Subsequent variable declarations must have the same type. Variable 'co1' must be of type 'any', but here has type 'number'. tests/cases/conformance/types/witness/witness.ts(30,12): error TS2695: Left side of comma operator is unused and has no side effects. @@ -12,12 +13,13 @@ tests/cases/conformance/types/witness/witness.ts(37,5): error TS2403: Subsequent tests/cases/conformance/types/witness/witness.ts(39,5): error TS2403: Subsequent variable declarations must have the same type. Variable 'as2' must be of type 'any', but here has type 'number'. tests/cases/conformance/types/witness/witness.ts(43,5): error TS2403: Subsequent variable declarations must have the same type. Variable 'cnd1' must be of type 'any', but here has type 'number'. tests/cases/conformance/types/witness/witness.ts(57,5): error TS2403: Subsequent variable declarations must have the same type. Variable 'and1' must be of type 'any', but here has type 'string'. +tests/cases/conformance/types/witness/witness.ts(68,5): error TS2403: Subsequent variable declarations must have the same type. Variable 'fnCallResult' must be of type 'never', but here has type 'any'. tests/cases/conformance/types/witness/witness.ts(110,5): error TS2403: Subsequent variable declarations must have the same type. Variable 'propAcc1' must be of type 'any', but here has type '{ m: any; }'. tests/cases/conformance/types/witness/witness.ts(121,14): error TS2729: Property 'n' is used before its initialization. tests/cases/conformance/types/witness/witness.ts(128,19): error TS2729: Property 'q' is used before its initialization. -==== tests/cases/conformance/types/witness/witness.ts (17 errors) ==== +==== tests/cases/conformance/types/witness/witness.ts (19 errors) ==== // Initializers var varInit = varInit; // any var pInit: any; @@ -43,6 +45,9 @@ tests/cases/conformance/types/witness/witness.ts(128,19): error TS2729: Property } var a: any; var a = fnReturn1(); + ~ +!!! error TS2403: Subsequent variable declarations must have the same type. Variable 'a' must be of type 'any', but here has type 'never'. +!!! related TS6203 tests/cases/conformance/types/witness/witness.ts:19:5: 'a' was also declared here. function fnReturn2() { return fnReturn2; @@ -121,6 +126,9 @@ tests/cases/conformance/types/witness/witness.ts(128,19): error TS2729: Property } var fnCallResult = fnCall(); var fnCallResult: any; + ~~~~~~~~~~~~ +!!! error TS2403: Subsequent variable declarations must have the same type. Variable 'fnCallResult' must be of type 'never', but here has type 'any'. +!!! related TS6203 tests/cases/conformance/types/witness/witness.ts:67:5: 'fnCallResult' was also declared here. // Call argument function fnArg1(x: typeof fnArg1, y: number) { diff --git a/tests/baselines/reference/witness.types b/tests/baselines/reference/witness.types index 69f318e875816..c9a04dbc469b3 100644 --- a/tests/baselines/reference/witness.types +++ b/tests/baselines/reference/witness.types @@ -40,19 +40,19 @@ class InitClass { // Return type function fnReturn1() { ->fnReturn1 : () => any +>fnReturn1 : () => never return fnReturn1(); ->fnReturn1() : any ->fnReturn1 : () => any +>fnReturn1() : never +>fnReturn1 : () => never } var a: any; >a : any var a = fnReturn1(); >a : any ->fnReturn1() : any ->fnReturn1 : () => any +>fnReturn1() : never +>fnReturn1 : () => never function fnReturn2() { >fnReturn2 : () => typeof fnReturn2 @@ -207,19 +207,19 @@ var and3: any; // function call return type function fnCall() { ->fnCall : () => any +>fnCall : () => never return fnCall(); ->fnCall() : any ->fnCall : () => any +>fnCall() : never +>fnCall : () => never } var fnCallResult = fnCall(); ->fnCallResult : any ->fnCall() : any ->fnCall : () => any +>fnCallResult : never +>fnCall() : never +>fnCall : () => never var fnCallResult: any; ->fnCallResult : any +>fnCallResult : never // Call argument function fnArg1(x: typeof fnArg1, y: number) { diff --git a/tests/cases/compiler/simpleRecursionWithBaseCase.ts b/tests/cases/compiler/simpleRecursionWithBaseCase.ts new file mode 100644 index 0000000000000..dd98dcdf4fb16 --- /dev/null +++ b/tests/cases/compiler/simpleRecursionWithBaseCase.ts @@ -0,0 +1,31 @@ +// @strict: true + +function fn1(n: number) { + if (n === 0) { + return 3; + } else { + return fn1(n - 1); + } +} +const num: number = fn1(); + +function fn2(n: number) { + return fn2(n); +} +const nev: never = fn2(); + +function fn3(n: number) { + if (n === 0) { + return 3; + } else { + return fn1("hello world"); + } +} + +function fn4(n: number) { + if (n === 0) { + return 3; + } else { + return notfoundsymbol("hello world"); + } +} From 674966bb0f335456913011b43be398039495d1cf Mon Sep 17 00:00:00 2001 From: Ryan Cavanaugh Date: Wed, 26 Apr 2023 21:32:22 -0700 Subject: [PATCH 2/2] Check for identifier operand and add testcase --- src/compiler/checker.ts | 4 +++- .../reference/simpleRecursionWithBaseCase.errors.txt | 9 ++++++++- .../reference/simpleRecursionWithBaseCase.js | 7 +++++++ .../reference/simpleRecursionWithBaseCase.symbols | 7 +++++++ .../reference/simpleRecursionWithBaseCase.types | 11 +++++++++++ tests/cases/compiler/simpleRecursionWithBaseCase.ts | 5 +++++ 6 files changed, 41 insertions(+), 2 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 044f220e34351..55cda9e4cd2ed 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -35615,7 +35615,9 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { const expr = returnStatement.expression; if (expr) { // Bare calls to this same function don't contribute to inference - if (expr.kind === SyntaxKind.CallExpression && checkExpressionCached((expr as CallExpression).expression).symbol === func.symbol) { + if (expr.kind === SyntaxKind.CallExpression && + (expr as CallExpression).expression.kind === SyntaxKind.Identifier && + checkExpressionCached((expr as CallExpression).expression).symbol === func.symbol) { hasReturnOfTypeNever = true; return; } diff --git a/tests/baselines/reference/simpleRecursionWithBaseCase.errors.txt b/tests/baselines/reference/simpleRecursionWithBaseCase.errors.txt index 44b9d8530321e..7d3aa74c45c30 100644 --- a/tests/baselines/reference/simpleRecursionWithBaseCase.errors.txt +++ b/tests/baselines/reference/simpleRecursionWithBaseCase.errors.txt @@ -2,9 +2,10 @@ tests/cases/compiler/simpleRecursionWithBaseCase.ts(8,21): error TS2554: Expecte tests/cases/compiler/simpleRecursionWithBaseCase.ts(13,20): error TS2554: Expected 1 arguments, but got 0. tests/cases/compiler/simpleRecursionWithBaseCase.ts(19,20): error TS2345: Argument of type 'string' is not assignable to parameter of type 'number'. tests/cases/compiler/simpleRecursionWithBaseCase.ts(27,16): error TS2304: Cannot find name 'notfoundsymbol'. +tests/cases/compiler/simpleRecursionWithBaseCase.ts(31,10): error TS7023: 'fn5' implicitly has return type 'any' because it does not have a return type annotation and is referenced directly or indirectly in one of its return expressions. -==== tests/cases/compiler/simpleRecursionWithBaseCase.ts (4 errors) ==== +==== tests/cases/compiler/simpleRecursionWithBaseCase.ts (5 errors) ==== function fn1(n: number) { if (n === 0) { return 3; @@ -44,4 +45,10 @@ tests/cases/compiler/simpleRecursionWithBaseCase.ts(27,16): error TS2304: Cannot !!! error TS2304: Cannot find name 'notfoundsymbol'. } } + + function fn5() { + ~~~ +!!! error TS7023: 'fn5' implicitly has return type 'any' because it does not have a return type annotation and is referenced directly or indirectly in one of its return expressions. + return [fn5][0](); + } \ No newline at end of file diff --git a/tests/baselines/reference/simpleRecursionWithBaseCase.js b/tests/baselines/reference/simpleRecursionWithBaseCase.js index 757eb87de7cc6..4d0797ca329ff 100644 --- a/tests/baselines/reference/simpleRecursionWithBaseCase.js +++ b/tests/baselines/reference/simpleRecursionWithBaseCase.js @@ -28,6 +28,10 @@ function fn4(n: number) { return notfoundsymbol("hello world"); } } + +function fn5() { + return [fn5][0](); +} //// [simpleRecursionWithBaseCase.js] @@ -61,3 +65,6 @@ function fn4(n) { return notfoundsymbol("hello world"); } } +function fn5() { + return [fn5][0](); +} diff --git a/tests/baselines/reference/simpleRecursionWithBaseCase.symbols b/tests/baselines/reference/simpleRecursionWithBaseCase.symbols index 42a85c0123625..9f45a6b7a3658 100644 --- a/tests/baselines/reference/simpleRecursionWithBaseCase.symbols +++ b/tests/baselines/reference/simpleRecursionWithBaseCase.symbols @@ -56,3 +56,10 @@ function fn4(n: number) { } } +function fn5() { +>fn5 : Symbol(fn5, Decl(simpleRecursionWithBaseCase.ts, 28, 1)) + + return [fn5][0](); +>fn5 : Symbol(fn5, Decl(simpleRecursionWithBaseCase.ts, 28, 1)) +} + diff --git a/tests/baselines/reference/simpleRecursionWithBaseCase.types b/tests/baselines/reference/simpleRecursionWithBaseCase.types index 6abfb17b1a3e8..e7bf7855e1b97 100644 --- a/tests/baselines/reference/simpleRecursionWithBaseCase.types +++ b/tests/baselines/reference/simpleRecursionWithBaseCase.types @@ -79,3 +79,14 @@ function fn4(n: number) { } } +function fn5() { +>fn5 : () => any + + return [fn5][0](); +>[fn5][0]() : any +>[fn5][0] : () => any +>[fn5] : (() => any)[] +>fn5 : () => any +>0 : 0 +} + diff --git a/tests/cases/compiler/simpleRecursionWithBaseCase.ts b/tests/cases/compiler/simpleRecursionWithBaseCase.ts index dd98dcdf4fb16..42ea1c7ab953b 100644 --- a/tests/cases/compiler/simpleRecursionWithBaseCase.ts +++ b/tests/cases/compiler/simpleRecursionWithBaseCase.ts @@ -1,4 +1,5 @@ // @strict: true +// @noImplicitAny: true function fn1(n: number) { if (n === 0) { @@ -29,3 +30,7 @@ function fn4(n: number) { return notfoundsymbol("hello world"); } } + +function fn5() { + return [fn5][0](); +}