Skip to content

Commit e5e923d

Browse files
authored
Disallow await as bound name in using declaration (#15391)
* refine checkLVal typings * refactor: pack let binding check to binding flags * Disallow await in using declaration * add more test cases * add module test cases
1 parent 3aee4e3 commit e5e923d

10 files changed

Lines changed: 406 additions & 50 deletions

File tree

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

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ export type LValAncestor =
1414
| "ImportSpecifier"
1515
| "ImportNamespaceSpecifier"
1616
| "ImportDefaultSpecifier"
17+
| "ParenthesizedExpression"
1718
| "ObjectPattern"
1819
| "RestElement"
1920
| "VariableDeclarator";
@@ -32,6 +33,8 @@ export default {
3233
"Can not use 'await' as identifier inside a static block.",
3334
AwaitExpressionFormalParameter:
3435
"'await' is not allowed in async function parameters.",
36+
AwaitInUsingBinding:
37+
"'await' is not allowed to be used as a name in 'using' declarations.",
3538
AwaitNotInAsyncContext:
3639
"'await' is only allowed within async functions and at the top levels of modules.",
3740
AwaitNotInAsyncFunction: "'await' is only allowed within async functions.",

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

Lines changed: 9 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ import { NodeUtils, type Undone } from "./node";
2929
import {
3030
type BindingTypes,
3131
BIND_NONE,
32-
BIND_SCOPE_LEXICAL,
32+
BIND_FLAGS_NO_LET_IN_LEXICAL,
3333
} from "../util/scopeflags";
3434
import type { ExpressionErrors } from "./util";
3535
import { Errors, type LValAncestor } from "../parse-error";
@@ -560,10 +560,6 @@ export default abstract class LValParser extends NodeUtils {
560560
* `checkLVal` will add checked identifier name to `checkClashes` It is
561561
* used in tracking duplicates in function parameter lists. If it is
562562
* false, `checkLVal` will skip duplicate checks
563-
* @param options.allowingSloppyLetBinding
564-
* Whether an identifier named "let" should be allowed in sloppy mode.
565-
* Defaults to `true` unless lexical scope its being used. This property
566-
* is only relevant if the parser's state is in sloppy mode.
567563
* @param options.strictModeChanged
568564
* Whether an identifier has been parsed in a sloppy context but should
569565
* be reinterpreted as strict-mode. e.g. `(arguments) => { "use strict "}`
@@ -579,14 +575,12 @@ export default abstract class LValParser extends NodeUtils {
579575
binding = BIND_NONE,
580576
checkClashes = false,
581577
strictModeChanged = false,
582-
allowingSloppyLetBinding = !(binding & BIND_SCOPE_LEXICAL),
583578
hasParenthesizedAncestor = false,
584579
}: {
585580
in: LValAncestor;
586581
binding?: BindingTypes;
587582
checkClashes?: Set<string> | false;
588583
strictModeChanged?: boolean;
589-
allowingSloppyLetBinding?: boolean;
590584
hasParenthesizedAncestor?: boolean;
591585
},
592586
): void {
@@ -604,12 +598,11 @@ export default abstract class LValParser extends NodeUtils {
604598
return;
605599
}
606600

607-
if (expression.type === "Identifier") {
601+
if (type === "Identifier") {
608602
this.checkIdentifier(
609603
expression as Identifier,
610604
binding,
611605
strictModeChanged,
612-
allowingSloppyLetBinding,
613606
);
614607

615608
const { name } = expression as Identifier;
@@ -626,7 +619,7 @@ export default abstract class LValParser extends NodeUtils {
626619
}
627620

628621
const validity = this.isValidLVal(
629-
expression.type,
622+
type,
630623
!(hasParenthesizedAncestor || expression.extra?.parenthesized) &&
631624
ancestor.type === "AssignmentExpression",
632625
binding,
@@ -637,35 +630,27 @@ export default abstract class LValParser extends NodeUtils {
637630
const ParseErrorClass =
638631
binding === BIND_NONE ? Errors.InvalidLhs : Errors.InvalidLhsBinding;
639632

640-
this.raise(ParseErrorClass, {
641-
at: expression,
642-
ancestor:
643-
ancestor.type === "UpdateExpression"
644-
? { type: "UpdateExpression", prefix: ancestor.prefix }
645-
: { type: ancestor.type },
646-
});
633+
this.raise(ParseErrorClass, { at: expression, ancestor });
647634
return;
648635
}
649636

650637
const [key, isParenthesizedExpression] = Array.isArray(validity)
651638
? validity
652639
: [validity, type === "ParenthesizedExpression"];
653640
const nextAncestor =
654-
expression.type === "ArrayPattern" ||
655-
expression.type === "ObjectPattern" ||
656-
expression.type === "ParenthesizedExpression"
657-
? expression
641+
type === "ArrayPattern" ||
642+
type === "ObjectPattern" ||
643+
type === "ParenthesizedExpression"
644+
? ({ type } as const)
658645
: ancestor;
659646

660647
// @ts-expect-error key may not index expression.
661648
for (const child of [].concat(expression[key])) {
662649
if (child) {
663650
this.checkLVal(child, {
664-
// @ts-expect-error: refine types
665651
in: nextAncestor,
666652
binding,
667653
checkClashes,
668-
allowingSloppyLetBinding,
669654
strictModeChanged,
670655
hasParenthesizedAncestor: isParenthesizedExpression,
671656
});
@@ -677,7 +662,6 @@ export default abstract class LValParser extends NodeUtils {
677662
at: Identifier,
678663
bindingType: BindingTypes,
679664
strictModeChanged: boolean = false,
680-
allowLetBinding: boolean = !(bindingType & BIND_SCOPE_LEXICAL),
681665
) {
682666
if (
683667
this.state.strict &&
@@ -695,7 +679,7 @@ export default abstract class LValParser extends NodeUtils {
695679
}
696680
}
697681

698-
if (!allowLetBinding && at.name === "let") {
682+
if (bindingType & BIND_FLAGS_NO_LET_IN_LEXICAL && at.name === "let") {
699683
this.raise(Errors.LetInLexicalBinding, { at });
700684
}
701685

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

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ import {
2929
CLASS_ELEMENT_STATIC_GETTER,
3030
CLASS_ELEMENT_STATIC_SETTER,
3131
type BindingTypes,
32+
BIND_CATCH_PARAM,
3233
} from "../util/scopeflags";
3334
import { ExpressionErrors } from "./util";
3435
import { PARAM, functionFlags } from "../util/production-parameter";
@@ -470,7 +471,7 @@ export default abstract class StatementParser extends ExpressionParser {
470471
return this.parseTryStatement(node as Undone<N.TryStatement>);
471472

472473
case tt._using:
473-
// using [no LineTerminator here] BindingList[+Using]
474+
// using [no LineTerminator here][lookahead != `await`] BindingList[+Using]
474475
if (
475476
this.hasFollowingLineBreak() ||
476477
this.state.containsEsc ||
@@ -1076,8 +1077,7 @@ export default abstract class StatementParser extends ExpressionParser {
10761077
this.scope.enter(simple ? SCOPE_SIMPLE_CATCH : 0);
10771078
this.checkLVal(param, {
10781079
in: { type: "CatchClause" },
1079-
binding: BIND_LEXICAL,
1080-
allowingSloppyLetBinding: true,
1080+
binding: BIND_CATCH_PARAM,
10811081
});
10821082

10831083
return param;
@@ -1507,6 +1507,11 @@ export default abstract class StatementParser extends ExpressionParser {
15071507
decl: Undone<N.VariableDeclarator>,
15081508
kind: "var" | "let" | "const" | "using",
15091509
): void {
1510+
// Unlike "let" which must be handled in checkLVal, it suffices to check
1511+
// await here because `using` must not precede binding patterns.
1512+
if (kind === "using" && !this.inModule && this.match(tt._await)) {
1513+
this.raise(Errors.AwaitInUsingBinding, { at: this.state.startLoc });
1514+
}
15101515
const id = this.parseBindingAtom();
15111516
this.checkLVal(id, {
15121517
in: { type: "VariableDeclarator" },
@@ -2959,8 +2964,7 @@ export default abstract class StatementParser extends ExpressionParser {
29592964
| N.ImportNamespaceSpecifier,
29602965
>(specifier: Undone<T>, type: T["type"], bindingType = BIND_LEXICAL) {
29612966
this.checkLVal(specifier.local, {
2962-
// @ts-expect-error refine types
2963-
in: specifier,
2967+
in: { type },
29642968
binding: bindingType,
29652969
});
29662970
return this.finishNode(specifier, type);

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

Lines changed: 23 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -26,42 +26,45 @@ export type ScopeFlags =
2626

2727
// These flags are meant to be _only_ used inside the Scope class (or subclasses).
2828
// prettier-ignore
29-
export const BIND_KIND_VALUE = 0b000000_0000_01,
30-
BIND_KIND_TYPE = 0b000000_0000_10,
29+
export const BIND_KIND_VALUE = 0b0000000_0000_01,
30+
BIND_KIND_TYPE = 0b0000000_0000_10,
3131
// Used in checkLVal and declareName to determine the type of a binding
32-
BIND_SCOPE_VAR = 0b000000_0001_00, // Var-style binding
33-
BIND_SCOPE_LEXICAL = 0b000000_0010_00, // Let- or const-style binding
34-
BIND_SCOPE_FUNCTION = 0b000000_0100_00, // Function declaration
35-
BIND_SCOPE_OUTSIDE = 0b000000_1000_00, // Special case for function names as
32+
BIND_SCOPE_VAR = 0b0000000_0001_00, // Var-style binding
33+
BIND_SCOPE_LEXICAL = 0b0000000_0010_00, // Let- or const-style binding
34+
BIND_SCOPE_FUNCTION = 0b0000000_0100_00, // Function declaration
35+
BIND_SCOPE_OUTSIDE = 0b0000000_1000_00, // Special case for function names as
3636
// bound inside the function
3737
// Misc flags
38-
BIND_FLAGS_NONE = 0b0000001_0000_00,
39-
BIND_FLAGS_CLASS = 0b0000010_0000_00,
40-
BIND_FLAGS_TS_ENUM = 0b0000100_0000_00,
41-
BIND_FLAGS_TS_CONST_ENUM = 0b0001000_0000_00,
42-
BIND_FLAGS_TS_EXPORT_ONLY = 0b0010000_0000_00,
43-
BIND_FLAGS_FLOW_DECLARE_FN = 0b0100000_0000_00,
44-
BIND_FLAGS_TS_IMPORT = 0b1000000_0000_00;
38+
BIND_FLAGS_NONE = 0b00000001_0000_00,
39+
BIND_FLAGS_CLASS = 0b00000010_0000_00,
40+
BIND_FLAGS_TS_ENUM = 0b00000100_0000_00,
41+
BIND_FLAGS_TS_CONST_ENUM = 0b00001000_0000_00,
42+
BIND_FLAGS_TS_EXPORT_ONLY = 0b00010000_0000_00,
43+
BIND_FLAGS_FLOW_DECLARE_FN = 0b00100000_0000_00,
44+
BIND_FLAGS_TS_IMPORT = 0b01000000_0000_00,
45+
// Whether "let" should be allowed in bound names in sloppy mode
46+
BIND_FLAGS_NO_LET_IN_LEXICAL = 0b10000000_0000_00;
4547

4648
// These flags are meant to be _only_ used by Scope consumers
4749
// prettier-ignore
4850
/* = is value? | is type? | scope | misc flags */
49-
export const BIND_CLASS = BIND_KIND_VALUE | BIND_KIND_TYPE | BIND_SCOPE_LEXICAL | BIND_FLAGS_CLASS ,
50-
BIND_LEXICAL = BIND_KIND_VALUE | 0 | BIND_SCOPE_LEXICAL | 0 ,
51+
export const BIND_CLASS = BIND_KIND_VALUE | BIND_KIND_TYPE | BIND_SCOPE_LEXICAL | BIND_FLAGS_CLASS|BIND_FLAGS_NO_LET_IN_LEXICAL,
52+
BIND_LEXICAL = BIND_KIND_VALUE | 0 | BIND_SCOPE_LEXICAL | BIND_FLAGS_NO_LET_IN_LEXICAL,
53+
BIND_CATCH_PARAM = BIND_KIND_VALUE | 0 | BIND_SCOPE_LEXICAL | 0 ,
5154
BIND_VAR = BIND_KIND_VALUE | 0 | BIND_SCOPE_VAR | 0 ,
5255
BIND_FUNCTION = BIND_KIND_VALUE | 0 | BIND_SCOPE_FUNCTION | 0 ,
5356
BIND_TS_INTERFACE = 0 | BIND_KIND_TYPE | 0 | BIND_FLAGS_CLASS ,
5457
BIND_TS_TYPE = 0 | BIND_KIND_TYPE | 0 | 0 ,
55-
BIND_TS_ENUM = BIND_KIND_VALUE | BIND_KIND_TYPE | BIND_SCOPE_LEXICAL | BIND_FLAGS_TS_ENUM,
58+
BIND_TS_ENUM = BIND_KIND_VALUE | BIND_KIND_TYPE | BIND_SCOPE_LEXICAL | BIND_FLAGS_TS_ENUM|BIND_FLAGS_NO_LET_IN_LEXICAL,
5659
BIND_TS_AMBIENT = 0 | 0 | 0 | BIND_FLAGS_TS_EXPORT_ONLY,
5760
// These bindings don't introduce anything in the scope. They are used for assignments and
5861
// function expressions IDs.
59-
BIND_NONE = 0 | 0 | 0 | BIND_FLAGS_NONE ,
60-
BIND_OUTSIDE = BIND_KIND_VALUE | 0 | 0 | BIND_FLAGS_NONE ,
62+
BIND_NONE = 0 | 0 | 0 | BIND_FLAGS_NONE ,
63+
BIND_OUTSIDE = BIND_KIND_VALUE | 0 | 0 | BIND_FLAGS_NONE ,
6164

62-
BIND_TS_CONST_ENUM = BIND_TS_ENUM | BIND_FLAGS_TS_CONST_ENUM ,
65+
BIND_TS_CONST_ENUM = BIND_TS_ENUM | BIND_FLAGS_TS_CONST_ENUM ,
6366
BIND_TS_NAMESPACE = 0 | 0 | 0 | BIND_FLAGS_TS_EXPORT_ONLY,
64-
BIND_TS_TYPE_IMPORT= 0 | BIND_KIND_TYPE | 0 | BIND_FLAGS_TS_IMPORT,
67+
BIND_TS_TYPE_IMPORT= 0 | BIND_KIND_TYPE | 0 | BIND_FLAGS_TS_IMPORT ,
6568

6669
BIND_FLOW_DECLARE_FN = BIND_FLAGS_FLOW_DECLARE_FN;
6770

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
{
2+
using await = h();
3+
}
4+
{
5+
using \u0061wait = h();
6+
}
7+
{
8+
using x, await = h();
9+
}
10+
{
11+
for (using await of []);
12+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
{
2+
"sourceType": "module"
3+
}

0 commit comments

Comments
 (0)