Skip to content

Commit

Permalink
fix(parser): better diagnostic for invalid for await syntax (#7649)
Browse files Browse the repository at this point in the history
  • Loading branch information
Boshen committed Dec 4, 2024
1 parent 1de2842 commit 8c0b0ee
Show file tree
Hide file tree
Showing 5 changed files with 255 additions and 31 deletions.
7 changes: 3 additions & 4 deletions crates/oxc_parser/src/js/expression.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1136,11 +1136,10 @@ impl<'a> ParserImpl<'a> {
/// await `UnaryExpression`[?Yield, +Await]
fn parse_await_expression(&mut self, lhs_span: Span) -> Result<Expression<'a>> {
let span = self.start_span();
self.bump_any();
let has_await = self.ctx.has_await();
if !has_await {
self.error(diagnostics::await_expression(Span::new(span.start, span.start + 5)));
if !self.ctx.has_await() {
self.error(diagnostics::await_expression(self.cur_token().span()));
}
self.bump_any();
let argument = self.context(Context::Await, Context::empty(), |p| {
p.parse_simple_unary_expression(lhs_span)
})?;
Expand Down
10 changes: 9 additions & 1 deletion crates/oxc_parser/src/js/statement.rs
Original file line number Diff line number Diff line change
Expand Up @@ -241,7 +241,15 @@ impl<'a> ParserImpl<'a> {
self.bump_any(); // bump `for`

// [+Await]
let r#await = self.ctx.has_await() && self.eat(Kind::Await);
let r#await = if self.at(Kind::Await) {
if !self.ctx.has_await() {
self.error(diagnostics::await_expression(self.cur_token().span()));
}
self.bump_any();
true
} else {
false
};

self.expect(Kind::LParen)?;

Expand Down
15 changes: 6 additions & 9 deletions tasks/coverage/snapshots/parser_babel.snap
Original file line number Diff line number Diff line change
Expand Up @@ -942,11 +942,10 @@ Expect to Parse: tasks/coverage/babel/packages/babel-parser/test/fixtures/typesc
· ──────
╰────

× Expected `(` but found `await`
× `await` is only allowed within async functions and at the top levels of modules
╭─[babel/packages/babel-parser/test/fixtures/core/opts/allowAwaitOutsideFunction-false/input.js:1:5]
1 │ for await (const i of imports) {}
· ──┬──
· ╰── `(` expected
· ─────
╰────

× Unexpected new.target expression
Expand Down Expand Up @@ -5370,12 +5369,11 @@ Expect to Parse: tasks/coverage/babel/packages/babel-parser/test/fixtures/typesc
· ╰── `)` expected
╰────

× Expected `(` but found `await`
× `await` is only allowed within async functions and at the top levels of modules
╭─[babel/packages/babel-parser/test/fixtures/es2018/async-generators/for-await-async-context/input.js:2:7]
1 │ function f() {
2 │ for await (let x of y);
· ──┬──
· ╰── `(` expected
· ─────
3 │ }
╰────

Expand Down Expand Up @@ -8317,11 +8315,10 @@ Expect to Parse: tasks/coverage/babel/packages/babel-parser/test/fixtures/typesc
3 │ }
╰────

× Expected `(` but found `await`
× `await` is only allowed within async functions and at the top levels of modules
╭─[babel/packages/babel-parser/test/fixtures/es2022/top-level-await-script/for-await/input.js:1:5]
1 │ for await (const a of b);
· ──┬──
· ╰── `(` expected
· ─────
╰────

× `await` is only allowed within async functions and at the top levels of modules
Expand Down
242 changes: 226 additions & 16 deletions tasks/coverage/snapshots/parser_typescript.snap
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
commit: d85767ab

parser_typescript Summary:
AST Parsed : 6494/6503 (99.86%)
AST Parsed : 6495/6503 (99.88%)
Positive Passed: 6483/6503 (99.69%)
Negative Passed: 1239/5747 (21.56%)
Expect Syntax Error: tasks/coverage/typescript/tests/cases/compiler/ClassDeclaration10.ts
Expand Down Expand Up @@ -4514,14 +4514,92 @@ Expect Syntax Error: tasks/coverage/typescript/tests/cases/conformance/typings/t
Expect Syntax Error: tasks/coverage/typescript/tests/cases/conformance/typings/typingsSuggestionBun2.ts
Expect to Parse: tasks/coverage/typescript/tests/cases/compiler/arrayFromAsync.ts

× Expected `(` but found `await`
× `await` is only allowed within async functions and at the top levels of modules
╭─[typescript/tests/cases/compiler/arrayFromAsync.ts:22:5]
21 │ const arr : number[] = [];
22 │ for await (const v of asyncGen(4)) {
· ──┬──
· ╰── `(` expected
· ─────
23 │ arr.push(v);
╰────

× `await` is only allowed within async functions and at the top levels of modules
╭─[typescript/tests/cases/compiler/arrayFromAsync.ts:26:18]
25 │
26 │ const sameArr1 = await Array.fromAsync(arrLike);
· ─────
27 │ const sameArr2 = await Array.fromAsync([Promise.resolve(0), Promise.resolve(2), Promise.resolve(4), Promise.resolve(6)]);
╰────

× `await` is only allowed within async functions and at the top levels of modules
╭─[typescript/tests/cases/compiler/arrayFromAsync.ts:27:18]
26 │ const sameArr1 = await Array.fromAsync(arrLike);
27 │ const sameArr2 = await Array.fromAsync([Promise.resolve(0), Promise.resolve(2), Promise.resolve(4), Promise.resolve(6)]);
· ─────
28 │ const sameArr3 = await Array.fromAsync(genPromises(4));
╰────

× `await` is only allowed within async functions and at the top levels of modules
╭─[typescript/tests/cases/compiler/arrayFromAsync.ts:28:18]
27 │ const sameArr2 = await Array.fromAsync([Promise.resolve(0), Promise.resolve(2), Promise.resolve(4), Promise.resolve(6)]);
28 │ const sameArr3 = await Array.fromAsync(genPromises(4));
· ─────
29 │ const sameArr4 = await Array.fromAsync(asyncGen(4));
╰────

× `await` is only allowed within async functions and at the top levels of modules
╭─[typescript/tests/cases/compiler/arrayFromAsync.ts:29:18]
28 │ const sameArr3 = await Array.fromAsync(genPromises(4));
29 │ const sameArr4 = await Array.fromAsync(asyncGen(4));
· ─────
30 │
╰────

× `await` is only allowed within async functions and at the top levels of modules
╭─[typescript/tests/cases/compiler/arrayFromAsync.ts:33:18]
32 │ Data.fromAsync = Array.fromAsync;
33 │ const sameArr5 = await Data.fromAsync(asyncGen(4));
· ─────
34 │
╰────

× `await` is only allowed within async functions and at the top levels of modules
╭─[typescript/tests/cases/compiler/arrayFromAsync.ts:35:17]
34 │
35 │ const mapArr1 = await Array.fromAsync(asyncGen(4), v => v ** 2);
· ─────
36 │ const mapArr2 = await Array.fromAsync([0,2,4,6], v => Promise.resolve(v ** 2));
╰────

× `await` is only allowed within async functions and at the top levels of modules
╭─[typescript/tests/cases/compiler/arrayFromAsync.ts:36:17]
35 │ const mapArr1 = await Array.fromAsync(asyncGen(4), v => v ** 2);
36 │ const mapArr2 = await Array.fromAsync([0,2,4,6], v => Promise.resolve(v ** 2));
· ─────
37 │ const mapArr3 = await Array.fromAsync([0,2,4,6], v => v ** 2);
╰────

× `await` is only allowed within async functions and at the top levels of modules
╭─[typescript/tests/cases/compiler/arrayFromAsync.ts:37:17]
36 │ const mapArr2 = await Array.fromAsync([0,2,4,6], v => Promise.resolve(v ** 2));
37 │ const mapArr3 = await Array.fromAsync([0,2,4,6], v => v ** 2);
· ─────
38 │
╰────

× `await` is only allowed within async functions and at the top levels of modules
╭─[typescript/tests/cases/compiler/arrayFromAsync.ts:42:18]
41 │ // This returns a promise that will reject with `err`.
42 │ const badArray = await Array.fromAsync(badIterable);
· ─────
43 │
╰────

× `await` is only allowed within async functions and at the top levels of modules
╭─[typescript/tests/cases/compiler/arrayFromAsync.ts:44:25]
43 │
44 │ const withIndexResult = await Array.fromAsync(["a", "b"], (str, index) => ({ index, str }));
· ─────
╰────
Expect to Parse: tasks/coverage/typescript/tests/cases/compiler/bom-utf16be.ts

× Invalid Character `￾`
Expand Down Expand Up @@ -5514,15 +5592,133 @@ Expect to Parse: tasks/coverage/typescript/tests/cases/conformance/salsa/private
╰────
help: Try insert a semicolon here

× Expected `(` but found `await`
× `await` is only allowed within async functions and at the top levels of modules
╭─[typescript/tests/cases/compiler/awaitInNonAsyncFunction.ts:4:7]
3 │ function normalFunc(p: Promise<number>) {
4 │ for await (const _ of []);
· ──┬──
· ╰── `(` expected
· ─────
5 │ return await p;
╰────

× `await` is only allowed within async functions and at the top levels of modules
╭─[typescript/tests/cases/compiler/awaitInNonAsyncFunction.ts:5:10]
4 │ for await (const _ of []);
5 │ return await p;
· ─────
6 │ }
╰────

× `await` is only allowed within async functions and at the top levels of modules
╭─[typescript/tests/cases/compiler/awaitInNonAsyncFunction.ts:9:7]
8 │ export function exportedFunc(p: Promise<number>) {
9 │ for await (const _ of []);
· ─────
10 │ return await p;
╰────

× `await` is only allowed within async functions and at the top levels of modules
╭─[typescript/tests/cases/compiler/awaitInNonAsyncFunction.ts:10:10]
9 │ for await (const _ of []);
10 │ return await p;
· ─────
11 │ }
╰────

× `await` is only allowed within async functions and at the top levels of modules
╭─[typescript/tests/cases/compiler/awaitInNonAsyncFunction.ts:14:7]
13 │ const functionExpression = function(p: Promise<number>) {
14 │ for await (const _ of []);
· ─────
15 │ await p;
╰────

× `await` is only allowed within async functions and at the top levels of modules
╭─[typescript/tests/cases/compiler/awaitInNonAsyncFunction.ts:15:3]
14 │ for await (const _ of []);
15 │ await p;
· ─────
16 │ }
╰────

× `await` is only allowed within async functions and at the top levels of modules
╭─[typescript/tests/cases/compiler/awaitInNonAsyncFunction.ts:19:7]
18 │ const arrowFunc = (p: Promise<number>) => {
19 │ for await (const _ of []);
· ─────
20 │ return await p;
╰────

× `await` is only allowed within async functions and at the top levels of modules
╭─[typescript/tests/cases/compiler/awaitInNonAsyncFunction.ts:20:10]
19 │ for await (const _ of []);
20 │ return await p;
· ─────
21 │ };
╰────

× `await` is only allowed within async functions and at the top levels of modules
╭─[typescript/tests/cases/compiler/awaitInNonAsyncFunction.ts:24:7]
23 │ function* generatorFunc(p: Promise<number>) {
24 │ for await (const _ of []);
· ─────
25 │ yield await p;
╰────

× `await` is only allowed within async functions and at the top levels of modules
╭─[typescript/tests/cases/compiler/awaitInNonAsyncFunction.ts:25:9]
24 │ for await (const _ of []);
25 │ yield await p;
· ─────
26 │ }
╰────

× `await` is only allowed within async functions and at the top levels of modules
╭─[typescript/tests/cases/compiler/awaitInNonAsyncFunction.ts:30:9]
29 │ constructor(p: Promise<number>) {
30 │ for await (const _ of []);
· ─────
31 │ await p;
╰────

× `await` is only allowed within async functions and at the top levels of modules
╭─[typescript/tests/cases/compiler/awaitInNonAsyncFunction.ts:31:5]
30 │ for await (const _ of []);
31 │ await p;
· ─────
32 │ }
╰────

× `await` is only allowed within async functions and at the top levels of modules
╭─[typescript/tests/cases/compiler/awaitInNonAsyncFunction.ts:34:7]
33 │ method(p: Promise<number>) {
34 │ for await (const _ of []);
· ─────
35 │ await p;
╰────

× `await` is only allowed within async functions and at the top levels of modules
╭─[typescript/tests/cases/compiler/awaitInNonAsyncFunction.ts:35:5]
34 │ for await (const _ of []);
35 │ await p;
· ─────
36 │ }
╰────

× `await` is only allowed within async functions and at the top levels of modules
╭─[typescript/tests/cases/compiler/awaitInNonAsyncFunction.ts:39:5]
38 │
39 │ for await (const _ of []);
· ─────
40 │ await null;
╰────

× `await` is only allowed within async functions and at the top levels of modules
╭─[typescript/tests/cases/compiler/awaitInNonAsyncFunction.ts:40:1]
39 │ for await (const _ of []);
40 │ await null;
· ─────
╰────

× `await` is only allowed within async functions and at the top levels of modules
╭─[typescript/tests/cases/compiler/awaitLiteralValues.ts:2:5]
1 │ function awaitString() {
Expand Down Expand Up @@ -9387,14 +9583,21 @@ Expect to Parse: tasks/coverage/typescript/tests/cases/conformance/salsa/private
╰────
help: Try insert a semicolon here

× Expected `(` but found `await`
× `await` is only allowed within async functions and at the top levels of modules
╭─[typescript/tests/cases/compiler/modulePreserveTopLevelAwait1.ts:1:5]
1 │ for await (const x of []) {}
· ──┬──
· ╰── `(` expected
· ─────
2 │ await Promise.resolve();
╰────

× `await` is only allowed within async functions and at the top levels of modules
╭─[typescript/tests/cases/compiler/modulePreserveTopLevelAwait1.ts:2:1]
1 │ for await (const x of []) {}
2 │ await Promise.resolve();
· ─────
3 │
╰────

× Expected a semicolon or an implicit semicolon after a statement, but found none
╭─[typescript/tests/cases/compiler/moduleProperty1.ts:9:12]
8 │ var x = 10; // variable local to this module body
Expand Down Expand Up @@ -19129,12 +19332,11 @@ Expect to Parse: tasks/coverage/typescript/tests/cases/conformance/salsa/private
2 │
╰────

× Expected `(` but found `await`
× `await` is only allowed within async functions and at the top levels of modules
╭─[typescript/tests/cases/conformance/externalModules/topLevelAwaitNonModule.ts:5:5]
4 │
5 │ for await (const item of arr) {
· ──┬──
· ╰── `(` expected
· ─────
6 │ item;
╰────

Expand Down Expand Up @@ -22808,12 +23010,20 @@ Expect to Parse: tasks/coverage/typescript/tests/cases/conformance/salsa/private
3 │ }
╰────

× Expected `(` but found `await`
× `await` is only allowed within async functions and at the top levels of modules
╭─[typescript/tests/cases/conformance/statements/VariableStatements/usingDeclarations/awaitUsingDeclarationsInForAwaitOf.3.ts:5:5]
4 │
5 │ for await (await using of x);
· ──┬──
· ╰── `(` expected
· ─────
6 │
╰────

× Expected `;` but found `Identifier`
╭─[typescript/tests/cases/conformance/statements/VariableStatements/usingDeclarations/awaitUsingDeclarationsInForAwaitOf.3.ts:5:27]
4 │
5 │ for await (await using of x);
· ┬
· ╰── `;` expected
6 │
╰────

Expand Down
12 changes: 11 additions & 1 deletion tasks/coverage/snapshots/semantic_typescript.snap
Original file line number Diff line number Diff line change
Expand Up @@ -987,7 +987,17 @@ after transform: ScopeId(1): ["T", "arr", "depth"]
rebuilt : ScopeId(1): ["arr", "depth"]

tasks/coverage/typescript/tests/cases/compiler/arrayFromAsync.ts
semantic error: Expected `(` but found `await`
semantic error: `await` is only allowed within async functions and at the top levels of modules
`await` is only allowed within async functions and at the top levels of modules
`await` is only allowed within async functions and at the top levels of modules
`await` is only allowed within async functions and at the top levels of modules
`await` is only allowed within async functions and at the top levels of modules
`await` is only allowed within async functions and at the top levels of modules
`await` is only allowed within async functions and at the top levels of modules
`await` is only allowed within async functions and at the top levels of modules
`await` is only allowed within async functions and at the top levels of modules
`await` is only allowed within async functions and at the top levels of modules
`await` is only allowed within async functions and at the top levels of modules

tasks/coverage/typescript/tests/cases/compiler/arrayLiteralContextualType.ts
semantic error: Bindings mismatch:
Expand Down

0 comments on commit 8c0b0ee

Please sign in to comment.