Skip to content

Commit f58e67b

Browse files
authored
Disallow using in bare case statement (#17323)
* fix: disallow using declaration in the bare case statement * add test cases * update test fixtures * fix: remove switch case handling in using transform * update test262 allowlist * polish: test allowDeclaration before async context
1 parent 0d41813 commit f58e67b

44 files changed

Lines changed: 1603 additions & 226 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

packages/babel-parser/src/parse-error/standard-errors.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -279,7 +279,7 @@ export default {
279279
UnexpectedTokenUnaryExponentiation:
280280
"Illegal expression. Wrap left hand side or entire exponentiation in parentheses.",
281281
UnexpectedUsingDeclaration:
282-
"Using declaration cannot appear in the top level when source type is `script`.",
282+
"Using declaration cannot appear in the top level when source type is `script` or in the bare case statement.",
283283
UnsupportedBind: "Binding should be performed on object property.",
284284
UnsupportedDecoratorExport:
285285
"A decorated export must export a class declaration.",

packages/babel-parser/src/parser/statement.ts

Lines changed: 14 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -368,6 +368,13 @@ export default abstract class StatementParser extends ExpressionParser {
368368
return false;
369369
}
370370

371+
allowsUsing(): boolean {
372+
return (
373+
(this.scope.inModule || !this.scope.inTopLevel) &&
374+
!this.scope.inBareCaseStatement
375+
);
376+
}
377+
371378
startsAwaitUsing(): boolean {
372379
let next = this.nextTokenInLineStart();
373380
if (this.isUnparsedContextual(next, "using")) {
@@ -518,10 +525,12 @@ export default abstract class StatementParser extends ExpressionParser {
518525
case tt._await:
519526
// [+Await] await [no LineTerminator here] using [no LineTerminator here] BindingList[+Using]
520527
if (!this.state.containsEsc && this.startsAwaitUsing()) {
521-
if (!this.recordAwaitIfAllowed()) {
522-
this.raise(Errors.AwaitUsingNotInAsyncContext, node);
528+
if (!this.allowsUsing()) {
529+
this.raise(Errors.UnexpectedUsingDeclaration, node);
523530
} else if (!allowDeclaration) {
524531
this.raise(Errors.UnexpectedLexicalDeclaration, node);
532+
} else if (!this.recordAwaitIfAllowed()) {
533+
this.raise(Errors.AwaitUsingNotInAsyncContext, node);
525534
}
526535
this.next(); // eat 'await'
527536
return this.parseVarStatement(
@@ -539,7 +548,7 @@ export default abstract class StatementParser extends ExpressionParser {
539548
break;
540549
}
541550
this.expectPlugin("explicitResourceManagement");
542-
if (!this.scope.inModule && this.scope.inTopLevel) {
551+
if (!this.allowsUsing()) {
543552
this.raise(Errors.UnexpectedUsingDeclaration, this.state.startLoc);
544553
} else if (!allowDeclaration) {
545554
this.raise(Errors.UnexpectedLexicalDeclaration, this.state.startLoc);
@@ -1097,7 +1106,7 @@ export default abstract class StatementParser extends ExpressionParser {
10971106
const cases: N.SwitchStatement["cases"] = (node.cases = []);
10981107
this.expect(tt.braceL);
10991108
this.state.labels.push(switchLabel);
1100-
this.scope.enter(ScopeFlag.OTHER);
1109+
this.scope.enter(ScopeFlag.SWITCH);
11011110

11021111
// Statements under must be grouped (by label) in SwitchCase
11031112
// nodes. `cur` is used to keep the node that we are currently
@@ -1156,7 +1165,7 @@ export default abstract class StatementParser extends ExpressionParser {
11561165
this.scope.enter(
11571166
this.options.annexB && param.type === "Identifier"
11581167
? ScopeFlag.SIMPLE_CATCH
1159-
: 0,
1168+
: ScopeFlag.OTHER,
11601169
);
11611170
this.checkLVal(
11621171
param,

packages/babel-parser/src/util/scope.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,9 @@ export default class ScopeHandler<IScope extends Scope = Scope> {
7171
get inNonArrowFunction() {
7272
return (this.currentThisScopeFlags() & ScopeFlag.FUNCTION) > 0;
7373
}
74+
get inBareCaseStatement() {
75+
return (this.currentScope().flags & ScopeFlag.SWITCH) > 0;
76+
}
7477
get treatFunctionsAsVar() {
7578
return this.treatFunctionsAsVarInScope(this.currentScope());
7679
}

packages/babel-parser/src/util/scopeflags.ts

Lines changed: 11 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,17 @@
11
// Each scope gets a bitset that may contain these flags
22
/* prettier-ignore */
33
export const enum ScopeFlag {
4-
OTHER = 0b000000000,
5-
PROGRAM = 0b000000001,
6-
FUNCTION = 0b000000010,
7-
ARROW = 0b000000100,
8-
SIMPLE_CATCH = 0b000001000,
9-
SUPER = 0b000010000,
10-
DIRECT_SUPER = 0b000100000,
11-
CLASS = 0b001000000,
12-
STATIC_BLOCK = 0b010000000,
13-
TS_MODULE = 0b100000000,
4+
OTHER = 0b0000000000,
5+
PROGRAM = 0b0000000001,
6+
FUNCTION = 0b0000000010,
7+
ARROW = 0b0000000100,
8+
SIMPLE_CATCH = 0b0000001000,
9+
SUPER = 0b0000010000,
10+
DIRECT_SUPER = 0b0000100000,
11+
CLASS = 0b0001000000,
12+
STATIC_BLOCK = 0b0010000000,
13+
SWITCH = 0b0100000000,
14+
TS_MODULE = 0b1000000000,
1415
VAR = PROGRAM | FUNCTION | STATIC_BLOCK | TS_MODULE,
1516
}
1617

packages/babel-parser/test/fixtures/experimental/async-explicit-resource-management/invalid-in-single-statement-context/input.js renamed to packages/babel-parser/test/fixtures/experimental/async-explicit-resource-management/invalid-in-single-statement-context-async/input.js

File renamed without changes.

packages/babel-parser/test/fixtures/experimental/async-explicit-resource-management/invalid-in-single-statement-context/output.json renamed to packages/babel-parser/test/fixtures/experimental/async-explicit-resource-management/invalid-in-single-statement-context-async/output.json

File renamed without changes.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
{
2+
while (1) await using a = foo;
3+
for (;0;) await using b = foo;
4+
do await using c = foo; while (1);
5+
if (1) await using d = foo;
6+
with (1) await using e = foo;
7+
label: await using f = foo;
8+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,231 @@
1+
{
2+
"type": "File",
3+
"start":0,"end":198,"loc":{"start":{"line":1,"column":0,"index":0},"end":{"line":8,"column":1,"index":198}},
4+
"errors": [
5+
"SyntaxError: Lexical declaration cannot appear in a single-statement context. (2:12)",
6+
"SyntaxError: Lexical declaration cannot appear in a single-statement context. (3:12)",
7+
"SyntaxError: Lexical declaration cannot appear in a single-statement context. (4:5)",
8+
"SyntaxError: Lexical declaration cannot appear in a single-statement context. (5:9)",
9+
"SyntaxError: Lexical declaration cannot appear in a single-statement context. (6:11)",
10+
"SyntaxError: Lexical declaration cannot appear in a single-statement context. (7:9)"
11+
],
12+
"program": {
13+
"type": "Program",
14+
"start":0,"end":198,"loc":{"start":{"line":1,"column":0,"index":0},"end":{"line":8,"column":1,"index":198}},
15+
"sourceType": "script",
16+
"interpreter": null,
17+
"body": [
18+
{
19+
"type": "BlockStatement",
20+
"start":0,"end":198,"loc":{"start":{"line":1,"column":0,"index":0},"end":{"line":8,"column":1,"index":198}},
21+
"body": [
22+
{
23+
"type": "WhileStatement",
24+
"start":4,"end":34,"loc":{"start":{"line":2,"column":2,"index":4},"end":{"line":2,"column":32,"index":34}},
25+
"test": {
26+
"type": "NumericLiteral",
27+
"start":11,"end":12,"loc":{"start":{"line":2,"column":9,"index":11},"end":{"line":2,"column":10,"index":12}},
28+
"extra": {
29+
"rawValue": 1,
30+
"raw": "1"
31+
},
32+
"value": 1
33+
},
34+
"body": {
35+
"type": "VariableDeclaration",
36+
"start":14,"end":34,"loc":{"start":{"line":2,"column":12,"index":14},"end":{"line":2,"column":32,"index":34}},
37+
"declarations": [
38+
{
39+
"type": "VariableDeclarator",
40+
"start":26,"end":33,"loc":{"start":{"line":2,"column":24,"index":26},"end":{"line":2,"column":31,"index":33}},
41+
"id": {
42+
"type": "Identifier",
43+
"start":26,"end":27,"loc":{"start":{"line":2,"column":24,"index":26},"end":{"line":2,"column":25,"index":27},"identifierName":"a"},
44+
"name": "a"
45+
},
46+
"init": {
47+
"type": "Identifier",
48+
"start":30,"end":33,"loc":{"start":{"line":2,"column":28,"index":30},"end":{"line":2,"column":31,"index":33},"identifierName":"foo"},
49+
"name": "foo"
50+
}
51+
}
52+
],
53+
"kind": "await using"
54+
}
55+
},
56+
{
57+
"type": "ForStatement",
58+
"start":37,"end":67,"loc":{"start":{"line":3,"column":2,"index":37},"end":{"line":3,"column":32,"index":67}},
59+
"init": null,
60+
"test": {
61+
"type": "NumericLiteral",
62+
"start":43,"end":44,"loc":{"start":{"line":3,"column":8,"index":43},"end":{"line":3,"column":9,"index":44}},
63+
"extra": {
64+
"rawValue": 0,
65+
"raw": "0"
66+
},
67+
"value": 0
68+
},
69+
"update": null,
70+
"body": {
71+
"type": "VariableDeclaration",
72+
"start":47,"end":67,"loc":{"start":{"line":3,"column":12,"index":47},"end":{"line":3,"column":32,"index":67}},
73+
"declarations": [
74+
{
75+
"type": "VariableDeclarator",
76+
"start":59,"end":66,"loc":{"start":{"line":3,"column":24,"index":59},"end":{"line":3,"column":31,"index":66}},
77+
"id": {
78+
"type": "Identifier",
79+
"start":59,"end":60,"loc":{"start":{"line":3,"column":24,"index":59},"end":{"line":3,"column":25,"index":60},"identifierName":"b"},
80+
"name": "b"
81+
},
82+
"init": {
83+
"type": "Identifier",
84+
"start":63,"end":66,"loc":{"start":{"line":3,"column":28,"index":63},"end":{"line":3,"column":31,"index":66},"identifierName":"foo"},
85+
"name": "foo"
86+
}
87+
}
88+
],
89+
"kind": "await using"
90+
}
91+
},
92+
{
93+
"type": "DoWhileStatement",
94+
"start":70,"end":104,"loc":{"start":{"line":4,"column":2,"index":70},"end":{"line":4,"column":36,"index":104}},
95+
"body": {
96+
"type": "VariableDeclaration",
97+
"start":73,"end":93,"loc":{"start":{"line":4,"column":5,"index":73},"end":{"line":4,"column":25,"index":93}},
98+
"declarations": [
99+
{
100+
"type": "VariableDeclarator",
101+
"start":85,"end":92,"loc":{"start":{"line":4,"column":17,"index":85},"end":{"line":4,"column":24,"index":92}},
102+
"id": {
103+
"type": "Identifier",
104+
"start":85,"end":86,"loc":{"start":{"line":4,"column":17,"index":85},"end":{"line":4,"column":18,"index":86},"identifierName":"c"},
105+
"name": "c"
106+
},
107+
"init": {
108+
"type": "Identifier",
109+
"start":89,"end":92,"loc":{"start":{"line":4,"column":21,"index":89},"end":{"line":4,"column":24,"index":92},"identifierName":"foo"},
110+
"name": "foo"
111+
}
112+
}
113+
],
114+
"kind": "await using"
115+
},
116+
"test": {
117+
"type": "NumericLiteral",
118+
"start":101,"end":102,"loc":{"start":{"line":4,"column":33,"index":101},"end":{"line":4,"column":34,"index":102}},
119+
"extra": {
120+
"rawValue": 1,
121+
"raw": "1"
122+
},
123+
"value": 1
124+
}
125+
},
126+
{
127+
"type": "IfStatement",
128+
"start":107,"end":134,"loc":{"start":{"line":5,"column":2,"index":107},"end":{"line":5,"column":29,"index":134}},
129+
"test": {
130+
"type": "NumericLiteral",
131+
"start":111,"end":112,"loc":{"start":{"line":5,"column":6,"index":111},"end":{"line":5,"column":7,"index":112}},
132+
"extra": {
133+
"rawValue": 1,
134+
"raw": "1"
135+
},
136+
"value": 1
137+
},
138+
"consequent": {
139+
"type": "VariableDeclaration",
140+
"start":114,"end":134,"loc":{"start":{"line":5,"column":9,"index":114},"end":{"line":5,"column":29,"index":134}},
141+
"declarations": [
142+
{
143+
"type": "VariableDeclarator",
144+
"start":126,"end":133,"loc":{"start":{"line":5,"column":21,"index":126},"end":{"line":5,"column":28,"index":133}},
145+
"id": {
146+
"type": "Identifier",
147+
"start":126,"end":127,"loc":{"start":{"line":5,"column":21,"index":126},"end":{"line":5,"column":22,"index":127},"identifierName":"d"},
148+
"name": "d"
149+
},
150+
"init": {
151+
"type": "Identifier",
152+
"start":130,"end":133,"loc":{"start":{"line":5,"column":25,"index":130},"end":{"line":5,"column":28,"index":133},"identifierName":"foo"},
153+
"name": "foo"
154+
}
155+
}
156+
],
157+
"kind": "await using"
158+
},
159+
"alternate": null
160+
},
161+
{
162+
"type": "WithStatement",
163+
"start":137,"end":166,"loc":{"start":{"line":6,"column":2,"index":137},"end":{"line":6,"column":31,"index":166}},
164+
"object": {
165+
"type": "NumericLiteral",
166+
"start":143,"end":144,"loc":{"start":{"line":6,"column":8,"index":143},"end":{"line":6,"column":9,"index":144}},
167+
"extra": {
168+
"rawValue": 1,
169+
"raw": "1"
170+
},
171+
"value": 1
172+
},
173+
"body": {
174+
"type": "VariableDeclaration",
175+
"start":146,"end":166,"loc":{"start":{"line":6,"column":11,"index":146},"end":{"line":6,"column":31,"index":166}},
176+
"declarations": [
177+
{
178+
"type": "VariableDeclarator",
179+
"start":158,"end":165,"loc":{"start":{"line":6,"column":23,"index":158},"end":{"line":6,"column":30,"index":165}},
180+
"id": {
181+
"type": "Identifier",
182+
"start":158,"end":159,"loc":{"start":{"line":6,"column":23,"index":158},"end":{"line":6,"column":24,"index":159},"identifierName":"e"},
183+
"name": "e"
184+
},
185+
"init": {
186+
"type": "Identifier",
187+
"start":162,"end":165,"loc":{"start":{"line":6,"column":27,"index":162},"end":{"line":6,"column":30,"index":165},"identifierName":"foo"},
188+
"name": "foo"
189+
}
190+
}
191+
],
192+
"kind": "await using"
193+
}
194+
},
195+
{
196+
"type": "LabeledStatement",
197+
"start":169,"end":196,"loc":{"start":{"line":7,"column":2,"index":169},"end":{"line":7,"column":29,"index":196}},
198+
"body": {
199+
"type": "VariableDeclaration",
200+
"start":176,"end":196,"loc":{"start":{"line":7,"column":9,"index":176},"end":{"line":7,"column":29,"index":196}},
201+
"declarations": [
202+
{
203+
"type": "VariableDeclarator",
204+
"start":188,"end":195,"loc":{"start":{"line":7,"column":21,"index":188},"end":{"line":7,"column":28,"index":195}},
205+
"id": {
206+
"type": "Identifier",
207+
"start":188,"end":189,"loc":{"start":{"line":7,"column":21,"index":188},"end":{"line":7,"column":22,"index":189},"identifierName":"f"},
208+
"name": "f"
209+
},
210+
"init": {
211+
"type": "Identifier",
212+
"start":192,"end":195,"loc":{"start":{"line":7,"column":25,"index":192},"end":{"line":7,"column":28,"index":195},"identifierName":"foo"},
213+
"name": "foo"
214+
}
215+
}
216+
],
217+
"kind": "await using"
218+
},
219+
"label": {
220+
"type": "Identifier",
221+
"start":169,"end":174,"loc":{"start":{"line":7,"column":2,"index":169},"end":{"line":7,"column":7,"index":174},"identifierName":"label"},
222+
"name": "label"
223+
}
224+
}
225+
],
226+
"directives": []
227+
}
228+
],
229+
"directives": []
230+
}
231+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
async () => {
2+
switch(1) {
3+
case 1:
4+
{}
5+
await using x = bar();
6+
default:
7+
{}
8+
await using y = bar();
9+
}
10+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
{
2+
"sourceType": "module"
3+
}

0 commit comments

Comments
 (0)