@@ -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
@@ -453,7 +480,7 @@ impl<O: ForestObligation> ObligationForest<O> {
453
480
} ;
454
481
}
455
482
456
- self . mark_as_waiting ( ) ;
483
+ self . update_waiting_and_success_states ( ) ;
457
484
self . process_cycles ( processor) ;
458
485
let completed = self . compress ( do_completed) ;
459
486
@@ -466,10 +493,9 @@ impl<O: ForestObligation> ObligationForest<O> {
466
493
}
467
494
}
468
495
469
- /// Mark all `NodeState::Success` nodes as `NodeState::Done` and
470
- /// report all cycles between them. This should be called
471
- /// after `mark_as_waiting` marks all nodes with pending
472
- /// subobligations as NodeState::Waiting.
496
+ /// Mark all `Success` nodes as `Done` and report all cycles between them.
497
+ /// This should be called after `update_waiting_and_success_states` updates
498
+ /// the status of all `Waiting` and `Success` nodes.
473
499
fn process_cycles < P > ( & self , processor : & mut P )
474
500
where P : ObligationProcessor < Obligation =O >
475
501
{
@@ -551,42 +577,47 @@ impl<O: ForestObligation> ObligationForest<O> {
551
577
552
578
// This always-inlined function is for the hot call site.
553
579
#[ inline( always) ]
554
- fn inlined_mark_neighbors_as_waiting_from ( & self , node : & Node < O > ) {
580
+ fn inlined_mark_dependents_as_waiting ( & self , node : & Node < O > ) {
555
581
for & index in node. dependents . iter ( ) {
556
582
let node = & self . nodes [ index] ;
557
583
match node. state . get ( ) {
558
584
NodeState :: Waiting | NodeState :: Error => { }
559
585
NodeState :: Success => {
560
586
node. state . set ( NodeState :: Waiting ) ;
561
587
// This call site is cold.
562
- self . uninlined_mark_neighbors_as_waiting_from ( node) ;
588
+ self . uninlined_mark_dependents_as_waiting ( node) ;
563
589
}
564
590
NodeState :: Pending | NodeState :: Done => {
565
591
// This call site is cold.
566
- self . uninlined_mark_neighbors_as_waiting_from ( node) ;
592
+ self . uninlined_mark_dependents_as_waiting ( node) ;
567
593
}
568
594
}
569
595
}
570
596
}
571
597
572
598
// This never-inlined function is for the cold call site.
573
599
#[ inline( never) ]
574
- fn uninlined_mark_neighbors_as_waiting_from ( & self , node : & Node < O > ) {
575
- self . inlined_mark_neighbors_as_waiting_from ( node)
600
+ fn uninlined_mark_dependents_as_waiting ( & self , node : & Node < O > ) {
601
+ self . inlined_mark_dependents_as_waiting ( node)
576
602
}
577
603
578
- /// Marks all nodes that depend on a pending node as `NodeState::Waiting`.
579
- fn mark_as_waiting ( & self ) {
604
+ /// Updates the states of all `Waiting` and `Success` nodes. Upon
605
+ /// completion, all such nodes that depend on a pending node will be marked
606
+ /// as `Waiting`, and all others will be marked as `Success`.
607
+ fn update_waiting_and_success_states ( & self ) {
608
+ // Optimistically mark all `Waiting` nodes as `Success`.
580
609
for node in & self . nodes {
581
610
if node. state . get ( ) == NodeState :: Waiting {
582
611
node. state . set ( NodeState :: Success ) ;
583
612
}
584
613
}
585
614
615
+ // Convert all `Success` nodes that still depend on a pending node to
616
+ // `Waiting`. This may undo some of the changes done in the loop above.
586
617
for node in & self . nodes {
587
618
if node. state . get ( ) == NodeState :: Pending {
588
619
// This call site is hot.
589
- self . inlined_mark_neighbors_as_waiting_from ( node) ;
620
+ self . inlined_mark_dependents_as_waiting ( node) ;
590
621
}
591
622
}
592
623
}
0 commit comments