mirror of
https://github.com/oxc-project/oxc.git
synced 2026-11-04 10:29:58 +00:00
perf(parser): skip checkpoint for infer T extends U constraint in disallow context (#23128)
## What
`parse_constraint_of_infer_type` always took a parser-level `checkpoint()` to speculatively parse the `extends U` constraint of an `infer T extends U` type, rewinding when a trailing `?` meant the `extends` actually belonged to an enclosing conditional type (`infer T extends U ? A : B`).
## Why the checkpoint was usually wasted
`infer` normally appears in a conditional type's `extends` clause, which is parsed under `DisallowConditionalTypes` (see `parse_ts_type`). In that context a trailing `?` cannot reinterpret the `extends`, so the old post-parse check short-circuited to `Some(constraint)` through the `||`:
```rust
if self.ctx.has_disallow_conditional_types() || !self.at(Kind::Question) {
Some(constraint) // <- always taken in the common case
} else {
self.rewind(checkpoint);
None
}
```
So the checkpoint was taken on every `infer T extends U` but never actually used.
## Change
Guard on `has_disallow_conditional_types()` up front and parse the constraint directly when it is set, taking the checkpoint only on the genuinely-speculative path — the rare case where `infer` is parsed in a conditional-*allowed* position and a trailing `?` reinterprets the `extends`.
Behavior-preserving:
- `cargo coverage -- parser` — test262 100%, snapshots unchanged.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
This commit is contained in:
1 file changed
+11
-3
@@ -323,14 +323,22 @@ impl<'a, C: Config> ParserImpl<'a, C> {
|
||||
if !self.at(Kind::Extends) {
|
||||
return None;
|
||||
}
|
||||
// When conditional types are already disallowed by the enclosing context — the normal case,
|
||||
// since `infer` lives in a conditional's `extends` clause which is parsed with
|
||||
// `DisallowConditionalTypes` — a trailing `?` cannot reinterpret `extends` as a conditional.
|
||||
// The constraint is then unambiguous, so parse it without a checkpoint/rewind.
|
||||
if self.ctx.has_disallow_conditional_types() {
|
||||
self.bump_any();
|
||||
return Some(self.context_add(Context::DisallowConditionalTypes, Self::parse_ts_type));
|
||||
}
|
||||
let checkpoint = self.checkpoint();
|
||||
self.bump_any();
|
||||
let constraint = self.context_add(Context::DisallowConditionalTypes, Self::parse_ts_type);
|
||||
if self.ctx.has_disallow_conditional_types() || !self.at(Kind::Question) {
|
||||
Some(constraint)
|
||||
} else {
|
||||
if self.at(Kind::Question) {
|
||||
self.rewind(checkpoint);
|
||||
None
|
||||
} else {
|
||||
Some(constraint)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in new issue
Block a user