7575use crate :: fx:: { FxHashMap , FxHashSet } ;
7676
7777use std:: cell:: { Cell , RefCell } ;
78+ use std:: cmp:: Ordering ;
7879use std:: collections:: hash_map:: Entry ;
80+ use std:: collections:: BinaryHeap ;
7981use std:: fmt:: Debug ;
8082use std:: hash;
8183use std:: marker:: PhantomData ;
@@ -87,8 +89,11 @@ mod graphviz;
8789mod tests;
8890
8991pub trait ForestObligation : Clone + Debug {
92+ /// A key used to avoid evaluating the same obligation twice
9093 type CacheKey : Clone + hash:: Hash + Eq + Debug ;
94+ /// The variable type used in the obligation when it could not yet be fulfilled
9195 type Variable : Clone + hash:: Hash + Eq + Debug ;
96+ /// A type which tracks which variables has been unified
9297 type WatcherOffset ;
9398
9499 /// Converts this `ForestObligation` suitable for use as a cache key.
@@ -97,6 +102,8 @@ pub trait ForestObligation: Clone + Debug {
97102 /// (e.g. success for error) for the other obligation
98103 fn as_cache_key ( & self ) -> Self :: CacheKey ;
99104
105+ /// Returns which variables this obligation is currently stalled on. If the slice is empty then
106+ /// the variables stalled on are unknown.
100107 fn stalled_on ( & self ) -> & [ Self :: Variable ] ;
101108}
102109
@@ -124,7 +131,7 @@ pub trait ObligationProcessor {
124131 fn unblocked (
125132 & self ,
126133 offset : & <Self :: Obligation as ForestObligation >:: WatcherOffset ,
127- f : impl FnMut ( <Self :: Obligation as ForestObligation >:: Variable ) -> bool ,
134+ f : impl FnMut ( <Self :: Obligation as ForestObligation >:: Variable ) ,
128135 ) ;
129136 fn register ( & self ) -> <Self :: Obligation as ForestObligation >:: WatcherOffset ;
130137 fn deregister ( & self , offset : <Self :: Obligation as ForestObligation >:: WatcherOffset ) ;
@@ -157,9 +164,16 @@ pub struct ObligationForest<O: ForestObligation> {
157164 /// this list only contains nodes in the `Pending` or `Waiting` state.
158165 nodes : Vec < Node < O > > ,
159166
160- /// Nodes must be processed in the order that they were added which this list keeps track of.
167+ /// Nodes must be processed in the order that they were added so we give each node a unique,
168+ /// number allowing them to be ordered when processing them.
169+ node_number : u32 ,
170+
171+ /// Stores the indices of the nodes currently in the pending state
161172 pending_nodes : Vec < NodeIndex > ,
173+
174+ /// Stores the indices of the nodes currently in the success or waiting states
162175 success_or_waiting_nodes : Vec < NodeIndex > ,
176+ /// Stores the indices of the nodes currently in the error or done states
163177 error_or_done_nodes : RefCell < Vec < NodeIndex > > ,
164178
165179 /// Nodes that have been removed and are ready to be reused
@@ -171,7 +185,6 @@ pub struct ObligationForest<O: ForestObligation> {
171185 active_cache : FxHashMap < O :: CacheKey , Option < NodeIndex > > ,
172186
173187 obligation_tree_id_generator : ObligationTreeIdGenerator ,
174- node_number : u32 ,
175188
176189 /// Per tree error cache. This is used to deduplicate errors,
177190 /// which is necessary to avoid trait resolution overflow in
@@ -182,18 +195,25 @@ pub struct ObligationForest<O: ForestObligation> {
182195 /// [details]: https://github.com/rust-lang/rust/pull/53255#issuecomment-421184780
183196 error_cache : FxHashMap < ObligationTreeId , FxHashSet < O :: CacheKey > > ,
184197
198+ /// Stores which nodes would be unblocked once `O::Variable` is unified
185199 stalled_on : FxHashMap < O :: Variable , Vec < NodeIndex > > ,
186- unblocked : std:: collections:: BinaryHeap < Unblocked > ,
200+ /// Stores the node indices that are unblocked and should be processed at the next opportunity
201+ unblocked : BinaryHeap < Unblocked > ,
202+ /// Stores nodes which should be processed on the next iteration since the variables they are
203+ /// actually blocked on are unknown
187204 check_next : Vec < NodeIndex > ,
205+ /// The offset that this `ObligationForest` has registered. Should be de-registered before
206+ /// dropping this forest.
188207 offset : Option < O :: WatcherOffset > ,
189208}
190209
210+ /// Helper struct for use with `BinaryHeap` to process nodes in the order that they were added to
211+ /// the forest
191212struct Unblocked {
192- index : usize ,
213+ index : NodeIndex ,
193214 order : u32 ,
194215}
195216
196- use std:: cmp:: Ordering ;
197217impl PartialEq for Unblocked {
198218 fn eq ( & self , other : & Self ) -> bool {
199219 self . order == other. order
@@ -216,11 +236,14 @@ struct Node<O: ForestObligation> {
216236 obligation : O ,
217237 state : Cell < NodeState > ,
218238
239+ /// A predicate (and its key) can changed during processing. If it does we need to register the
240+ /// old predicate so that we can remove or mark it as done if this node errors or is done.
219241 alternative_predicates : Vec < O :: CacheKey > ,
220242
221243 /// Obligations that depend on this obligation for their completion. They
222244 /// must all be in a non-pending state.
223245 dependents : Vec < NodeIndex > ,
246+ /// Obligations that this obligation depends on for their completion.
224247 reverse_dependents : Vec < NodeIndex > ,
225248
226249 /// If true, `dependents[0]` points to a "parent" node, which requires
@@ -257,6 +280,7 @@ where
257280 }
258281 }
259282
283+ /// Initializes a node, reusing the existing allocations
260284 fn init (
261285 & mut self ,
262286 parent : Option < NodeIndex > ,
@@ -473,12 +497,16 @@ impl<O: ForestObligation> ObligationForest<O> {
473497 . get ( & obligation_tree_id)
474498 . map ( |errors| errors. contains ( & obligation. as_cache_key ( ) ) )
475499 . unwrap_or ( false ) ;
500+ // Retrieves a fresh number for the new node so that each node are processed in the
501+ // order that they were created
476502 let node_number = self . node_number ;
477503 self . node_number += 1 ;
478504
479505 if already_failed {
480506 Err ( ( ) )
481507 } else {
508+ // If we have a dead node we can reuse it and it's associated allocations,
509+ // otherwise allocate a new node
482510 let new_index = if let Some ( new_index) = self . dead_nodes . pop ( ) {
483511 let node = & mut self . nodes [ new_index] ;
484512 node. init ( parent, obligation, obligation_tree_id, node_number) ;
@@ -549,11 +577,6 @@ impl<O: ForestObligation> ObligationForest<O> {
549577 if self . offset . is_none ( ) {
550578 self . offset = Some ( processor. register ( ) ) ;
551579 }
552- warn ! (
553- "Begin process {}, pending: {}" ,
554- self . nodes. len( ) ,
555- self . nodes. iter( ) . filter( |n| n. state. get( ) == NodeState :: Pending ) . count( )
556- ) ;
557580 let mut errors = vec ! [ ] ;
558581 let mut stalled = true ;
559582
@@ -577,6 +600,8 @@ impl<O: ForestObligation> ObligationForest<O> {
577600 if node. state . get ( ) != NodeState :: Pending {
578601 continue ;
579602 }
603+
604+ // Any variables we were stalled on are now resolved so remove the watches
580605 for var in node. obligation . stalled_on ( ) {
581606 match self . stalled_on . entry ( var. clone ( ) ) {
582607 Entry :: Vacant ( _) => ( ) ,
@@ -607,18 +632,22 @@ impl<O: ForestObligation> ObligationForest<O> {
607632 let node = & mut self . nodes [ index] ;
608633 match result {
609634 ProcessResult :: Unchanged => {
610- for var in node. obligation . stalled_on ( ) {
611- self . stalled_on
612- . entry ( var. clone ( ) )
613- . or_insert_with ( || {
614- processor. watch_variable ( var. clone ( ) ) ;
615- Vec :: new ( )
616- } )
617- . push ( index) ;
618- }
619-
620- if node. obligation . stalled_on ( ) . is_empty ( ) {
635+ // We stalled but the variables that caused it are unknown so we run
636+ // `index` again at the next opportunity
637+ let stalled_on = node. obligation . stalled_on ( ) ;
638+ if stalled_on. is_empty ( ) {
621639 self . check_next . push ( index) ;
640+ } else {
641+ // Register every variable that we stal
642+ for var in stalled_on {
643+ self . stalled_on
644+ . entry ( var. clone ( ) )
645+ . or_insert_with ( || {
646+ processor. watch_variable ( var. clone ( ) ) ;
647+ Vec :: new ( )
648+ } )
649+ . push ( index) ;
650+ }
622651 }
623652 // No change in state.
624653 }
@@ -646,7 +675,6 @@ impl<O: ForestObligation> ObligationForest<O> {
646675 }
647676
648677 if stalled {
649- warn ! ( "Stalled {}" , self . nodes. len( ) ) ;
650678 // There's no need to perform marking, cycle processing and compression when nothing
651679 // changed.
652680 return Outcome {
@@ -655,13 +683,9 @@ impl<O: ForestObligation> ObligationForest<O> {
655683 } ;
656684 }
657685
658- warn ! ( "Compressing {}" , self . nodes. len( ) ) ;
659686 self . mark_successes ( ) ;
660687 self . process_cycles ( processor) ;
661688 let completed = self . compress ( do_completed) ;
662- warn ! ( "Compressed {}" , self . nodes. len( ) ) ;
663-
664- warn ! ( "Stalled on: {:?}" , self . stalled_on. keys( ) . collect:: <Vec <_>>( ) ) ;
665689
666690 Outcome { completed, errors }
667691 }
@@ -678,19 +702,16 @@ impl<O: ForestObligation> ObligationForest<O> {
678702 processor. unblocked ( self . offset . as_ref ( ) . unwrap ( ) , |var| {
679703 if let Some ( unblocked_nodes) = stalled_on. remove ( & var) {
680704 for node_index in unblocked_nodes {
705+ let node = & nodes[ node_index] ;
681706 debug_assert ! (
682- nodes [ node_index ] . state. get( ) == NodeState :: Pending ,
707+ node . state. get( ) == NodeState :: Pending ,
683708 "Unblocking non-pending2: {:?}" ,
684- nodes [ node_index ] . obligation
709+ node . obligation
685710 ) ;
686- unblocked. push ( Unblocked {
687- index : node_index,
688- order : nodes[ node_index] . node_number ,
689- } ) ;
711+ unblocked. push ( Unblocked { index : node_index, order : node. node_number } ) ;
690712 }
691713 temp. push ( var) ;
692714 }
693- true
694715 } ) ;
695716 for var in temp {
696717 processor. unwatch_variable ( var) ;
@@ -848,6 +869,7 @@ impl<O: ForestObligation> ObligationForest<O> {
848869 fn compress ( & mut self , do_completed : DoCompleted ) -> Option < Vec < O > > {
849870 let mut removed_done_obligations: Vec < O > = vec ! [ ] ;
850871
872+ // Compress the forest by removing any nodes marked as error or done
851873 let mut error_or_done_nodes = mem:: take ( self . error_or_done_nodes . get_mut ( ) ) ;
852874 for & index in & error_or_done_nodes {
853875 let node = & mut self . nodes [ index] ;
0 commit comments