|
79 | 79 | max_size,
|
80 | 80 | }
|
81 | 81 | }
|
| 82 | + |
| 83 | + #[instrument(level = "debug", skip(self, solve_iteration, reached_fixed_point))] |
| 84 | + fn solve_new_subgoal( |
| 85 | + &mut self, |
| 86 | + canonical_goal: &K, |
| 87 | + depth: StackDepth, |
| 88 | + dfn: DepthFirstNumber, |
| 89 | + mut solve_iteration: impl FnMut(&mut Self, &K, &mut Minimums) -> V, |
| 90 | + reached_fixed_point: impl Fn(&V, &V) -> bool, |
| 91 | + ) -> Minimums { |
| 92 | + // We start with `answer = None` and try to solve the goal. At the end of the iteration, |
| 93 | + // `answer` will be updated with the result of the solving process. If we detect a cycle |
| 94 | + // during the solving process, we cache `answer` and try to solve the goal again. We repeat |
| 95 | + // until we reach a fixed point for `answer`. |
| 96 | + // Considering the partial order: |
| 97 | + // - None < Some(Unique) < Some(Ambiguous) |
| 98 | + // - None < Some(CannotProve) |
| 99 | + // the function which maps the loop iteration to `answer` is a nondecreasing function |
| 100 | + // so this function will eventually be constant and the loop terminates. |
| 101 | + loop { |
| 102 | + let minimums = &mut Minimums::new(); |
| 103 | + let current_answer = solve_iteration(self, &canonical_goal, minimums); |
| 104 | + |
| 105 | + debug!( |
| 106 | + "solve_new_subgoal: loop iteration result = {:?} with minimums {:?}", |
| 107 | + current_answer, minimums |
| 108 | + ); |
| 109 | + |
| 110 | + if !self.stack[depth].read_and_reset_cycle_flag() { |
| 111 | + // None of our subgoals depended on us directly. |
| 112 | + // We can return. |
| 113 | + self.search_graph[dfn].solution = current_answer; |
| 114 | + return *minimums; |
| 115 | + } |
| 116 | + |
| 117 | + let old_answer = |
| 118 | + std::mem::replace(&mut self.search_graph[dfn].solution, current_answer); |
| 119 | + |
| 120 | + if reached_fixed_point(&old_answer, &self.search_graph[dfn].solution) { |
| 121 | + return *minimums; |
| 122 | + } |
| 123 | + |
| 124 | + // Otherwise: rollback the search tree and try again. |
| 125 | + self.search_graph.rollback_to(dfn + 1); |
| 126 | + } |
| 127 | + } |
82 | 128 | }
|
83 | 129 |
|
84 | 130 | impl<'me, I: Interner> Solver<'me, I> {
|
@@ -177,7 +223,30 @@ impl<'me, I: Interner> Solver<'me, I> {
|
177 | 223 | .context
|
178 | 224 | .search_graph
|
179 | 225 | .insert(&goal, depth, initial_solution);
|
180 |
| - let subgoal_minimums = self.solve_new_subgoal(goal, depth, dfn); |
| 226 | + |
| 227 | + let program = self.program; |
| 228 | + let subgoal_minimums = self.context.solve_new_subgoal( |
| 229 | + &goal, |
| 230 | + depth, |
| 231 | + dfn, |
| 232 | + |context, goal, minimums| { |
| 233 | + Solver::new(context, program).solve_iteration(goal, minimums) |
| 234 | + }, |
| 235 | + |old_answer, current_answer| { |
| 236 | + // Some of our subgoals depended on us. We need to re-run |
| 237 | + // with the current answer. |
| 238 | + old_answer == current_answer || { |
| 239 | + // Subtle: if our current answer is ambiguous, we can just stop, and |
| 240 | + // in fact we *must* -- otherwise, we sometimes fail to reach a |
| 241 | + // fixed point. See `multiple_ambiguous_cycles` for more. |
| 242 | + match ¤t_answer { |
| 243 | + Ok(s) => s.is_ambig(), |
| 244 | + Err(_) => false, |
| 245 | + } |
| 246 | + } |
| 247 | + }, |
| 248 | + ); |
| 249 | + |
181 | 250 | self.context.search_graph[dfn].links = subgoal_minimums;
|
182 | 251 | self.context.search_graph[dfn].stack_depth = None;
|
183 | 252 | self.context.stack.pop(depth);
|
@@ -206,64 +275,6 @@ impl<'me, I: Interner> Solver<'me, I> {
|
206 | 275 | result
|
207 | 276 | }
|
208 | 277 | }
|
209 |
| - |
210 |
| - #[instrument(level = "debug", skip(self))] |
211 |
| - fn solve_new_subgoal( |
212 |
| - &mut self, |
213 |
| - canonical_goal: UCanonicalGoal<I>, |
214 |
| - depth: StackDepth, |
215 |
| - dfn: DepthFirstNumber, |
216 |
| - ) -> Minimums { |
217 |
| - // We start with `answer = None` and try to solve the goal. At the end of the iteration, |
218 |
| - // `answer` will be updated with the result of the solving process. If we detect a cycle |
219 |
| - // during the solving process, we cache `answer` and try to solve the goal again. We repeat |
220 |
| - // until we reach a fixed point for `answer`. |
221 |
| - // Considering the partial order: |
222 |
| - // - None < Some(Unique) < Some(Ambiguous) |
223 |
| - // - None < Some(CannotProve) |
224 |
| - // the function which maps the loop iteration to `answer` is a nondecreasing function |
225 |
| - // so this function will eventually be constant and the loop terminates. |
226 |
| - loop { |
227 |
| - let minimums = &mut Minimums::new(); |
228 |
| - let current_answer = self.solve_iteration(&canonical_goal, minimums); |
229 |
| - |
230 |
| - debug!( |
231 |
| - "solve_new_subgoal: loop iteration result = {:?} with minimums {:?}", |
232 |
| - current_answer, minimums |
233 |
| - ); |
234 |
| - |
235 |
| - if !self.context.stack[depth].read_and_reset_cycle_flag() { |
236 |
| - // None of our subgoals depended on us directly. |
237 |
| - // We can return. |
238 |
| - self.context.search_graph[dfn].solution = current_answer; |
239 |
| - return *minimums; |
240 |
| - } |
241 |
| - |
242 |
| - // Some of our subgoals depended on us. We need to re-run |
243 |
| - // with the current answer. |
244 |
| - if self.context.search_graph[dfn].solution == current_answer { |
245 |
| - // Reached a fixed point. |
246 |
| - return *minimums; |
247 |
| - } |
248 |
| - |
249 |
| - let current_answer_is_ambig = match ¤t_answer { |
250 |
| - Ok(s) => s.is_ambig(), |
251 |
| - Err(_) => false, |
252 |
| - }; |
253 |
| - |
254 |
| - self.context.search_graph[dfn].solution = current_answer; |
255 |
| - |
256 |
| - // Subtle: if our current answer is ambiguous, we can just stop, and |
257 |
| - // in fact we *must* -- otherwise, we sometimes fail to reach a |
258 |
| - // fixed point. See `multiple_ambiguous_cycles` for more. |
259 |
| - if current_answer_is_ambig { |
260 |
| - return *minimums; |
261 |
| - } |
262 |
| - |
263 |
| - // Otherwise: rollback the search tree and try again. |
264 |
| - self.context.search_graph.rollback_to(dfn + 1); |
265 |
| - } |
266 |
| - } |
267 | 278 | }
|
268 | 279 |
|
269 | 280 | impl<'me, I: Interner> SolveDatabase<I> for Solver<'me, I> {
|
|
0 commit comments