From 42bd431db517c6014e02c6484b5916052844b5fb Mon Sep 17 00:00:00 2001 From: camc314 <18101008+camc314@users.noreply.github.com> Date: Sat, 28 Feb 2026 13:12:03 +0000 Subject: [PATCH] feat(parser): report error for missing initializer in using decl (#19824) --- crates/oxc_parser/src/js/declaration.rs | 17 ++-- tasks/coverage/snapshots/parser_babel.snap | 65 ++----------- .../coverage/snapshots/parser_typescript.snap | 95 +++---------------- 3 files changed, 28 insertions(+), 149 deletions(-) diff --git a/crates/oxc_parser/src/js/declaration.rs b/crates/oxc_parser/src/js/declaration.rs index de18134af89e7..aa8ab4accb398 100644 --- a/crates/oxc_parser/src/js/declaration.rs +++ b/crates/oxc_parser/src/js/declaration.rs @@ -161,6 +161,8 @@ impl<'a, C: Config> ParserImpl<'a, C> { } else if decl.kind == VariableDeclarationKind::Const { // It is a Syntax Error if Initializer is not present and IsConstantDeclaration of the LexicalDeclaration containing this LexicalBinding is true. self.error(diagnostics::missing_initializer_in_const(decl.id.span())); + } else if decl.kind.is_using() { + self.error(diagnostics::using_declarations_must_be_initialized(decl.id.span())); } } } @@ -186,8 +188,12 @@ impl<'a, C: Config> ParserImpl<'a, C> { // BindingList[?In, ?Yield, ?Await, ~Pattern] let mut declarations = self.ast.vec(); loop { - let declaration = - self.parse_variable_declarator(VariableDeclarationParent::Statement, kind); + let decl_parent = if matches!(statement_ctx, StatementContext::For) { + VariableDeclarationParent::For + } else { + VariableDeclarationParent::Statement + }; + let declaration = self.parse_variable_declarator(decl_parent, kind); if !matches!(declaration.id, BindingPattern::BindingIdentifier(_)) { self.error(diagnostics::invalid_identifier_in_using_declaration( @@ -195,13 +201,6 @@ impl<'a, C: Config> ParserImpl<'a, C> { )); } - // Excluding `for` loops, an initializer is required in a UsingDeclaration. - if declaration.init.is_none() && !matches!(statement_ctx, StatementContext::For) { - self.error(diagnostics::using_declarations_must_be_initialized( - declaration.id.span(), - )); - } - declarations.push(declaration); if !self.eat(Kind::Comma) { break; diff --git a/tasks/coverage/snapshots/parser_babel.snap b/tasks/coverage/snapshots/parser_babel.snap index 5e4cc22c28acd..52abf3b048629 100644 --- a/tasks/coverage/snapshots/parser_babel.snap +++ b/tasks/coverage/snapshots/parser_babel.snap @@ -3,9 +3,7 @@ commit: 308c8d85 parser_babel Summary: AST Parsed : 2227/2227 (100.00%) Positive Passed: 2214/2227 (99.42%) -Negative Passed: 1675/1692 (99.00%) -Expect Syntax Error: tasks/coverage/babel/packages/babel-parser/test/fixtures/es2026/explicit-resource-management/invalid-for-using-of-no-initializer/input.js - +Negative Passed: 1676/1692 (99.05%) Expect Syntax Error: tasks/coverage/babel/packages/babel-parser/test/fixtures/typescript/cast/unparenthesized-assert-and-assign/input.ts Expect Syntax Error: tasks/coverage/babel/packages/babel-parser/test/fixtures/typescript/cast/unparenthesized-type-assertion-and-assign/input.ts @@ -8949,6 +8947,13 @@ Expect to Parse: tasks/coverage/babel/packages/babel-parser/test/fixtures/typesc · ── ╰──── + × Using declarations must have an initializer. + ╭─[babel/packages/babel-parser/test/fixtures/es2026/explicit-resource-management/invalid-for-using-of-no-initializer/input.js:1:12] + 1 │ for (using of;of.isValid;); + · ── + ╰──── + help: Add an initializer (e.g. ` = undefined`) here + × Lexical declaration cannot appear in a single-statement context ╭─[babel/packages/babel-parser/test/fixtures/es2026/explicit-resource-management/invalid-in-single-statement-context/input.js:2:13] 1 │ { @@ -13175,15 +13180,6 @@ Expect to Parse: tasks/coverage/babel/packages/babel-parser/test/fixtures/typesc ╰──── help: Try inserting a semicolon here - × Using declarations must have an initializer. - ╭─[babel/packages/babel-parser/test/fixtures/typescript/declare/invalid-namespace-await-using/input.ts:2:15] - 1 │ declare namespace invalid_namespace_var { - 2 │ await using A; - · ─ - 3 │ await using A1 = 0; - ╰──── - help: Add an initializer (e.g. ` = undefined`) here - × TS(1039): Initializers are not allowed in ambient contexts. ╭─[babel/packages/babel-parser/test/fixtures/typescript/declare/invalid-namespace-await-using/input.ts:3:20] 2 │ await using A; @@ -13200,33 +13196,6 @@ Expect to Parse: tasks/coverage/babel/packages/babel-parser/test/fixtures/typesc 5 │ await using B, C; ╰──── - × Using declarations must have an initializer. - ╭─[babel/packages/babel-parser/test/fixtures/typescript/declare/invalid-namespace-await-using/input.ts:5:15] - 4 │ await using A2: number = 0; - 5 │ await using B, C; - · ─ - 6 │ } - ╰──── - help: Add an initializer (e.g. ` = undefined`) here - - × Using declarations must have an initializer. - ╭─[babel/packages/babel-parser/test/fixtures/typescript/declare/invalid-namespace-await-using/input.ts:5:18] - 4 │ await using A2: number = 0; - 5 │ await using B, C; - · ─ - 6 │ } - ╰──── - help: Add an initializer (e.g. ` = undefined`) here - - × Using declarations must have an initializer. - ╭─[babel/packages/babel-parser/test/fixtures/typescript/declare/invalid-namespace-using/input.ts:2:9] - 1 │ declare namespace invalid_namespace_var { - 2 │ using A; - · ─ - 3 │ using A1 = 0; - ╰──── - help: Add an initializer (e.g. ` = undefined`) here - × TS(1039): Initializers are not allowed in ambient contexts. ╭─[babel/packages/babel-parser/test/fixtures/typescript/declare/invalid-namespace-using/input.ts:3:14] 2 │ using A; @@ -13243,24 +13212,6 @@ Expect to Parse: tasks/coverage/babel/packages/babel-parser/test/fixtures/typesc 5 │ using B, C; ╰──── - × Using declarations must have an initializer. - ╭─[babel/packages/babel-parser/test/fixtures/typescript/declare/invalid-namespace-using/input.ts:5:9] - 4 │ using A2: number = 0; - 5 │ using B, C; - · ─ - 6 │ } - ╰──── - help: Add an initializer (e.g. ` = undefined`) here - - × Using declarations must have an initializer. - ╭─[babel/packages/babel-parser/test/fixtures/typescript/declare/invalid-namespace-using/input.ts:5:12] - 4 │ using A2: number = 0; - 5 │ using B, C; - · ─ - 6 │ } - ╰──── - help: Add an initializer (e.g. ` = undefined`) here - × TS(1039): Initializers are not allowed in ambient contexts. ╭─[babel/packages/babel-parser/test/fixtures/typescript/declare/invalid-namespace-var/input.ts:2:11] 1 │ declare namespace invalid_namespace_var { diff --git a/tasks/coverage/snapshots/parser_typescript.snap b/tasks/coverage/snapshots/parser_typescript.snap index 12853113038e9..a8e19430b5b07 100644 --- a/tasks/coverage/snapshots/parser_typescript.snap +++ b/tasks/coverage/snapshots/parser_typescript.snap @@ -3,7 +3,7 @@ commit: 34725489 parser_typescript Summary: AST Parsed : 9831/9834 (99.97%) Positive Passed: 9820/9834 (99.86%) -Negative Passed: 1528/2578 (59.27%) +Negative Passed: 1527/2578 (59.23%) Expect Syntax Error: tasks/coverage/typescript/tests/cases/compiler/FunctionDeclaration3.ts Expect Syntax Error: tasks/coverage/typescript/tests/cases/compiler/FunctionDeclaration4.ts @@ -1954,9 +1954,11 @@ Expect Syntax Error: tasks/coverage/typescript/tests/cases/conformance/scanner/e Expect Syntax Error: tasks/coverage/typescript/tests/cases/conformance/statements/VariableStatements/usingDeclarations/awaitUsingDeclarations.14.ts +Expect Syntax Error: tasks/coverage/typescript/tests/cases/conformance/statements/VariableStatements/usingDeclarations/awaitUsingDeclarations.16.ts + Expect Syntax Error: tasks/coverage/typescript/tests/cases/conformance/statements/VariableStatements/usingDeclarations/awaitUsingDeclarationsInForOf.4.ts -Expect Syntax Error: tasks/coverage/typescript/tests/cases/conformance/statements/VariableStatements/usingDeclarations/usingDeclarationsInForOf.4.ts +Expect Syntax Error: tasks/coverage/typescript/tests/cases/conformance/statements/VariableStatements/usingDeclarations/usingDeclarations.16.ts Expect Syntax Error: tasks/coverage/typescript/tests/cases/conformance/statements/for-inStatements/for-inStatementsArrayErrors.ts @@ -25842,42 +25844,6 @@ Expect to Parse: tasks/coverage/typescript/tests/cases/conformance/parser/ecmasc ╰──── help: Wrap this code in a block or use a module - × Using declarations must have an initializer. - ╭─[typescript/tests/cases/conformance/statements/VariableStatements/usingDeclarations/awaitUsingDeclarations.16.ts:2:17] - 1 │ declare namespace N { - 2 │ await using x: { [Symbol.asyncDispose](): Promise }; - · ─ - 3 │ await using y: null; - ╰──── - help: Add an initializer (e.g. ` = undefined`) here - - × Using declarations must have an initializer. - ╭─[typescript/tests/cases/conformance/statements/VariableStatements/usingDeclarations/awaitUsingDeclarations.16.ts:3:17] - 2 │ await using x: { [Symbol.asyncDispose](): Promise }; - 3 │ await using y: null; - · ─ - 4 │ } - ╰──── - help: Add an initializer (e.g. ` = undefined`) here - - × Using declarations must have an initializer. - ╭─[typescript/tests/cases/conformance/statements/VariableStatements/usingDeclarations/awaitUsingDeclarations.16.ts:6:17] - 5 │ declare module 'M' { - 6 │ await using x: { [Symbol.asyncDispose](): Promise }; - · ─ - 7 │ await using y: null; - ╰──── - help: Add an initializer (e.g. ` = undefined`) here - - × Using declarations must have an initializer. - ╭─[typescript/tests/cases/conformance/statements/VariableStatements/usingDeclarations/awaitUsingDeclarations.16.ts:7:17] - 6 │ await using x: { [Symbol.asyncDispose](): Promise }; - 7 │ await using y: null; - · ─ - 8 │ } - ╰──── - help: Add an initializer (e.g. ` = undefined`) here - × Using declaration cannot appear in the bare case statement. ╭─[typescript/tests/cases/conformance/statements/VariableStatements/usingDeclarations/awaitUsingDeclarations.17.ts:3:9] 2 │ case 0: @@ -25993,15 +25959,6 @@ Expect to Parse: tasks/coverage/typescript/tests/cases/conformance/parser/ecmasc ╰──── help: Did you mean to use a for...of statement? - × Missing initializer in destructuring declaration - ╭─[typescript/tests/cases/conformance/statements/VariableStatements/usingDeclarations/awaitUsingDeclarationsInForOf.3.ts:2:22] - 1 │ async function main() { - 2 │ for (await using {} of []) { - · ── - 3 │ } - ╰──── - help: Add an initializer (e.g. ` = undefined`) here - × Using declarations may not have binding patterns. ╭─[typescript/tests/cases/conformance/statements/VariableStatements/usingDeclarations/awaitUsingDeclarationsInForOf.3.ts:2:22] 1 │ async function main() { @@ -26043,42 +26000,6 @@ Expect to Parse: tasks/coverage/typescript/tests/cases/conformance/parser/ecmasc ╰──── help: Remove the `export` here and add `export { x }` as a separate statement to export the declaration - × Using declarations must have an initializer. - ╭─[typescript/tests/cases/conformance/statements/VariableStatements/usingDeclarations/usingDeclarations.16.ts:2:11] - 1 │ declare namespace N { - 2 │ using x: { [Symbol.dispose](): void }; - · ─ - 3 │ using y: null; - ╰──── - help: Add an initializer (e.g. ` = undefined`) here - - × Using declarations must have an initializer. - ╭─[typescript/tests/cases/conformance/statements/VariableStatements/usingDeclarations/usingDeclarations.16.ts:3:11] - 2 │ using x: { [Symbol.dispose](): void }; - 3 │ using y: null; - · ─ - 4 │ } - ╰──── - help: Add an initializer (e.g. ` = undefined`) here - - × Using declarations must have an initializer. - ╭─[typescript/tests/cases/conformance/statements/VariableStatements/usingDeclarations/usingDeclarations.16.ts:6:11] - 5 │ declare module 'M' { - 6 │ using x: { [Symbol.dispose](): void }; - · ─ - 7 │ using y: null; - ╰──── - help: Add an initializer (e.g. ` = undefined`) here - - × Using declarations must have an initializer. - ╭─[typescript/tests/cases/conformance/statements/VariableStatements/usingDeclarations/usingDeclarations.16.ts:7:11] - 6 │ using x: { [Symbol.dispose](): void }; - 7 │ using y: null; - · ─ - 8 │ } - ╰──── - help: Add an initializer (e.g. ` = undefined`) here - × Using declaration cannot appear in the bare case statement. ╭─[typescript/tests/cases/conformance/statements/VariableStatements/usingDeclarations/usingDeclarations.17.ts:3:9] 2 │ case 0: @@ -26180,6 +26101,14 @@ Expect to Parse: tasks/coverage/typescript/tests/cases/conformance/parser/ecmasc 2 │ } ╰──── + × Using declarations must have an initializer. + ╭─[typescript/tests/cases/conformance/statements/VariableStatements/usingDeclarations/usingDeclarationsInForOf.4.ts:3:12] + 2 │ for (using of: null = null;;) break; + 3 │ for (using of;;) break; + · ── + ╰──── + help: Add an initializer (e.g. ` = undefined`) here + × Illegal break statement ╭─[typescript/tests/cases/conformance/statements/breakStatements/invalidDoWhileBreakStatements.ts:4:1] 3 │ // naked break not allowed