Rollup merge of #127508 - lcnr:search-graph-prep, r=compiler-errors

small search graph refactor

small improvements which shouldn't impact behavior.

r? ``````@compiler-errors``````
This commit is contained in:
Jacob Pratt 2024-07-10 00:37:12 -04:00 committed by GitHub
commit 64695adbd7
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 32 additions and 34 deletions

View File

@ -48,12 +48,20 @@ enum GoalEvaluationKind {
Nested,
}
// FIXME(trait-system-refactor-initiative#117): we don't detect whether a response
// ended up pulling down any universes.
fn has_no_inference_or_external_constraints<I: Interner>(
response: ty::Canonical<I, Response<I>>,
) -> bool {
response.value.external_constraints.region_constraints.is_empty()
&& response.value.var_values.is_identity()
&& response.value.external_constraints.opaque_types.is_empty()
let ExternalConstraintsData {
ref region_constraints,
ref opaque_types,
ref normalization_nested_goals,
} = *response.value.external_constraints;
response.value.var_values.is_identity()
&& region_constraints.is_empty()
&& opaque_types.is_empty()
&& normalization_nested_goals.is_empty()
}
impl<'a, D, I> EvalCtxt<'a, D>

View File

@ -71,7 +71,7 @@ struct StackEntry<I: Interner> {
/// C :- D
/// D :- C
/// ```
cycle_participants: HashSet<CanonicalInput<I>>,
nested_goals: HashSet<CanonicalInput<I>>,
/// Starts out as `None` and gets set when rerunning this
/// goal in case we encounter a cycle.
provisional_result: Option<QueryResult<I>>,
@ -139,18 +139,11 @@ impl<I: Interner> SearchGraph<I> {
self.mode
}
/// Pops the highest goal from the stack, lazily updating the
/// the next goal in the stack.
///
/// Directly popping from the stack instead of using this method
/// would cause us to not track overflow and recursion depth correctly.
fn pop_stack(&mut self) -> StackEntry<I> {
let elem = self.stack.pop().unwrap();
if let Some(last) = self.stack.raw.last_mut() {
last.reached_depth = last.reached_depth.max(elem.reached_depth);
last.encountered_overflow |= elem.encountered_overflow;
fn update_parent_goal(&mut self, reached_depth: StackDepth, encountered_overflow: bool) {
if let Some(parent) = self.stack.raw.last_mut() {
parent.reached_depth = parent.reached_depth.max(reached_depth);
parent.encountered_overflow |= encountered_overflow;
}
elem
}
pub(super) fn is_empty(&self) -> bool {
@ -222,8 +215,8 @@ impl<I: Interner> SearchGraph<I> {
let current_cycle_root = &mut stack[current_root.as_usize()];
for entry in cycle_participants {
entry.non_root_cycle_participant = entry.non_root_cycle_participant.max(Some(head));
current_cycle_root.cycle_participants.insert(entry.input);
current_cycle_root.cycle_participants.extend(mem::take(&mut entry.cycle_participants));
current_cycle_root.nested_goals.insert(entry.input);
current_cycle_root.nested_goals.extend(mem::take(&mut entry.nested_goals));
}
}
@ -342,7 +335,7 @@ impl<I: Interner> SearchGraph<I> {
non_root_cycle_participant: None,
encountered_overflow: false,
has_been_used: HasBeenUsed::empty(),
cycle_participants: Default::default(),
nested_goals: Default::default(),
provisional_result: None,
};
assert_eq!(self.stack.push(entry), depth);
@ -364,7 +357,7 @@ impl<I: Interner> SearchGraph<I> {
}
debug!("canonical cycle overflow");
let current_entry = self.pop_stack();
let current_entry = self.stack.pop().unwrap();
debug_assert!(current_entry.has_been_used.is_empty());
let result = Self::response_no_constraints(cx, input, Certainty::overflow(false));
(current_entry, result)
@ -372,6 +365,8 @@ impl<I: Interner> SearchGraph<I> {
let proof_tree = inspect.finalize_canonical_goal_evaluation(cx);
self.update_parent_goal(final_entry.reached_depth, final_entry.encountered_overflow);
// We're now done with this goal. In case this goal is involved in a larger cycle
// do not remove it from the provisional cache and update its provisional result.
// We only add the root of cycles to the global cache.
@ -394,7 +389,7 @@ impl<I: Interner> SearchGraph<I> {
//
// We must not use the global cache entry of a root goal if a cycle
// participant is on the stack. This is necessary to prevent unstable
// results. See the comment of `StackEntry::cycle_participants` for
// results. See the comment of `StackEntry::nested_goals` for
// more details.
self.global_cache(cx).insert(
cx,
@ -402,7 +397,7 @@ impl<I: Interner> SearchGraph<I> {
proof_tree,
reached_depth,
final_entry.encountered_overflow,
final_entry.cycle_participants,
final_entry.nested_goals,
dep_node,
result,
)
@ -441,14 +436,9 @@ impl<I: Interner> SearchGraph<I> {
}
}
// Update the reached depth of the current goal to make sure
// its state is the same regardless of whether we've used the
// global cache or not.
// Adjust the parent goal as if we actually computed this goal.
let reached_depth = self.stack.next_index().plus(additional_depth);
if let Some(last) = self.stack.raw.last_mut() {
last.reached_depth = last.reached_depth.max(reached_depth);
last.encountered_overflow |= encountered_overflow;
}
self.update_parent_goal(reached_depth, encountered_overflow);
Some(result)
}
@ -477,7 +467,7 @@ impl<I: Interner> SearchGraph<I> {
F: FnMut(&mut Self, &mut ProofTreeBuilder<D>) -> QueryResult<I>,
{
let result = prove_goal(self, inspect);
let stack_entry = self.pop_stack();
let stack_entry = self.stack.pop().unwrap();
debug_assert_eq!(stack_entry.input, input);
// If the current goal is not the root of a cycle, we are done.
@ -554,27 +544,27 @@ impl<I: Interner> SearchGraph<I> {
non_root_cycle_participant,
encountered_overflow: _,
has_been_used,
ref cycle_participants,
ref nested_goals,
provisional_result,
} = *entry;
let cache_entry = provisional_cache.get(&entry.input).unwrap();
assert_eq!(cache_entry.stack_depth, Some(depth));
if let Some(head) = non_root_cycle_participant {
assert!(head < depth);
assert!(cycle_participants.is_empty());
assert!(nested_goals.is_empty());
assert_ne!(stack[head].has_been_used, HasBeenUsed::empty());
let mut current_root = head;
while let Some(parent) = stack[current_root].non_root_cycle_participant {
current_root = parent;
}
assert!(stack[current_root].cycle_participants.contains(&input));
assert!(stack[current_root].nested_goals.contains(&input));
}
if !cycle_participants.is_empty() {
if !nested_goals.is_empty() {
assert!(provisional_result.is_some() || !has_been_used.is_empty());
for entry in stack.iter().take(depth.as_usize()) {
assert_eq!(cycle_participants.get(&entry.input), None);
assert_eq!(nested_goals.get(&entry.input), None);
}
}
}