@@ -251,12 +251,22 @@ enum NodeState {
251251 Error ,
252252}
253253
254+ /// This trait allows us to have two different Outcome types:
255+ /// - the normal one that does as little as possible
256+ /// - one for tests that does some additional work and checking
257+ pub trait OutcomeTrait {
258+ type Error ;
259+ type Obligation ;
260+
261+ fn new ( ) -> Self ;
262+ fn mark_not_stalled ( & mut self ) ;
263+ fn is_stalled ( & self ) -> bool ;
264+ fn record_completed ( & mut self , outcome : & Self :: Obligation ) ;
265+ fn record_error ( & mut self , error : Self :: Error ) ;
266+ }
267+
254268#[ derive( Debug ) ]
255269pub struct Outcome < O , E > {
256- /// Obligations that were completely evaluated, including all
257- /// (transitive) subobligations. Only computed if requested.
258- pub completed : Option < Vec < O > > ,
259-
260270 /// Backtrace of obligations that were found to be in error.
261271 pub errors : Vec < Error < O , E > > ,
262272
@@ -269,12 +279,29 @@ pub struct Outcome<O, E> {
269279 pub stalled : bool ,
270280}
271281
272- /// Should `process_obligations` compute the `Outcome::completed` field of its
273- /// result?
274- #[ derive( PartialEq ) ]
275- pub enum DoCompleted {
276- No ,
277- Yes ,
282+ impl < O , E > OutcomeTrait for Outcome < O , E > {
283+ type Error = Error < O , E > ;
284+ type Obligation = O ;
285+
286+ fn new ( ) -> Self {
287+ Self { stalled : true , errors : vec ! [ ] }
288+ }
289+
290+ fn mark_not_stalled ( & mut self ) {
291+ self . stalled = false ;
292+ }
293+
294+ fn is_stalled ( & self ) -> bool {
295+ self . stalled
296+ }
297+
298+ fn record_completed ( & mut self , _outcome : & Self :: Obligation ) {
299+ // do nothing
300+ }
301+
302+ fn record_error ( & mut self , error : Self :: Error ) {
303+ self . errors . push ( error)
304+ }
278305}
279306
280307#[ derive( Debug , PartialEq , Eq ) ]
@@ -363,8 +390,7 @@ impl<O: ForestObligation> ObligationForest<O> {
363390 . map ( |( index, _node) | Error { error : error. clone ( ) , backtrace : self . error_at ( index) } )
364391 . collect ( ) ;
365392
366- let successful_obligations = self . compress ( DoCompleted :: Yes ) ;
367- assert ! ( successful_obligations. unwrap( ) . is_empty( ) ) ;
393+ self . compress ( |_| assert ! ( false ) ) ;
368394 errors
369395 }
370396
@@ -392,16 +418,12 @@ impl<O: ForestObligation> ObligationForest<O> {
392418 /// be called in a loop until `outcome.stalled` is false.
393419 ///
394420 /// This _cannot_ be unrolled (presently, at least).
395- pub fn process_obligations < P > (
396- & mut self ,
397- processor : & mut P ,
398- do_completed : DoCompleted ,
399- ) -> Outcome < O , P :: Error >
421+ pub fn process_obligations < P , OUT > ( & mut self , processor : & mut P ) -> OUT
400422 where
401423 P : ObligationProcessor < Obligation = O > ,
424+ OUT : OutcomeTrait < Obligation = O , Error = Error < O , P :: Error > > ,
402425 {
403- let mut errors = vec ! [ ] ;
404- let mut stalled = true ;
426+ let mut outcome = OUT :: new ( ) ;
405427
406428 // Note that the loop body can append new nodes, and those new nodes
407429 // will then be processed by subsequent iterations of the loop.
@@ -429,7 +451,7 @@ impl<O: ForestObligation> ObligationForest<O> {
429451 }
430452 ProcessResult :: Changed ( children) => {
431453 // We are not (yet) stalled.
432- stalled = false ;
454+ outcome . mark_not_stalled ( ) ;
433455 node. state . set ( NodeState :: Success ) ;
434456
435457 for child in children {
@@ -442,28 +464,22 @@ impl<O: ForestObligation> ObligationForest<O> {
442464 }
443465 }
444466 ProcessResult :: Error ( err) => {
445- stalled = false ;
446- errors . push ( Error { error : err, backtrace : self . error_at ( index) } ) ;
467+ outcome . mark_not_stalled ( ) ;
468+ outcome . record_error ( Error { error : err, backtrace : self . error_at ( index) } ) ;
447469 }
448470 }
449471 index += 1 ;
450472 }
451473
452- if stalled {
453- // There's no need to perform marking, cycle processing and compression when nothing
454- // changed.
455- return Outcome {
456- completed : if do_completed == DoCompleted :: Yes { Some ( vec ! [ ] ) } else { None } ,
457- errors,
458- stalled,
459- } ;
474+ // There's no need to perform marking, cycle processing and compression when nothing
475+ // changed.
476+ if !outcome. is_stalled ( ) {
477+ self . mark_successes ( ) ;
478+ self . process_cycles ( processor) ;
479+ self . compress ( |obl| outcome. record_completed ( obl) ) ;
460480 }
461481
462- self . mark_successes ( ) ;
463- self . process_cycles ( processor) ;
464- let completed = self . compress ( do_completed) ;
465-
466- Outcome { completed, errors, stalled }
482+ outcome
467483 }
468484
469485 /// Returns a vector of obligations for `p` and all of its
@@ -592,13 +608,12 @@ impl<O: ForestObligation> ObligationForest<O> {
592608 /// indices and hence invalidates any outstanding indices. `process_cycles`
593609 /// must be run beforehand to remove any cycles on `Success` nodes.
594610 #[ inline( never) ]
595- fn compress ( & mut self , do_completed : DoCompleted ) -> Option < Vec < O > > {
611+ fn compress ( & mut self , mut outcome_cb : impl FnMut ( & O ) ) {
596612 let orig_nodes_len = self . nodes . len ( ) ;
597613 let mut node_rewrites: Vec < _ > = std:: mem:: take ( & mut self . reused_node_vec ) ;
598614 debug_assert ! ( node_rewrites. is_empty( ) ) ;
599615 node_rewrites. extend ( 0 ..orig_nodes_len) ;
600616 let mut dead_nodes = 0 ;
601- let mut removed_done_obligations: Vec < O > = vec ! [ ] ;
602617
603618 // Move removable nodes to the end, preserving the order of the
604619 // remaining nodes.
@@ -628,10 +643,8 @@ impl<O: ForestObligation> ObligationForest<O> {
628643 } else {
629644 self . done_cache . insert ( node. obligation . as_cache_key ( ) . clone ( ) ) ;
630645 }
631- if do_completed == DoCompleted :: Yes {
632- // Extract the success stories.
633- removed_done_obligations. push ( node. obligation . clone ( ) ) ;
634- }
646+ // Extract the success stories.
647+ outcome_cb ( & node. obligation ) ;
635648 node_rewrites[ index] = orig_nodes_len;
636649 dead_nodes += 1 ;
637650 }
@@ -656,8 +669,6 @@ impl<O: ForestObligation> ObligationForest<O> {
656669
657670 node_rewrites. truncate ( 0 ) ;
658671 self . reused_node_vec = node_rewrites;
659-
660- if do_completed == DoCompleted :: Yes { Some ( removed_done_obligations) } else { None }
661672 }
662673
663674 fn apply_rewrites ( & mut self , node_rewrites : & [ usize ] ) {
0 commit comments