mirror of
https://github.com/oxc-project/oxc.git
synced 2026-11-04 10:29:58 +00:00
perf(parser): skip redundant member-rest re-scan on call entry (#23068)
Follow-up to #23063. `parse_lhs_expression_or_higher` parses the `MemberExpression` to completion before entering `parse_call_expression_rest`, and (since #23063) only enters it when the current token is `(` (Arguments) or `?.` (OptionalChain). The loop in `parse_call_expression_rest` then re-ran `parse_member_expression_rest` — the hottest function in the parser — as its first step on every iteration. For a `(` entry that first call is the identity: `(` is not in the member-expression continuation FIRST set (`?.`, `.`, `[`, template, TS `!`/`<`). So skip it on the `(` first-entry. The `?.` entry and every later iteration (after `Arguments`) still run it. Behavior-preserving: - `cargo coverage -- parser` — Test262 / Babel / TypeScript / ESTree snapshots byte-identical (no `.snap` changes). - `just allocs` — allocation snapshot unchanged. 🤖 Generated with [Claude Code](https://claude.com/claude-code)
This commit is contained in:
1 file changed
+18
-6
@@ -1029,13 +1029,25 @@ impl<'a, C: Config> ParserImpl<'a, C> {
|
||||
in_optional_chain: &mut bool,
|
||||
) -> Expression<'a> {
|
||||
let mut lhs = lhs;
|
||||
// The caller only enters here with the current token being `(` or `?.`. For `(`,
|
||||
// `parse_member_expression_rest` is a no-op (`(` ∉ its FIRST set: `?.`, `.`, `[`,
|
||||
// template, TS `!`/`<`), so skip the redundant re-scan on entry; entering on `?.`, and
|
||||
// every later iteration (after `Arguments`), still needs it.
|
||||
debug_assert!(
|
||||
matches!(self.cur_kind(), Kind::LParen | Kind::QuestionDot),
|
||||
"parse_call_expression_rest is only entered on `(` or `?.`",
|
||||
);
|
||||
let mut rescan_members = !self.at(Kind::LParen);
|
||||
while self.fatal_error.is_none() {
|
||||
lhs = self.parse_member_expression_rest(
|
||||
lhs_span,
|
||||
lhs,
|
||||
in_optional_chain,
|
||||
/* allow_optional_chain */ true,
|
||||
);
|
||||
if rescan_members {
|
||||
lhs = self.parse_member_expression_rest(
|
||||
lhs_span,
|
||||
lhs,
|
||||
in_optional_chain,
|
||||
/* allow_optional_chain */ true,
|
||||
);
|
||||
}
|
||||
rescan_members = true;
|
||||
let question_dot_span = self.at(Kind::QuestionDot).then(|| self.cur_token().span());
|
||||
let question_dot = question_dot_span.is_some();
|
||||
if question_dot {
|
||||
|
||||
Reference in new issue
Block a user