@@ -2,7 +2,7 @@ mod fulfill;
22mod search_graph;
33mod stack;
44
5- use self :: fulfill:: { Fulfill , RecursiveInferenceTable } ;
5+ use self :: fulfill:: { Fulfill , RecursiveInferenceTable , RecursiveSolver } ;
66use self :: search_graph:: { DepthFirstNumber , SearchGraph } ;
77use self :: stack:: { Stack , StackDepth } ;
88use crate :: clauses:: program_clauses_for_goal;
@@ -144,7 +144,7 @@ pub(crate) struct Solver<'me, I: Interner> {
144144/// The `minimums` struct is used while solving to track whether we encountered
145145/// any cycles in the process.
146146#[ derive( Copy , Clone , Debug ) ]
147- struct Minimums {
147+ pub struct Minimums {
148148 positive : DepthFirstNumber ,
149149}
150150
@@ -234,94 +234,6 @@ impl<'me, I: Interner> Solver<'me, I> {
234234 self . solve_goal ( canonical_goal. clone ( ) , minimums)
235235 }
236236
237- /// Attempt to solve a goal that has been fully broken down into leaf form
238- /// and canonicalized. This is where the action really happens, and is the
239- /// place where we would perform caching in rustc (and may eventually do in Chalk).
240- fn solve_goal (
241- & mut self ,
242- goal : UCanonicalGoal < I > ,
243- minimums : & mut Minimums ,
244- ) -> Fallible < Solution < I > > {
245- info_heading ! ( "solve_goal({:?})" , goal) ;
246-
247- // First check the cache.
248- if let Some ( value) = self . context . cache . get ( & goal) {
249- debug ! ( "solve_reduced_goal: cache hit, value={:?}" , value) ;
250- return value. clone ( ) ;
251- }
252-
253- // Next, check if the goal is in the search tree already.
254- if let Some ( dfn) = self . context . search_graph . lookup ( & goal) {
255- // Check if this table is still on the stack.
256- if let Some ( depth) = self . context . search_graph [ dfn] . stack_depth {
257- // Is this a coinductive goal? If so, that is success,
258- // so we can return normally. Note that this return is
259- // not tabled.
260- //
261- // XXX how does caching with coinduction work?
262- if self . context . stack . coinductive_cycle_from ( depth) {
263- let value = ConstrainedSubst {
264- subst : goal. trivial_substitution ( self . program . interner ( ) ) ,
265- constraints : vec ! [ ] ,
266- } ;
267- debug ! ( "applying coinductive semantics" ) ;
268- return Ok ( Solution :: Unique ( Canonical {
269- value,
270- binders : goal. canonical . binders ,
271- } ) ) ;
272- }
273-
274- self . context . stack [ depth] . flag_cycle ( ) ;
275- }
276-
277- minimums. update_from ( self . context . search_graph [ dfn] . links ) ;
278-
279- // Return the solution from the table.
280- let previous_solution = self . context . search_graph [ dfn] . solution . clone ( ) ;
281- let previous_solution_priority = self . context . search_graph [ dfn] . solution_priority ;
282- info ! (
283- "solve_goal: cycle detected, previous solution {:?} with prio {:?}" ,
284- previous_solution, previous_solution_priority
285- ) ;
286- previous_solution
287- } else {
288- // Otherwise, push the goal onto the stack and create a table.
289- // The initial result for this table is error.
290- let depth = self . context . stack . push ( self . program , & goal) ;
291- let dfn = self . context . search_graph . insert ( & goal, depth) ;
292- let subgoal_minimums = self . solve_new_subgoal ( goal, depth, dfn) ;
293- self . context . search_graph [ dfn] . links = subgoal_minimums;
294- self . context . search_graph [ dfn] . stack_depth = None ;
295- self . context . stack . pop ( depth) ;
296- minimums. update_from ( subgoal_minimums) ;
297-
298- // Read final result from table.
299- let result = self . context . search_graph [ dfn] . solution . clone ( ) ;
300- let priority = self . context . search_graph [ dfn] . solution_priority ;
301-
302- // If processing this subgoal did not involve anything
303- // outside of its subtree, then we can promote it to the
304- // cache now. This is a sort of hack to alleviate the
305- // worst of the repeated work that we do during tabling.
306- if subgoal_minimums. positive >= dfn {
307- if self . context . caching_enabled {
308- self . context
309- . search_graph
310- . move_to_cache ( dfn, & mut self . context . cache ) ;
311- debug ! ( "solve_reduced_goal: SCC head encountered, moving to cache" ) ;
312- } else {
313- debug ! (
314- "solve_reduced_goal: SCC head encountered, rolling back as caching disabled"
315- ) ;
316- self . context . search_graph . rollback_to ( dfn) ;
317- }
318- }
319-
320- info ! ( "solve_goal: solution = {:?} prio {:?}" , result, priority) ;
321- result
322- }
323- }
324-
325237 fn solve_new_subgoal (
326238 & mut self ,
327239 canonical_goal : UCanonicalGoal < I > ,
@@ -557,6 +469,100 @@ impl<'me, I: Interner> Solver<'me, I> {
557469 }
558470}
559471
472+ impl < ' me , I : Interner > RecursiveSolver < I > for Solver < ' me , I > {
473+ /// Attempt to solve a goal that has been fully broken down into leaf form
474+ /// and canonicalized. This is where the action really happens, and is the
475+ /// place where we would perform caching in rustc (and may eventually do in Chalk).
476+ fn solve_goal (
477+ & mut self ,
478+ goal : UCanonicalGoal < I > ,
479+ minimums : & mut Minimums ,
480+ ) -> Fallible < Solution < I > > {
481+ info_heading ! ( "solve_goal({:?})" , goal) ;
482+
483+ // First check the cache.
484+ if let Some ( value) = self . context . cache . get ( & goal) {
485+ debug ! ( "solve_reduced_goal: cache hit, value={:?}" , value) ;
486+ return value. clone ( ) ;
487+ }
488+
489+ // Next, check if the goal is in the search tree already.
490+ if let Some ( dfn) = self . context . search_graph . lookup ( & goal) {
491+ // Check if this table is still on the stack.
492+ if let Some ( depth) = self . context . search_graph [ dfn] . stack_depth {
493+ // Is this a coinductive goal? If so, that is success,
494+ // so we can return normally. Note that this return is
495+ // not tabled.
496+ //
497+ // XXX how does caching with coinduction work?
498+ if self . context . stack . coinductive_cycle_from ( depth) {
499+ let value = ConstrainedSubst {
500+ subst : goal. trivial_substitution ( self . program . interner ( ) ) ,
501+ constraints : vec ! [ ] ,
502+ } ;
503+ debug ! ( "applying coinductive semantics" ) ;
504+ return Ok ( Solution :: Unique ( Canonical {
505+ value,
506+ binders : goal. canonical . binders ,
507+ } ) ) ;
508+ }
509+
510+ self . context . stack [ depth] . flag_cycle ( ) ;
511+ }
512+
513+ minimums. update_from ( self . context . search_graph [ dfn] . links ) ;
514+
515+ // Return the solution from the table.
516+ let previous_solution = self . context . search_graph [ dfn] . solution . clone ( ) ;
517+ let previous_solution_priority = self . context . search_graph [ dfn] . solution_priority ;
518+ info ! (
519+ "solve_goal: cycle detected, previous solution {:?} with prio {:?}" ,
520+ previous_solution, previous_solution_priority
521+ ) ;
522+ previous_solution
523+ } else {
524+ // Otherwise, push the goal onto the stack and create a table.
525+ // The initial result for this table is error.
526+ let depth = self . context . stack . push ( self . program , & goal) ;
527+ let dfn = self . context . search_graph . insert ( & goal, depth) ;
528+ let subgoal_minimums = self . solve_new_subgoal ( goal, depth, dfn) ;
529+ self . context . search_graph [ dfn] . links = subgoal_minimums;
530+ self . context . search_graph [ dfn] . stack_depth = None ;
531+ self . context . stack . pop ( depth) ;
532+ minimums. update_from ( subgoal_minimums) ;
533+
534+ // Read final result from table.
535+ let result = self . context . search_graph [ dfn] . solution . clone ( ) ;
536+ let priority = self . context . search_graph [ dfn] . solution_priority ;
537+
538+ // If processing this subgoal did not involve anything
539+ // outside of its subtree, then we can promote it to the
540+ // cache now. This is a sort of hack to alleviate the
541+ // worst of the repeated work that we do during tabling.
542+ if subgoal_minimums. positive >= dfn {
543+ if self . context . caching_enabled {
544+ self . context
545+ . search_graph
546+ . move_to_cache ( dfn, & mut self . context . cache ) ;
547+ debug ! ( "solve_reduced_goal: SCC head encountered, moving to cache" ) ;
548+ } else {
549+ debug ! (
550+ "solve_reduced_goal: SCC head encountered, rolling back as caching disabled"
551+ ) ;
552+ self . context . search_graph . rollback_to ( dfn) ;
553+ }
554+ }
555+
556+ info ! ( "solve_goal: solution = {:?} prio {:?}" , result, priority) ;
557+ result
558+ }
559+ }
560+
561+ fn interner ( & self ) -> & I {
562+ & self . program . interner ( )
563+ }
564+ }
565+
560566fn calculate_inputs < I : Interner > (
561567 interner : & I ,
562568 domain_goal : & DomainGoal < I > ,
0 commit comments