Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Improve error message for use of 'await' in non-async context #31194

Merged
merged 6 commits into from May 1, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
29 changes: 27 additions & 2 deletions src/compiler/checker.ts
Expand Up @@ -23087,7 +23087,19 @@ namespace ts {
// Grammar checking
if (produceDiagnostics) {
if (!(node.flags & NodeFlags.AwaitContext)) {
grammarErrorOnFirstToken(node, Diagnostics.await_expression_is_only_allowed_within_an_async_function);
// use of 'await' in non-async function
const sourceFile = getSourceFileOfNode(node);
if (!hasParseDiagnostics(sourceFile)) {
const span = getSpanOfTokenAtPosition(sourceFile, node.pos);
const diagnostic = createFileDiagnostic(sourceFile, span.start, span.length, Diagnostics.await_expression_is_only_allowed_within_an_async_function);
const func = getContainingFunction(node);
if (func && func.kind !== SyntaxKind.Constructor) {
Debug.assert((getFunctionFlags(func) & FunctionFlags.Async) === 0, "Enclosing function should never be an async function.");
const relatedInfo = createDiagnosticForNode(func, Diagnostics.Did_you_mean_to_mark_this_function_as_async);
addRelatedInfo(diagnostic, relatedInfo);
}
uhyo marked this conversation as resolved.
Show resolved Hide resolved
diagnostics.add(diagnostic);
}
}

if (isInParameterInitializerBeforeContainingFunction(node)) {
Expand Down Expand Up @@ -31585,7 +31597,20 @@ namespace ts {

if (forInOrOfStatement.kind === SyntaxKind.ForOfStatement && forInOrOfStatement.awaitModifier) {
if ((forInOrOfStatement.flags & NodeFlags.AwaitContext) === NodeFlags.None) {
return grammarErrorOnNode(forInOrOfStatement.awaitModifier, Diagnostics.A_for_await_of_statement_is_only_allowed_within_an_async_function_or_async_generator);
// use of 'for-await-of' in non-async function
const sourceFile = getSourceFileOfNode(forInOrOfStatement);
if (!hasParseDiagnostics(sourceFile)) {
const diagnostic = createDiagnosticForNode(forInOrOfStatement.awaitModifier, Diagnostics.A_for_await_of_statement_is_only_allowed_within_an_async_function_or_async_generator);
const func = getContainingFunction(forInOrOfStatement);
if (func && func.kind !== SyntaxKind.Constructor) {
Debug.assert((getFunctionFlags(func) & FunctionFlags.Async) === 0, "Enclosing function should never be an async function.");
const relatedInfo = createDiagnosticForNode(func, Diagnostics.Did_you_mean_to_mark_this_function_as_async);
addRelatedInfo(diagnostic, relatedInfo);
}
diagnostics.add(diagnostic);
return true;
}
return false;
}
}

Expand Down
6 changes: 5 additions & 1 deletion src/compiler/diagnosticMessages.json
Expand Up @@ -1035,6 +1035,10 @@
"category": "Error",
"code": 1355
},
"Did you mean to mark this function as 'async'?": {
"category": "Error",
"code": 1356
},

"Duplicate identifier '{0}'.": {
"category": "Error",
Expand Down Expand Up @@ -2959,7 +2963,7 @@
"category": "Error",
"code": 4104
},

"The current host does not support the '{0}' option.": {
"category": "Error",
"code": 5001
Expand Down
103 changes: 103 additions & 0 deletions tests/baselines/reference/awaitInNonAsyncFunction.errors.txt
@@ -0,0 +1,103 @@
tests/cases/compiler/awaitInNonAsyncFunction.ts(4,7): error TS1103: A 'for-await-of' statement is only allowed within an async function or async generator.
tests/cases/compiler/awaitInNonAsyncFunction.ts(5,10): error TS1308: 'await' expression is only allowed within an async function.
tests/cases/compiler/awaitInNonAsyncFunction.ts(9,7): error TS1103: A 'for-await-of' statement is only allowed within an async function or async generator.
tests/cases/compiler/awaitInNonAsyncFunction.ts(10,10): error TS1308: 'await' expression is only allowed within an async function.
tests/cases/compiler/awaitInNonAsyncFunction.ts(14,7): error TS1103: A 'for-await-of' statement is only allowed within an async function or async generator.
tests/cases/compiler/awaitInNonAsyncFunction.ts(15,3): error TS1308: 'await' expression is only allowed within an async function.
tests/cases/compiler/awaitInNonAsyncFunction.ts(19,7): error TS1103: A 'for-await-of' statement is only allowed within an async function or async generator.
tests/cases/compiler/awaitInNonAsyncFunction.ts(20,10): error TS1308: 'await' expression is only allowed within an async function.
tests/cases/compiler/awaitInNonAsyncFunction.ts(24,7): error TS1103: A 'for-await-of' statement is only allowed within an async function or async generator.
tests/cases/compiler/awaitInNonAsyncFunction.ts(25,9): error TS1308: 'await' expression is only allowed within an async function.
tests/cases/compiler/awaitInNonAsyncFunction.ts(30,9): error TS1103: A 'for-await-of' statement is only allowed within an async function or async generator.
tests/cases/compiler/awaitInNonAsyncFunction.ts(31,5): error TS1308: 'await' expression is only allowed within an async function.
tests/cases/compiler/awaitInNonAsyncFunction.ts(34,7): error TS1103: A 'for-await-of' statement is only allowed within an async function or async generator.
tests/cases/compiler/awaitInNonAsyncFunction.ts(35,5): error TS1308: 'await' expression is only allowed within an async function.
tests/cases/compiler/awaitInNonAsyncFunction.ts(39,5): error TS1103: A 'for-await-of' statement is only allowed within an async function or async generator.
tests/cases/compiler/awaitInNonAsyncFunction.ts(40,1): error TS1308: 'await' expression is only allowed within an async function.


==== tests/cases/compiler/awaitInNonAsyncFunction.ts (16 errors) ====
// https://github.com/Microsoft/TypeScript/issues/26586

function normalFunc(p: Promise<number>) {
for await (const _ of []);
~~~~~
!!! error TS1103: A 'for-await-of' statement is only allowed within an async function or async generator.
!!! related TS1356 tests/cases/compiler/awaitInNonAsyncFunction.ts:3:10: Did you mean to mark this function as 'async'?
return await p;
~~~~~
!!! error TS1308: 'await' expression is only allowed within an async function.
!!! related TS1356 tests/cases/compiler/awaitInNonAsyncFunction.ts:3:10: Did you mean to mark this function as 'async'?
}

export function exportedFunc(p: Promise<number>) {
for await (const _ of []);
~~~~~
!!! error TS1103: A 'for-await-of' statement is only allowed within an async function or async generator.
!!! related TS1356 tests/cases/compiler/awaitInNonAsyncFunction.ts:8:17: Did you mean to mark this function as 'async'?
return await p;
~~~~~
!!! error TS1308: 'await' expression is only allowed within an async function.
!!! related TS1356 tests/cases/compiler/awaitInNonAsyncFunction.ts:8:17: Did you mean to mark this function as 'async'?
}

const functionExpression = function(p: Promise<number>) {
for await (const _ of []);
~~~~~
!!! error TS1103: A 'for-await-of' statement is only allowed within an async function or async generator.
!!! related TS1356 tests/cases/compiler/awaitInNonAsyncFunction.ts:13:28: Did you mean to mark this function as 'async'?
await p;
~~~~~
!!! error TS1308: 'await' expression is only allowed within an async function.
!!! related TS1356 tests/cases/compiler/awaitInNonAsyncFunction.ts:13:28: Did you mean to mark this function as 'async'?
}

const arrowFunc = (p: Promise<number>) => {
for await (const _ of []);
~~~~~
!!! error TS1103: A 'for-await-of' statement is only allowed within an async function or async generator.
!!! related TS1356 tests/cases/compiler/awaitInNonAsyncFunction.ts:18:19: Did you mean to mark this function as 'async'?
return await p;
~~~~~
!!! error TS1308: 'await' expression is only allowed within an async function.
!!! related TS1356 tests/cases/compiler/awaitInNonAsyncFunction.ts:18:19: Did you mean to mark this function as 'async'?
};

function* generatorFunc(p: Promise<number>) {
for await (const _ of []);
~~~~~
!!! error TS1103: A 'for-await-of' statement is only allowed within an async function or async generator.
!!! related TS1356 tests/cases/compiler/awaitInNonAsyncFunction.ts:23:11: Did you mean to mark this function as 'async'?
yield await p;
~~~~~
!!! error TS1308: 'await' expression is only allowed within an async function.
!!! related TS1356 tests/cases/compiler/awaitInNonAsyncFunction.ts:23:11: Did you mean to mark this function as 'async'?
}

class clazz {
constructor(p: Promise<number>) {
for await (const _ of []);
~~~~~
!!! error TS1103: A 'for-await-of' statement is only allowed within an async function or async generator.
await p;
~~~~~
!!! error TS1308: 'await' expression is only allowed within an async function.
}
method(p: Promise<number>) {
for await (const _ of []);
~~~~~
!!! error TS1103: A 'for-await-of' statement is only allowed within an async function or async generator.
!!! related TS1356 tests/cases/compiler/awaitInNonAsyncFunction.ts:33:3: Did you mean to mark this function as 'async'?
await p;
~~~~~
!!! error TS1308: 'await' expression is only allowed within an async function.
!!! related TS1356 tests/cases/compiler/awaitInNonAsyncFunction.ts:33:3: Did you mean to mark this function as 'async'?
}
}

for await (const _ of []);
~~~~~
!!! error TS1103: A 'for-await-of' statement is only allowed within an async function or async generator.
await null;
~~~~~
!!! error TS1308: 'await' expression is only allowed within an async function.
84 changes: 84 additions & 0 deletions tests/baselines/reference/awaitInNonAsyncFunction.js
@@ -0,0 +1,84 @@
//// [awaitInNonAsyncFunction.ts]
// https://github.com/Microsoft/TypeScript/issues/26586

function normalFunc(p: Promise<number>) {
for await (const _ of []);
return await p;
}

export function exportedFunc(p: Promise<number>) {
for await (const _ of []);
return await p;
}

const functionExpression = function(p: Promise<number>) {
for await (const _ of []);
await p;
}

const arrowFunc = (p: Promise<number>) => {
for await (const _ of []);
return await p;
};

function* generatorFunc(p: Promise<number>) {
for await (const _ of []);
yield await p;
}

class clazz {
constructor(p: Promise<number>) {
for await (const _ of []);
await p;
}
method(p: Promise<number>) {
for await (const _ of []);
await p;
}
}

for await (const _ of []);
await null;

//// [awaitInNonAsyncFunction.js]
// https://github.com/Microsoft/TypeScript/issues/26586
function normalFunc(p) {
for await (const _ of [])
;
return await p;
}
export function exportedFunc(p) {
for await (const _ of [])
;
return await p;
}
const functionExpression = function (p) {
for await (const _ of [])
;
await p;
};
const arrowFunc = (p) => {
for await (const _ of [])
;
return await p;
};
function* generatorFunc(p) {
for await (const _ of [])
;
yield await p;
}
class clazz {
constructor(p) {
for await (const _ of [])
;
await p;
}
method(p) {
for await (const _ of [])
;
await p;
}
}
for await (const _ of [])
;
await null;
94 changes: 94 additions & 0 deletions tests/baselines/reference/awaitInNonAsyncFunction.symbols
@@ -0,0 +1,94 @@
=== tests/cases/compiler/awaitInNonAsyncFunction.ts ===
// https://github.com/Microsoft/TypeScript/issues/26586

function normalFunc(p: Promise<number>) {
>normalFunc : Symbol(normalFunc, Decl(awaitInNonAsyncFunction.ts, 0, 0))
>p : Symbol(p, Decl(awaitInNonAsyncFunction.ts, 2, 20))
>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, --, --))

for await (const _ of []);
>_ : Symbol(_, Decl(awaitInNonAsyncFunction.ts, 3, 18))

return await p;
>p : Symbol(p, Decl(awaitInNonAsyncFunction.ts, 2, 20))
}

export function exportedFunc(p: Promise<number>) {
>exportedFunc : Symbol(exportedFunc, Decl(awaitInNonAsyncFunction.ts, 5, 1))
>p : Symbol(p, Decl(awaitInNonAsyncFunction.ts, 7, 29))
>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, --, --))

for await (const _ of []);
>_ : Symbol(_, Decl(awaitInNonAsyncFunction.ts, 8, 18))

return await p;
>p : Symbol(p, Decl(awaitInNonAsyncFunction.ts, 7, 29))
}

const functionExpression = function(p: Promise<number>) {
>functionExpression : Symbol(functionExpression, Decl(awaitInNonAsyncFunction.ts, 12, 5))
>p : Symbol(p, Decl(awaitInNonAsyncFunction.ts, 12, 36))
>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, --, --))

for await (const _ of []);
>_ : Symbol(_, Decl(awaitInNonAsyncFunction.ts, 13, 18))

await p;
>p : Symbol(p, Decl(awaitInNonAsyncFunction.ts, 12, 36))
}

const arrowFunc = (p: Promise<number>) => {
>arrowFunc : Symbol(arrowFunc, Decl(awaitInNonAsyncFunction.ts, 17, 5))
>p : Symbol(p, Decl(awaitInNonAsyncFunction.ts, 17, 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, --, --))

for await (const _ of []);
>_ : Symbol(_, Decl(awaitInNonAsyncFunction.ts, 18, 18))

return await p;
>p : Symbol(p, Decl(awaitInNonAsyncFunction.ts, 17, 19))

};

function* generatorFunc(p: Promise<number>) {
>generatorFunc : Symbol(generatorFunc, Decl(awaitInNonAsyncFunction.ts, 20, 2))
>p : Symbol(p, Decl(awaitInNonAsyncFunction.ts, 22, 24))
>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, --, --))

for await (const _ of []);
>_ : Symbol(_, Decl(awaitInNonAsyncFunction.ts, 23, 18))

yield await p;
>p : Symbol(p, Decl(awaitInNonAsyncFunction.ts, 22, 24))
}

class clazz {
>clazz : Symbol(clazz, Decl(awaitInNonAsyncFunction.ts, 25, 1))

constructor(p: Promise<number>) {
>p : Symbol(p, Decl(awaitInNonAsyncFunction.ts, 28, 14))
>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, --, --))

for await (const _ of []);
>_ : Symbol(_, Decl(awaitInNonAsyncFunction.ts, 29, 20))

await p;
>p : Symbol(p, Decl(awaitInNonAsyncFunction.ts, 28, 14))
}
method(p: Promise<number>) {
>method : Symbol(clazz.method, Decl(awaitInNonAsyncFunction.ts, 31, 3))
>p : Symbol(p, Decl(awaitInNonAsyncFunction.ts, 32, 9))
>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, --, --))

for await (const _ of []);
>_ : Symbol(_, Decl(awaitInNonAsyncFunction.ts, 33, 18))

await p;
>p : Symbol(p, Decl(awaitInNonAsyncFunction.ts, 32, 9))
}
}

for await (const _ of []);
>_ : Symbol(_, Decl(awaitInNonAsyncFunction.ts, 38, 16))

await null;