fix(tsort): correct minimal cycle reporting and precise back-edge removal with iterative DFS (#8786)

- Implement iterative DFS to prevent stack overflows (from PR #8737)
- Fix minimal cycle reporting to show only actual cycle nodes
- Remove redundant back-edge from last cycle node to first
- Update test expectations for corrected cycle handling
This commit is contained in:
Cả thế giới là Rust
2025-11-07 23:48:11 +01:00
committed by GitHub
parent 477b37ad06
commit adcfcfaf68
3 changed files with 4 additions and 8 deletions
+2 -6
View File
@@ -236,8 +236,8 @@ impl<'input> Graph<'input> {
for &node in &cycle {
show!(LoopNode(node));
}
let u = cycle[0];
let v = cycle[1];
let u = *cycle.last().expect("cycle must be non-empty");
let v = cycle[0];
self.remove_edge(u, v);
if self.indegree(v).unwrap() == 0 {
frontier.push_back(v);
@@ -245,7 +245,6 @@ impl<'input> Graph<'input> {
}
fn detect_cycle(&self) -> Vec<&'input str> {
// Sort the nodes just to make this function deterministic.
let mut nodes: Vec<_> = self.nodes.keys().collect();
nodes.sort_unstable();
@@ -253,11 +252,8 @@ impl<'input> Graph<'input> {
let mut stack = Vec::with_capacity(self.nodes.len());
for node in nodes {
if self.dfs(node, &mut visited, &mut stack) {
// last element in the stack appears twice: at the begin
// and at the end of the loop
let (loop_entry, _) = stack.pop().expect("loop is not empty");
// skip the prefix which doesn't belong to the loop
return stack
.into_iter()
.map(|(node, _)| node)
Executable
BIN
View File
Binary file not shown.
+2 -2
View File
@@ -103,7 +103,7 @@ fn test_cycle() {
new_ucmd!()
.pipe_in("a b b c c d c b")
.fails_with_code(1)
.stdout_is("a\nc\nd\nb\n")
.stdout_is("a\nb\nc\nd\n")
.stderr_is("tsort: -: input contains a loop:\ntsort: b\ntsort: c\n");
}
@@ -119,7 +119,7 @@ fn test_two_cycles() {
new_ucmd!()
.pipe_in("a b b c c b b d d b")
.fails_with_code(1)
.stdout_is("a\nc\nd\nb\n")
.stdout_is("a\nb\nc\nd\n")
.stderr_is("tsort: -: input contains a loop:\ntsort: b\ntsort: c\ntsort: -: input contains a loop:\ntsort: b\ntsort: d\n");
}