@@ -130,12 +130,11 @@ type ObligationTreeIdGenerator =
130
130
pub struct ObligationForest < O : ForestObligation > {
131
131
/// The list of obligations. In between calls to
132
132
/// `process_obligations`, this list only contains nodes in the
133
- /// `Pending` or `Success ` state (with a non-zero number of
133
+ /// `Pending` or `Waiting ` state (with a non-zero number of
134
134
/// incomplete children). During processing, some of those nodes
135
135
/// may be changed to the error state, or we may find that they
136
- /// are completed (That is, `num_incomplete_children` drops to 0).
137
- /// At the end of processing, those nodes will be removed by a
138
- /// call to `compress`.
136
+ /// are completed. At the end of processing, those nodes will be
137
+ /// removed by a call to `compress`.
139
138
///
140
139
/// `usize` indices are used here and throughout this module, rather than
141
140
/// `rustc_index::newtype_index!` indices, because this code is hot enough that the
@@ -211,28 +210,56 @@ impl<O> Node<O> {
211
210
/// represents the current state of processing for the obligation (of
212
211
/// type `O`) associated with this node.
213
212
///
214
- /// Outside of ObligationForest methods, nodes should be either Pending
215
- /// or Waiting.
213
+ /// The non-`Error` state transitions are as follows.
214
+ /// ```
215
+ /// (Pre-creation)
216
+ /// |
217
+ /// | register_obligation_at() (called by process_obligations() and
218
+ /// v from outside the crate)
219
+ /// Pending
220
+ /// |
221
+ /// | process_obligations()
222
+ /// v
223
+ /// Success
224
+ /// | ^
225
+ /// | | update_waiting_and_success_states()
226
+ /// | v
227
+ /// | Waiting
228
+ /// |
229
+ /// | process_cycles()
230
+ /// v
231
+ /// Done
232
+ /// |
233
+ /// | compress()
234
+ /// v
235
+ /// (Removed)
236
+ /// ```
237
+ /// The `Error` state can be introduced in several places, via `error_at()`.
238
+ ///
239
+ /// Outside of `ObligationForest` methods, nodes should be either `Pending` or
240
+ /// `Waiting`.
216
241
#[ derive( Debug , Copy , Clone , PartialEq , Eq ) ]
217
242
enum NodeState {
218
- /// Obligations for which selection had not yet returned a
219
- /// non-ambiguous result .
243
+ /// This obligation has not yet been selected successfully. Cannot have
244
+ /// subobligations .
220
245
Pending ,
221
246
222
- /// This obligation was selected successfully, but may or
223
- /// may not have subobligations.
247
+ /// This obligation was selected successfully, but the state of any
248
+ /// subobligations are current unknown. It will be converted to `Waiting`
249
+ /// or `Done` once the states of the subobligations become known.
224
250
Success ,
225
251
226
- /// This obligation was selected successfully, but it has
227
- /// a pending subobligation .
252
+ /// This obligation was selected successfully, but it has one or more
253
+ /// pending subobligations .
228
254
Waiting ,
229
255
230
- /// This obligation, along with its subobligations, are complete,
231
- /// and will be removed in the next collection.
256
+ /// This obligation was selected successfully, as were all of its
257
+ /// subobligations (of which there may be none). It will be removed by the
258
+ /// next compression step.
232
259
Done ,
233
260
234
- /// This obligation was resolved to an error. Error nodes are
235
- /// removed from the vector by the compression step.
261
+ /// This obligation was resolved to an error. It will be removed by the
262
+ /// next compression step.
236
263
Error ,
237
264
}
238
265
@@ -464,7 +491,7 @@ impl<O: ForestObligation> ObligationForest<O> {
464
491
} ;
465
492
}
466
493
467
- self . mark_as_waiting ( ) ;
494
+ self . update_waiting_and_success_states ( ) ;
468
495
self . process_cycles ( processor) ;
469
496
let completed = self . compress ( do_completed) ;
470
497
@@ -477,10 +504,9 @@ impl<O: ForestObligation> ObligationForest<O> {
477
504
}
478
505
}
479
506
480
- /// Mark all `NodeState::Success` nodes as `NodeState::Done` and
481
- /// report all cycles between them. This should be called
482
- /// after `mark_as_waiting` marks all nodes with pending
483
- /// subobligations as NodeState::Waiting.
507
+ /// Mark all `Success` nodes as `Done` and report all cycles between them.
508
+ /// This should be called after `update_waiting_and_success_states` updates
509
+ /// the status of all `Waiting` and `Success` nodes.
484
510
fn process_cycles < P > ( & self , processor : & mut P )
485
511
where P : ObligationProcessor < Obligation =O >
486
512
{
@@ -562,42 +588,47 @@ impl<O: ForestObligation> ObligationForest<O> {
562
588
563
589
// This always-inlined function is for the hot call site.
564
590
#[ inline( always) ]
565
- fn inlined_mark_neighbors_as_waiting_from ( & self , node : & Node < O > ) {
591
+ fn inlined_mark_dependents_as_waiting ( & self , node : & Node < O > ) {
566
592
for & index in node. dependents . iter ( ) {
567
593
let node = & self . nodes [ index] ;
568
594
match node. state . get ( ) {
569
595
NodeState :: Waiting | NodeState :: Error => { }
570
596
NodeState :: Success => {
571
597
node. state . set ( NodeState :: Waiting ) ;
572
598
// This call site is cold.
573
- self . uninlined_mark_neighbors_as_waiting_from ( node) ;
599
+ self . uninlined_mark_dependents_as_waiting ( node) ;
574
600
}
575
601
NodeState :: Pending | NodeState :: Done => {
576
602
// This call site is cold.
577
- self . uninlined_mark_neighbors_as_waiting_from ( node) ;
603
+ self . uninlined_mark_dependents_as_waiting ( node) ;
578
604
}
579
605
}
580
606
}
581
607
}
582
608
583
609
// This never-inlined function is for the cold call site.
584
610
#[ inline( never) ]
585
- fn uninlined_mark_neighbors_as_waiting_from ( & self , node : & Node < O > ) {
586
- self . inlined_mark_neighbors_as_waiting_from ( node)
611
+ fn uninlined_mark_dependents_as_waiting ( & self , node : & Node < O > ) {
612
+ self . inlined_mark_dependents_as_waiting ( node)
587
613
}
588
614
589
- /// Marks all nodes that depend on a pending node as `NodeState::Waiting`.
590
- fn mark_as_waiting ( & self ) {
615
+ /// Updates the states of all `Waiting` and `Success` nodes. Upon
616
+ /// completion, all such nodes that depend on a pending node will be marked
617
+ /// as `Waiting`, and all others will be marked as `Success`.
618
+ fn update_waiting_and_success_states ( & self ) {
619
+ // Optimistically mark all `Waiting` nodes as `Success`.
591
620
for node in & self . nodes {
592
621
if node. state . get ( ) == NodeState :: Waiting {
593
622
node. state . set ( NodeState :: Success ) ;
594
623
}
595
624
}
596
625
626
+ // Convert all `Success` nodes that still depend on a pending node to
627
+ // `Waiting`. This may undo some of the changes done in the loop above.
597
628
for node in & self . nodes {
598
629
if node. state . get ( ) == NodeState :: Pending {
599
630
// This call site is hot.
600
- self . inlined_mark_neighbors_as_waiting_from ( node) ;
631
+ self . inlined_mark_dependents_as_waiting ( node) ;
601
632
}
602
633
}
603
634
}
0 commit comments