From 8da2e1d59beda72b3975b2aa3b5b687481160c31 Mon Sep 17 00:00:00 2001 From: Wilco Kusee Date: Fri, 19 Aug 2022 08:50:52 +0200 Subject: [PATCH 1/5] Thread should_continue through recursive solver --- chalk-recursive/src/fixed_point.rs | 16 +++++++++---- chalk-recursive/src/fulfill.rs | 38 ++++++++++++++++++++++-------- chalk-recursive/src/recursive.rs | 15 ++++++++---- chalk-recursive/src/solve.rs | 19 ++++++++++----- 4 files changed, 62 insertions(+), 26 deletions(-) diff --git a/chalk-recursive/src/fixed_point.rs b/chalk-recursive/src/fixed_point.rs index b948c1c827b..4e4e2ab08d0 100644 --- a/chalk-recursive/src/fixed_point.rs +++ b/chalk-recursive/src/fixed_point.rs @@ -43,6 +43,7 @@ where context: &mut RecursiveContext, goal: &K, minimums: &mut Minimums, + should_continue: impl std::ops::Fn() -> bool, ) -> V; fn reached_fixed_point(self, old_value: &V, new_value: &V) -> bool; fn error_value(self) -> V; @@ -104,22 +105,24 @@ where &mut self, canonical_goal: &K, solver_stuff: impl SolverStuff, + should_continue: impl std::ops::Fn() -> bool, ) -> V { debug!("solve_root_goal(canonical_goal={:?})", canonical_goal); assert!(self.stack.is_empty()); let minimums = &mut Minimums::new(); - self.solve_goal(canonical_goal, minimums, solver_stuff) + self.solve_goal(canonical_goal, minimums, solver_stuff, should_continue) } /// Attempt to solve a goal that has been fully broken down into leaf form /// and canonicalized. This is where the action really happens, and is the /// place where we would perform caching in rustc (and may eventually do in Chalk). - #[instrument(level = "info", skip(self, minimums, solver_stuff,))] + #[instrument(level = "info", skip(self, minimums, solver_stuff, should_continue))] pub fn solve_goal( &mut self, goal: &K, minimums: &mut Minimums, solver_stuff: impl SolverStuff, + should_continue: impl std::ops::Fn() -> bool, ) -> V { // First check the cache. if let Some(cache) = &self.cache { @@ -159,7 +162,8 @@ where let depth = self.stack.push(coinductive_goal); let dfn = self.search_graph.insert(goal, depth, initial_solution); - let subgoal_minimums = self.solve_new_subgoal(goal, depth, dfn, solver_stuff); + let subgoal_minimums = + self.solve_new_subgoal(goal, depth, dfn, solver_stuff, should_continue); self.search_graph[dfn].links = subgoal_minimums; self.search_graph[dfn].stack_depth = None; @@ -190,13 +194,14 @@ where } } - #[instrument(level = "debug", skip(self, solver_stuff))] + #[instrument(level = "debug", skip(self, solver_stuff, should_continue))] fn solve_new_subgoal( &mut self, canonical_goal: &K, depth: StackDepth, dfn: DepthFirstNumber, solver_stuff: impl SolverStuff, + should_continue: impl std::ops::Fn() -> bool, ) -> Minimums { // We start with `answer = None` and try to solve the goal. At the end of the iteration, // `answer` will be updated with the result of the solving process. If we detect a cycle @@ -209,7 +214,8 @@ where // so this function will eventually be constant and the loop terminates. loop { let minimums = &mut Minimums::new(); - let current_answer = solver_stuff.solve_iteration(self, canonical_goal, minimums); + let current_answer = + solver_stuff.solve_iteration(self, canonical_goal, minimums, &should_continue); debug!( "solve_new_subgoal: loop iteration result = {:?} with minimums {:?}", diff --git a/chalk-recursive/src/fulfill.rs b/chalk-recursive/src/fulfill.rs index 6dbfb1f4086..a4120d3972d 100644 --- a/chalk-recursive/src/fulfill.rs +++ b/chalk-recursive/src/fulfill.rs @@ -342,16 +342,19 @@ impl<'s, I: Interner, Solver: SolveDatabase> Fulfill<'s, I, Solver> { Ok(()) } - #[instrument(level = "debug", skip(self, minimums))] + #[instrument(level = "debug", skip(self, minimums, should_continue))] fn prove( &mut self, wc: InEnvironment>, minimums: &mut Minimums, + should_continue: impl std::ops::Fn() -> bool, ) -> Fallible> { let interner = self.solver.interner(); let (quantified, free_vars) = canonicalize(&mut self.infer, interner, wc); let (quantified, universes) = u_canonicalize(&mut self.infer, interner, &quantified); - let result = self.solver.solve_goal(quantified, minimums); + let result = self + .solver + .solve_goal(quantified, minimums, should_continue); Ok(PositiveSolution { free_vars, universes, @@ -359,7 +362,11 @@ impl<'s, I: Interner, Solver: SolveDatabase> Fulfill<'s, I, Solver> { }) } - fn refute(&mut self, goal: InEnvironment>) -> Fallible { + fn refute( + &mut self, + goal: InEnvironment>, + should_continue: impl std::ops::Fn() -> bool, + ) -> Fallible { let canonicalized = match self .infer .invert_then_canonicalize(self.solver.interner(), goal) @@ -376,7 +383,10 @@ impl<'s, I: Interner, Solver: SolveDatabase> Fulfill<'s, I, Solver> { let (quantified, _) = u_canonicalize(&mut self.infer, self.solver.interner(), &canonicalized); let mut minimums = Minimums::new(); // FIXME -- minimums here seems wrong - if let Ok(solution) = self.solver.solve_goal(quantified, &mut minimums) { + if let Ok(solution) = self + .solver + .solve_goal(quantified, &mut minimums, should_continue) + { if solution.is_unique() { Err(NoSolution) } else { @@ -431,7 +441,11 @@ impl<'s, I: Interner, Solver: SolveDatabase> Fulfill<'s, I, Solver> { } } - fn fulfill(&mut self, minimums: &mut Minimums) -> Fallible { + fn fulfill( + &mut self, + minimums: &mut Minimums, + should_continue: impl std::ops::Fn() -> bool, + ) -> Fallible { debug_span!("fulfill", obligations=?self.obligations); // Try to solve all the obligations. We do this via a fixed-point @@ -460,7 +474,7 @@ impl<'s, I: Interner, Solver: SolveDatabase> Fulfill<'s, I, Solver> { free_vars, universes, solution, - } = self.prove(wc.clone(), minimums)?; + } = self.prove(wc.clone(), minimums, &should_continue)?; if let Some(constrained_subst) = solution.definite_subst(self.interner()) { // If the substitution is trivial, we won't actually make any progress by applying it! @@ -484,7 +498,7 @@ impl<'s, I: Interner, Solver: SolveDatabase> Fulfill<'s, I, Solver> { solution.is_ambig() } Obligation::Refute(goal) => { - let answer = self.refute(goal.clone())?; + let answer = self.refute(goal.clone(), &should_continue)?; answer == NegativeSolution::Ambiguous } }; @@ -514,8 +528,12 @@ impl<'s, I: Interner, Solver: SolveDatabase> Fulfill<'s, I, Solver> { /// Try to fulfill all pending obligations and build the resulting /// solution. The returned solution will transform `subst` substitution with /// the outcome of type inference by updating the replacements it provides. - pub(super) fn solve(mut self, minimums: &mut Minimums) -> Fallible> { - let outcome = match self.fulfill(minimums) { + pub(super) fn solve( + mut self, + minimums: &mut Minimums, + should_continue: impl std::ops::Fn() -> bool, + ) -> Fallible> { + let outcome = match self.fulfill(minimums, &should_continue) { Ok(o) => o, Err(e) => return Err(e), }; @@ -567,7 +585,7 @@ impl<'s, I: Interner, Solver: SolveDatabase> Fulfill<'s, I, Solver> { free_vars, universes, solution, - } = self.prove(goal, minimums).unwrap(); + } = self.prove(goal, minimums, &should_continue).unwrap(); if let Some(constrained_subst) = solution.constrained_subst(self.solver.interner()) { diff --git a/chalk-recursive/src/recursive.rs b/chalk-recursive/src/recursive.rs index 7f5203f01f7..0e76eb3f916 100644 --- a/chalk-recursive/src/recursive.rs +++ b/chalk-recursive/src/recursive.rs @@ -76,8 +76,9 @@ impl SolverStuff, Fallible>> for &dyn context: &mut RecursiveContext, Fallible>>, goal: &UCanonicalGoal, minimums: &mut Minimums, + should_continue: impl std::ops::Fn() -> bool, ) -> Fallible> { - Solver::new(context, self).solve_iteration(goal, minimums) + Solver::new(context, self).solve_iteration(goal, minimums, should_continue) } fn reached_fixed_point( @@ -108,8 +109,10 @@ impl<'me, I: Interner> SolveDatabase for Solver<'me, I> { &mut self, goal: UCanonicalGoal, minimums: &mut Minimums, + should_continue: impl std::ops::Fn() -> bool, ) -> Fallible> { - self.context.solve_goal(&goal, minimums, self.program) + self.context + .solve_goal(&goal, minimums, self.program, should_continue) } fn interner(&self) -> I { @@ -131,17 +134,19 @@ impl chalk_solve::Solver for RecursiveSolver { program: &dyn RustIrDatabase, goal: &UCanonical>>, ) -> Option> { - self.ctx.solve_root_goal(goal, program).ok() + self.ctx.solve_root_goal(goal, program, || true).ok() } fn solve_limited( &mut self, program: &dyn RustIrDatabase, goal: &UCanonical>>, - _should_continue: &dyn std::ops::Fn() -> bool, + should_continue: &dyn std::ops::Fn() -> bool, ) -> Option> { // TODO support should_continue in recursive solver - self.ctx.solve_root_goal(goal, program).ok() + self.ctx + .solve_root_goal(goal, program, should_continue) + .ok() } fn solve_multiple( diff --git a/chalk-recursive/src/solve.rs b/chalk-recursive/src/solve.rs index 62b029d33ee..b810d47da09 100644 --- a/chalk-recursive/src/solve.rs +++ b/chalk-recursive/src/solve.rs @@ -20,6 +20,7 @@ pub(super) trait SolveDatabase: Sized { &mut self, goal: UCanonical>>, minimums: &mut Minimums, + should_continue: impl std::ops::Fn() -> bool, ) -> Fallible>; fn max_size(&self) -> usize; @@ -35,11 +36,12 @@ pub(super) trait SolveIteration: SolveDatabase { /// Executes one iteration of the recursive solver, computing the current /// solution to the given canonical goal. This is used as part of a loop in /// the case of cyclic goals. - #[instrument(level = "debug", skip(self))] + #[instrument(level = "debug", skip(self, should_continue))] fn solve_iteration( &mut self, canonical_goal: &UCanonicalGoal, minimums: &mut Minimums, + should_continue: impl std::ops::Fn() -> bool, ) -> Fallible> { let UCanonical { universes, @@ -72,7 +74,7 @@ pub(super) trait SolveIteration: SolveDatabase { let prog_solution = { debug_span!("prog_clauses"); - self.solve_from_clauses(&canonical_goal, minimums) + self.solve_from_clauses(&canonical_goal, minimums, should_continue) }; debug!(?prog_solution); @@ -88,7 +90,7 @@ pub(super) trait SolveIteration: SolveDatabase { }, }; - self.solve_via_simplification(&canonical_goal, minimums) + self.solve_via_simplification(&canonical_goal, minimums, should_continue) } } } @@ -103,15 +105,16 @@ where /// Helper methods for `solve_iteration`, private to this module. trait SolveIterationHelpers: SolveDatabase { - #[instrument(level = "debug", skip(self, minimums))] + #[instrument(level = "debug", skip(self, minimums, should_continue))] fn solve_via_simplification( &mut self, canonical_goal: &UCanonicalGoal, minimums: &mut Minimums, + should_continue: impl std::ops::Fn() -> bool, ) -> Fallible> { let (infer, subst, goal) = self.new_inference_table(canonical_goal); match Fulfill::new_with_simplification(self, infer, subst, goal) { - Ok(fulfill) => fulfill.solve(minimums), + Ok(fulfill) => fulfill.solve(minimums, should_continue), Err(e) => Err(e), } } @@ -123,6 +126,7 @@ trait SolveIterationHelpers: SolveDatabase { &mut self, canonical_goal: &UCanonical>>, minimums: &mut Minimums, + should_continue: impl std::ops::Fn() -> bool, ) -> Fallible> { let mut clauses = vec![]; @@ -159,7 +163,10 @@ trait SolveIterationHelpers: SolveDatabase { let subst = subst.clone(); let goal = goal.clone(); let res = match Fulfill::new_with_clause(self, infer, subst, goal, implication) { - Ok(fulfill) => (fulfill.solve(minimums), implication.skip_binders().priority), + Ok(fulfill) => ( + fulfill.solve(minimums, &should_continue), + implication.skip_binders().priority, + ), Err(e) => (Err(e), ClausePriority::High), }; From 82657b9dd8aecd85991d3490e0fca3db420babf9 Mon Sep 17 00:00:00 2001 From: Wilco Kusee Date: Tue, 23 Aug 2022 16:00:23 +0200 Subject: [PATCH 2/5] Clone should_continue closure to avoid rustc/LLVM bug #95734 --- chalk-engine/src/slg/aggregate.rs | 4 ++-- chalk-recursive/src/fixed_point.rs | 16 ++++++++++------ chalk-recursive/src/fulfill.rs | 16 ++++++++-------- chalk-recursive/src/recursive.rs | 4 ++-- chalk-recursive/src/solve.rs | 10 +++++----- 5 files changed, 27 insertions(+), 23 deletions(-) diff --git a/chalk-engine/src/slg/aggregate.rs b/chalk-engine/src/slg/aggregate.rs index cce4e14dd61..24da5bdb127 100644 --- a/chalk-engine/src/slg/aggregate.rs +++ b/chalk-engine/src/slg/aggregate.rs @@ -17,7 +17,7 @@ pub trait AggregateOps { &self, root_goal: &UCanonical>>, answers: impl context::AnswerStream, - should_continue: impl std::ops::Fn() -> bool, + should_continue: impl std::ops::Fn() -> bool + Clone, ) -> Option>; } @@ -28,7 +28,7 @@ impl AggregateOps for SlgContextOps<'_, I> { &self, root_goal: &UCanonical>>, mut answers: impl context::AnswerStream, - should_continue: impl std::ops::Fn() -> bool, + should_continue: impl std::ops::Fn() -> bool + Clone, ) -> Option> { let interner = self.program.interner(); let CompleteAnswer { subst, ambiguous } = match answers.next_answer(&should_continue) { diff --git a/chalk-recursive/src/fixed_point.rs b/chalk-recursive/src/fixed_point.rs index 4e4e2ab08d0..60bb797f693 100644 --- a/chalk-recursive/src/fixed_point.rs +++ b/chalk-recursive/src/fixed_point.rs @@ -43,7 +43,7 @@ where context: &mut RecursiveContext, goal: &K, minimums: &mut Minimums, - should_continue: impl std::ops::Fn() -> bool, + should_continue: impl std::ops::Fn() -> bool + Clone, ) -> V; fn reached_fixed_point(self, old_value: &V, new_value: &V) -> bool; fn error_value(self) -> V; @@ -105,7 +105,7 @@ where &mut self, canonical_goal: &K, solver_stuff: impl SolverStuff, - should_continue: impl std::ops::Fn() -> bool, + should_continue: impl std::ops::Fn() -> bool + Clone, ) -> V { debug!("solve_root_goal(canonical_goal={:?})", canonical_goal); assert!(self.stack.is_empty()); @@ -122,7 +122,7 @@ where goal: &K, minimums: &mut Minimums, solver_stuff: impl SolverStuff, - should_continue: impl std::ops::Fn() -> bool, + should_continue: impl std::ops::Fn() -> bool + Clone, ) -> V { // First check the cache. if let Some(cache) = &self.cache { @@ -201,7 +201,7 @@ where depth: StackDepth, dfn: DepthFirstNumber, solver_stuff: impl SolverStuff, - should_continue: impl std::ops::Fn() -> bool, + should_continue: impl std::ops::Fn() -> bool + Clone, ) -> Minimums { // We start with `answer = None` and try to solve the goal. At the end of the iteration, // `answer` will be updated with the result of the solving process. If we detect a cycle @@ -214,8 +214,12 @@ where // so this function will eventually be constant and the loop terminates. loop { let minimums = &mut Minimums::new(); - let current_answer = - solver_stuff.solve_iteration(self, canonical_goal, minimums, &should_continue); + let current_answer = solver_stuff.solve_iteration( + self, + canonical_goal, + minimums, + should_continue.clone(), + ); debug!( "solve_new_subgoal: loop iteration result = {:?} with minimums {:?}", diff --git a/chalk-recursive/src/fulfill.rs b/chalk-recursive/src/fulfill.rs index a4120d3972d..2524ff795b8 100644 --- a/chalk-recursive/src/fulfill.rs +++ b/chalk-recursive/src/fulfill.rs @@ -347,7 +347,7 @@ impl<'s, I: Interner, Solver: SolveDatabase> Fulfill<'s, I, Solver> { &mut self, wc: InEnvironment>, minimums: &mut Minimums, - should_continue: impl std::ops::Fn() -> bool, + should_continue: impl std::ops::Fn() -> bool + Clone, ) -> Fallible> { let interner = self.solver.interner(); let (quantified, free_vars) = canonicalize(&mut self.infer, interner, wc); @@ -365,7 +365,7 @@ impl<'s, I: Interner, Solver: SolveDatabase> Fulfill<'s, I, Solver> { fn refute( &mut self, goal: InEnvironment>, - should_continue: impl std::ops::Fn() -> bool, + should_continue: impl std::ops::Fn() -> bool + Clone, ) -> Fallible { let canonicalized = match self .infer @@ -444,7 +444,7 @@ impl<'s, I: Interner, Solver: SolveDatabase> Fulfill<'s, I, Solver> { fn fulfill( &mut self, minimums: &mut Minimums, - should_continue: impl std::ops::Fn() -> bool, + should_continue: impl std::ops::Fn() -> bool + Clone, ) -> Fallible { debug_span!("fulfill", obligations=?self.obligations); @@ -474,7 +474,7 @@ impl<'s, I: Interner, Solver: SolveDatabase> Fulfill<'s, I, Solver> { free_vars, universes, solution, - } = self.prove(wc.clone(), minimums, &should_continue)?; + } = self.prove(wc.clone(), minimums, should_continue.clone())?; if let Some(constrained_subst) = solution.definite_subst(self.interner()) { // If the substitution is trivial, we won't actually make any progress by applying it! @@ -498,7 +498,7 @@ impl<'s, I: Interner, Solver: SolveDatabase> Fulfill<'s, I, Solver> { solution.is_ambig() } Obligation::Refute(goal) => { - let answer = self.refute(goal.clone(), &should_continue)?; + let answer = self.refute(goal.clone(), should_continue.clone())?; answer == NegativeSolution::Ambiguous } }; @@ -531,9 +531,9 @@ impl<'s, I: Interner, Solver: SolveDatabase> Fulfill<'s, I, Solver> { pub(super) fn solve( mut self, minimums: &mut Minimums, - should_continue: impl std::ops::Fn() -> bool, + should_continue: impl std::ops::Fn() -> bool + Clone, ) -> Fallible> { - let outcome = match self.fulfill(minimums, &should_continue) { + let outcome = match self.fulfill(minimums, should_continue.clone()) { Ok(o) => o, Err(e) => return Err(e), }; @@ -585,7 +585,7 @@ impl<'s, I: Interner, Solver: SolveDatabase> Fulfill<'s, I, Solver> { free_vars, universes, solution, - } = self.prove(goal, minimums, &should_continue).unwrap(); + } = self.prove(goal, minimums, should_continue.clone()).unwrap(); if let Some(constrained_subst) = solution.constrained_subst(self.solver.interner()) { diff --git a/chalk-recursive/src/recursive.rs b/chalk-recursive/src/recursive.rs index 0e76eb3f916..7014ccb319e 100644 --- a/chalk-recursive/src/recursive.rs +++ b/chalk-recursive/src/recursive.rs @@ -76,7 +76,7 @@ impl SolverStuff, Fallible>> for &dyn context: &mut RecursiveContext, Fallible>>, goal: &UCanonicalGoal, minimums: &mut Minimums, - should_continue: impl std::ops::Fn() -> bool, + should_continue: impl std::ops::Fn() -> bool + Clone, ) -> Fallible> { Solver::new(context, self).solve_iteration(goal, minimums, should_continue) } @@ -109,7 +109,7 @@ impl<'me, I: Interner> SolveDatabase for Solver<'me, I> { &mut self, goal: UCanonicalGoal, minimums: &mut Minimums, - should_continue: impl std::ops::Fn() -> bool, + should_continue: impl std::ops::Fn() -> bool + Clone, ) -> Fallible> { self.context .solve_goal(&goal, minimums, self.program, should_continue) diff --git a/chalk-recursive/src/solve.rs b/chalk-recursive/src/solve.rs index b810d47da09..c540f2f48d3 100644 --- a/chalk-recursive/src/solve.rs +++ b/chalk-recursive/src/solve.rs @@ -20,7 +20,7 @@ pub(super) trait SolveDatabase: Sized { &mut self, goal: UCanonical>>, minimums: &mut Minimums, - should_continue: impl std::ops::Fn() -> bool, + should_continue: impl std::ops::Fn() -> bool + Clone, ) -> Fallible>; fn max_size(&self) -> usize; @@ -41,7 +41,7 @@ pub(super) trait SolveIteration: SolveDatabase { &mut self, canonical_goal: &UCanonicalGoal, minimums: &mut Minimums, - should_continue: impl std::ops::Fn() -> bool, + should_continue: impl std::ops::Fn() -> bool + Clone, ) -> Fallible> { let UCanonical { universes, @@ -110,7 +110,7 @@ trait SolveIterationHelpers: SolveDatabase { &mut self, canonical_goal: &UCanonicalGoal, minimums: &mut Minimums, - should_continue: impl std::ops::Fn() -> bool, + should_continue: impl std::ops::Fn() -> bool + Clone, ) -> Fallible> { let (infer, subst, goal) = self.new_inference_table(canonical_goal); match Fulfill::new_with_simplification(self, infer, subst, goal) { @@ -126,7 +126,7 @@ trait SolveIterationHelpers: SolveDatabase { &mut self, canonical_goal: &UCanonical>>, minimums: &mut Minimums, - should_continue: impl std::ops::Fn() -> bool, + should_continue: impl std::ops::Fn() -> bool + Clone, ) -> Fallible> { let mut clauses = vec![]; @@ -164,7 +164,7 @@ trait SolveIterationHelpers: SolveDatabase { let goal = goal.clone(); let res = match Fulfill::new_with_clause(self, infer, subst, goal, implication) { Ok(fulfill) => ( - fulfill.solve(minimums, &should_continue), + fulfill.solve(minimums, should_continue.clone()), implication.skip_binders().priority, ), Err(e) => (Err(e), ClausePriority::High), From 59b1b9aae8ca2406bc81e09b89e8ddde00e6d765 Mon Sep 17 00:00:00 2001 From: Wilco Kusee Date: Tue, 23 Aug 2022 16:21:15 +0200 Subject: [PATCH 3/5] Check should_continue once per iteration --- chalk-recursive/src/recursive.rs | 1 - chalk-recursive/src/solve.rs | 4 ++++ 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/chalk-recursive/src/recursive.rs b/chalk-recursive/src/recursive.rs index 7014ccb319e..61680c75269 100644 --- a/chalk-recursive/src/recursive.rs +++ b/chalk-recursive/src/recursive.rs @@ -143,7 +143,6 @@ impl chalk_solve::Solver for RecursiveSolver { goal: &UCanonical>>, should_continue: &dyn std::ops::Fn() -> bool, ) -> Option> { - // TODO support should_continue in recursive solver self.ctx .solve_root_goal(goal, program, should_continue) .ok() diff --git a/chalk-recursive/src/solve.rs b/chalk-recursive/src/solve.rs index c540f2f48d3..0c53534cdfa 100644 --- a/chalk-recursive/src/solve.rs +++ b/chalk-recursive/src/solve.rs @@ -43,6 +43,10 @@ pub(super) trait SolveIteration: SolveDatabase { minimums: &mut Minimums, should_continue: impl std::ops::Fn() -> bool + Clone, ) -> Fallible> { + if !should_continue() { + return Err(NoSolution); + } + let UCanonical { universes, canonical: From 05e6f4310918d16f28dd6258925537a1397d6372 Mon Sep 17 00:00:00 2001 From: Wilco Kusee Date: Tue, 29 Nov 2022 13:20:30 +0100 Subject: [PATCH 4/5] Return ambiguous solution on !should_continue --- chalk-recursive/src/solve.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/chalk-recursive/src/solve.rs b/chalk-recursive/src/solve.rs index 0c53534cdfa..ba2525467b9 100644 --- a/chalk-recursive/src/solve.rs +++ b/chalk-recursive/src/solve.rs @@ -44,7 +44,7 @@ pub(super) trait SolveIteration: SolveDatabase { should_continue: impl std::ops::Fn() -> bool + Clone, ) -> Fallible> { if !should_continue() { - return Err(NoSolution); + return Ok(Solution::Ambig(Guidance::Unknown)); } let UCanonical { From f6ac6f5534d4cb91180782ddac7570956ccc1ffe Mon Sep 17 00:00:00 2001 From: Wilco Kusee Date: Tue, 29 Nov 2022 17:07:33 +0100 Subject: [PATCH 5/5] Add comment to document reason for workaround --- chalk-recursive/src/fixed_point.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/chalk-recursive/src/fixed_point.rs b/chalk-recursive/src/fixed_point.rs index 60bb797f693..517ca253b4d 100644 --- a/chalk-recursive/src/fixed_point.rs +++ b/chalk-recursive/src/fixed_point.rs @@ -218,7 +218,7 @@ where self, canonical_goal, minimums, - should_continue.clone(), + should_continue.clone(), // Note: cloning required as workaround for https://github.com/rust-lang/rust/issues/95734 ); debug!(