perf(semantic): reorder binding identifier checks (#22656)

`check_binding_identifier` runs for every binding identifier during semantic checking, but the strict-mode binding diagnostic only applies to `eval` and `arguments`, while the sloppy-mode lexical declaration diagnostic only applies to `let`.

Previously we queried `ctx.strict_mode()` before checking the identifier name, so every binding identifier paid for the current scope flag lookup even though most names cannot trigger either diagnostic. Rewriting this as a name-first match keeps the same behavior while making the common path cheaper: ordinary binding names fall through without asking whether the current scope is strict.
This commit is contained in:
camc314 committed 2026-05-22 04:21:02 +00:00
1 parent e32acd8a1e
commit 4d5ddb1fe9
1 file changed
+6 -6
@@ -211,9 +211,9 @@ pub fn check_binding_identifier(ident: &BindingIdentifier, ctx: &SemanticBuilder
return;
}
if ctx.strict_mode() {
match ident.name.as_str() {
// In strict mode, `eval` and `arguments` are banned as identifiers.
if matches!(ident.name.as_str(), "eval" | "arguments") {
"eval" | "arguments" if ctx.strict_mode() => {
// `eval` and `arguments` are allowed as the names of declare functions as well as their arguments.
//
// declare function eval(): void; // OK
@@ -249,10 +249,9 @@ pub fn check_binding_identifier(ident: &BindingIdentifier, ctx: &SemanticBuilder
ctx.error(diagnostics::unexpected_identifier_assign(&ident.name, ident.span));
}
}
} else {
// LexicalDeclaration : LetOrConst BindingList ;
// * It is a Syntax Error if the BoundNames of BindingList contains "let".
if ident.name == "let" {
"let" if !ctx.strict_mode() => {
// LexicalDeclaration : LetOrConst BindingList ;
// * It is a Syntax Error if the BoundNames of BindingList contains "let".
for node_kind in ctx.nodes.ancestor_kinds(ctx.current_node_id) {
match node_kind {
AstKind::VariableDeclarator(decl) => {
@@ -269,6 +268,7 @@ pub fn check_binding_identifier(ident: &BindingIdentifier, ctx: &SemanticBuilder
}
}
}
_ => {}
}
}