Skip to content

Commit 892ca2d

Browse files
committed
Only scan the affected suffix of the provisional cache
`insert_provisional` walks the whole provisional cache on every insert to lower `reached_depth`. Everything it can affect was inserted while `from_dfn` was on the stack, so it is a suffix of this insertion-ordered map and the walk can stop at the first older entry. The full walk is quadratic in the size of the cache, which only fills up for types that are mutually recursive. Proving `Send` for a graph of N such types did about N^2 iterations of this loop: 641M for N=480. `evaluate_obligation` on that graph, before and after: N=60 63ms -> 41ms N=120 172ms -> 80ms N=240 531ms -> 167ms N=480 - -> 316ms which is the linear growth the same graph already has when it is acyclic.
1 parent 2850f83 commit 892ca2d

1 file changed

Lines changed: 6 additions & 3 deletions

File tree

  • compiler/rustc_trait_selection/src/traits/select

compiler/rustc_trait_selection/src/traits/select/mod.rs

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3116,10 +3116,13 @@ impl<'tcx> ProvisionalEvaluationCache<'tcx> {
31163116
// A // depth 0
31173117
// D (reached depth 1)
31183118
// C (cache -- reached depth = 2)
3119-
for (_k, v) in &mut *map {
3120-
if v.from_dfn >= from_dfn {
3121-
v.reached_depth = reached_depth.min(v.reached_depth);
3119+
// Anything this can affect was inserted while `from_dfn` was on the
3120+
// stack, so it is a suffix of this insertion-ordered map.
3121+
for (_k, v) in map.iter_mut().rev() {
3122+
if v.from_dfn < from_dfn {
3123+
break;
31223124
}
3125+
v.reached_depth = reached_depth.min(v.reached_depth);
31233126
}
31243127

31253128
map.insert(fresh_trait_pred, ProvisionalEvaluation { from_dfn, reached_depth, result });

0 commit comments

Comments
 (0)