@@ -129,18 +129,14 @@ type ObligationTreeIdGenerator =
129
129
130
130
pub struct ObligationForest < O : ForestObligation > {
131
131
/// The list of obligations. In between calls to `process_obligations`,
132
- /// this list only contains nodes in the `Pending` or `Success ` state.
132
+ /// this list only contains nodes in the `Pending` or `Waiting ` state.
133
133
///
134
134
/// `usize` indices are used here and throughout this module, rather than
135
135
/// `rustc_index::newtype_index!` indices, because this code is hot enough
136
136
/// that the `u32`-to-`usize` conversions that would be required are
137
137
/// significant, and space considerations are not important.
138
138
nodes : Vec < Node < O > > ,
139
139
140
- /// The process generation is 1 on the first call to `process_obligations`,
141
- /// 2 on the second call, etc.
142
- gen : u32 ,
143
-
144
140
/// A cache of predicates that have been successfully completed.
145
141
done_cache : FxHashSet < O :: Predicate > ,
146
142
@@ -196,9 +192,9 @@ impl<O> Node<O> {
196
192
}
197
193
}
198
194
199
- /// The state of one node in some tree within the forest. This
200
- /// represents the current state of processing for the obligation (of
201
- /// type `O`) associated with this node.
195
+ /// The state of one node in some tree within the forest. This represents the
196
+ /// current state of processing for the obligation (of type `O`) associated
197
+ /// with this node.
202
198
///
203
199
/// The non-`Error` state transitions are as follows.
204
200
/// ```
@@ -210,51 +206,47 @@ impl<O> Node<O> {
210
206
/// |
211
207
/// | process_obligations()
212
208
/// v
213
- /// Success(not_waiting())
214
- /// | |
215
- /// | | mark_still_waiting_nodes ()
209
+ /// Success
210
+ /// | ^
211
+ /// | | mark_successes ()
216
212
/// | v
217
- /// | Success(still_waiting())
218
- /// | |
219
- /// | | compress()
220
- /// v v
213
+ /// | Waiting
214
+ /// |
215
+ /// | process_cycles()
216
+ /// v
217
+ /// Done
218
+ /// |
219
+ /// | compress()
220
+ /// v
221
221
/// (Removed)
222
222
/// ```
223
223
/// The `Error` state can be introduced in several places, via `error_at()`.
224
224
///
225
225
/// Outside of `ObligationForest` methods, nodes should be either `Pending` or
226
- /// `Success `.
226
+ /// `Waiting `.
227
227
#[ derive( Debug , Copy , Clone , PartialEq , Eq ) ]
228
228
enum NodeState {
229
229
/// This obligation has not yet been selected successfully. Cannot have
230
230
/// subobligations.
231
231
Pending ,
232
232
233
- /// This obligation was selected successfully, but it may be waiting on one
234
- /// or more pending subobligations, as indicated by the `WaitingState`.
235
- Success ( WaitingState ) ,
233
+ /// This obligation was selected successfully, but may or may not have
234
+ /// subobligations.
235
+ Success ,
236
+
237
+ /// This obligation was selected successfully, but it has a pending
238
+ /// subobligation.
239
+ Waiting ,
240
+
241
+ /// This obligation, along with its subobligations, are complete, and will
242
+ /// be removed in the next collection.
243
+ Done ,
236
244
237
245
/// This obligation was resolved to an error. It will be removed by the
238
246
/// next compression step.
239
247
Error ,
240
248
}
241
249
242
- /// Indicates when a `Success` node was last (if ever) waiting on one or more
243
- /// `Pending` nodes. The notion of "when" comes from `ObligationForest::gen`.
244
- /// - 0: "Not waiting". This is a special value, set by `process_obligation`,
245
- /// and usable because generation counting starts at 1.
246
- /// - 1..ObligationForest::gen: "Was waiting" in a previous generation, but
247
- /// waiting no longer. In other words, finished.
248
- /// - ObligationForest::gen: "Still waiting" in this generation.
249
- ///
250
- /// Things to note about this encoding:
251
- /// - Every time `ObligationForest::gen` is incremented, all the "still
252
- /// waiting" nodes automatically become "was waiting".
253
- /// - `ObligationForest::is_still_waiting` is very cheap.
254
- ///
255
- #[ derive( Clone , Copy , Debug , PartialEq , Eq , PartialOrd ) ]
256
- struct WaitingState ( u32 ) ;
257
-
258
250
#[ derive( Debug ) ]
259
251
pub struct Outcome < O , E > {
260
252
/// Obligations that were completely evaluated, including all
@@ -291,7 +283,6 @@ impl<O: ForestObligation> ObligationForest<O> {
291
283
pub fn new ( ) -> ObligationForest < O > {
292
284
ObligationForest {
293
285
nodes : vec ! [ ] ,
294
- gen : 0 ,
295
286
done_cache : Default :: default ( ) ,
296
287
active_cache : Default :: default ( ) ,
297
288
node_rewrites : RefCell :: new ( vec ! [ ] ) ,
@@ -392,18 +383,6 @@ impl<O: ForestObligation> ObligationForest<O> {
392
383
. insert ( node. obligation . as_predicate ( ) . clone ( ) ) ;
393
384
}
394
385
395
- fn not_waiting ( ) -> WaitingState {
396
- WaitingState ( 0 )
397
- }
398
-
399
- fn still_waiting ( & self ) -> WaitingState {
400
- WaitingState ( self . gen )
401
- }
402
-
403
- fn is_still_waiting ( & self , waiting : WaitingState ) -> bool {
404
- waiting. 0 == self . gen
405
- }
406
-
407
386
/// Performs a pass through the obligation list. This must
408
387
/// be called in a loop until `outcome.stalled` is false.
409
388
///
@@ -416,8 +395,6 @@ impl<O: ForestObligation> ObligationForest<O> {
416
395
where
417
396
P : ObligationProcessor < Obligation = O > ,
418
397
{
419
- self . gen += 1 ;
420
-
421
398
let mut errors = vec ! [ ] ;
422
399
let mut stalled = true ;
423
400
@@ -450,7 +427,7 @@ impl<O: ForestObligation> ObligationForest<O> {
450
427
ProcessResult :: Changed ( children) => {
451
428
// We are not (yet) stalled.
452
429
stalled = false ;
453
- node. state . set ( NodeState :: Success ( Self :: not_waiting ( ) ) ) ;
430
+ node. state . set ( NodeState :: Success ) ;
454
431
455
432
for child in children {
456
433
let st = self . register_obligation_at ( child, Some ( index) ) ;
@@ -479,7 +456,7 @@ impl<O: ForestObligation> ObligationForest<O> {
479
456
} ;
480
457
}
481
458
482
- self . mark_still_waiting_nodes ( ) ;
459
+ self . mark_successes ( ) ;
483
460
self . process_cycles ( processor) ;
484
461
let completed = self . compress ( do_completed) ;
485
462
@@ -519,41 +496,50 @@ impl<O: ForestObligation> ObligationForest<O> {
519
496
trace
520
497
}
521
498
522
- /// Mark all `Success` nodes that depend on a pending node as still
523
- /// waiting. Upon completion, any `Success` nodes that aren't still waiting
524
- /// can be removed by `compress`.
525
- fn mark_still_waiting_nodes ( & self ) {
499
+ /// Mark all `Waiting` nodes as `Success`, except those that depend on a
500
+ /// pending node.
501
+ fn mark_successes ( & self ) {
502
+ // Convert all `Waiting` nodes to `Success`.
503
+ for node in & self . nodes {
504
+ if node. state . get ( ) == NodeState :: Waiting {
505
+ node. state . set ( NodeState :: Success ) ;
506
+ }
507
+ }
508
+
509
+ // Convert `Success` nodes that depend on a pending node back to
510
+ // `Waiting`.
526
511
for node in & self . nodes {
527
512
if node. state . get ( ) == NodeState :: Pending {
528
513
// This call site is hot.
529
- self . inlined_mark_dependents_as_still_waiting ( node) ;
514
+ self . inlined_mark_dependents_as_waiting ( node) ;
530
515
}
531
516
}
532
517
}
533
518
534
519
// This always-inlined function is for the hot call site.
535
520
#[ inline( always) ]
536
- fn inlined_mark_dependents_as_still_waiting ( & self , node : & Node < O > ) {
521
+ fn inlined_mark_dependents_as_waiting ( & self , node : & Node < O > ) {
537
522
for & index in node. dependents . iter ( ) {
538
523
let node = & self . nodes [ index] ;
539
- if let NodeState :: Success ( waiting) = node. state . get ( ) {
540
- if !self . is_still_waiting ( waiting) {
541
- node. state . set ( NodeState :: Success ( self . still_waiting ( ) ) ) ;
542
- // This call site is cold.
543
- self . uninlined_mark_dependents_as_still_waiting ( node) ;
544
- }
524
+ let state = node. state . get ( ) ;
525
+ if state == NodeState :: Success {
526
+ node. state . set ( NodeState :: Waiting ) ;
527
+ // This call site is cold.
528
+ self . uninlined_mark_dependents_as_waiting ( node) ;
529
+ } else {
530
+ debug_assert ! ( state == NodeState :: Waiting || state == NodeState :: Error )
545
531
}
546
532
}
547
533
}
548
534
549
535
// This never-inlined function is for the cold call site.
550
536
#[ inline( never) ]
551
- fn uninlined_mark_dependents_as_still_waiting ( & self , node : & Node < O > ) {
552
- self . inlined_mark_dependents_as_still_waiting ( node)
537
+ fn uninlined_mark_dependents_as_waiting ( & self , node : & Node < O > ) {
538
+ self . inlined_mark_dependents_as_waiting ( node)
553
539
}
554
540
555
- /// Report cycles between all `Success` nodes that aren't still waiting.
556
- /// This must be called after `mark_still_waiting_nodes `.
541
+ /// Report cycles between all `Success` nodes, and convert all `Success`
542
+ /// nodes to `Done`. This must be called after `mark_successes `.
557
543
fn process_cycles < P > ( & self , processor : & mut P )
558
544
where
559
545
P : ObligationProcessor < Obligation = O > ,
@@ -564,63 +550,51 @@ impl<O: ForestObligation> ObligationForest<O> {
564
550
// For some benchmarks this state test is extremely hot. It's a win
565
551
// to handle the no-op cases immediately to avoid the cost of the
566
552
// function call.
567
- if let NodeState :: Success ( waiting) = node. state . get ( ) {
568
- if !self . is_still_waiting ( waiting) {
569
- self . find_cycles_from_node ( & mut stack, processor, index, index) ;
570
- }
553
+ if node. state . get ( ) == NodeState :: Success {
554
+ self . find_cycles_from_node ( & mut stack, processor, index) ;
571
555
}
572
556
}
573
557
574
558
debug_assert ! ( stack. is_empty( ) ) ;
575
559
}
576
560
577
- fn find_cycles_from_node < P > (
578
- & self ,
579
- stack : & mut Vec < usize > ,
580
- processor : & mut P ,
581
- min_index : usize ,
582
- index : usize ,
583
- ) where
561
+ fn find_cycles_from_node < P > ( & self , stack : & mut Vec < usize > , processor : & mut P , index : usize )
562
+ where
584
563
P : ObligationProcessor < Obligation = O > ,
585
564
{
586
565
let node = & self . nodes [ index] ;
587
- if let NodeState :: Success ( waiting) = node. state . get ( ) {
588
- if !self . is_still_waiting ( waiting) {
589
- match stack. iter ( ) . rposition ( |& n| n == index) {
590
- None => {
591
- stack. push ( index) ;
592
- for & dep_index in node. dependents . iter ( ) {
593
- // The index check avoids re-considering a node.
594
- if dep_index >= min_index {
595
- self . find_cycles_from_node ( stack, processor, min_index, dep_index) ;
596
- }
597
- }
598
- stack. pop ( ) ;
599
- }
600
- Some ( rpos) => {
601
- // Cycle detected.
602
- processor. process_backedge (
603
- stack[ rpos..] . iter ( ) . map ( GetObligation ( & self . nodes ) ) ,
604
- PhantomData ,
605
- ) ;
566
+ if node. state . get ( ) == NodeState :: Success {
567
+ match stack. iter ( ) . rposition ( |& n| n == index) {
568
+ None => {
569
+ stack. push ( index) ;
570
+ for & dep_index in node. dependents . iter ( ) {
571
+ self . find_cycles_from_node ( stack, processor, dep_index) ;
606
572
}
573
+ stack. pop ( ) ;
574
+ node. state . set ( NodeState :: Done ) ;
575
+ }
576
+ Some ( rpos) => {
577
+ // Cycle detected.
578
+ processor. process_backedge (
579
+ stack[ rpos..] . iter ( ) . map ( GetObligation ( & self . nodes ) ) ,
580
+ PhantomData ,
581
+ ) ;
607
582
}
608
583
}
609
584
}
610
585
}
611
586
612
587
/// Compresses the vector, removing all popped nodes. This adjusts the
613
588
/// indices and hence invalidates any outstanding indices. `process_cycles`
614
- /// must be run beforehand to remove any cycles on not-still-waiting
615
- /// `Success` nodes.
589
+ /// must be run beforehand to remove any cycles on `Success` nodes.
616
590
#[ inline( never) ]
617
591
fn compress ( & mut self , do_completed : DoCompleted ) -> Option < Vec < O > > {
618
592
let orig_nodes_len = self . nodes . len ( ) ;
619
593
let mut node_rewrites: Vec < _ > = self . node_rewrites . replace ( vec ! [ ] ) ;
620
594
debug_assert ! ( node_rewrites. is_empty( ) ) ;
621
595
node_rewrites. extend ( 0 ..orig_nodes_len) ;
622
596
let mut dead_nodes = 0 ;
623
- let mut removed_success_obligations : Vec < O > = vec ! [ ] ;
597
+ let mut removed_done_obligations : Vec < O > = vec ! [ ] ;
624
598
625
599
// Move removable nodes to the end, preserving the order of the
626
600
// remaining nodes.
@@ -632,19 +606,13 @@ impl<O: ForestObligation> ObligationForest<O> {
632
606
for index in 0 ..orig_nodes_len {
633
607
let node = & self . nodes [ index] ;
634
608
match node. state . get ( ) {
635
- NodeState :: Pending => {
636
- if dead_nodes > 0 {
637
- self . nodes . swap ( index, index - dead_nodes) ;
638
- node_rewrites[ index] -= dead_nodes;
639
- }
640
- }
641
- NodeState :: Success ( waiting) if self . is_still_waiting ( waiting) => {
609
+ NodeState :: Pending | NodeState :: Waiting => {
642
610
if dead_nodes > 0 {
643
611
self . nodes . swap ( index, index - dead_nodes) ;
644
612
node_rewrites[ index] -= dead_nodes;
645
613
}
646
614
}
647
- NodeState :: Success ( _ ) => {
615
+ NodeState :: Done => {
648
616
// This lookup can fail because the contents of
649
617
// `self.active_cache` are not guaranteed to match those of
650
618
// `self.nodes`. See the comment in `process_obligation`
@@ -658,7 +626,7 @@ impl<O: ForestObligation> ObligationForest<O> {
658
626
}
659
627
if do_completed == DoCompleted :: Yes {
660
628
// Extract the success stories.
661
- removed_success_obligations . push ( node. obligation . clone ( ) ) ;
629
+ removed_done_obligations . push ( node. obligation . clone ( ) ) ;
662
630
}
663
631
node_rewrites[ index] = orig_nodes_len;
664
632
dead_nodes += 1 ;
@@ -672,6 +640,7 @@ impl<O: ForestObligation> ObligationForest<O> {
672
640
node_rewrites[ index] = orig_nodes_len;
673
641
dead_nodes += 1 ;
674
642
}
643
+ NodeState :: Success => unreachable ! ( ) ,
675
644
}
676
645
}
677
646
@@ -684,7 +653,7 @@ impl<O: ForestObligation> ObligationForest<O> {
684
653
node_rewrites. truncate ( 0 ) ;
685
654
self . node_rewrites . replace ( node_rewrites) ;
686
655
687
- if do_completed == DoCompleted :: Yes { Some ( removed_success_obligations ) } else { None }
656
+ if do_completed == DoCompleted :: Yes { Some ( removed_done_obligations ) } else { None }
688
657
}
689
658
690
659
fn apply_rewrites ( & mut self , node_rewrites : & [ usize ] ) {
0 commit comments