Skip to content

Commit c9eb846

Browse files
Improve error message for use of 'await' in non-async context (microsoft#31194)
Improve error message for use of 'await' in non-async context
2 parents e8161ef + bafdf4b commit c9eb846

9 files changed

+472
-3
lines changed

src/compiler/checker.ts

Lines changed: 27 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23087,7 +23087,19 @@ namespace ts {
2308723087
// Grammar checking
2308823088
if (produceDiagnostics) {
2308923089
if (!(node.flags & NodeFlags.AwaitContext)) {
23090-
grammarErrorOnFirstToken(node, Diagnostics.await_expression_is_only_allowed_within_an_async_function);
23090+
// use of 'await' in non-async function
23091+
const sourceFile = getSourceFileOfNode(node);
23092+
if (!hasParseDiagnostics(sourceFile)) {
23093+
const span = getSpanOfTokenAtPosition(sourceFile, node.pos);
23094+
const diagnostic = createFileDiagnostic(sourceFile, span.start, span.length, Diagnostics.await_expression_is_only_allowed_within_an_async_function);
23095+
const func = getContainingFunction(node);
23096+
if (func && func.kind !== SyntaxKind.Constructor) {
23097+
Debug.assert((getFunctionFlags(func) & FunctionFlags.Async) === 0, "Enclosing function should never be an async function.");
23098+
const relatedInfo = createDiagnosticForNode(func, Diagnostics.Did_you_mean_to_mark_this_function_as_async);
23099+
addRelatedInfo(diagnostic, relatedInfo);
23100+
}
23101+
diagnostics.add(diagnostic);
23102+
}
2309123103
}
2309223104

2309323105
if (isInParameterInitializerBeforeContainingFunction(node)) {
@@ -31585,7 +31597,20 @@ namespace ts {
3158531597

3158631598
if (forInOrOfStatement.kind === SyntaxKind.ForOfStatement && forInOrOfStatement.awaitModifier) {
3158731599
if ((forInOrOfStatement.flags & NodeFlags.AwaitContext) === NodeFlags.None) {
31588-
return grammarErrorOnNode(forInOrOfStatement.awaitModifier, Diagnostics.A_for_await_of_statement_is_only_allowed_within_an_async_function_or_async_generator);
31600+
// use of 'for-await-of' in non-async function
31601+
const sourceFile = getSourceFileOfNode(forInOrOfStatement);
31602+
if (!hasParseDiagnostics(sourceFile)) {
31603+
const diagnostic = createDiagnosticForNode(forInOrOfStatement.awaitModifier, Diagnostics.A_for_await_of_statement_is_only_allowed_within_an_async_function_or_async_generator);
31604+
const func = getContainingFunction(forInOrOfStatement);
31605+
if (func && func.kind !== SyntaxKind.Constructor) {
31606+
Debug.assert((getFunctionFlags(func) & FunctionFlags.Async) === 0, "Enclosing function should never be an async function.");
31607+
const relatedInfo = createDiagnosticForNode(func, Diagnostics.Did_you_mean_to_mark_this_function_as_async);
31608+
addRelatedInfo(diagnostic, relatedInfo);
31609+
}
31610+
diagnostics.add(diagnostic);
31611+
return true;
31612+
}
31613+
return false;
3158931614
}
3159031615
}
3159131616

src/compiler/diagnosticMessages.json

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1035,6 +1035,10 @@
10351035
"category": "Error",
10361036
"code": 1355
10371037
},
1038+
"Did you mean to mark this function as 'async'?": {
1039+
"category": "Error",
1040+
"code": 1356
1041+
},
10381042

10391043
"Duplicate identifier '{0}'.": {
10401044
"category": "Error",
@@ -2959,7 +2963,7 @@
29592963
"category": "Error",
29602964
"code": 4104
29612965
},
2962-
2966+
29632967
"The current host does not support the '{0}' option.": {
29642968
"category": "Error",
29652969
"code": 5001
Lines changed: 103 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,103 @@
1+
tests/cases/compiler/awaitInNonAsyncFunction.ts(4,7): error TS1103: A 'for-await-of' statement is only allowed within an async function or async generator.
2+
tests/cases/compiler/awaitInNonAsyncFunction.ts(5,10): error TS1308: 'await' expression is only allowed within an async function.
3+
tests/cases/compiler/awaitInNonAsyncFunction.ts(9,7): error TS1103: A 'for-await-of' statement is only allowed within an async function or async generator.
4+
tests/cases/compiler/awaitInNonAsyncFunction.ts(10,10): error TS1308: 'await' expression is only allowed within an async function.
5+
tests/cases/compiler/awaitInNonAsyncFunction.ts(14,7): error TS1103: A 'for-await-of' statement is only allowed within an async function or async generator.
6+
tests/cases/compiler/awaitInNonAsyncFunction.ts(15,3): error TS1308: 'await' expression is only allowed within an async function.
7+
tests/cases/compiler/awaitInNonAsyncFunction.ts(19,7): error TS1103: A 'for-await-of' statement is only allowed within an async function or async generator.
8+
tests/cases/compiler/awaitInNonAsyncFunction.ts(20,10): error TS1308: 'await' expression is only allowed within an async function.
9+
tests/cases/compiler/awaitInNonAsyncFunction.ts(24,7): error TS1103: A 'for-await-of' statement is only allowed within an async function or async generator.
10+
tests/cases/compiler/awaitInNonAsyncFunction.ts(25,9): error TS1308: 'await' expression is only allowed within an async function.
11+
tests/cases/compiler/awaitInNonAsyncFunction.ts(30,9): error TS1103: A 'for-await-of' statement is only allowed within an async function or async generator.
12+
tests/cases/compiler/awaitInNonAsyncFunction.ts(31,5): error TS1308: 'await' expression is only allowed within an async function.
13+
tests/cases/compiler/awaitInNonAsyncFunction.ts(34,7): error TS1103: A 'for-await-of' statement is only allowed within an async function or async generator.
14+
tests/cases/compiler/awaitInNonAsyncFunction.ts(35,5): error TS1308: 'await' expression is only allowed within an async function.
15+
tests/cases/compiler/awaitInNonAsyncFunction.ts(39,5): error TS1103: A 'for-await-of' statement is only allowed within an async function or async generator.
16+
tests/cases/compiler/awaitInNonAsyncFunction.ts(40,1): error TS1308: 'await' expression is only allowed within an async function.
17+
18+
19+
==== tests/cases/compiler/awaitInNonAsyncFunction.ts (16 errors) ====
20+
// https://github.com/Microsoft/TypeScript/issues/26586
21+
22+
function normalFunc(p: Promise<number>) {
23+
for await (const _ of []);
24+
~~~~~
25+
!!! error TS1103: A 'for-await-of' statement is only allowed within an async function or async generator.
26+
!!! related TS1356 tests/cases/compiler/awaitInNonAsyncFunction.ts:3:10: Did you mean to mark this function as 'async'?
27+
return await p;
28+
~~~~~
29+
!!! error TS1308: 'await' expression is only allowed within an async function.
30+
!!! related TS1356 tests/cases/compiler/awaitInNonAsyncFunction.ts:3:10: Did you mean to mark this function as 'async'?
31+
}
32+
33+
export function exportedFunc(p: Promise<number>) {
34+
for await (const _ of []);
35+
~~~~~
36+
!!! error TS1103: A 'for-await-of' statement is only allowed within an async function or async generator.
37+
!!! related TS1356 tests/cases/compiler/awaitInNonAsyncFunction.ts:8:17: Did you mean to mark this function as 'async'?
38+
return await p;
39+
~~~~~
40+
!!! error TS1308: 'await' expression is only allowed within an async function.
41+
!!! related TS1356 tests/cases/compiler/awaitInNonAsyncFunction.ts:8:17: Did you mean to mark this function as 'async'?
42+
}
43+
44+
const functionExpression = function(p: Promise<number>) {
45+
for await (const _ of []);
46+
~~~~~
47+
!!! error TS1103: A 'for-await-of' statement is only allowed within an async function or async generator.
48+
!!! related TS1356 tests/cases/compiler/awaitInNonAsyncFunction.ts:13:28: Did you mean to mark this function as 'async'?
49+
await p;
50+
~~~~~
51+
!!! error TS1308: 'await' expression is only allowed within an async function.
52+
!!! related TS1356 tests/cases/compiler/awaitInNonAsyncFunction.ts:13:28: Did you mean to mark this function as 'async'?
53+
}
54+
55+
const arrowFunc = (p: Promise<number>) => {
56+
for await (const _ of []);
57+
~~~~~
58+
!!! error TS1103: A 'for-await-of' statement is only allowed within an async function or async generator.
59+
!!! related TS1356 tests/cases/compiler/awaitInNonAsyncFunction.ts:18:19: Did you mean to mark this function as 'async'?
60+
return await p;
61+
~~~~~
62+
!!! error TS1308: 'await' expression is only allowed within an async function.
63+
!!! related TS1356 tests/cases/compiler/awaitInNonAsyncFunction.ts:18:19: Did you mean to mark this function as 'async'?
64+
};
65+
66+
function* generatorFunc(p: Promise<number>) {
67+
for await (const _ of []);
68+
~~~~~
69+
!!! error TS1103: A 'for-await-of' statement is only allowed within an async function or async generator.
70+
!!! related TS1356 tests/cases/compiler/awaitInNonAsyncFunction.ts:23:11: Did you mean to mark this function as 'async'?
71+
yield await p;
72+
~~~~~
73+
!!! error TS1308: 'await' expression is only allowed within an async function.
74+
!!! related TS1356 tests/cases/compiler/awaitInNonAsyncFunction.ts:23:11: Did you mean to mark this function as 'async'?
75+
}
76+
77+
class clazz {
78+
constructor(p: Promise<number>) {
79+
for await (const _ of []);
80+
~~~~~
81+
!!! error TS1103: A 'for-await-of' statement is only allowed within an async function or async generator.
82+
await p;
83+
~~~~~
84+
!!! error TS1308: 'await' expression is only allowed within an async function.
85+
}
86+
method(p: Promise<number>) {
87+
for await (const _ of []);
88+
~~~~~
89+
!!! error TS1103: A 'for-await-of' statement is only allowed within an async function or async generator.
90+
!!! related TS1356 tests/cases/compiler/awaitInNonAsyncFunction.ts:33:3: Did you mean to mark this function as 'async'?
91+
await p;
92+
~~~~~
93+
!!! error TS1308: 'await' expression is only allowed within an async function.
94+
!!! related TS1356 tests/cases/compiler/awaitInNonAsyncFunction.ts:33:3: Did you mean to mark this function as 'async'?
95+
}
96+
}
97+
98+
for await (const _ of []);
99+
~~~~~
100+
!!! error TS1103: A 'for-await-of' statement is only allowed within an async function or async generator.
101+
await null;
102+
~~~~~
103+
!!! error TS1308: 'await' expression is only allowed within an async function.
Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
//// [awaitInNonAsyncFunction.ts]
2+
// https://github.com/Microsoft/TypeScript/issues/26586
3+
4+
function normalFunc(p: Promise<number>) {
5+
for await (const _ of []);
6+
return await p;
7+
}
8+
9+
export function exportedFunc(p: Promise<number>) {
10+
for await (const _ of []);
11+
return await p;
12+
}
13+
14+
const functionExpression = function(p: Promise<number>) {
15+
for await (const _ of []);
16+
await p;
17+
}
18+
19+
const arrowFunc = (p: Promise<number>) => {
20+
for await (const _ of []);
21+
return await p;
22+
};
23+
24+
function* generatorFunc(p: Promise<number>) {
25+
for await (const _ of []);
26+
yield await p;
27+
}
28+
29+
class clazz {
30+
constructor(p: Promise<number>) {
31+
for await (const _ of []);
32+
await p;
33+
}
34+
method(p: Promise<number>) {
35+
for await (const _ of []);
36+
await p;
37+
}
38+
}
39+
40+
for await (const _ of []);
41+
await null;
42+
43+
//// [awaitInNonAsyncFunction.js]
44+
// https://github.com/Microsoft/TypeScript/issues/26586
45+
function normalFunc(p) {
46+
for await (const _ of [])
47+
;
48+
return await p;
49+
}
50+
export function exportedFunc(p) {
51+
for await (const _ of [])
52+
;
53+
return await p;
54+
}
55+
const functionExpression = function (p) {
56+
for await (const _ of [])
57+
;
58+
await p;
59+
};
60+
const arrowFunc = (p) => {
61+
for await (const _ of [])
62+
;
63+
return await p;
64+
};
65+
function* generatorFunc(p) {
66+
for await (const _ of [])
67+
;
68+
yield await p;
69+
}
70+
class clazz {
71+
constructor(p) {
72+
for await (const _ of [])
73+
;
74+
await p;
75+
}
76+
method(p) {
77+
for await (const _ of [])
78+
;
79+
await p;
80+
}
81+
}
82+
for await (const _ of [])
83+
;
84+
await null;
Lines changed: 94 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,94 @@
1+
=== tests/cases/compiler/awaitInNonAsyncFunction.ts ===
2+
// https://github.com/Microsoft/TypeScript/issues/26586
3+
4+
function normalFunc(p: Promise<number>) {
5+
>normalFunc : Symbol(normalFunc, Decl(awaitInNonAsyncFunction.ts, 0, 0))
6+
>p : Symbol(p, Decl(awaitInNonAsyncFunction.ts, 2, 20))
7+
>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, --, --))
8+
9+
for await (const _ of []);
10+
>_ : Symbol(_, Decl(awaitInNonAsyncFunction.ts, 3, 18))
11+
12+
return await p;
13+
>p : Symbol(p, Decl(awaitInNonAsyncFunction.ts, 2, 20))
14+
}
15+
16+
export function exportedFunc(p: Promise<number>) {
17+
>exportedFunc : Symbol(exportedFunc, Decl(awaitInNonAsyncFunction.ts, 5, 1))
18+
>p : Symbol(p, Decl(awaitInNonAsyncFunction.ts, 7, 29))
19+
>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, --, --))
20+
21+
for await (const _ of []);
22+
>_ : Symbol(_, Decl(awaitInNonAsyncFunction.ts, 8, 18))
23+
24+
return await p;
25+
>p : Symbol(p, Decl(awaitInNonAsyncFunction.ts, 7, 29))
26+
}
27+
28+
const functionExpression = function(p: Promise<number>) {
29+
>functionExpression : Symbol(functionExpression, Decl(awaitInNonAsyncFunction.ts, 12, 5))
30+
>p : Symbol(p, Decl(awaitInNonAsyncFunction.ts, 12, 36))
31+
>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, --, --))
32+
33+
for await (const _ of []);
34+
>_ : Symbol(_, Decl(awaitInNonAsyncFunction.ts, 13, 18))
35+
36+
await p;
37+
>p : Symbol(p, Decl(awaitInNonAsyncFunction.ts, 12, 36))
38+
}
39+
40+
const arrowFunc = (p: Promise<number>) => {
41+
>arrowFunc : Symbol(arrowFunc, Decl(awaitInNonAsyncFunction.ts, 17, 5))
42+
>p : Symbol(p, Decl(awaitInNonAsyncFunction.ts, 17, 19))
43+
>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, --, --))
44+
45+
for await (const _ of []);
46+
>_ : Symbol(_, Decl(awaitInNonAsyncFunction.ts, 18, 18))
47+
48+
return await p;
49+
>p : Symbol(p, Decl(awaitInNonAsyncFunction.ts, 17, 19))
50+
51+
};
52+
53+
function* generatorFunc(p: Promise<number>) {
54+
>generatorFunc : Symbol(generatorFunc, Decl(awaitInNonAsyncFunction.ts, 20, 2))
55+
>p : Symbol(p, Decl(awaitInNonAsyncFunction.ts, 22, 24))
56+
>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, --, --))
57+
58+
for await (const _ of []);
59+
>_ : Symbol(_, Decl(awaitInNonAsyncFunction.ts, 23, 18))
60+
61+
yield await p;
62+
>p : Symbol(p, Decl(awaitInNonAsyncFunction.ts, 22, 24))
63+
}
64+
65+
class clazz {
66+
>clazz : Symbol(clazz, Decl(awaitInNonAsyncFunction.ts, 25, 1))
67+
68+
constructor(p: Promise<number>) {
69+
>p : Symbol(p, Decl(awaitInNonAsyncFunction.ts, 28, 14))
70+
>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, --, --))
71+
72+
for await (const _ of []);
73+
>_ : Symbol(_, Decl(awaitInNonAsyncFunction.ts, 29, 20))
74+
75+
await p;
76+
>p : Symbol(p, Decl(awaitInNonAsyncFunction.ts, 28, 14))
77+
}
78+
method(p: Promise<number>) {
79+
>method : Symbol(clazz.method, Decl(awaitInNonAsyncFunction.ts, 31, 3))
80+
>p : Symbol(p, Decl(awaitInNonAsyncFunction.ts, 32, 9))
81+
>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, --, --))
82+
83+
for await (const _ of []);
84+
>_ : Symbol(_, Decl(awaitInNonAsyncFunction.ts, 33, 18))
85+
86+
await p;
87+
>p : Symbol(p, Decl(awaitInNonAsyncFunction.ts, 32, 9))
88+
}
89+
}
90+
91+
for await (const _ of []);
92+
>_ : Symbol(_, Decl(awaitInNonAsyncFunction.ts, 38, 16))
93+
94+
await null;

0 commit comments

Comments
 (0)