Skip to content

Commit 2522469

Browse files
committed
Issue unawaited promise error on symbol-less expressions
1 parent faefc72 commit 2522469

6 files changed

+126
-25
lines changed

Diff for: src/compiler/checker.ts

+8-9
Original file line numberDiff line numberDiff line change
@@ -35699,15 +35699,14 @@ namespace ts {
3569935699
if (getFalsyFlags(type)) return;
3570035700

3570135701
const location = isBinaryExpression(condExpr) ? condExpr.right : condExpr;
35702+
if (isPropertyAccessExpression(location) && isAssertionExpression(skipParentheses(location.expression))) {
35703+
return;
35704+
}
35705+
3570235706
const testedNode = isIdentifier(location) ? location
3570335707
: isPropertyAccessExpression(location) ? location.name
3570435708
: isBinaryExpression(location) && isIdentifier(location.right) ? location.right
3570535709
: undefined;
35706-
const isPropertyExpressionCast = isPropertyAccessExpression(location)
35707-
&& isAssertionExpression(skipParentheses(location.expression));
35708-
if (!testedNode || isPropertyExpressionCast) {
35709-
return;
35710-
}
3571135710

3571235711
// While it technically should be invalid for any known-truthy value
3571335712
// to be tested, we de-scope to functions and Promises unreferenced in
@@ -35720,13 +35719,13 @@ namespace ts {
3572035719
return;
3572135720
}
3572235721

35723-
const testedSymbol = getSymbolAtLocation(testedNode);
35724-
if (!testedSymbol) {
35722+
const testedSymbol = testedNode && getSymbolAtLocation(testedNode);
35723+
if (!testedSymbol && !isPromise) {
3572535724
return;
3572635725
}
3572735726

35728-
const isUsed = isBinaryExpression(condExpr.parent) && isSymbolUsedInBinaryExpressionChain(condExpr.parent, testedSymbol)
35729-
|| body && isSymbolUsedInConditionBody(condExpr, body, testedNode, testedSymbol);
35727+
const isUsed = testedSymbol && isBinaryExpression(condExpr.parent) && isSymbolUsedInBinaryExpressionChain(condExpr.parent, testedSymbol)
35728+
|| testedSymbol && body && isSymbolUsedInConditionBody(condExpr, body, testedNode!, testedSymbol);
3573035729
if (!isUsed) {
3573135730
if (isPromise) {
3573235731
errorAndMaybeSuggestAwait(

Diff for: tests/baselines/reference/truthinessPromiseCoercion.errors.txt

+26-7
Original file line numberDiff line numberDiff line change
@@ -1,25 +1,28 @@
1-
tests/cases/compiler/truthinessPromiseCoercion.ts(6,9): error TS2801: This condition will always return true since this 'Promise<number>' is always defined.
2-
tests/cases/compiler/truthinessPromiseCoercion.ts(10,5): error TS2801: This condition will always return true since this 'Promise<number>' is always defined.
3-
tests/cases/compiler/truthinessPromiseCoercion.ts(31,9): error TS2801: This condition will always return true since this 'Promise<unknown>' is always defined.
1+
tests/cases/compiler/truthinessPromiseCoercion.ts(7,9): error TS2801: This condition will always return true since this 'Promise<number>' is always defined.
2+
tests/cases/compiler/truthinessPromiseCoercion.ts(11,5): error TS2801: This condition will always return true since this 'Promise<number>' is always defined.
3+
tests/cases/compiler/truthinessPromiseCoercion.ts(32,9): error TS2801: This condition will always return true since this 'Promise<unknown>' is always defined.
4+
tests/cases/compiler/truthinessPromiseCoercion.ts(40,9): error TS2801: This condition will always return true since this 'Promise<boolean>' is always defined.
5+
tests/cases/compiler/truthinessPromiseCoercion.ts(43,9): error TS2801: This condition will always return true since this 'Promise<boolean>' is always defined.
46

57

6-
==== tests/cases/compiler/truthinessPromiseCoercion.ts (3 errors) ====
8+
==== tests/cases/compiler/truthinessPromiseCoercion.ts (5 errors) ====
79
declare const p: Promise<number>
810
declare const p2: null | Promise<number>
911
declare const obj: { p: Promise<unknown> }
12+
declare function pf(): Promise<boolean>
1013

1114
async function f() {
1215
if (p) {} // err
1316
~
1417
!!! error TS2801: This condition will always return true since this 'Promise<number>' is always defined.
15-
!!! related TS2773 tests/cases/compiler/truthinessPromiseCoercion.ts:6:9: Did you forget to use 'await'?
18+
!!! related TS2773 tests/cases/compiler/truthinessPromiseCoercion.ts:7:9: Did you forget to use 'await'?
1619
if (!!p) {} // no err
1720
if (p2) {} // no err
1821

1922
p ? f.arguments : f.arguments;
2023
~
2124
!!! error TS2801: This condition will always return true since this 'Promise<number>' is always defined.
22-
!!! related TS2773 tests/cases/compiler/truthinessPromiseCoercion.ts:10:5: Did you forget to use 'await'?
25+
!!! related TS2773 tests/cases/compiler/truthinessPromiseCoercion.ts:11:5: Did you forget to use 'await'?
2326
!!p ? f.arguments : f.arguments;
2427
p2 ? f.arguments : f.arguments;
2528
}
@@ -43,10 +46,26 @@ tests/cases/compiler/truthinessPromiseCoercion.ts(31,9): error TS2801: This cond
4346
if (obj.p) {} // error
4447
~~~~~
4548
!!! error TS2801: This condition will always return true since this 'Promise<unknown>' is always defined.
46-
!!! related TS2773 tests/cases/compiler/truthinessPromiseCoercion.ts:31:9: Did you forget to use 'await'?
49+
!!! related TS2773 tests/cases/compiler/truthinessPromiseCoercion.ts:32:9: Did you forget to use 'await'?
4750
if (obj.p) { // ok
4851
await obj.p;
4952
}
5053
if (obj.p && await obj.p) {} // ok
5154
}
55+
56+
async function i(): Promise<string> {
57+
if (pf()) { // error
58+
~~~~
59+
!!! error TS2801: This condition will always return true since this 'Promise<boolean>' is always defined.
60+
!!! related TS2773 tests/cases/compiler/truthinessPromiseCoercion.ts:40:9: Did you forget to use 'await'?
61+
return "true";
62+
}
63+
if (pf()) { // error
64+
~~~~
65+
!!! error TS2801: This condition will always return true since this 'Promise<boolean>' is always defined.
66+
!!! related TS2773 tests/cases/compiler/truthinessPromiseCoercion.ts:43:9: Did you forget to use 'await'?
67+
pf().then();
68+
}
69+
return "false";
70+
}
5271

Diff for: tests/baselines/reference/truthinessPromiseCoercion.js

+20
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
declare const p: Promise<number>
33
declare const p2: null | Promise<number>
44
declare const obj: { p: Promise<unknown> }
5+
declare function pf(): Promise<boolean>
56

67
async function f() {
78
if (p) {} // err
@@ -35,6 +36,16 @@ async function h() {
3536
}
3637
if (obj.p && await obj.p) {} // ok
3738
}
39+
40+
async function i(): Promise<string> {
41+
if (pf()) { // error
42+
return "true";
43+
}
44+
if (pf()) { // error
45+
pf().then();
46+
}
47+
return "false";
48+
}
3849

3950

4051
//// [truthinessPromiseCoercion.js]
@@ -67,3 +78,12 @@ async function h() {
6778
}
6879
if (obj.p && await obj.p) { } // ok
6980
}
81+
async function i() {
82+
if (pf()) { // error
83+
return "true";
84+
}
85+
if (pf()) { // error
86+
pf().then();
87+
}
88+
return "false";
89+
}

Diff for: tests/baselines/reference/truthinessPromiseCoercion.symbols

+33-9
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,12 @@ declare const obj: { p: Promise<unknown> }
1212
>p : Symbol(p, Decl(truthinessPromiseCoercion.ts, 2, 20))
1313
>Promise : Symbol(Promise, Decl(lib.es5.d.ts, --, --), Decl(lib.es2015.iterable.d.ts, --, --), Decl(lib.es2015.promise.d.ts, --, --), Decl(lib.es2015.symbol.wellknown.d.ts, --, --), Decl(lib.es2018.promise.d.ts, --, --))
1414

15+
declare function pf(): Promise<boolean>
16+
>pf : Symbol(pf, Decl(truthinessPromiseCoercion.ts, 2, 42))
17+
>Promise : Symbol(Promise, Decl(lib.es5.d.ts, --, --), Decl(lib.es2015.iterable.d.ts, --, --), Decl(lib.es2015.promise.d.ts, --, --), Decl(lib.es2015.symbol.wellknown.d.ts, --, --), Decl(lib.es2018.promise.d.ts, --, --))
18+
1519
async function f() {
16-
>f : Symbol(f, Decl(truthinessPromiseCoercion.ts, 2, 42))
20+
>f : Symbol(f, Decl(truthinessPromiseCoercion.ts, 3, 39))
1721

1822
if (p) {} // err
1923
>p : Symbol(p, Decl(truthinessPromiseCoercion.ts, 0, 13))
@@ -27,34 +31,34 @@ async function f() {
2731
p ? f.arguments : f.arguments;
2832
>p : Symbol(p, Decl(truthinessPromiseCoercion.ts, 0, 13))
2933
>f.arguments : Symbol(Function.arguments, Decl(lib.es5.d.ts, --, --))
30-
>f : Symbol(f, Decl(truthinessPromiseCoercion.ts, 2, 42))
34+
>f : Symbol(f, Decl(truthinessPromiseCoercion.ts, 3, 39))
3135
>arguments : Symbol(Function.arguments, Decl(lib.es5.d.ts, --, --))
3236
>f.arguments : Symbol(Function.arguments, Decl(lib.es5.d.ts, --, --))
33-
>f : Symbol(f, Decl(truthinessPromiseCoercion.ts, 2, 42))
37+
>f : Symbol(f, Decl(truthinessPromiseCoercion.ts, 3, 39))
3438
>arguments : Symbol(Function.arguments, Decl(lib.es5.d.ts, --, --))
3539

3640
!!p ? f.arguments : f.arguments;
3741
>p : Symbol(p, Decl(truthinessPromiseCoercion.ts, 0, 13))
3842
>f.arguments : Symbol(Function.arguments, Decl(lib.es5.d.ts, --, --))
39-
>f : Symbol(f, Decl(truthinessPromiseCoercion.ts, 2, 42))
43+
>f : Symbol(f, Decl(truthinessPromiseCoercion.ts, 3, 39))
4044
>arguments : Symbol(Function.arguments, Decl(lib.es5.d.ts, --, --))
4145
>f.arguments : Symbol(Function.arguments, Decl(lib.es5.d.ts, --, --))
42-
>f : Symbol(f, Decl(truthinessPromiseCoercion.ts, 2, 42))
46+
>f : Symbol(f, Decl(truthinessPromiseCoercion.ts, 3, 39))
4347
>arguments : Symbol(Function.arguments, Decl(lib.es5.d.ts, --, --))
4448

4549
p2 ? f.arguments : f.arguments;
4650
>p2 : Symbol(p2, Decl(truthinessPromiseCoercion.ts, 1, 13))
4751
>f.arguments : Symbol(Function.arguments, Decl(lib.es5.d.ts, --, --))
48-
>f : Symbol(f, Decl(truthinessPromiseCoercion.ts, 2, 42))
52+
>f : Symbol(f, Decl(truthinessPromiseCoercion.ts, 3, 39))
4953
>arguments : Symbol(Function.arguments, Decl(lib.es5.d.ts, --, --))
5054
>f.arguments : Symbol(Function.arguments, Decl(lib.es5.d.ts, --, --))
51-
>f : Symbol(f, Decl(truthinessPromiseCoercion.ts, 2, 42))
55+
>f : Symbol(f, Decl(truthinessPromiseCoercion.ts, 3, 39))
5256
>arguments : Symbol(Function.arguments, Decl(lib.es5.d.ts, --, --))
5357
}
5458

5559
// all ok
5660
async function g() {
57-
>g : Symbol(g, Decl(truthinessPromiseCoercion.ts, 12, 1))
61+
>g : Symbol(g, Decl(truthinessPromiseCoercion.ts, 13, 1))
5862

5963
if (p) {
6064
>p : Symbol(p, Decl(truthinessPromiseCoercion.ts, 0, 13))
@@ -87,7 +91,7 @@ async function g() {
8791
}
8892

8993
async function h() {
90-
>h : Symbol(h, Decl(truthinessPromiseCoercion.ts, 27, 1))
94+
>h : Symbol(h, Decl(truthinessPromiseCoercion.ts, 28, 1))
9195

9296
if (obj.p) {} // error
9397
>obj.p : Symbol(p, Decl(truthinessPromiseCoercion.ts, 2, 20))
@@ -113,3 +117,23 @@ async function h() {
113117
>p : Symbol(p, Decl(truthinessPromiseCoercion.ts, 2, 20))
114118
}
115119

120+
async function i(): Promise<string> {
121+
>i : Symbol(i, Decl(truthinessPromiseCoercion.ts, 36, 1))
122+
>Promise : Symbol(Promise, Decl(lib.es5.d.ts, --, --), Decl(lib.es2015.iterable.d.ts, --, --), Decl(lib.es2015.promise.d.ts, --, --), Decl(lib.es2015.symbol.wellknown.d.ts, --, --), Decl(lib.es2018.promise.d.ts, --, --))
123+
124+
if (pf()) { // error
125+
>pf : Symbol(pf, Decl(truthinessPromiseCoercion.ts, 2, 42))
126+
127+
return "true";
128+
}
129+
if (pf()) { // error
130+
>pf : Symbol(pf, Decl(truthinessPromiseCoercion.ts, 2, 42))
131+
132+
pf().then();
133+
>pf().then : Symbol(Promise.then, Decl(lib.es5.d.ts, --, --))
134+
>pf : Symbol(pf, Decl(truthinessPromiseCoercion.ts, 2, 42))
135+
>then : Symbol(Promise.then, Decl(lib.es5.d.ts, --, --))
136+
}
137+
return "false";
138+
}
139+

Diff for: tests/baselines/reference/truthinessPromiseCoercion.types

+28
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,9 @@ declare const obj: { p: Promise<unknown> }
1010
>obj : { p: Promise<unknown>; }
1111
>p : Promise<unknown>
1212

13+
declare function pf(): Promise<boolean>
14+
>pf : () => Promise<boolean>
15+
1316
async function f() {
1417
>f : () => Promise<void>
1518

@@ -132,3 +135,28 @@ async function h() {
132135
>p : Promise<unknown>
133136
}
134137

138+
async function i(): Promise<string> {
139+
>i : () => Promise<string>
140+
141+
if (pf()) { // error
142+
>pf() : Promise<boolean>
143+
>pf : () => Promise<boolean>
144+
145+
return "true";
146+
>"true" : "true"
147+
}
148+
if (pf()) { // error
149+
>pf() : Promise<boolean>
150+
>pf : () => Promise<boolean>
151+
152+
pf().then();
153+
>pf().then() : Promise<boolean>
154+
>pf().then : <TResult1 = boolean, TResult2 = never>(onfulfilled?: ((value: boolean) => TResult1 | PromiseLike<TResult1>) | null | undefined, onrejected?: ((reason: any) => TResult2 | PromiseLike<TResult2>) | null | undefined) => Promise<TResult1 | TResult2>
155+
>pf() : Promise<boolean>
156+
>pf : () => Promise<boolean>
157+
>then : <TResult1 = boolean, TResult2 = never>(onfulfilled?: ((value: boolean) => TResult1 | PromiseLike<TResult1>) | null | undefined, onrejected?: ((reason: any) => TResult2 | PromiseLike<TResult2>) | null | undefined) => Promise<TResult1 | TResult2>
158+
}
159+
return "false";
160+
>"false" : "false"
161+
}
162+

Diff for: tests/cases/compiler/truthinessPromiseCoercion.ts

+11
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
declare const p: Promise<number>
55
declare const p2: null | Promise<number>
66
declare const obj: { p: Promise<unknown> }
7+
declare function pf(): Promise<boolean>
78

89
async function f() {
910
if (p) {} // err
@@ -37,3 +38,13 @@ async function h() {
3738
}
3839
if (obj.p && await obj.p) {} // ok
3940
}
41+
42+
async function i(): Promise<string> {
43+
if (pf()) { // error
44+
return "true";
45+
}
46+
if (pf()) { // error
47+
pf().then();
48+
}
49+
return "false";
50+
}

0 commit comments

Comments
 (0)