Skip redundant next-solver fulfillment scans - #1
Conversation
When every pending goal is stalled only on type inference variables older than any vid changed since the last fulfillment pass, skip walking the pending queue. This removes the quadratic rescan from large typeck bodies (rustc#159933) without tracking a set of vids. Int/float/const stalls and opaque-storage count mismatches still take the existing retain_mut path. -Zdisable-fast-paths disables the skip.
typos already allowlists 'unstalled'; the verb form trips CI.
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes and found 1 potential issue.
❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, have a team admin enable autofix in the Cursor dashboard.
Reviewed by Cursor Bugbot for commit 18ea519. Configure here.
| } | ||
|
|
||
| infcx.reset_min_changed_ty_vid(); | ||
| self.recompute_tracking(); |
There was a problem hiding this comment.
Shared min-changed reset breaks skip
High Severity
reset_min_changed_ty_vid clears InferCtxt-global change tracking after any fulfillment scan. Temporary ObligationCtxt / FulfillmentCtxt instances used during typeck (e.g. coercion) share that state with the main fulfillment engine, so a successful nested scan can wipe a relevant min_changed and cause the outer context to take the skip path even though pending goals were unstalled. Those goals are later reported as ambiguity instead of being re-solved or hard-errored.
Additional Locations (2)
Reviewed by Cursor Bugbot for commit 18ea519. Configure here.


This change was implemented by a Cursor cloud agent. It is intended for this fork, not as an upstream rust-lang/rust PR.
Skip walking the next-solver pending fulfillment queue when no pending goal can have been unstalled.
Refs rust-lang#159933. Related idea: rust-lang#161348, but this keeps a simpler conservative check:
retain_mutscan when every pending goal is type-var-only and trackable, opaque storage is unchanged, and every infer change is to a strictly newer vid.-Zdisable-fast-pathstake the existing path.Missing a
min_changedbump is conservative (extra scans). Missing a bump onequate/instantiate/sub_unifywould be incorrect; those three paths all record the change.Measurements
Same-commit stage1 rustc,
--crate-type=lib --edition=2024 --emit=metadata. Median of 4 runs after warmup.Vec::push(Default::default())Default/unwrap_or_defaultbindingsThe 10%+ win is on next-solver typeck of large function bodies with many stalled obligations, which is the default solver on this tree.
Note
Medium Risk
Touches next-solver fulfillment and type-inference undo logging. A missed
min_changedbump on equate/instantiate/sub_unify could skip needed re-evaluation; the skip is otherwise conservative.Overview
Next-solver fulfillment can now skip walking the pending obligation queue when no pending goal could have been unstalled (rustc#159933).
It tracks the smallest type vid equated, sub-unified, or instantiated since the last fulfillment pass (snapshot-aware via the infer undo log) and the largest stalled type vid among pending goals. The scan is skipped only when every pending goal is type-var-only and trackable, opaque storage is unchanged, and every infer change is to a strictly newer vid. Int/float/const stalls, mixed opaque counts, overflow, and
-Zdisable-fast-pathskeep the existing full walk.A UI test covers a long chain of stalled
Defaultobligations that must still resolve when a lateru8constraint appears.Reviewed by Cursor Bugbot for commit 18ea519. Bugbot is set up for automated code reviews on this repo. Configure here.