@@ -129,18 +129,14 @@ type ObligationTreeIdGenerator =
129129
130130pub struct ObligationForest < O : ForestObligation > {
131131 /// The list of obligations. In between calls to `process_obligations`,
132- /// this list only contains nodes in the `Pending` or `Success ` state.
132+ /// this list only contains nodes in the `Pending` or `Waiting ` state.
133133 ///
134134 /// `usize` indices are used here and throughout this module, rather than
135135 /// `rustc_index::newtype_index!` indices, because this code is hot enough
136136 /// that the `u32`-to-`usize` conversions that would be required are
137137 /// significant, and space considerations are not important.
138138 nodes : Vec < Node < O > > ,
139139
140- /// The process generation is 1 on the first call to `process_obligations`,
141- /// 2 on the second call, etc.
142- gen : u32 ,
143-
144140 /// A cache of predicates that have been successfully completed.
145141 done_cache : FxHashSet < O :: Predicate > ,
146142
@@ -196,9 +192,9 @@ impl<O> Node<O> {
196192 }
197193}
198194
199- /// The state of one node in some tree within the forest. This
200- /// represents the current state of processing for the obligation (of
201- /// type `O`) associated with this node.
195+ /// The state of one node in some tree within the forest. This represents the
196+ /// current state of processing for the obligation (of type `O`) associated
197+ /// with this node.
202198///
203199/// The non-`Error` state transitions are as follows.
204200/// ```
@@ -210,51 +206,47 @@ impl<O> Node<O> {
210206/// |
211207/// | process_obligations()
212208/// v
213- /// Success(not_waiting())
214- /// | |
215- /// | | mark_still_waiting_nodes ()
209+ /// Success
210+ /// | ^
211+ /// | | mark_successes ()
216212/// | v
217- /// | Success(still_waiting())
218- /// | |
219- /// | | compress()
220- /// v v
213+ /// | Waiting
214+ /// |
215+ /// | process_cycles()
216+ /// v
217+ /// Done
218+ /// |
219+ /// | compress()
220+ /// v
221221/// (Removed)
222222/// ```
223223/// The `Error` state can be introduced in several places, via `error_at()`.
224224///
225225/// Outside of `ObligationForest` methods, nodes should be either `Pending` or
226- /// `Success `.
226+ /// `Waiting `.
227227#[ derive( Debug , Copy , Clone , PartialEq , Eq ) ]
228228enum NodeState {
229229 /// This obligation has not yet been selected successfully. Cannot have
230230 /// subobligations.
231231 Pending ,
232232
233- /// This obligation was selected successfully, but it may be waiting on one
234- /// or more pending subobligations, as indicated by the `WaitingState`.
235- Success ( WaitingState ) ,
233+ /// This obligation was selected successfully, but may or may not have
234+ /// subobligations.
235+ Success ,
236+
237+ /// This obligation was selected successfully, but it has a pending
238+ /// subobligation.
239+ Waiting ,
240+
241+ /// This obligation, along with its subobligations, are complete, and will
242+ /// be removed in the next collection.
243+ Done ,
236244
237245 /// This obligation was resolved to an error. It will be removed by the
238246 /// next compression step.
239247 Error ,
240248}
241249
242- /// Indicates when a `Success` node was last (if ever) waiting on one or more
243- /// `Pending` nodes. The notion of "when" comes from `ObligationForest::gen`.
244- /// - 0: "Not waiting". This is a special value, set by `process_obligation`,
245- /// and usable because generation counting starts at 1.
246- /// - 1..ObligationForest::gen: "Was waiting" in a previous generation, but
247- /// waiting no longer. In other words, finished.
248- /// - ObligationForest::gen: "Still waiting" in this generation.
249- ///
250- /// Things to note about this encoding:
251- /// - Every time `ObligationForest::gen` is incremented, all the "still
252- /// waiting" nodes automatically become "was waiting".
253- /// - `ObligationForest::is_still_waiting` is very cheap.
254- ///
255- #[ derive( Clone , Copy , Debug , PartialEq , Eq , PartialOrd ) ]
256- struct WaitingState ( u32 ) ;
257-
258250#[ derive( Debug ) ]
259251pub struct Outcome < O , E > {
260252 /// Obligations that were completely evaluated, including all
@@ -291,7 +283,6 @@ impl<O: ForestObligation> ObligationForest<O> {
291283 pub fn new ( ) -> ObligationForest < O > {
292284 ObligationForest {
293285 nodes : vec ! [ ] ,
294- gen : 0 ,
295286 done_cache : Default :: default ( ) ,
296287 active_cache : Default :: default ( ) ,
297288 node_rewrites : RefCell :: new ( vec ! [ ] ) ,
@@ -392,18 +383,6 @@ impl<O: ForestObligation> ObligationForest<O> {
392383 . insert ( node. obligation . as_predicate ( ) . clone ( ) ) ;
393384 }
394385
395- fn not_waiting ( ) -> WaitingState {
396- WaitingState ( 0 )
397- }
398-
399- fn still_waiting ( & self ) -> WaitingState {
400- WaitingState ( self . gen )
401- }
402-
403- fn is_still_waiting ( & self , waiting : WaitingState ) -> bool {
404- waiting. 0 == self . gen
405- }
406-
407386 /// Performs a pass through the obligation list. This must
408387 /// be called in a loop until `outcome.stalled` is false.
409388 ///
@@ -416,8 +395,6 @@ impl<O: ForestObligation> ObligationForest<O> {
416395 where
417396 P : ObligationProcessor < Obligation = O > ,
418397 {
419- self . gen += 1 ;
420-
421398 let mut errors = vec ! [ ] ;
422399 let mut stalled = true ;
423400
@@ -450,7 +427,7 @@ impl<O: ForestObligation> ObligationForest<O> {
450427 ProcessResult :: Changed ( children) => {
451428 // We are not (yet) stalled.
452429 stalled = false ;
453- node. state . set ( NodeState :: Success ( Self :: not_waiting ( ) ) ) ;
430+ node. state . set ( NodeState :: Success ) ;
454431
455432 for child in children {
456433 let st = self . register_obligation_at ( child, Some ( index) ) ;
@@ -479,7 +456,7 @@ impl<O: ForestObligation> ObligationForest<O> {
479456 } ;
480457 }
481458
482- self . mark_still_waiting_nodes ( ) ;
459+ self . mark_successes ( ) ;
483460 self . process_cycles ( processor) ;
484461 let completed = self . compress ( do_completed) ;
485462
@@ -519,41 +496,50 @@ impl<O: ForestObligation> ObligationForest<O> {
519496 trace
520497 }
521498
522- /// Mark all `Success` nodes that depend on a pending node as still
523- /// waiting. Upon completion, any `Success` nodes that aren't still waiting
524- /// can be removed by `compress`.
525- fn mark_still_waiting_nodes ( & self ) {
499+ /// Mark all `Waiting` nodes as `Success`, except those that depend on a
500+ /// pending node.
501+ fn mark_successes ( & self ) {
502+ // Convert all `Waiting` nodes to `Success`.
503+ for node in & self . nodes {
504+ if node. state . get ( ) == NodeState :: Waiting {
505+ node. state . set ( NodeState :: Success ) ;
506+ }
507+ }
508+
509+ // Convert `Success` nodes that depend on a pending node back to
510+ // `Waiting`.
526511 for node in & self . nodes {
527512 if node. state . get ( ) == NodeState :: Pending {
528513 // This call site is hot.
529- self . inlined_mark_dependents_as_still_waiting ( node) ;
514+ self . inlined_mark_dependents_as_waiting ( node) ;
530515 }
531516 }
532517 }
533518
534519 // This always-inlined function is for the hot call site.
535520 #[ inline( always) ]
536- fn inlined_mark_dependents_as_still_waiting ( & self , node : & Node < O > ) {
521+ fn inlined_mark_dependents_as_waiting ( & self , node : & Node < O > ) {
537522 for & index in node. dependents . iter ( ) {
538523 let node = & self . nodes [ index] ;
539- if let NodeState :: Success ( waiting) = node. state . get ( ) {
540- if !self . is_still_waiting ( waiting) {
541- node. state . set ( NodeState :: Success ( self . still_waiting ( ) ) ) ;
542- // This call site is cold.
543- self . uninlined_mark_dependents_as_still_waiting ( node) ;
544- }
524+ let state = node. state . get ( ) ;
525+ if state == NodeState :: Success {
526+ node. state . set ( NodeState :: Waiting ) ;
527+ // This call site is cold.
528+ self . uninlined_mark_dependents_as_waiting ( node) ;
529+ } else {
530+ debug_assert ! ( state == NodeState :: Waiting || state == NodeState :: Error )
545531 }
546532 }
547533 }
548534
549535 // This never-inlined function is for the cold call site.
550536 #[ inline( never) ]
551- fn uninlined_mark_dependents_as_still_waiting ( & self , node : & Node < O > ) {
552- self . inlined_mark_dependents_as_still_waiting ( node)
537+ fn uninlined_mark_dependents_as_waiting ( & self , node : & Node < O > ) {
538+ self . inlined_mark_dependents_as_waiting ( node)
553539 }
554540
555- /// Report cycles between all `Success` nodes that aren't still waiting.
556- /// This must be called after `mark_still_waiting_nodes `.
541+ /// Report cycles between all `Success` nodes, and convert all `Success`
542+ /// nodes to `Done`. This must be called after `mark_successes `.
557543 fn process_cycles < P > ( & self , processor : & mut P )
558544 where
559545 P : ObligationProcessor < Obligation = O > ,
@@ -564,63 +550,51 @@ impl<O: ForestObligation> ObligationForest<O> {
564550 // For some benchmarks this state test is extremely hot. It's a win
565551 // to handle the no-op cases immediately to avoid the cost of the
566552 // function call.
567- if let NodeState :: Success ( waiting) = node. state . get ( ) {
568- if !self . is_still_waiting ( waiting) {
569- self . find_cycles_from_node ( & mut stack, processor, index, index) ;
570- }
553+ if node. state . get ( ) == NodeState :: Success {
554+ self . find_cycles_from_node ( & mut stack, processor, index) ;
571555 }
572556 }
573557
574558 debug_assert ! ( stack. is_empty( ) ) ;
575559 }
576560
577- fn find_cycles_from_node < P > (
578- & self ,
579- stack : & mut Vec < usize > ,
580- processor : & mut P ,
581- min_index : usize ,
582- index : usize ,
583- ) where
561+ fn find_cycles_from_node < P > ( & self , stack : & mut Vec < usize > , processor : & mut P , index : usize )
562+ where
584563 P : ObligationProcessor < Obligation = O > ,
585564 {
586565 let node = & self . nodes [ index] ;
587- if let NodeState :: Success ( waiting) = node. state . get ( ) {
588- if !self . is_still_waiting ( waiting) {
589- match stack. iter ( ) . rposition ( |& n| n == index) {
590- None => {
591- stack. push ( index) ;
592- for & dep_index in node. dependents . iter ( ) {
593- // The index check avoids re-considering a node.
594- if dep_index >= min_index {
595- self . find_cycles_from_node ( stack, processor, min_index, dep_index) ;
596- }
597- }
598- stack. pop ( ) ;
599- }
600- Some ( rpos) => {
601- // Cycle detected.
602- processor. process_backedge (
603- stack[ rpos..] . iter ( ) . map ( GetObligation ( & self . nodes ) ) ,
604- PhantomData ,
605- ) ;
566+ if node. state . get ( ) == NodeState :: Success {
567+ match stack. iter ( ) . rposition ( |& n| n == index) {
568+ None => {
569+ stack. push ( index) ;
570+ for & dep_index in node. dependents . iter ( ) {
571+ self . find_cycles_from_node ( stack, processor, dep_index) ;
606572 }
573+ stack. pop ( ) ;
574+ node. state . set ( NodeState :: Done ) ;
575+ }
576+ Some ( rpos) => {
577+ // Cycle detected.
578+ processor. process_backedge (
579+ stack[ rpos..] . iter ( ) . map ( GetObligation ( & self . nodes ) ) ,
580+ PhantomData ,
581+ ) ;
607582 }
608583 }
609584 }
610585 }
611586
612587 /// Compresses the vector, removing all popped nodes. This adjusts the
613588 /// indices and hence invalidates any outstanding indices. `process_cycles`
614- /// must be run beforehand to remove any cycles on not-still-waiting
615- /// `Success` nodes.
589+ /// must be run beforehand to remove any cycles on `Success` nodes.
616590 #[ inline( never) ]
617591 fn compress ( & mut self , do_completed : DoCompleted ) -> Option < Vec < O > > {
618592 let orig_nodes_len = self . nodes . len ( ) ;
619593 let mut node_rewrites: Vec < _ > = self . node_rewrites . replace ( vec ! [ ] ) ;
620594 debug_assert ! ( node_rewrites. is_empty( ) ) ;
621595 node_rewrites. extend ( 0 ..orig_nodes_len) ;
622596 let mut dead_nodes = 0 ;
623- let mut removed_success_obligations : Vec < O > = vec ! [ ] ;
597+ let mut removed_done_obligations : Vec < O > = vec ! [ ] ;
624598
625599 // Move removable nodes to the end, preserving the order of the
626600 // remaining nodes.
@@ -632,19 +606,13 @@ impl<O: ForestObligation> ObligationForest<O> {
632606 for index in 0 ..orig_nodes_len {
633607 let node = & self . nodes [ index] ;
634608 match node. state . get ( ) {
635- NodeState :: Pending => {
636- if dead_nodes > 0 {
637- self . nodes . swap ( index, index - dead_nodes) ;
638- node_rewrites[ index] -= dead_nodes;
639- }
640- }
641- NodeState :: Success ( waiting) if self . is_still_waiting ( waiting) => {
609+ NodeState :: Pending | NodeState :: Waiting => {
642610 if dead_nodes > 0 {
643611 self . nodes . swap ( index, index - dead_nodes) ;
644612 node_rewrites[ index] -= dead_nodes;
645613 }
646614 }
647- NodeState :: Success ( _ ) => {
615+ NodeState :: Done => {
648616 // This lookup can fail because the contents of
649617 // `self.active_cache` are not guaranteed to match those of
650618 // `self.nodes`. See the comment in `process_obligation`
@@ -658,7 +626,7 @@ impl<O: ForestObligation> ObligationForest<O> {
658626 }
659627 if do_completed == DoCompleted :: Yes {
660628 // Extract the success stories.
661- removed_success_obligations . push ( node. obligation . clone ( ) ) ;
629+ removed_done_obligations . push ( node. obligation . clone ( ) ) ;
662630 }
663631 node_rewrites[ index] = orig_nodes_len;
664632 dead_nodes += 1 ;
@@ -672,6 +640,7 @@ impl<O: ForestObligation> ObligationForest<O> {
672640 node_rewrites[ index] = orig_nodes_len;
673641 dead_nodes += 1 ;
674642 }
643+ NodeState :: Success => unreachable ! ( ) ,
675644 }
676645 }
677646
@@ -684,7 +653,7 @@ impl<O: ForestObligation> ObligationForest<O> {
684653 node_rewrites. truncate ( 0 ) ;
685654 self . node_rewrites . replace ( node_rewrites) ;
686655
687- if do_completed == DoCompleted :: Yes { Some ( removed_success_obligations ) } else { None }
656+ if do_completed == DoCompleted :: Yes { Some ( removed_done_obligations ) } else { None }
688657 }
689658
690659 fn apply_rewrites ( & mut self , node_rewrites : & [ usize ] ) {
0 commit comments