@@ -129,18 +129,14 @@ type ObligationTreeIdGenerator =
129129
130130pub struct ObligationForest<O: ForestObligation> {
131131 /// 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.
133133 ///
134134 /// `usize` indices are used here and throughout this module, rather than
135135 /// `rustc_index::newtype_index!` indices, because this code is hot enough
136136 /// that the `u32`-to-`usize` conversions that would be required are
137137 /// significant, and space considerations are not important.
138138 nodes: Vec<Node<O>>,
139139
140- /// The process generation is 1 on the first call to `process_obligations`,
141- /// 2 on the second call, etc.
142- gen: u32,
143-
144140 /// A cache of predicates that have been successfully completed.
145141 done_cache: FxHashSet<O::Predicate>,
146142
@@ -196,9 +192,9 @@ impl<O> Node<O> {
196192 }
197193}
198194
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.
202198///
203199/// The non-`Error` state transitions are as follows.
204200/// ```
@@ -210,51 +206,47 @@ impl<O> Node<O> {
210206/// |
211207/// | process_obligations()
212208/// v
213- /// Success(not_waiting())
214- /// | |
215- /// | | mark_still_waiting_nodes ()
209+ /// Success
210+ /// | ^
211+ /// | | mark_successes ()
216212/// | 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
221221/// (Removed)
222222/// ```
223223/// The `Error` state can be introduced in several places, via `error_at()`.
224224///
225225/// Outside of `ObligationForest` methods, nodes should be either `Pending` or
226- /// `Success `.
226+ /// `Waiting `.
227227#[derive(Debug, Copy, Clone, PartialEq, Eq)]
228228enum NodeState {
229229 /// This obligation has not yet been selected successfully. Cannot have
230230 /// subobligations.
231231 Pending,
232232
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,
236244
237245 /// This obligation was resolved to an error. It will be removed by the
238246 /// next compression step.
239247 Error,
240248}
241249
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-
258250#[derive(Debug)]
259251pub struct Outcome<O, E> {
260252 /// Obligations that were completely evaluated, including all
@@ -291,7 +283,6 @@ impl<O: ForestObligation> ObligationForest<O> {
291283 pub fn new() -> ObligationForest<O> {
292284 ObligationForest {
293285 nodes: vec![],
294- gen: 0,
295286 done_cache: Default::default(),
296287 active_cache: Default::default(),
297288 node_rewrites: RefCell::new(vec![]),
@@ -392,18 +383,6 @@ impl<O: ForestObligation> ObligationForest<O> {
392383 .insert(node.obligation.as_predicate().clone());
393384 }
394385
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-
407386 /// Performs a pass through the obligation list. This must
408387 /// be called in a loop until `outcome.stalled` is false.
409388 ///
@@ -416,8 +395,6 @@ impl<O: ForestObligation> ObligationForest<O> {
416395 where
417396 P: ObligationProcessor<Obligation = O>,
418397 {
419- self.gen += 1;
420-
421398 let mut errors = vec![];
422399 let mut stalled = true;
423400
@@ -450,7 +427,7 @@ impl<O: ForestObligation> ObligationForest<O> {
450427 ProcessResult::Changed(children) => {
451428 // We are not (yet) stalled.
452429 stalled = false;
453- node.state.set(NodeState::Success(Self::not_waiting()) );
430+ node.state.set(NodeState::Success);
454431
455432 for child in children {
456433 let st = self.register_obligation_at(child, Some(index));
@@ -479,7 +456,7 @@ impl<O: ForestObligation> ObligationForest<O> {
479456 };
480457 }
481458
482- self.mark_still_waiting_nodes ();
459+ self.mark_successes ();
483460 self.process_cycles(processor);
484461 let completed = self.compress(do_completed);
485462
@@ -519,41 +496,50 @@ impl<O: ForestObligation> ObligationForest<O> {
519496 trace
520497 }
521498
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`.
526511 for node in &self.nodes {
527512 if node.state.get() == NodeState::Pending {
528513 // This call site is hot.
529- self.inlined_mark_dependents_as_still_waiting (node);
514+ self.inlined_mark_dependents_as_waiting (node);
530515 }
531516 }
532517 }
533518
534519 // This always-inlined function is for the hot call site.
535520 #[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>) {
537522 for &index in node.dependents.iter() {
538523 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)
545531 }
546532 }
547533 }
548534
549535 // This never-inlined function is for the cold call site.
550536 #[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)
553539 }
554540
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 `.
557543 fn process_cycles<P>(&self, processor: &mut P)
558544 where
559545 P: ObligationProcessor<Obligation = O>,
@@ -564,63 +550,51 @@ impl<O: ForestObligation> ObligationForest<O> {
564550 // For some benchmarks this state test is extremely hot. It's a win
565551 // to handle the no-op cases immediately to avoid the cost of the
566552 // 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);
571555 }
572556 }
573557
574558 debug_assert!(stack.is_empty());
575559 }
576560
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
584563 P: ObligationProcessor<Obligation = O>,
585564 {
586565 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);
606572 }
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+ );
607582 }
608583 }
609584 }
610585 }
611586
612587 /// Compresses the vector, removing all popped nodes. This adjusts the
613588 /// 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.
616590 #[inline(never)]
617591 fn compress(&mut self, do_completed: DoCompleted) -> Option<Vec<O>> {
618592 let orig_nodes_len = self.nodes.len();
619593 let mut node_rewrites: Vec<_> = self.node_rewrites.replace(vec![]);
620594 debug_assert!(node_rewrites.is_empty());
621595 node_rewrites.extend(0..orig_nodes_len);
622596 let mut dead_nodes = 0;
623- let mut removed_success_obligations : Vec<O> = vec![];
597+ let mut removed_done_obligations : Vec<O> = vec![];
624598
625599 // Move removable nodes to the end, preserving the order of the
626600 // remaining nodes.
@@ -632,19 +606,13 @@ impl<O: ForestObligation> ObligationForest<O> {
632606 for index in 0..orig_nodes_len {
633607 let node = &self.nodes[index];
634608 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 => {
642610 if dead_nodes > 0 {
643611 self.nodes.swap(index, index - dead_nodes);
644612 node_rewrites[index] -= dead_nodes;
645613 }
646614 }
647- NodeState::Success(_) => {
615+ NodeState::Done => {
648616 // This lookup can fail because the contents of
649617 // `self.active_cache` are not guaranteed to match those of
650618 // `self.nodes`. See the comment in `process_obligation`
@@ -658,7 +626,7 @@ impl<O: ForestObligation> ObligationForest<O> {
658626 }
659627 if do_completed == DoCompleted::Yes {
660628 // Extract the success stories.
661- removed_success_obligations .push(node.obligation.clone());
629+ removed_done_obligations .push(node.obligation.clone());
662630 }
663631 node_rewrites[index] = orig_nodes_len;
664632 dead_nodes += 1;
@@ -672,6 +640,7 @@ impl<O: ForestObligation> ObligationForest<O> {
672640 node_rewrites[index] = orig_nodes_len;
673641 dead_nodes += 1;
674642 }
643+ NodeState::Success => unreachable!(),
675644 }
676645 }
677646
@@ -684,7 +653,7 @@ impl<O: ForestObligation> ObligationForest<O> {
684653 node_rewrites.truncate(0);
685654 self.node_rewrites.replace(node_rewrites);
686655
687- if do_completed == DoCompleted::Yes { Some(removed_success_obligations ) } else { None }
656+ if do_completed == DoCompleted::Yes { Some(removed_done_obligations ) } else { None }
688657 }
689658
690659 fn apply_rewrites(&mut self, node_rewrites: &[usize]) {
0 commit comments