@@ -177,21 +177,17 @@ struct Node<O> {
177
177
obligation : O ,
178
178
state : Cell < NodeState > ,
179
179
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
-
189
180
/// Obligations that depend on this obligation for their completion. They
190
181
/// must all be in a non-pending state.
191
- ///
192
- /// This uses `NodeIndex` for the same reason as `parent`.
193
182
dependents : Vec < NodeIndex > ,
194
183
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
+
195
191
/// Identifier of the obligation tree to which this node belongs.
196
192
obligation_tree_id : ObligationTreeId ,
197
193
}
@@ -205,8 +201,13 @@ impl<O> Node<O> {
205
201
Node {
206
202
obligation,
207
203
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 ( ) ,
210
211
obligation_tree_id,
211
212
}
212
213
}
@@ -315,13 +316,11 @@ impl<O: ForestObligation> ObligationForest<O> {
315
316
obligation, parent, o. get( ) ) ;
316
317
let node = & mut self . nodes [ o. get ( ) . index ( ) ] ;
317
318
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) {
325
324
node. dependents . push ( parent_index) ;
326
325
}
327
326
}
@@ -523,7 +522,7 @@ impl<O: ForestObligation> ObligationForest<O> {
523
522
NodeState :: Success => {
524
523
node. state . set ( NodeState :: OnDfsStack ) ;
525
524
stack. push ( i) ;
526
- for index in node. parent . iter ( ) . chain ( node . dependents . iter ( ) ) {
525
+ for index in node. dependents . iter ( ) {
527
526
self . find_cycles_from_node ( stack, processor, index. index ( ) ) ;
528
527
}
529
528
stack. pop ( ) ;
@@ -549,12 +548,15 @@ impl<O: ForestObligation> ObligationForest<O> {
549
548
let node = & self . nodes [ i] ;
550
549
node. state . set ( NodeState :: Error ) ;
551
550
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 ;
558
560
}
559
561
}
560
562
@@ -565,9 +567,7 @@ impl<O: ForestObligation> ObligationForest<O> {
565
567
_ => node. state . set ( NodeState :: Error ) ,
566
568
}
567
569
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 ( ) ) ) ;
571
571
}
572
572
573
573
self . scratch . replace ( error_stack) ;
@@ -577,7 +577,7 @@ impl<O: ForestObligation> ObligationForest<O> {
577
577
// This always-inlined function is for the hot call site.
578
578
#[ inline( always) ]
579
579
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 ( ) {
581
581
self . mark_as_waiting_from ( & self . nodes [ dependent. index ( ) ] ) ;
582
582
}
583
583
}
@@ -706,20 +706,15 @@ impl<O: ForestObligation> ObligationForest<O> {
706
706
let nodes_len = node_rewrites. len ( ) ;
707
707
708
708
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
-
718
709
let mut i = 0 ;
719
710
while i < node. dependents . len ( ) {
720
711
let new_i = node_rewrites[ node. dependents [ i] . index ( ) ] ;
721
712
if new_i >= nodes_len {
722
713
node. dependents . swap_remove ( i) ;
714
+ if i == 0 && node. has_parent {
715
+ // We just removed the parent.
716
+ node. has_parent = false ;
717
+ }
723
718
} else {
724
719
node. dependents [ i] = NodeIndex :: new ( new_i) ;
725
720
i += 1 ;
0 commit comments