@@ -2,7 +2,7 @@ mod fulfill;
2
2
mod search_graph;
3
3
mod stack;
4
4
5
- use self :: fulfill:: { Fulfill , RecursiveInferenceTable } ;
5
+ use self :: fulfill:: { Fulfill , RecursiveInferenceTable , RecursiveSolver } ;
6
6
use self :: search_graph:: { DepthFirstNumber , SearchGraph } ;
7
7
use self :: stack:: { Stack , StackDepth } ;
8
8
use crate :: clauses:: program_clauses_for_goal;
@@ -144,7 +144,7 @@ pub(crate) struct Solver<'me, I: Interner> {
144
144
/// The `minimums` struct is used while solving to track whether we encountered
145
145
/// any cycles in the process.
146
146
#[ derive( Copy , Clone , Debug ) ]
147
- struct Minimums {
147
+ pub struct Minimums {
148
148
positive : DepthFirstNumber ,
149
149
}
150
150
@@ -234,94 +234,6 @@ impl<'me, I: Interner> Solver<'me, I> {
234
234
self . solve_goal ( canonical_goal. clone ( ) , minimums)
235
235
}
236
236
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
-
325
237
fn solve_new_subgoal (
326
238
& mut self ,
327
239
canonical_goal : UCanonicalGoal < I > ,
@@ -557,6 +469,100 @@ impl<'me, I: Interner> Solver<'me, I> {
557
469
}
558
470
}
559
471
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
+
560
566
fn calculate_inputs < I : Interner > (
561
567
interner : & I ,
562
568
domain_goal : & DomainGoal < I > ,
0 commit comments