Skip to content

Commit

Permalink
fix: Mark obligation forest nodes as "Done" after cycle checking them
Browse files Browse the repository at this point in the history
This was lost in rust-lang#66405 , perhaps
due to the added `dep_index >= min_index` check which attempts to avoid
reprocessing in a different way. Unfortunately that does not cover the
case where a node points to a higher index which can in degenerate cases
where a lot of nodes point to a lot of higher indexed nodes end up with
`O(N ^ 2)` complexity. With this fix restored it is `O(N)` again since
nodes will never be reprocessed.
  • Loading branch information
Marwes committed Jan 3, 2020
1 parent 0a58f58 commit 981b928
Showing 1 changed file with 20 additions and 6 deletions.
26 changes: 20 additions & 6 deletions src/librustc_data_structures/obligation_forest/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -563,12 +563,26 @@ impl<O: ForestObligation> ObligationForest<O> {
P: ObligationProcessor<Obligation = O>,
{
let node = &self.nodes[index];
if node.state.get() == NodeState::Success {
match stack.iter().rposition(|&n| n == index) {
None => {
stack.push(index);
for &dep_index in node.dependents.iter() {
self.find_cycles_from_node(stack, processor, dep_index);
if let NodeState::Success(waiting) = node.state.get() {
if !self.is_still_waiting(waiting) {
match stack.iter().rposition(|&n| n == index) {
None => {
stack.push(index);
for &dep_index in node.dependents.iter() {
// The index check avoids re-considering a node.
if dep_index >= min_index {
self.find_cycles_from_node(stack, processor, min_index, dep_index);
}
}
stack.pop();
node.state.set(NodeState::Success(Self::not_waiting()));
}
Some(rpos) => {
// Cycle detected.
processor.process_backedge(
stack[rpos..].iter().map(GetObligation(&self.nodes)),
PhantomData,
);
}
stack.pop();
node.state.set(NodeState::Done);
Expand Down

0 comments on commit 981b928

Please sign in to comment.