Skip to content

Commit 572ddf1

Browse files
Reject using and await using declarations in switch case/default clauses
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 <noreply@anthropic.com>
1 parent 6f4fb01 commit 572ddf1

File tree

3 files changed

+38
-0
lines changed

3 files changed

+38
-0
lines changed

src/compiler/diagnosticMessages.json

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8332,6 +8332,10 @@
83328332
"category": "Message",
83338333
"code": 95197
83348334
},
8335+
"A '{0}' declaration cannot be placed within a 'case' or 'default' clause.": {
8336+
"category": "Error",
8337+
"code": 95198
8338+
},
83358339

83368340
"No value exists in scope for the shorthand property '{0}'. Either declare one or provide an initializer.": {
83378341
"category": "Error",

src/compiler/parser.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7678,12 +7678,18 @@ namespace Parser {
76787678
break;
76797679
case SyntaxKind.UsingKeyword:
76807680
flags |= NodeFlags.Using;
7681+
if (parsingContext === ParsingContext.SwitchClauseStatements) {
7682+
parseErrorAtCurrentToken(Diagnostics.A_0_declaration_cannot_be_placed_within_a_case_or_default_clause, "using");
7683+
}
76817684
break;
76827685
case SyntaxKind.AwaitKeyword:
76837686
if (!isAwaitUsingDeclaration()) {
76847687
break;
76857688
}
76867689
flags |= NodeFlags.AwaitUsing;
7690+
if (parsingContext === ParsingContext.SwitchClauseStatements) {
7691+
parseErrorAtCurrentToken(Diagnostics.A_0_declaration_cannot_be_placed_within_a_case_or_default_clause, "await using");
7692+
}
76877693
nextToken();
76887694
break;
76897695
default:
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
usingDeclarations.1.ts(100,9): error TS95198: A 'using' declaration cannot be placed within a 'case' or 'default' clause.
2+
usingDeclarations.1.ts(104,9): error TS95198: A 'using' declaration cannot be placed within a 'case' or 'default' clause.
3+
usingDeclarations.1.ts(111,13): error TS95198: A 'using' declaration cannot be placed within a 'case' or 'default' clause.
4+
5+
6+
==== usingDeclarations.1.ts (3 errors) ====
7+
switch (Math.random()) {
8+
case 0:
9+
using d20 = { [Symbol.dispose]() {} };
10+
~~~~~
11+
!!! error TS95198: A 'using' declaration cannot be placed within a 'case' or 'default' clause.
12+
break;
13+
14+
case 1:
15+
using d21 = { [Symbol.dispose]() {} };
16+
~~~~~
17+
!!! error TS95198: A 'using' declaration cannot be placed within a 'case' or 'default' clause.
18+
break;
19+
}
20+
21+
if (true)
22+
switch (0) {
23+
case 0:
24+
using d22 = { [Symbol.dispose]() {} };
25+
~~~~~
26+
!!! error TS95198: A 'using' declaration cannot be placed within a 'case' or 'default' clause.
27+
break;
28+
}

0 commit comments

Comments
 (0)