Skip to content

Commit 01a1e8d

Browse files
committed
w
1 parent f4e9efa commit 01a1e8d

File tree

1 file changed

+75
-52
lines changed
  • compiler/rustc_type_ir/src/search_graph

1 file changed

+75
-52
lines changed

compiler/rustc_type_ir/src/search_graph/mod.rs

Lines changed: 75 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -290,7 +290,7 @@ impl CycleHeads {
290290
}
291291

292292
fn contains(&self, other: &CycleHeads) -> bool {
293-
other.heads.iter().all(|(h, _)| self.heads.contains_key(h))
293+
other.heads.iter().all(|(h, &path)| self.heads.get(h).is_some_and(|p| p.contains(path)))
294294
}
295295
}
296296

@@ -785,11 +785,14 @@ impl<D: Delegate<Cx = X>, X: Cx> SearchGraph<D> {
785785
fn clear_dependent_provisional_results(
786786
stack: &Stack<X>,
787787
provisional_cache: &mut HashMap<X::Input, Vec<ProvisionalCacheEntry<X>>>,
788+
mut handle_removed_entry: impl FnMut(X::Input, ProvisionalCacheEntry<X>),
788789
) {
789790
let head = stack.next_index();
790791
#[allow(rustc::potential_query_instability)]
791-
provisional_cache.retain(|_, entries| {
792-
entries.retain(|entry| entry.heads.highest_cycle_head() != head);
792+
provisional_cache.retain(|&input, entries| {
793+
for e in entries.extract_if(.., |entry| entry.heads.highest_cycle_head() == head) {
794+
handle_removed_entry(input, e)
795+
}
793796
!entries.is_empty()
794797
});
795798
}
@@ -875,6 +878,7 @@ impl<D: Delegate<Cx = X>, X: Cx> SearchGraph<D> {
875878
// Mutate the result of the provisional cache entry in case we did
876879
// not reach a fixpoint.
877880
*result = mutate_result(input, *result);
881+
debug!(?input, ?entry, "rebased entry");
878882
true
879883
});
880884
!entries.is_empty()
@@ -1209,10 +1213,6 @@ impl<D: Delegate<Cx = X>, X: Cx> SearchGraph<D> {
12091213
return EvaluationResult::finalize(stack_entry, encountered_overflow, result);
12101214
}
12111215

1212-
// Clear all provisional cache entries which depend on a previous provisional
1213-
// result of this goal and rerun.
1214-
Self::clear_dependent_provisional_results(&self.stack, &mut self.provisional_cache);
1215-
12161216
debug!(?i, ?result, "changed provisional results");
12171217
match self.reevaluate_goal_on_stack(cx, stack_entry, result, inspect) {
12181218
(new_stack_entry, new_result) => {
@@ -1247,6 +1247,20 @@ impl<D: Delegate<Cx = X>, X: Cx> SearchGraph<D> {
12471247
) -> (StackEntry<X>, X::Result) {
12481248
let node_id = prev_stack_entry.node_id;
12491249
let current_depth = self.stack.next_index();
1250+
1251+
let mut removed_entries = BTreeMap::new();
1252+
// Clear all provisional cache entries which depend on a previous provisional
1253+
// result of this goal and rerun.
1254+
Self::clear_dependent_provisional_results(
1255+
&self.stack,
1256+
&mut self.provisional_cache,
1257+
|input, entry| {
1258+
let prev = removed_entries.insert(entry.entry_node_id, (input, entry));
1259+
if let Some(prev) = prev {
1260+
unreachable!("duplicate entries for the same `NodeId`: {prev:?}");
1261+
}
1262+
},
1263+
);
12501264
self.stack.push(StackEntry {
12511265
node_id,
12521266
input: prev_stack_entry.input,
@@ -1272,7 +1286,7 @@ impl<D: Delegate<Cx = X>, X: Cx> SearchGraph<D> {
12721286
// TODO: How can we tell whether this entry was the final revision.
12731287
//
12741288
// We should be able to rebase provisional entries in most cases.
1275-
Self::clear_dependent_provisional_results(stack, provisional_cache);
1289+
Self::clear_dependent_provisional_results(stack, provisional_cache, |_, _| ());
12761290
Self::update_parent_goal(
12771291
stack,
12781292
reeval_entry.step_kind_from_parent,
@@ -1286,7 +1300,6 @@ impl<D: Delegate<Cx = X>, X: Cx> SearchGraph<D> {
12861300

12871301
let cycles = self.tree.rerun_get_and_reset_cycles(prev_stack_entry.node_id);
12881302
let current_stack_len = self.stack.len();
1289-
let mut first_cycle = true;
12901303
let mut has_changed = HashSet::default();
12911304
'outer: for cycle in cycles {
12921305
let &tree::Cycle { node_id: cycle_node_id, ref provisional_results } =
@@ -1328,63 +1341,53 @@ impl<D: Delegate<Cx = X>, X: Cx> SearchGraph<D> {
13281341
let span = tracing::debug_span!("reevaluate cycle", ?rev_stack, ?provisional_result);
13291342
let _span = span.enter();
13301343
let mut current_goal = rev_stack.remove(0);
1331-
let mut added_goals = rev_stack
1332-
.into_iter()
1333-
.rev()
1334-
.enumerate()
1335-
.map(|(idx, (node_id, info))| {
1336-
(StackDepth::from(current_stack_len + idx), node_id, info)
1337-
})
1338-
.peekable();
1344+
let mut added_goals = rev_stack.into_iter().rev().peekable();
13391345
// We only pop from the stack when checking whether a result has changed.
13401346
// If a later cycle does not have to truncate the stack, we've already reevaluated
13411347
// a parent so there's no need to consider that goal.
1342-
if first_cycle {
1343-
first_cycle = false;
1344-
} else {
1345-
if added_goals.peek().is_none() {
1346-
if self.stack.len() > current_stack_len {
1347-
truncate_stack(
1348-
&mut self.stack,
1349-
&mut self.provisional_cache,
1350-
StackDepth::from_usize(current_stack_len),
1351-
);
1348+
for idx in current_stack_len.. {
1349+
let stack_depth = StackDepth::from_usize(idx);
1350+
match (added_goals.peek(), self.stack.get(stack_depth)) {
1351+
(Some(&(node_id, info)), Some(existing_entry)) => {
1352+
let provisional_result = provisional_results.get(&stack_depth).copied();
1353+
if existing_entry.node_id == node_id
1354+
&& provisional_result == existing_entry.provisional_result
1355+
{
1356+
debug_assert_eq!(existing_entry.input, info.input);
1357+
debug_assert_eq!(
1358+
existing_entry.step_kind_from_parent,
1359+
info.step_kind_from_parent
1360+
);
1361+
let _ = added_goals.next().unwrap();
1362+
} else {
1363+
truncate_stack(
1364+
&mut self.stack,
1365+
&mut self.provisional_cache,
1366+
stack_depth,
1367+
);
1368+
break;
1369+
}
13521370
}
1353-
} else {
1354-
while let Some(&(stack_depth, node_id, info)) = added_goals.peek() {
1355-
if let Some(existing_entry) = self.stack.get(stack_depth) {
1356-
let provisional_result = provisional_results.get(&stack_depth).copied();
1357-
if existing_entry.node_id == node_id
1358-
&& provisional_result == existing_entry.provisional_result
1359-
{
1360-
debug_assert_eq!(existing_entry.input, info.input);
1361-
debug_assert_eq!(
1362-
existing_entry.step_kind_from_parent,
1363-
info.step_kind_from_parent
1364-
);
1365-
let _ = added_goals.next().unwrap();
1366-
} else {
1367-
truncate_stack(
1368-
&mut self.stack,
1369-
&mut self.provisional_cache,
1370-
stack_depth,
1371-
);
1372-
break;
1373-
}
1374-
} else if current_goal.0 == node_id {
1371+
(Some(&(node_id, info)), None) => {
1372+
if current_goal.0 == node_id {
13751373
debug!(parent = ?info.input, cycle = ?added_goals.last().unwrap(), "reevaluated parent, skip cycle");
13761374
continue 'outer;
13771375
} else {
13781376
break;
13791377
}
13801378
}
1379+
(None, Some(_)) => {
1380+
truncate_stack(&mut self.stack, &mut self.provisional_cache, stack_depth);
1381+
break;
1382+
}
1383+
(None, None) => break,
13811384
}
13821385
}
13831386

1384-
for (stack_depth, node_id, info) in added_goals {
1387+
for (node_id, info) in added_goals {
13851388
let tree::GoalInfo { input, step_kind_from_parent, available_depth } = info;
1389+
let stack_depth = self.stack.next_index();
13861390
let provisional_result = provisional_results.get(&stack_depth).copied();
1387-
debug_assert_eq!(self.stack.next_index(), stack_depth);
13881391
self.stack.push(StackEntry {
13891392
node_id,
13901393
input,
@@ -1399,10 +1402,22 @@ impl<D: Delegate<Cx = X>, X: Cx> SearchGraph<D> {
13991402
});
14001403
}
14011404

1405+
/*
1406+
while let Some((&entry_node_id, _)) = removed_entries.first_key_value() {
1407+
if entry_node_id < current_goal.0
1408+
&& self.stack.iter().all(|e| e.node_id != entry_node_id)
1409+
{
1410+
let (entry_node_id, (input, entry)) = removed_entries.pop_first().unwrap();
1411+
if !self.tree.goal_or_parent_has_changed(node_id, &has_changed, entry_node_id) {
1412+
self.provisional_cache.entry(input).or_default().push(entry);
1413+
}
1414+
}
1415+
}*/
1416+
14021417
loop {
14031418
let span = tracing::debug_span!(
14041419
"reevaluate_canonical_goal",
1405-
node = ?current_goal.1.input,
1420+
input = ?current_goal.1.input,
14061421
step_kind_from_parent = ?current_goal.1.step_kind_from_parent
14071422
);
14081423
let _span = span.enter();
@@ -1414,6 +1429,7 @@ impl<D: Delegate<Cx = X>, X: Cx> SearchGraph<D> {
14141429
);
14151430
if node_id.is_some_and(|node_id| self.tree.result_matches(current_goal.0, node_id))
14161431
{
1432+
removed_entries.remove(&current_goal.0);
14171433
debug!(input = ?current_goal.1.input, ?result, "goal did not change");
14181434
continue 'outer;
14191435
} else {
@@ -1424,6 +1440,7 @@ impl<D: Delegate<Cx = X>, X: Cx> SearchGraph<D> {
14241440
Self::clear_dependent_provisional_results(
14251441
&self.stack,
14261442
&mut self.provisional_cache,
1443+
|_, _| (),
14271444
);
14281445
Self::update_parent_goal(
14291446
&mut self.stack,
@@ -1461,6 +1478,12 @@ impl<D: Delegate<Cx = X>, X: Cx> SearchGraph<D> {
14611478
StackDepth::from_usize(current_stack_len),
14621479
);
14631480

1481+
for (entry_node_id, (input, entry)) in removed_entries {
1482+
if !self.tree.goal_or_parent_has_changed(node_id, &has_changed, entry_node_id) {
1483+
self.provisional_cache.entry(input).or_default().push(entry);
1484+
}
1485+
}
1486+
14641487
debug_assert_eq!(self.stack.len(), current_stack_len);
14651488
let reeval_entry = self.stack.pop();
14661489
(reeval_entry, provisional_result)

0 commit comments

Comments
 (0)