about summary refs log tree commit diff
path: root/compiler/rustc_data_structures
diff options
context:
space:
mode:
authorJoshua Nelson <jnelson@cloudflare.com>2022-09-19 20:45:00 -0500
committerJoshua Nelson <jnelson@cloudflare.com>2022-09-19 22:14:40 -0500
commit1512ce5925eeafc01f011c46216c157e4e5644cb (patch)
tree60e16916a82a26a1635edc0db527588a5c76d286 /compiler/rustc_data_structures
parent749dec64519b5bdfe688cb945eeee5afd6ab68d0 (diff)
downloadrust-1512ce5925eeafc01f011c46216c157e4e5644cb.tar.gz
rust-1512ce5925eeafc01f011c46216c157e4e5644cb.zip
Make cycle errors recoverable
In particular, this allows rustdoc to recover from cycle errors when normalizing associated types for documentation.

In the past, `@jackh726` has said we need to be careful about overflow errors:

> Off the top of my head, we definitely should be careful about treating overflow errors the same as
"not implemented for some reason" errors. Otherwise, you could end up with behavior that is
different depending on recursion depth. But, that might be context-dependent.

But cycle errors should be safe to unconditionally report; they don't depend on the recursion depth, they will always be an error whenever they're encountered.
Diffstat (limited to 'compiler/rustc_data_structures')
-rw-r--r--compiler/rustc_data_structures/src/obligation_forest/mod.rs33
-rw-r--r--compiler/rustc_data_structures/src/obligation_forest/tests.rs7
2 files changed, 28 insertions, 12 deletions
diff --git a/compiler/rustc_data_structures/src/obligation_forest/mod.rs b/compiler/rustc_data_structures/src/obligation_forest/mod.rs
index f2d72647a66..10e673cd929 100644
--- a/compiler/rustc_data_structures/src/obligation_forest/mod.rs
+++ b/compiler/rustc_data_structures/src/obligation_forest/mod.rs
@@ -115,7 +115,11 @@ pub trait ObligationProcessor {
     /// In other words, if we had O1 which required O2 which required
     /// O3 which required O1, we would give an iterator yielding O1,
     /// O2, O3 (O1 is not yielded twice).
-    fn process_backedge<'c, I>(&mut self, cycle: I, _marker: PhantomData<&'c Self::Obligation>)
+    fn process_backedge<'c, I>(
+        &mut self,
+        cycle: I,
+        _marker: PhantomData<&'c Self::Obligation>,
+    ) -> Result<(), Self::Error>
     where
         I: Clone + Iterator<Item = &'c Self::Obligation>;
 }
@@ -406,12 +410,11 @@ impl<O: ForestObligation> ObligationForest<O> {
 
     /// Performs a fixpoint computation over the obligation list.
     #[inline(never)]
-    pub fn process_obligations<P, OUT>(&mut self, processor: &mut P) -> OUT
+    pub fn process_obligations<P>(&mut self, processor: &mut P) -> P::OUT
     where
         P: ObligationProcessor<Obligation = O>,
-        OUT: OutcomeTrait<Obligation = O, Error = Error<O, P::Error>>,
     {
-        let mut outcome = OUT::new();
+        let mut outcome = P::OUT::new();
 
         // Fixpoint computation: we repeat until the inner loop stalls.
         loop {
@@ -477,7 +480,7 @@ impl<O: ForestObligation> ObligationForest<O> {
             }
 
             self.mark_successes();
-            self.process_cycles(processor);
+            self.process_cycles(processor, &mut outcome);
             self.compress(|obl| outcome.record_completed(obl));
         }
 
@@ -562,7 +565,7 @@ impl<O: ForestObligation> ObligationForest<O> {
 
     /// Report cycles between all `Success` nodes, and convert all `Success`
     /// nodes to `Done`. This must be called after `mark_successes`.
-    fn process_cycles<P>(&mut self, processor: &mut P)
+    fn process_cycles<P>(&mut self, processor: &mut P, outcome: &mut P::OUT)
     where
         P: ObligationProcessor<Obligation = O>,
     {
@@ -572,7 +575,7 @@ impl<O: ForestObligation> ObligationForest<O> {
             // to handle the no-op cases immediately to avoid the cost of the
             // function call.
             if node.state.get() == NodeState::Success {
-                self.find_cycles_from_node(&mut stack, processor, index);
+                self.find_cycles_from_node(&mut stack, processor, index, outcome);
             }
         }
 
@@ -580,8 +583,13 @@ impl<O: ForestObligation> ObligationForest<O> {
         self.reused_node_vec = stack;
     }
 
-    fn find_cycles_from_node<P>(&self, stack: &mut Vec<usize>, processor: &mut P, index: usize)
-    where
+    fn find_cycles_from_node<P>(
+        &self,
+        stack: &mut Vec<usize>,
+        processor: &mut P,
+        index: usize,
+        outcome: &mut P::OUT,
+    ) where
         P: ObligationProcessor<Obligation = O>,
     {
         let node = &self.nodes[index];
@@ -590,17 +598,20 @@ impl<O: ForestObligation> ObligationForest<O> {
                 None => {
                     stack.push(index);
                     for &dep_index in node.dependents.iter() {
-                        self.find_cycles_from_node(stack, processor, dep_index);
+                        self.find_cycles_from_node(stack, processor, dep_index, outcome);
                     }
                     stack.pop();
                     node.state.set(NodeState::Done);
                 }
                 Some(rpos) => {
                     // Cycle detected.
-                    processor.process_backedge(
+                    let result = processor.process_backedge(
                         stack[rpos..].iter().map(|&i| &self.nodes[i].obligation),
                         PhantomData,
                     );
+                    if let Err(err) = result {
+                        outcome.record_error(Error { error: err, backtrace: self.error_at(index) });
+                    }
                 }
             }
         }
diff --git a/compiler/rustc_data_structures/src/obligation_forest/tests.rs b/compiler/rustc_data_structures/src/obligation_forest/tests.rs
index f2a04796691..bc252f772a1 100644
--- a/compiler/rustc_data_structures/src/obligation_forest/tests.rs
+++ b/compiler/rustc_data_structures/src/obligation_forest/tests.rs
@@ -77,10 +77,15 @@ where
         (self.process_obligation)(obligation)
     }
 
-    fn process_backedge<'c, I>(&mut self, _cycle: I, _marker: PhantomData<&'c Self::Obligation>)
+    fn process_backedge<'c, I>(
+        &mut self,
+        _cycle: I,
+        _marker: PhantomData<&'c Self::Obligation>,
+    ) -> Result<(), Self::Error>
     where
         I: Clone + Iterator<Item = &'c Self::Obligation>,
     {
+        Ok(())
     }
 }