From 572ddf1365b40b213ed4275949ceacb6ba95523d Mon Sep 17 00:00:00 2001 From: PaulyBearCoding Date: Thu, 6 Nov 2025 23:30:02 -0800 Subject: [PATCH] Reject using and await using declarations in switch case/default clauses MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fixes #62708 This change implements parser validation to reject `using` and `await using` declarations when directly nested within `case` or `default` clauses of switch statements, as per the updated ECMAScript spec. The spec was updated to disallow this pattern (see rbuckton/ecma262#14) because: - It makes the number of resource declarations statically knowable - All major JS engines agreed to this restriction - The pattern is rarely used in practice Changes: - Add new diagnostic (TS95198) for the error message - Add validation in parseVariableDeclarationList() to check parsingContext - Add error baseline for existing test case that now produces errors Valid workaround: Wrap using declarations in a block statement: case 0: { using x = ...; // OK } 🤖 Generated with Claude Code Co-Authored-By: Claude --- src/compiler/diagnosticMessages.json | 4 +++ src/compiler/parser.ts | 6 ++++ ...ngDeclarations.1(target=esnext).errors.txt | 28 +++++++++++++++++++ 3 files changed, 38 insertions(+) create mode 100644 tests/baselines/reference/usingDeclarations.1(target=esnext).errors.txt diff --git a/src/compiler/diagnosticMessages.json b/src/compiler/diagnosticMessages.json index 5731936e4978e..b12931c9a7684 100644 --- a/src/compiler/diagnosticMessages.json +++ b/src/compiler/diagnosticMessages.json @@ -8332,6 +8332,10 @@ "category": "Message", "code": 95197 }, + "A '{0}' declaration cannot be placed within a 'case' or 'default' clause.": { + "category": "Error", + "code": 95198 + }, "No value exists in scope for the shorthand property '{0}'. Either declare one or provide an initializer.": { "category": "Error", diff --git a/src/compiler/parser.ts b/src/compiler/parser.ts index 68133ac5f1e40..6053a12717662 100644 --- a/src/compiler/parser.ts +++ b/src/compiler/parser.ts @@ -7678,12 +7678,18 @@ namespace Parser { break; case SyntaxKind.UsingKeyword: flags |= NodeFlags.Using; + if (parsingContext === ParsingContext.SwitchClauseStatements) { + parseErrorAtCurrentToken(Diagnostics.A_0_declaration_cannot_be_placed_within_a_case_or_default_clause, "using"); + } break; case SyntaxKind.AwaitKeyword: if (!isAwaitUsingDeclaration()) { break; } flags |= NodeFlags.AwaitUsing; + if (parsingContext === ParsingContext.SwitchClauseStatements) { + parseErrorAtCurrentToken(Diagnostics.A_0_declaration_cannot_be_placed_within_a_case_or_default_clause, "await using"); + } nextToken(); break; default: diff --git a/tests/baselines/reference/usingDeclarations.1(target=esnext).errors.txt b/tests/baselines/reference/usingDeclarations.1(target=esnext).errors.txt new file mode 100644 index 0000000000000..7a043110be79c --- /dev/null +++ b/tests/baselines/reference/usingDeclarations.1(target=esnext).errors.txt @@ -0,0 +1,28 @@ +usingDeclarations.1.ts(100,9): error TS95198: A 'using' declaration cannot be placed within a 'case' or 'default' clause. +usingDeclarations.1.ts(104,9): error TS95198: A 'using' declaration cannot be placed within a 'case' or 'default' clause. +usingDeclarations.1.ts(111,13): error TS95198: A 'using' declaration cannot be placed within a 'case' or 'default' clause. + + +==== usingDeclarations.1.ts (3 errors) ==== + switch (Math.random()) { + case 0: + using d20 = { [Symbol.dispose]() {} }; + ~~~~~ +!!! error TS95198: A 'using' declaration cannot be placed within a 'case' or 'default' clause. + break; + + case 1: + using d21 = { [Symbol.dispose]() {} }; + ~~~~~ +!!! error TS95198: A 'using' declaration cannot be placed within a 'case' or 'default' clause. + break; + } + + if (true) + switch (0) { + case 0: + using d22 = { [Symbol.dispose]() {} }; + ~~~~~ +!!! error TS95198: A 'using' declaration cannot be placed within a 'case' or 'default' clause. + break; + }