From 560b0578f6e4f13fc0e503293331b0fa322131e2 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Mon, 3 Aug 2026 16:29:16 +1000 Subject: [PATCH] Manage `pending` better in `try_evaluate_obligations` For extreme new-solver cases like `nacl-0.5.3` and `ijson-0.1.6` the loop in `try_evaluate_obligations` can be very inefficient. This commit makes a very simple capacity tweak to the `pending` vec to fix that. There are some other possible changes to this function to improve performance further but they are more complicated so I'm doing this easy one first. --- compiler/rustc_trait_selection/src/solve/fulfill.rs | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/compiler/rustc_trait_selection/src/solve/fulfill.rs b/compiler/rustc_trait_selection/src/solve/fulfill.rs index 342609d9d3bd5..4f7230e3d930b 100644 --- a/compiler/rustc_trait_selection/src/solve/fulfill.rs +++ b/compiler/rustc_trait_selection/src/solve/fulfill.rs @@ -209,7 +209,15 @@ where let mut errors = Vec::new(); loop { let mut any_changed = false; - for (mut obligation, stalled_on) in mem::take(&mut self.obligations.pending) { + + // This loop empties and reconstructs `self.obligations.pending`, which can have many + // items (thousands in extreme cases) and very often the new length is the same as the + // old. Reserving capacity up front avoids repeated reallocations during the + // reconstruction. + let pending = mem::take(&mut self.obligations.pending); + self.obligations.pending.reserve(pending.capacity()); + + for (mut obligation, stalled_on) in pending { let goal = obligation.as_goal(); let delegate = <&SolverDelegate<'tcx>>::from(infcx);