Skip to content

Commit 4668004

Browse files
committed
fix(parser): reject using / await using in single statement contexts (#15224)
Reject codes like `while (1) using foo = {}` similar to `while (1) let foo = {}`.
1 parent 0398d40 commit 4668004

File tree

4 files changed

+212
-22
lines changed

4 files changed

+212
-22
lines changed

crates/oxc_parser/src/js/declaration.rs

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -53,10 +53,14 @@ impl<'a> ParserImpl<'a> {
5353
}
5454
}
5555

56-
pub(crate) fn parse_using_statement(&mut self) -> Statement<'a> {
57-
let mut decl = self.parse_using_declaration(StatementContext::StatementList);
56+
pub(crate) fn parse_using_statement(&mut self, stmt_ctx: StatementContext) -> Statement<'a> {
57+
let mut decl = self.parse_using_declaration(stmt_ctx);
5858
self.asi();
5959
decl.span = self.end_span(decl.span.start);
60+
debug_assert!(decl.kind.is_lexical());
61+
if stmt_ctx.is_single_statement() {
62+
self.error(diagnostics::lexical_declaration_single_statement(decl.span));
63+
}
6064
Statement::VariableDeclaration(self.alloc(decl))
6165
}
6266

crates/oxc_parser/src/js/statement.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -123,8 +123,8 @@ impl<'a> ParserImpl<'a> {
123123
Kind::Async => self.parse_async_statement(self.start_span(), stmt_ctx),
124124
Kind::Import => self.parse_import_statement(stmt_ctx),
125125
Kind::Const => self.parse_const_statement(stmt_ctx),
126-
Kind::Using if self.is_using_declaration() => self.parse_using_statement(),
127-
Kind::Await if self.is_using_statement() => self.parse_using_statement(),
126+
Kind::Using if self.is_using_declaration() => self.parse_using_statement(stmt_ctx),
127+
Kind::Await if self.is_using_statement() => self.parse_using_statement(stmt_ctx),
128128
Kind::Interface
129129
| Kind::Type
130130
| Kind::Module

tasks/coverage/snapshots/parser_babel.snap

Lines changed: 186 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -3,31 +3,19 @@ commit: 4cc3d888
33
parser_babel Summary:
44
AST Parsed : 2422/2440 (99.26%)
55
Positive Passed: 2395/2440 (98.16%)
6-
Negative Passed: 1679/1752 (95.83%)
6+
Negative Passed: 1685/1752 (96.18%)
77
Expect Syntax Error: tasks/coverage/babel/packages/babel-parser/test/fixtures/es2022/private-in/invalid-private-followed-by-in-2/input.js
88

9-
Expect Syntax Error: tasks/coverage/babel/packages/babel-parser/test/fixtures/es2026/async-explicit-resource-management/invalid-in-single-statement-context-async/input.js
10-
11-
Expect Syntax Error: tasks/coverage/babel/packages/babel-parser/test/fixtures/es2026/async-explicit-resource-management/invalid-in-single-statement-context-sync/input.js
12-
139
Expect Syntax Error: tasks/coverage/babel/packages/babel-parser/test/fixtures/es2026/async-explicit-resource-management/invalid-module-bare-case-await-using-binding/input.js
1410

1511
Expect Syntax Error: tasks/coverage/babel/packages/babel-parser/test/fixtures/es2026/async-explicit-resource-management/invalid-script-bare-case-await-using-binding/input.js
1612

17-
Expect Syntax Error: tasks/coverage/babel/packages/babel-parser/test/fixtures/es2026/async-explicit-resource-management/invalid-script-top-level-labeled-using-binding/input.js
18-
1913
Expect Syntax Error: tasks/coverage/babel/packages/babel-parser/test/fixtures/es2026/async-explicit-resource-management/invalid-script-top-level-using-binding/input.js
2014

21-
Expect Syntax Error: tasks/coverage/babel/packages/babel-parser/test/fixtures/es2026/explicit-resource-management/invalid-in-single-statement-context/input.js
22-
23-
Expect Syntax Error: tasks/coverage/babel/packages/babel-parser/test/fixtures/es2026/explicit-resource-management/invalid-labeled-using-binding/input.js
24-
2515
Expect Syntax Error: tasks/coverage/babel/packages/babel-parser/test/fixtures/es2026/explicit-resource-management/invalid-module-bare-case-using-binding/input.js
2616

2717
Expect Syntax Error: tasks/coverage/babel/packages/babel-parser/test/fixtures/es2026/explicit-resource-management/invalid-script-bare-case-using-binding/input.js
2818

29-
Expect Syntax Error: tasks/coverage/babel/packages/babel-parser/test/fixtures/es2026/explicit-resource-management/invalid-script-top-level-labeled-using-binding/input.js
30-
3119
Expect Syntax Error: tasks/coverage/babel/packages/babel-parser/test/fixtures/es2026/explicit-resource-management/invalid-script-top-level-using-binding/input.js
3220

3321
Expect Syntax Error: tasks/coverage/babel/packages/babel-parser/test/fixtures/estree/class-private-property/typescript-invalid-abstract/input.ts
@@ -9103,6 +9091,121 @@ Expect to Parse: tasks/coverage/babel/packages/babel-parser/test/fixtures/typesc
91039091
4 │ }
91049092
╰────
91059093

9094+
× Lexical declaration cannot appear in a single-statement context
9095+
╭─[babel/packages/babel-parser/test/fixtures/es2026/async-explicit-resource-management/invalid-in-single-statement-context-async/input.js:2:13]
9096+
1 │ async function f() {
9097+
2 │ while (1) await using a = foo;
9098+
· ────────────────────
9099+
3 │ for (;;) await using b = foo;
9100+
╰────
9101+
help: Wrap this declaration in a block statement
9102+
9103+
× Lexical declaration cannot appear in a single-statement context
9104+
╭─[babel/packages/babel-parser/test/fixtures/es2026/async-explicit-resource-management/invalid-in-single-statement-context-async/input.js:3:12]
9105+
2 │ while (1) await using a = foo;
9106+
3 │ for (;;) await using b = foo;
9107+
· ────────────────────
9108+
4 │ do await using c = foo; while (1);
9109+
╰────
9110+
help: Wrap this declaration in a block statement
9111+
9112+
× Lexical declaration cannot appear in a single-statement context
9113+
╭─[babel/packages/babel-parser/test/fixtures/es2026/async-explicit-resource-management/invalid-in-single-statement-context-async/input.js:4:6]
9114+
3 │ for (;;) await using b = foo;
9115+
4 │ do await using c = foo; while (1);
9116+
· ────────────────────
9117+
5 │ if (1) await using d = foo;
9118+
╰────
9119+
help: Wrap this declaration in a block statement
9120+
9121+
× Lexical declaration cannot appear in a single-statement context
9122+
╭─[babel/packages/babel-parser/test/fixtures/es2026/async-explicit-resource-management/invalid-in-single-statement-context-async/input.js:5:10]
9123+
4 │ do await using c = foo; while (1);
9124+
5 │ if (1) await using d = foo;
9125+
· ────────────────────
9126+
6 │ with (1) await using e = foo;
9127+
╰────
9128+
help: Wrap this declaration in a block statement
9129+
9130+
× Lexical declaration cannot appear in a single-statement context
9131+
╭─[babel/packages/babel-parser/test/fixtures/es2026/async-explicit-resource-management/invalid-in-single-statement-context-async/input.js:6:12]
9132+
5 │ if (1) await using d = foo;
9133+
6 │ with (1) await using e = foo;
9134+
· ────────────────────
9135+
7 │ label: await using f = foo;
9136+
╰────
9137+
help: Wrap this declaration in a block statement
9138+
9139+
× Lexical declaration cannot appear in a single-statement context
9140+
╭─[babel/packages/babel-parser/test/fixtures/es2026/async-explicit-resource-management/invalid-in-single-statement-context-async/input.js:7:10]
9141+
6 │ with (1) await using e = foo;
9142+
7 │ label: await using f = foo;
9143+
· ────────────────────
9144+
8 │ }
9145+
╰────
9146+
help: Wrap this declaration in a block statement
9147+
9148+
× Lexical declaration cannot appear in a single-statement context
9149+
╭─[babel/packages/babel-parser/test/fixtures/es2026/async-explicit-resource-management/invalid-in-single-statement-context-sync/input.js:2:13]
9150+
1 │ {
9151+
2 │ while (1) await using a = foo;
9152+
· ────────────────────
9153+
3 │ for (;0;) await using b = foo;
9154+
╰────
9155+
help: Wrap this declaration in a block statement
9156+
9157+
× Lexical declaration cannot appear in a single-statement context
9158+
╭─[babel/packages/babel-parser/test/fixtures/es2026/async-explicit-resource-management/invalid-in-single-statement-context-sync/input.js:3:13]
9159+
2 │ while (1) await using a = foo;
9160+
3 │ for (;0;) await using b = foo;
9161+
· ────────────────────
9162+
4 │ do await using c = foo; while (1);
9163+
╰────
9164+
help: Wrap this declaration in a block statement
9165+
9166+
× Lexical declaration cannot appear in a single-statement context
9167+
╭─[babel/packages/babel-parser/test/fixtures/es2026/async-explicit-resource-management/invalid-in-single-statement-context-sync/input.js:4:6]
9168+
3 │ for (;0;) await using b = foo;
9169+
4 │ do await using c = foo; while (1);
9170+
· ────────────────────
9171+
5 │ if (1) await using d = foo;
9172+
╰────
9173+
help: Wrap this declaration in a block statement
9174+
9175+
× Lexical declaration cannot appear in a single-statement context
9176+
╭─[babel/packages/babel-parser/test/fixtures/es2026/async-explicit-resource-management/invalid-in-single-statement-context-sync/input.js:5:10]
9177+
4 │ do await using c = foo; while (1);
9178+
5 │ if (1) await using d = foo;
9179+
· ────────────────────
9180+
6 │ with (1) await using e = foo;
9181+
╰────
9182+
help: Wrap this declaration in a block statement
9183+
9184+
× Lexical declaration cannot appear in a single-statement context
9185+
╭─[babel/packages/babel-parser/test/fixtures/es2026/async-explicit-resource-management/invalid-in-single-statement-context-sync/input.js:6:12]
9186+
5 │ if (1) await using d = foo;
9187+
6 │ with (1) await using e = foo;
9188+
· ────────────────────
9189+
7 │ label: await using f = foo;
9190+
╰────
9191+
help: Wrap this declaration in a block statement
9192+
9193+
× Lexical declaration cannot appear in a single-statement context
9194+
╭─[babel/packages/babel-parser/test/fixtures/es2026/async-explicit-resource-management/invalid-in-single-statement-context-sync/input.js:7:10]
9195+
6 │ with (1) await using e = foo;
9196+
7 │ label: await using f = foo;
9197+
· ────────────────────
9198+
8 │ }
9199+
╰────
9200+
help: Wrap this declaration in a block statement
9201+
9202+
× Lexical declaration cannot appear in a single-statement context
9203+
╭─[babel/packages/babel-parser/test/fixtures/es2026/async-explicit-resource-management/invalid-script-top-level-labeled-using-binding/input.js:1:8]
9204+
1 │ label: await using x = bar();
9205+
· ──────────────────────
9206+
╰────
9207+
help: Wrap this declaration in a block statement
9208+
91069209
× Cannot assign to this expression
91079210
╭─[babel/packages/babel-parser/test/fixtures/es2026/async-explicit-resource-management/invalid-using-array-pattern/input.js:2:3]
91089211
1 │ async function f() {
@@ -9338,6 +9441,76 @@ Expect to Parse: tasks/coverage/babel/packages/babel-parser/test/fixtures/typesc
93389441
· ─
93399442
╰────
93409443

9444+
× Lexical declaration cannot appear in a single-statement context
9445+
╭─[babel/packages/babel-parser/test/fixtures/es2026/explicit-resource-management/invalid-in-single-statement-context/input.js:2:13]
9446+
1 │ {
9447+
2 │ while (1) using a = foo;
9448+
· ──────────────
9449+
3 │ for (;;) using b = foo;
9450+
╰────
9451+
help: Wrap this declaration in a block statement
9452+
9453+
× Lexical declaration cannot appear in a single-statement context
9454+
╭─[babel/packages/babel-parser/test/fixtures/es2026/explicit-resource-management/invalid-in-single-statement-context/input.js:3:12]
9455+
2 │ while (1) using a = foo;
9456+
3 │ for (;;) using b = foo;
9457+
· ──────────────
9458+
4 │ do using c = foo; while (1);
9459+
╰────
9460+
help: Wrap this declaration in a block statement
9461+
9462+
× Lexical declaration cannot appear in a single-statement context
9463+
╭─[babel/packages/babel-parser/test/fixtures/es2026/explicit-resource-management/invalid-in-single-statement-context/input.js:4:6]
9464+
3 │ for (;;) using b = foo;
9465+
4 │ do using c = foo; while (1);
9466+
· ──────────────
9467+
5 │ if (1) using d = foo;
9468+
╰────
9469+
help: Wrap this declaration in a block statement
9470+
9471+
× Lexical declaration cannot appear in a single-statement context
9472+
╭─[babel/packages/babel-parser/test/fixtures/es2026/explicit-resource-management/invalid-in-single-statement-context/input.js:5:10]
9473+
4 │ do using c = foo; while (1);
9474+
5 │ if (1) using d = foo;
9475+
· ──────────────
9476+
6 │ with (1) using e = foo;
9477+
╰────
9478+
help: Wrap this declaration in a block statement
9479+
9480+
× Lexical declaration cannot appear in a single-statement context
9481+
╭─[babel/packages/babel-parser/test/fixtures/es2026/explicit-resource-management/invalid-in-single-statement-context/input.js:6:12]
9482+
5 │ if (1) using d = foo;
9483+
6 │ with (1) using e = foo;
9484+
· ──────────────
9485+
7 │ label: using f = foo;
9486+
╰────
9487+
help: Wrap this declaration in a block statement
9488+
9489+
× Lexical declaration cannot appear in a single-statement context
9490+
╭─[babel/packages/babel-parser/test/fixtures/es2026/explicit-resource-management/invalid-in-single-statement-context/input.js:7:10]
9491+
6 │ with (1) using e = foo;
9492+
7 │ label: using f = foo;
9493+
· ──────────────
9494+
8 │ }
9495+
╰────
9496+
help: Wrap this declaration in a block statement
9497+
9498+
× Lexical declaration cannot appear in a single-statement context
9499+
╭─[babel/packages/babel-parser/test/fixtures/es2026/explicit-resource-management/invalid-labeled-using-binding/input.js:2:10]
9500+
1 │ {
9501+
2 │ label: using x = bar();
9502+
· ────────────────
9503+
3 │ }
9504+
╰────
9505+
help: Wrap this declaration in a block statement
9506+
9507+
× Lexical declaration cannot appear in a single-statement context
9508+
╭─[babel/packages/babel-parser/test/fixtures/es2026/explicit-resource-management/invalid-script-top-level-labeled-using-binding/input.js:1:8]
9509+
1 │ label: using x = bar();
9510+
· ────────────────
9511+
╰────
9512+
help: Wrap this declaration in a block statement
9513+
93419514
× Cannot use `await` as an identifier in an async context
93429515
╭─[babel/packages/babel-parser/test/fixtures/es2026/explicit-resource-management/invalid-using-binding-await-module/input.js:2:9]
93439516
1 │ {

tasks/coverage/snapshots/parser_typescript.snap

Lines changed: 18 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ commit: 8ea03f88
33
parser_typescript Summary:
44
AST Parsed : 8825/8827 (99.98%)
55
Positive Passed: 8814/8827 (99.85%)
6-
Negative Passed: 1451/3530 (41.10%)
6+
Negative Passed: 1453/3530 (41.16%)
77
Expect Syntax Error: tasks/coverage/typescript/tests/cases/compiler/ExportAssignment7.ts
88

99
Expect Syntax Error: tasks/coverage/typescript/tests/cases/compiler/ExportAssignment8.ts
@@ -3796,8 +3796,6 @@ Expect Syntax Error: tasks/coverage/typescript/tests/cases/conformance/statement
37963796

37973797
Expect Syntax Error: tasks/coverage/typescript/tests/cases/conformance/statements/VariableStatements/usingDeclarations/awaitUsingDeclarations.1.ts
37983798

3799-
Expect Syntax Error: tasks/coverage/typescript/tests/cases/conformance/statements/VariableStatements/usingDeclarations/awaitUsingDeclarations.10.ts
3800-
38013799
Expect Syntax Error: tasks/coverage/typescript/tests/cases/conformance/statements/VariableStatements/usingDeclarations/awaitUsingDeclarations.12.ts
38023800

38033801
Expect Syntax Error: tasks/coverage/typescript/tests/cases/conformance/statements/VariableStatements/usingDeclarations/awaitUsingDeclarations.13.ts
@@ -3814,8 +3812,6 @@ Expect Syntax Error: tasks/coverage/typescript/tests/cases/conformance/statement
38143812

38153813
Expect Syntax Error: tasks/coverage/typescript/tests/cases/conformance/statements/VariableStatements/usingDeclarations/awaitUsingDeclarationsWithIteratorObject.ts
38163814

3817-
Expect Syntax Error: tasks/coverage/typescript/tests/cases/conformance/statements/VariableStatements/usingDeclarations/usingDeclarations.10.ts
3818-
38193815
Expect Syntax Error: tasks/coverage/typescript/tests/cases/conformance/statements/VariableStatements/usingDeclarations/usingDeclarations.14.ts
38203816

38213817
Expect Syntax Error: tasks/coverage/typescript/tests/cases/conformance/statements/VariableStatements/usingDeclarations/usingDeclarationsWithIteratorObject.ts
@@ -25570,6 +25566,15 @@ Expect to Parse: tasks/coverage/typescript/tests/cases/conformance/parser/ecmasc
2557025566
7 │ function *gen() {
2557125567
╰────
2557225568

25569+
× Lexical declaration cannot appear in a single-statement context
25570+
╭─[typescript/tests/cases/conformance/statements/VariableStatements/usingDeclarations/awaitUsingDeclarations.10.ts:5:12]
25571+
4 │ async function f() {
25572+
5 │ if (x) await using a = null;
25573+
· ─────────────────────
25574+
6 │ }
25575+
╰────
25576+
help: Wrap this declaration in a block statement
25577+
2557325578
× Unexpected token
2557425579
╭─[typescript/tests/cases/conformance/statements/VariableStatements/usingDeclarations/awaitUsingDeclarations.11.ts:1:8]
2557525580
1 │ export await using x = null;
@@ -25726,6 +25731,14 @@ Expect to Parse: tasks/coverage/typescript/tests/cases/conformance/parser/ecmasc
2572625731
6 │
2572725732
╰────
2572825733

25734+
× Lexical declaration cannot appear in a single-statement context
25735+
╭─[typescript/tests/cases/conformance/statements/VariableStatements/usingDeclarations/usingDeclarations.10.ts:2:8]
25736+
1 │ declare var x: any;
25737+
2 │ if (x) using a = null;
25738+
· ───────────────
25739+
╰────
25740+
help: Wrap this declaration in a block statement
25741+
2572925742
× Unexpected token
2573025743
╭─[typescript/tests/cases/conformance/statements/VariableStatements/usingDeclarations/usingDeclarations.13.ts:1:8]
2573125744
1 │ export using x = null;

0 commit comments

Comments
 (0)