Skip to content

Commit 76d9214

Browse files
committed
move fixpoint step into subfunction
1 parent 78a7751 commit 76d9214

File tree

1 file changed

+76
-53
lines changed

1 file changed

+76
-53
lines changed

compiler/rustc_trait_selection/src/solve/search_graph.rs

Lines changed: 76 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -379,60 +379,10 @@ impl<'tcx> SearchGraph<'tcx> {
379379
// `with_anon_task` closure.
380380
let ((final_entry, result), dep_node) =
381381
tcx.dep_graph.with_anon_task(tcx, dep_kinds::TraitSelect, || {
382-
// When we encounter a coinductive cycle, we have to fetch the
383-
// result of that cycle while we are still computing it. Because
384-
// of this we continuously recompute the cycle until the result
385-
// of the previous iteration is equal to the final result, at which
386-
// point we are done.
387382
for _ in 0..FIXPOINT_STEP_LIMIT {
388-
let result = prove_goal(self, inspect);
389-
let stack_entry = self.pop_stack();
390-
debug_assert_eq!(stack_entry.input, input);
391-
392-
// If the current goal is not the root of a cycle, we are done.
393-
if stack_entry.has_been_used.is_empty() {
394-
return (stack_entry, result);
395-
}
396-
397-
// If it is a cycle head, we have to keep trying to prove it until
398-
// we reach a fixpoint. We need to do so for all cycle heads,
399-
// not only for the root.
400-
//
401-
// See tests/ui/traits/next-solver/cycles/fixpoint-rerun-all-cycle-heads.rs
402-
// for an example.
403-
404-
// Start by clearing all provisional cache entries which depend on this
405-
// the current goal.
406-
Self::clear_dependent_provisional_results(
407-
&mut self.provisional_cache,
408-
self.stack.next_index(),
409-
);
410-
411-
// Check whether we reached a fixpoint, either because the final result
412-
// is equal to the provisional result of the previous iteration, or because
413-
// this was only the root of either coinductive or inductive cycles, and the
414-
// final result is equal to the initial response for that case.
415-
let reached_fixpoint = if let Some(r) = stack_entry.provisional_result {
416-
r == result
417-
} else if stack_entry.has_been_used == HasBeenUsed::COINDUCTIVE_CYCLE {
418-
Self::response_no_constraints(tcx, input, Certainty::Yes) == result
419-
} else if stack_entry.has_been_used == HasBeenUsed::INDUCTIVE_CYCLE {
420-
Self::response_no_constraints(tcx, input, Certainty::overflow(false))
421-
== result
422-
} else {
423-
false
424-
};
425-
426-
// If we did not reach a fixpoint, update the provisional result and reevaluate.
427-
if reached_fixpoint {
428-
return (stack_entry, result);
429-
} else {
430-
let depth = self.stack.push(StackEntry {
431-
has_been_used: HasBeenUsed::empty(),
432-
provisional_result: Some(result),
433-
..stack_entry
434-
});
435-
debug_assert_eq!(self.provisional_cache[&input].stack_depth, Some(depth));
383+
match self.fixpoint_step_in_task(tcx, input, inspect, &mut prove_goal) {
384+
StepResult::Done(final_entry, result) => return (final_entry, result),
385+
StepResult::HasChanged => {}
436386
}
437387
}
438388

@@ -484,6 +434,79 @@ impl<'tcx> SearchGraph<'tcx> {
484434

485435
result
486436
}
437+
}
438+
439+
enum StepResult<'tcx> {
440+
Done(StackEntry<'tcx>, QueryResult<'tcx>),
441+
HasChanged,
442+
}
443+
444+
impl<'tcx> SearchGraph<'tcx> {
445+
/// When we encounter a coinductive cycle, we have to fetch the
446+
/// result of that cycle while we are still computing it. Because
447+
/// of this we continuously recompute the cycle until the result
448+
/// of the previous iteration is equal to the final result, at which
449+
/// point we are done.
450+
fn fixpoint_step_in_task<F>(
451+
&mut self,
452+
tcx: TyCtxt<'tcx>,
453+
input: CanonicalInput<'tcx>,
454+
inspect: &mut ProofTreeBuilder<'tcx>,
455+
prove_goal: &mut F,
456+
) -> StepResult<'tcx>
457+
where
458+
F: FnMut(&mut Self, &mut ProofTreeBuilder<'tcx>) -> QueryResult<'tcx>,
459+
{
460+
let result = prove_goal(self, inspect);
461+
let stack_entry = self.pop_stack();
462+
debug_assert_eq!(stack_entry.input, input);
463+
464+
// If the current goal is not the root of a cycle, we are done.
465+
if stack_entry.has_been_used.is_empty() {
466+
return StepResult::Done(stack_entry, result);
467+
}
468+
469+
// If it is a cycle head, we have to keep trying to prove it until
470+
// we reach a fixpoint. We need to do so for all cycle heads,
471+
// not only for the root.
472+
//
473+
// See tests/ui/traits/next-solver/cycles/fixpoint-rerun-all-cycle-heads.rs
474+
// for an example.
475+
476+
// Start by clearing all provisional cache entries which depend on this
477+
// the current goal.
478+
Self::clear_dependent_provisional_results(
479+
&mut self.provisional_cache,
480+
self.stack.next_index(),
481+
);
482+
483+
// Check whether we reached a fixpoint, either because the final result
484+
// is equal to the provisional result of the previous iteration, or because
485+
// this was only the root of either coinductive or inductive cycles, and the
486+
// final result is equal to the initial response for that case.
487+
let reached_fixpoint = if let Some(r) = stack_entry.provisional_result {
488+
r == result
489+
} else if stack_entry.has_been_used == HasBeenUsed::COINDUCTIVE_CYCLE {
490+
Self::response_no_constraints(tcx, input, Certainty::Yes) == result
491+
} else if stack_entry.has_been_used == HasBeenUsed::INDUCTIVE_CYCLE {
492+
Self::response_no_constraints(tcx, input, Certainty::overflow(false)) == result
493+
} else {
494+
false
495+
};
496+
497+
// If we did not reach a fixpoint, update the provisional result and reevaluate.
498+
if reached_fixpoint {
499+
StepResult::Done(stack_entry, result)
500+
} else {
501+
let depth = self.stack.push(StackEntry {
502+
has_been_used: HasBeenUsed::empty(),
503+
provisional_result: Some(result),
504+
..stack_entry
505+
});
506+
debug_assert_eq!(self.provisional_cache[&input].stack_depth, Some(depth));
507+
StepResult::HasChanged
508+
}
509+
}
487510

488511
fn response_no_constraints(
489512
tcx: TyCtxt<'tcx>,

0 commit comments

Comments
 (0)