Skip to content

Commit 732205e

Browse files
committed
fix(parser): reject using / await using in a switch case / default clause (#15225)
`using` / `await using` directly nested within a `case` or `default` clause are now disallowed (rbuckton/ecma262#14). This PR implements this change. Note that TypeScript does not disallow them yet (microsoft/TypeScript#62708) and the test failing in `tasks/coverage/snapshots/parser_typescript.snap` is caused by that.
1 parent 7b1e6f3 commit 732205e

File tree

9 files changed

+187
-21
lines changed

9 files changed

+187
-21
lines changed

crates/oxc_linter/src/snapshots/eslint_no_case_declarations.snap

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -49,14 +49,16 @@ source: crates/oxc_linter/src/tester.rs
4949
· ─────
5050
╰────
5151

52-
eslint(no-case-declarations): Unexpected lexical declaration in case block.
52+
× Using declaration cannot appear in the bare case statement.
5353
╭─[no_case_declarations.tsx:1:23]
5454
1switch (a) { default: using x = {}; break; }
55-
· ─────
55+
· ─────────────
5656
╰────
57+
help: Wrap this declaration in a block statement
5758

58-
eslint(no-case-declarations): Unexpected lexical declaration in case block.
59+
× Using declaration cannot appear in the bare case statement.
5960
╭─[no_case_declarations.tsx:1:23]
6061
1switch (a) { default: await using x = {}; break; }
61-
· ───────────
62+
· ───────────────────
6263
╰────
64+
help: Wrap this declaration in a block statement

crates/oxc_parser/src/diagnostics.rs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -639,6 +639,13 @@ pub fn using_declaration_cannot_be_exported(identifier: &str, span: Span) -> Oxc
639639
.with_help(format!("Remove the `export` here and add `export {{ {identifier} }}` as a separate statement to export the declaration"))
640640
}
641641

642+
#[cold]
643+
pub fn using_declaration_not_allowed_in_switch_bare_case(span: Span) -> OxcDiagnostic {
644+
OxcDiagnostic::error("Using declaration cannot appear in the bare case statement.")
645+
.with_label(span)
646+
.with_help("Wrap this declaration in a block statement")
647+
}
648+
642649
#[cold]
643650
pub fn jsx_element_no_match(span: Span, span1: Span, name: &str) -> OxcDiagnostic {
644651
OxcDiagnostic::error(format!("Expected corresponding JSX closing tag for '{name}'."))

crates/oxc_parser/src/js/statement.rs

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -658,6 +658,15 @@ impl<'a> ParserImpl<'a> {
658658
break;
659659
}
660660
let stmt = self.parse_statement_list_item(StatementContext::StatementList);
661+
if let Statement::VariableDeclaration(var_decl) = &stmt
662+
&& var_decl.kind.is_using()
663+
{
664+
// It is a Syntax Error if UsingDeclaration is contained directly within the StatementList of either a CaseClause or DefaultClause.
665+
// It is a Syntax Error if AwaitUsingDeclaration is contained directly within the StatementList of either a CaseClause or DefaultClause.
666+
self.error(diagnostics::using_declaration_not_allowed_in_switch_bare_case(
667+
stmt.span(),
668+
));
669+
}
661670
consequent.push(stmt);
662671
}
663672
self.ast.switch_case(self.end_span(span), test, consequent)

tasks/coverage/snapshots/estree_typescript.snap

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ commit: 8ea03f88
22

33
estree_typescript Summary:
44
AST Parsed : 8767/8767 (100.00%)
5-
Positive Passed: 8762/8767 (99.94%)
5+
Positive Passed: 8761/8767 (99.93%)
66
Mismatch: tasks/coverage/typescript/tests/cases/conformance/importDefer/importDeferComments.ts
77

88
Mismatch: tasks/coverage/typescript/tests/cases/conformance/importDefer/importDeferDeclaration.ts
@@ -13,3 +13,6 @@ Mismatch: tasks/coverage/typescript/tests/cases/conformance/jsx/tsxReactEmitEnti
1313

1414
Mismatch: tasks/coverage/typescript/tests/cases/conformance/jsx/tsxReactEmitNesting.tsx
1515

16+
Expect to Parse: tasks/coverage/typescript/tests/cases/conformance/statements/VariableStatements/usingDeclarations/usingDeclarations.1.ts
17+
Using declaration cannot appear in the bare case statement.
18+

tasks/coverage/snapshots/formatter_typescript.snap

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ commit: 8ea03f88
22

33
formatter_typescript Summary:
44
AST Parsed : 8827/8827 (100.00%)
5-
Positive Passed: 8818/8827 (99.90%)
5+
Positive Passed: 8817/8827 (99.89%)
66
Mismatch: tasks/coverage/typescript/tests/cases/compiler/amdLikeInputDeclarationEmit.ts
77

88
Expect to Parse: tasks/coverage/typescript/tests/cases/compiler/arrayFromAsync.ts
@@ -19,5 +19,7 @@ Expect to Parse: tasks/coverage/typescript/tests/cases/conformance/expressions/e
1919
Unexpected token
2020
Mismatch: tasks/coverage/typescript/tests/cases/conformance/generators/yieldStatementNoAsiAfterTransform.ts
2121

22+
Expect to Parse: tasks/coverage/typescript/tests/cases/conformance/statements/VariableStatements/usingDeclarations/usingDeclarations.1.ts
23+
Using declaration cannot appear in the bare case statement.Using declaration cannot appear in the bare case statement.Using declaration cannot appear in the bare case statement.
2224
Mismatch: tasks/coverage/typescript/tests/cases/conformance/statements/returnStatements/returnStatementNoAsiAfterTransform.ts
2325

tasks/coverage/snapshots/parser_babel.snap

Lines changed: 73 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -3,19 +3,11 @@ commit: 4cc3d888
33
parser_babel Summary:
44
AST Parsed : 2422/2440 (99.26%)
55
Positive Passed: 2396/2440 (98.20%)
6-
Negative Passed: 1685/1752 (96.18%)
6+
Negative Passed: 1689/1752 (96.40%)
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-module-bare-case-await-using-binding/input.js
10-
11-
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
12-
139
Expect Syntax Error: tasks/coverage/babel/packages/babel-parser/test/fixtures/es2026/async-explicit-resource-management/invalid-script-top-level-using-binding/input.js
1410

15-
Expect Syntax Error: tasks/coverage/babel/packages/babel-parser/test/fixtures/es2026/explicit-resource-management/invalid-module-bare-case-using-binding/input.js
16-
17-
Expect Syntax Error: tasks/coverage/babel/packages/babel-parser/test/fixtures/es2026/explicit-resource-management/invalid-script-bare-case-using-binding/input.js
18-
1911
Expect Syntax Error: tasks/coverage/babel/packages/babel-parser/test/fixtures/es2026/explicit-resource-management/invalid-script-top-level-using-binding/input.js
2012

2113
Expect Syntax Error: tasks/coverage/babel/packages/babel-parser/test/fixtures/estree/class-private-property/typescript-invalid-abstract/input.ts
@@ -9214,6 +9206,42 @@ Expect to Parse: tasks/coverage/babel/packages/babel-parser/test/fixtures/typesc
92149206
╰────
92159207
help: Wrap this declaration in a block statement
92169208

9209+
× Using declaration cannot appear in the bare case statement.
9210+
╭─[babel/packages/babel-parser/test/fixtures/es2026/async-explicit-resource-management/invalid-module-bare-case-await-using-binding/input.js:5:7]
9211+
4 │ {}
9212+
5 │ await using x = bar();
9213+
· ──────────────────────
9214+
6 │ default:
9215+
╰────
9216+
help: Wrap this declaration in a block statement
9217+
9218+
× Using declaration cannot appear in the bare case statement.
9219+
╭─[babel/packages/babel-parser/test/fixtures/es2026/async-explicit-resource-management/invalid-module-bare-case-await-using-binding/input.js:8:7]
9220+
7 │ {}
9221+
8 │ await using y = bar();
9222+
· ──────────────────────
9223+
9 │ }
9224+
╰────
9225+
help: Wrap this declaration in a block statement
9226+
9227+
× Using declaration cannot appear in the bare case statement.
9228+
╭─[babel/packages/babel-parser/test/fixtures/es2026/async-explicit-resource-management/invalid-script-bare-case-await-using-binding/input.js:5:7]
9229+
4 │ {}
9230+
5 │ await using x = bar();
9231+
· ──────────────────────
9232+
6 │ default:
9233+
╰────
9234+
help: Wrap this declaration in a block statement
9235+
9236+
× Using declaration cannot appear in the bare case statement.
9237+
╭─[babel/packages/babel-parser/test/fixtures/es2026/async-explicit-resource-management/invalid-script-bare-case-await-using-binding/input.js:8:7]
9238+
7 │ {}
9239+
8 │ await using y = bar();
9240+
· ──────────────────────
9241+
9 │ }
9242+
╰────
9243+
help: Wrap this declaration in a block statement
9244+
92179245
× Lexical declaration cannot appear in a single-statement context
92189246
╭─[babel/packages/babel-parser/test/fixtures/es2026/async-explicit-resource-management/invalid-script-top-level-labeled-using-binding/input.js:1:8]
92199247
1 │ label: await using x = bar();
@@ -9522,6 +9550,42 @@ Expect to Parse: tasks/coverage/babel/packages/babel-parser/test/fixtures/typesc
95229550
╰────
95239551
help: Wrap this declaration in a block statement
95249552

9553+
× Using declaration cannot appear in the bare case statement.
9554+
╭─[babel/packages/babel-parser/test/fixtures/es2026/explicit-resource-management/invalid-module-bare-case-using-binding/input.js:5:7]
9555+
4 │ {}
9556+
5 │ using x = bar();
9557+
· ────────────────
9558+
6 │ default:
9559+
╰────
9560+
help: Wrap this declaration in a block statement
9561+
9562+
× Using declaration cannot appear in the bare case statement.
9563+
╭─[babel/packages/babel-parser/test/fixtures/es2026/explicit-resource-management/invalid-module-bare-case-using-binding/input.js:8:7]
9564+
7 │ {}
9565+
8 │ using y = bar();
9566+
· ────────────────
9567+
9 │ }
9568+
╰────
9569+
help: Wrap this declaration in a block statement
9570+
9571+
× Using declaration cannot appear in the bare case statement.
9572+
╭─[babel/packages/babel-parser/test/fixtures/es2026/explicit-resource-management/invalid-script-bare-case-using-binding/input.js:5:7]
9573+
4 │ {}
9574+
5 │ using x = bar();
9575+
· ────────────────
9576+
6 │ default:
9577+
╰────
9578+
help: Wrap this declaration in a block statement
9579+
9580+
× Using declaration cannot appear in the bare case statement.
9581+
╭─[babel/packages/babel-parser/test/fixtures/es2026/explicit-resource-management/invalid-script-bare-case-using-binding/input.js:8:7]
9582+
7 │ {}
9583+
8 │ using y = bar();
9584+
· ────────────────
9585+
9 │ }
9586+
╰────
9587+
help: Wrap this declaration in a block statement
9588+
95259589
× Lexical declaration cannot appear in a single-statement context
95269590
╭─[babel/packages/babel-parser/test/fixtures/es2026/explicit-resource-management/invalid-script-top-level-labeled-using-binding/input.js:1:8]
95279591
1 │ label: using x = bar();

tasks/coverage/snapshots/parser_typescript.snap

Lines changed: 58 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,8 @@ commit: 8ea03f88
22

33
parser_typescript Summary:
44
AST Parsed : 8825/8827 (99.98%)
5-
Positive Passed: 8814/8827 (99.85%)
6-
Negative Passed: 1453/3530 (41.16%)
5+
Positive Passed: 8813/8827 (99.84%)
6+
Negative Passed: 1454/3530 (41.19%)
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
@@ -3794,8 +3794,6 @@ Expect Syntax Error: tasks/coverage/typescript/tests/cases/conformance/scanner/e
37943794

37953795
Expect Syntax Error: tasks/coverage/typescript/tests/cases/conformance/statements/VariableStatements/everyTypeWithAnnotationAndInvalidInitializer.ts
37963796

3797-
Expect Syntax Error: tasks/coverage/typescript/tests/cases/conformance/statements/VariableStatements/usingDeclarations/awaitUsingDeclarations.1.ts
3798-
37993797
Expect Syntax Error: tasks/coverage/typescript/tests/cases/conformance/statements/VariableStatements/usingDeclarations/awaitUsingDeclarations.12.ts
38003798

38013799
Expect Syntax Error: tasks/coverage/typescript/tests/cases/conformance/statements/VariableStatements/usingDeclarations/awaitUsingDeclarations.13.ts
@@ -4435,6 +4433,35 @@ Expect to Parse: tasks/coverage/typescript/tests/cases/conformance/parser/ecmasc
44354433
3 │ }
44364434
╰────
44374435

4436+
Expect to Parse: tasks/coverage/typescript/tests/cases/conformance/statements/VariableStatements/usingDeclarations/usingDeclarations.1.ts
4437+
4438+
× Using declaration cannot appear in the bare case statement.
4439+
╭─[typescript/tests/cases/conformance/statements/VariableStatements/usingDeclarations/usingDeclarations.1.ts:95:9]
4440+
94 │ case 0:
4441+
95 │ using d20 = { [Symbol.dispose]() {} };
4442+
· ──────────────────────────────────────
4443+
96 │ break;
4444+
╰────
4445+
help: Wrap this declaration in a block statement
4446+
4447+
× Using declaration cannot appear in the bare case statement.
4448+
╭─[typescript/tests/cases/conformance/statements/VariableStatements/usingDeclarations/usingDeclarations.1.ts:99:9]
4449+
98 │ case 1:
4450+
99 │ using d21 = { [Symbol.dispose]() {} };
4451+
· ──────────────────────────────────────
4452+
100 │ break;
4453+
╰────
4454+
help: Wrap this declaration in a block statement
4455+
4456+
× Using declaration cannot appear in the bare case statement.
4457+
╭─[typescript/tests/cases/conformance/statements/VariableStatements/usingDeclarations/usingDeclarations.1.ts:106:13]
4458+
105 │ case 0:
4459+
106 │ using d22 = { [Symbol.dispose]() {} };
4460+
· ──────────────────────────────────────
4461+
107 │ break;
4462+
╰────
4463+
help: Wrap this declaration in a block statement
4464+
44384465

44394466
× TS(1090): 'public' modifier cannot appear on a parameter.
44404467
╭─[typescript/tests/cases/compiler/ArrowFunctionExpression1.ts:1:10]
@@ -25931,6 +25958,33 @@ Expect to Parse: tasks/coverage/typescript/tests/cases/conformance/parser/ecmasc
2593125958
7 │ function *gen() {
2593225959
╰────
2593325960

25961+
× Using declaration cannot appear in the bare case statement.
25962+
╭─[typescript/tests/cases/conformance/statements/VariableStatements/usingDeclarations/awaitUsingDeclarations.1.ts:41:9]
25963+
40 │ case 0:
25964+
41 │ await using d20 = { async [Symbol.asyncDispose]() {} };
25965+
· ───────────────────────────────────────────────────────
25966+
42 │ break;
25967+
╰────
25968+
help: Wrap this declaration in a block statement
25969+
25970+
× Using declaration cannot appear in the bare case statement.
25971+
╭─[typescript/tests/cases/conformance/statements/VariableStatements/usingDeclarations/awaitUsingDeclarations.1.ts:45:9]
25972+
44 │ case 1:
25973+
45 │ await using d21 = { async [Symbol.asyncDispose]() {} };
25974+
· ───────────────────────────────────────────────────────
25975+
46 │ break;
25976+
╰────
25977+
help: Wrap this declaration in a block statement
25978+
25979+
× Using declaration cannot appear in the bare case statement.
25980+
╭─[typescript/tests/cases/conformance/statements/VariableStatements/usingDeclarations/awaitUsingDeclarations.1.ts:52:13]
25981+
51 │ case 0:
25982+
52 │ await using d22 = { async [Symbol.asyncDispose]() {} };
25983+
· ───────────────────────────────────────────────────────
25984+
53 │ break;
25985+
╰────
25986+
help: Wrap this declaration in a block statement
25987+
2593425988
× Lexical declaration cannot appear in a single-statement context
2593525989
╭─[typescript/tests/cases/conformance/statements/VariableStatements/usingDeclarations/awaitUsingDeclarations.10.ts:5:12]
2593625990
4 │ async function f() {

tasks/coverage/snapshots/semantic_typescript.snap

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46161,6 +46161,9 @@ after transform: ScopeId(2): [ScopeId(4)]
4616146161
rebuilt : ScopeId(9): []
4616246162

4616346163
semantic Error: tasks/coverage/typescript/tests/cases/conformance/statements/VariableStatements/usingDeclarations/usingDeclarations.1.ts
46164+
Using declaration cannot appear in the bare case statement.
46165+
Using declaration cannot appear in the bare case statement.
46166+
Using declaration cannot appear in the bare case statement.
4616446167
Bindings mismatch:
4616546168
after transform: ScopeId(0): ["C1", "C2", "C3", "N", "_af", "_ag", "_asyncToGenerator", "_awaitAsyncGenerator", "_defineProperty", "_usingCtx2", "_usingCtx20", "_usingCtx23", "_usingCtx24", "_usingCtx25", "_usingCtx26", "_usingCtx27", "_usingCtx28", "_usingCtx29", "_usingCtx30", "_usingCtx6", "_wrapAsyncGenerator", "a", "af", "ag", "d1", "f", "g"]
4616646169
rebuilt : ScopeId(0): ["C1", "C2", "C3", "N", "_af", "_ag", "_asyncToGenerator", "_awaitAsyncGenerator", "_defineProperty", "_usingCtx2", "_usingCtx20", "_usingCtx21", "_usingCtx22", "_usingCtx23", "_usingCtx24", "_usingCtx25", "_usingCtx26", "_usingCtx27", "_usingCtx28", "_usingCtx29", "_usingCtx30", "_usingCtx6", "_wrapAsyncGenerator", "a", "af", "ag", "d1", "f", "g"]

tasks/transform_conformance/snapshots/babel.snap.md

Lines changed: 24 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
commit: 4cc3d888
22

3-
Passed: 712/1217
3+
Passed: 711/1217
44

55
# All Passed:
66
* babel-plugin-transform-logical-assignment-operators
@@ -268,7 +268,7 @@ x Output mismatch
268268
x Output mismatch
269269

270270

271-
# babel-plugin-transform-explicit-resource-management (21/29)
271+
# babel-plugin-transform-explicit-resource-management (20/29)
272272
* integration/commonjs-transform/input.js
273273
x Output mismatch
274274

@@ -286,6 +286,28 @@ Symbol scope ID mismatch for "x":
286286
after transform: SymbolId(1): ScopeId(1)
287287
rebuilt : SymbolId(2): ScopeId(2)
288288

289+
* transform-sync/invalid-switch-bare-case/input.js
290+
291+
x Using declaration cannot appear in the bare case statement.
292+
,-[tasks/coverage/babel/packages/babel-plugin-transform-explicit-resource-management/test/fixtures/transform-sync/invalid-switch-bare-case/input.js:4:7]
293+
3 | case 0:
294+
4 | using x = 0;
295+
: ^^^^^^^^^^^^
296+
5 | break;
297+
`----
298+
help: Wrap this declaration in a block statement
299+
300+
301+
x Using declaration cannot appear in the bare case statement.
302+
,-[tasks/coverage/babel/packages/babel-plugin-transform-explicit-resource-management/test/fixtures/transform-sync/invalid-switch-bare-case/input.js:7:7]
303+
6 | default:
304+
7 | using y = 1;
305+
: ^^^^^^^^^^^^
306+
8 | break;
307+
`----
308+
help: Wrap this declaration in a block statement
309+
310+
289311
* transform-sync/multiple-nested/input.js
290312
Bindings mismatch:
291313
after transform: ScopeId(3): ["_usingCtx3", "z"]

0 commit comments

Comments
 (0)