@@ -177,21 +177,17 @@ struct Node<O> {
177177 obligation : O ,
178178 state : Cell < NodeState > ,
179179
180- /// The parent of a node - the original obligation of which it is a
181- /// subobligation. Except for error reporting, it is just like any member
182- /// of `dependents`.
183- ///
184- /// Unlike `ObligationForest::nodes`, this uses `NodeIndex` rather than
185- /// `usize` for the index, because keeping the size down is more important
186- /// than the cost of converting to a `usize` for indexing.
187- parent : Option < NodeIndex > ,
188-
189180 /// Obligations that depend on this obligation for their completion. They
190181 /// must all be in a non-pending state.
191- ///
192- /// This uses `NodeIndex` for the same reason as `parent`.
193182 dependents : Vec < NodeIndex > ,
194183
184+ /// If true, dependents[0] points to a "parent" node, which requires
185+ /// special treatment upon error but is otherwise treated the same.
186+ /// (It would be more idiomatic to store the parent node in a separate
187+ /// `Option<NodeIndex>` field, but that slows down the common case of
188+ /// iterating over the parent and other descendants together.)
189+ has_parent : bool ,
190+
195191 /// Identifier of the obligation tree to which this node belongs.
196192 obligation_tree_id : ObligationTreeId ,
197193}
@@ -205,8 +201,13 @@ impl<O> Node<O> {
205201 Node {
206202 obligation,
207203 state : Cell :: new ( NodeState :: Pending ) ,
208- parent,
209- dependents : vec ! [ ] ,
204+ dependents :
205+ if let Some ( parent_index) = parent {
206+ vec ! [ parent_index]
207+ } else {
208+ vec ! [ ]
209+ } ,
210+ has_parent : parent. is_some ( ) ,
210211 obligation_tree_id,
211212 }
212213 }
@@ -315,13 +316,11 @@ impl<O: ForestObligation> ObligationForest<O> {
315316 obligation, parent, o. get( ) ) ;
316317 let node = & mut self . nodes [ o. get ( ) . index ( ) ] ;
317318 if let Some ( parent_index) = parent {
318- // If the node is already in `waiting_cache`, it's already
319- // been marked with a parent. (It's possible that parent
320- // has been cleared by `apply_rewrites`, though.) So just
321- // dump `parent` into `node.dependents`... unless it's
322- // already in `node.dependents` or `node.parent`.
323- if !node. dependents . contains ( & parent_index) &&
324- Some ( parent_index) != node. parent {
319+ // If the node is already in `waiting_cache`, it has
320+ // already had its chance to be marked with a parent. So if
321+ // it's not already present, just dump `parent` into the
322+ // dependents as a non-parent.
323+ if !node. dependents . contains ( & parent_index) {
325324 node. dependents . push ( parent_index) ;
326325 }
327326 }
@@ -523,7 +522,7 @@ impl<O: ForestObligation> ObligationForest<O> {
523522 NodeState :: Success => {
524523 node. state . set ( NodeState :: OnDfsStack ) ;
525524 stack. push ( i) ;
526- for index in node. parent . iter ( ) . chain ( node . dependents . iter ( ) ) {
525+ for index in node. dependents . iter ( ) {
527526 self . find_cycles_from_node ( stack, processor, index. index ( ) ) ;
528527 }
529528 stack. pop ( ) ;
@@ -549,12 +548,15 @@ impl<O: ForestObligation> ObligationForest<O> {
549548 let node = & self . nodes [ i] ;
550549 node. state . set ( NodeState :: Error ) ;
551550 trace. push ( node. obligation . clone ( ) ) ;
552- error_stack. extend ( node. dependents . iter ( ) . map ( |index| index. index ( ) ) ) ;
553-
554- // Loop to the parent.
555- match node. parent {
556- Some ( parent_index) => i = parent_index. index ( ) ,
557- None => break
551+ if node. has_parent {
552+ // The first dependent is the parent, which is treated
553+ // specially.
554+ error_stack. extend ( node. dependents . iter ( ) . skip ( 1 ) . map ( |index| index. index ( ) ) ) ;
555+ i = node. dependents [ 0 ] . index ( ) ;
556+ } else {
557+ // No parent; treat all dependents non-specially.
558+ error_stack. extend ( node. dependents . iter ( ) . map ( |index| index. index ( ) ) ) ;
559+ break ;
558560 }
559561 }
560562
@@ -565,9 +567,7 @@ impl<O: ForestObligation> ObligationForest<O> {
565567 _ => node. state . set ( NodeState :: Error ) ,
566568 }
567569
568- error_stack. extend (
569- node. parent . iter ( ) . chain ( node. dependents . iter ( ) ) . map ( |index| index. index ( ) )
570- ) ;
570+ error_stack. extend ( node. dependents . iter ( ) . map ( |index| index. index ( ) ) ) ;
571571 }
572572
573573 self . scratch . replace ( error_stack) ;
@@ -577,7 +577,7 @@ impl<O: ForestObligation> ObligationForest<O> {
577577 // This always-inlined function is for the hot call site.
578578 #[ inline( always) ]
579579 fn inlined_mark_neighbors_as_waiting_from ( & self , node : & Node < O > ) {
580- for dependent in node. parent . iter ( ) . chain ( node . dependents . iter ( ) ) {
580+ for dependent in node. dependents . iter ( ) {
581581 self . mark_as_waiting_from ( & self . nodes [ dependent. index ( ) ] ) ;
582582 }
583583 }
@@ -706,20 +706,15 @@ impl<O: ForestObligation> ObligationForest<O> {
706706 let nodes_len = node_rewrites. len ( ) ;
707707
708708 for node in & mut self . nodes {
709- if let Some ( index) = node. parent {
710- let new_i = node_rewrites[ index. index ( ) ] ;
711- if new_i >= nodes_len {
712- node. parent = None ;
713- } else {
714- node. parent = Some ( NodeIndex :: new ( new_i) ) ;
715- }
716- }
717-
718709 let mut i = 0 ;
719710 while i < node. dependents . len ( ) {
720711 let new_i = node_rewrites[ node. dependents [ i] . index ( ) ] ;
721712 if new_i >= nodes_len {
722713 node. dependents . swap_remove ( i) ;
714+ if i == 0 && node. has_parent {
715+ // We just removed the parent.
716+ node. has_parent = false ;
717+ }
723718 } else {
724719 node. dependents [ i] = NodeIndex :: new ( new_i) ;
725720 i += 1 ;
0 commit comments