Skip to content

Commit 0d970e4

Browse files
committed
Ignore awaited self tail calls when collecting the return type of an async function
1 parent d1a2e7e commit 0d970e4

11 files changed

+491
-81
lines changed

src/compiler/checker.ts

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36674,9 +36674,14 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
3667436674
let hasReturnWithNoExpression = functionHasImplicitReturn(func);
3667536675
let hasReturnOfTypeNever = false;
3667636676
forEachReturnStatement(func.body as Block, returnStatement => {
36677-
const expr = returnStatement.expression;
36677+
let expr = returnStatement.expression;
3667836678
if (expr) {
36679+
expr = skipParentheses(expr);
3667936680
// Bare calls to this same function don't contribute to inference
36681+
// and `return await` is also safe to unwrap here
36682+
if (functionFlags & FunctionFlags.Async && expr.kind === SyntaxKind.AwaitExpression) {
36683+
expr = skipParentheses((expr as AwaitExpression).expression);
36684+
}
3668036685
if (
3668136686
expr.kind === SyntaxKind.CallExpression &&
3668236687
(expr as CallExpression).expression.kind === SyntaxKind.Identifier &&

tests/baselines/reference/simpleRecursionWithBaseCase.symbols

Lines changed: 0 additions & 67 deletions
This file was deleted.

tests/baselines/reference/simpleRecursionWithBaseCase.errors.txt renamed to tests/baselines/reference/simpleRecursionWithBaseCase1.errors.txt

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
1-
simpleRecursionWithBaseCase.ts(8,21): error TS2554: Expected 1 arguments, but got 0.
2-
simpleRecursionWithBaseCase.ts(13,20): error TS2554: Expected 1 arguments, but got 0.
3-
simpleRecursionWithBaseCase.ts(19,20): error TS2345: Argument of type 'string' is not assignable to parameter of type 'number'.
4-
simpleRecursionWithBaseCase.ts(27,16): error TS2304: Cannot find name 'notfoundsymbol'.
5-
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.
1+
simpleRecursionWithBaseCase1.ts(8,21): error TS2554: Expected 1 arguments, but got 0.
2+
simpleRecursionWithBaseCase1.ts(13,20): error TS2554: Expected 1 arguments, but got 0.
3+
simpleRecursionWithBaseCase1.ts(19,20): error TS2345: Argument of type 'string' is not assignable to parameter of type 'number'.
4+
simpleRecursionWithBaseCase1.ts(27,16): error TS2304: Cannot find name 'notfoundsymbol'.
5+
simpleRecursionWithBaseCase1.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.
66

77

8-
==== simpleRecursionWithBaseCase.ts (5 errors) ====
8+
==== simpleRecursionWithBaseCase1.ts (5 errors) ====
99
function fn1(n: number) {
1010
if (n === 0) {
1111
return 3;
@@ -16,15 +16,15 @@ simpleRecursionWithBaseCase.ts(31,10): error TS7023: 'fn5' implicitly has return
1616
const num: number = fn1();
1717
~~~~~
1818
!!! error TS2554: Expected 1 arguments, but got 0.
19-
!!! related TS6210 simpleRecursionWithBaseCase.ts:1:14: An argument for 'n' was not provided.
19+
!!! related TS6210 simpleRecursionWithBaseCase1.ts:1:14: An argument for 'n' was not provided.
2020

2121
function fn2(n: number) {
2222
return fn2(n);
2323
}
2424
const nev: never = fn2();
2525
~~~~~
2626
!!! error TS2554: Expected 1 arguments, but got 0.
27-
!!! related TS6210 simpleRecursionWithBaseCase.ts:10:14: An argument for 'n' was not provided.
27+
!!! related TS6210 simpleRecursionWithBaseCase1.ts:10:14: An argument for 'n' was not provided.
2828

2929
function fn3(n: number) {
3030
if (n === 0) {

tests/baselines/reference/simpleRecursionWithBaseCase.js renamed to tests/baselines/reference/simpleRecursionWithBaseCase1.js

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
1-
//// [tests/cases/compiler/simpleRecursionWithBaseCase.ts] ////
1+
//// [tests/cases/compiler/simpleRecursionWithBaseCase1.ts] ////
22

3-
//// [simpleRecursionWithBaseCase.ts]
3+
//// [simpleRecursionWithBaseCase1.ts]
44
function fn1(n: number) {
55
if (n === 0) {
66
return 3;
@@ -36,7 +36,7 @@ function fn5() {
3636
}
3737

3838

39-
//// [simpleRecursionWithBaseCase.js]
39+
//// [simpleRecursionWithBaseCase1.js]
4040
"use strict";
4141
function fn1(n) {
4242
if (n === 0) {
Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
//// [tests/cases/compiler/simpleRecursionWithBaseCase1.ts] ////
2+
3+
=== simpleRecursionWithBaseCase1.ts ===
4+
function fn1(n: number) {
5+
>fn1 : Symbol(fn1, Decl(simpleRecursionWithBaseCase1.ts, 0, 0))
6+
>n : Symbol(n, Decl(simpleRecursionWithBaseCase1.ts, 0, 13))
7+
8+
if (n === 0) {
9+
>n : Symbol(n, Decl(simpleRecursionWithBaseCase1.ts, 0, 13))
10+
11+
return 3;
12+
} else {
13+
return fn1(n - 1);
14+
>fn1 : Symbol(fn1, Decl(simpleRecursionWithBaseCase1.ts, 0, 0))
15+
>n : Symbol(n, Decl(simpleRecursionWithBaseCase1.ts, 0, 13))
16+
}
17+
}
18+
const num: number = fn1();
19+
>num : Symbol(num, Decl(simpleRecursionWithBaseCase1.ts, 7, 5))
20+
>fn1 : Symbol(fn1, Decl(simpleRecursionWithBaseCase1.ts, 0, 0))
21+
22+
function fn2(n: number) {
23+
>fn2 : Symbol(fn2, Decl(simpleRecursionWithBaseCase1.ts, 7, 26))
24+
>n : Symbol(n, Decl(simpleRecursionWithBaseCase1.ts, 9, 13))
25+
26+
return fn2(n);
27+
>fn2 : Symbol(fn2, Decl(simpleRecursionWithBaseCase1.ts, 7, 26))
28+
>n : Symbol(n, Decl(simpleRecursionWithBaseCase1.ts, 9, 13))
29+
}
30+
const nev: never = fn2();
31+
>nev : Symbol(nev, Decl(simpleRecursionWithBaseCase1.ts, 12, 5))
32+
>fn2 : Symbol(fn2, Decl(simpleRecursionWithBaseCase1.ts, 7, 26))
33+
34+
function fn3(n: number) {
35+
>fn3 : Symbol(fn3, Decl(simpleRecursionWithBaseCase1.ts, 12, 25))
36+
>n : Symbol(n, Decl(simpleRecursionWithBaseCase1.ts, 14, 13))
37+
38+
if (n === 0) {
39+
>n : Symbol(n, Decl(simpleRecursionWithBaseCase1.ts, 14, 13))
40+
41+
return 3;
42+
} else {
43+
return fn1("hello world");
44+
>fn1 : Symbol(fn1, Decl(simpleRecursionWithBaseCase1.ts, 0, 0))
45+
}
46+
}
47+
48+
function fn4(n: number) {
49+
>fn4 : Symbol(fn4, Decl(simpleRecursionWithBaseCase1.ts, 20, 1))
50+
>n : Symbol(n, Decl(simpleRecursionWithBaseCase1.ts, 22, 13))
51+
52+
if (n === 0) {
53+
>n : Symbol(n, Decl(simpleRecursionWithBaseCase1.ts, 22, 13))
54+
55+
return 3;
56+
} else {
57+
return notfoundsymbol("hello world");
58+
}
59+
}
60+
61+
function fn5() {
62+
>fn5 : Symbol(fn5, Decl(simpleRecursionWithBaseCase1.ts, 28, 1))
63+
64+
return [fn5][0]();
65+
>fn5 : Symbol(fn5, Decl(simpleRecursionWithBaseCase1.ts, 28, 1))
66+
}
67+

tests/baselines/reference/simpleRecursionWithBaseCase.types renamed to tests/baselines/reference/simpleRecursionWithBaseCase1.types

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
1-
//// [tests/cases/compiler/simpleRecursionWithBaseCase.ts] ////
1+
//// [tests/cases/compiler/simpleRecursionWithBaseCase1.ts] ////
22

3-
=== simpleRecursionWithBaseCase.ts ===
3+
=== simpleRecursionWithBaseCase1.ts ===
44
function fn1(n: number) {
55
>fn1 : (n: number) => number
66
>n : number
Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
error TS2468: Cannot find global value 'Promise'.
2+
simpleRecursionWithBaseCase2.ts(17,16): error TS2705: An async function or method in ES5/ES3 requires the 'Promise' constructor. Make sure you have a declaration for the 'Promise' constructor or include 'ES2015' in your '--lib' option.
3+
simpleRecursionWithBaseCase2.ts(21,16): error TS2705: An async function or method in ES5/ES3 requires the 'Promise' constructor. Make sure you have a declaration for the 'Promise' constructor or include 'ES2015' in your '--lib' option.
4+
5+
6+
!!! error TS2468: Cannot find global value 'Promise'.
7+
==== simpleRecursionWithBaseCase2.ts (2 errors) ====
8+
async function rec1() {
9+
if (Math.random() < 0.5) {
10+
return rec1();
11+
} else {
12+
return "hello";
13+
}
14+
}
15+
16+
async function rec2() {
17+
if (Math.random() < 0.5) {
18+
return await rec2();
19+
} else {
20+
return "hello";
21+
}
22+
}
23+
24+
async function rec3() {
25+
~~~~
26+
!!! error TS2705: An async function or method in ES5/ES3 requires the 'Promise' constructor. Make sure you have a declaration for the 'Promise' constructor or include 'ES2015' in your '--lib' option.
27+
return rec3();
28+
}
29+
30+
async function rec4() {
31+
~~~~
32+
!!! error TS2705: An async function or method in ES5/ES3 requires the 'Promise' constructor. Make sure you have a declaration for the 'Promise' constructor or include 'ES2015' in your '--lib' option.
33+
return await rec4();
34+
}
35+
36+
async function rec5() {
37+
if (Math.random() < 0.5) {
38+
return ((rec1()));
39+
} else {
40+
return "hello";
41+
}
42+
}
43+
44+
async function rec6() {
45+
if (Math.random() < 0.5) {
46+
return await ((rec1()));
47+
} else {
48+
return "hello";
49+
}
50+
}
51+
52+
declare const ps: Promise<string> | number;
53+
54+
async function foo1() {
55+
if (Math.random() > 0.5) {
56+
return ps;
57+
} else {
58+
return await foo1();
59+
}
60+
}
61+
62+
async function foo2() {
63+
if (Math.random() > 0.5) {
64+
return ps;
65+
} else {
66+
return foo2();
67+
}
68+
}
69+

0 commit comments

Comments
 (0)