use topo_sort to correct acyclic_term (#2124, #2125)

This commit is contained in:
Mark
2023-10-18 11:58:04 -06:00
parent 43f0b6c28d
commit bf46c4b5c1
6 changed files with 151 additions and 199 deletions

View File

@@ -1131,6 +1131,8 @@ impl MachineState {
#[inline]
pub fn is_cyclic_term(&mut self, value: HeapCellValue) -> bool {
use topo_sort::TopoSort;
let value = self.store(self.deref(value));
if value.is_constant() || value.is_stack_var() {
@@ -1140,17 +1142,52 @@ impl MachineState {
let h = self.heap.len();
self.heap.push(value);
let found_cycle = {
let found_cycle = (|| {
let mut topo_graph = TopoSort::new();
let mut iter = cycle_detecting_stackless_preorder_iter(&mut self.heap, h);
while let Some(_) = iter.next() {
if iter.found_cycle() {
while let Some(cell) = iter.next() {
let focus = iter.focus();
read_heap_cell!(cell,
(HeapCellValueTag::Atom, (_name, arity)) => {
if arity > 0 {
// focus is actually the location of Str(s) here.
let s = iter.current() - arity;
topo_graph.insert(focus, vec![s]);
topo_graph.insert(s, (s + 1 .. s + arity + 1).collect::<Vec<_>>());
}
}
(HeapCellValueTag::Str, s) => {
topo_graph.insert(focus, vec![s]);
}
(HeapCellValueTag::Lis | HeapCellValueTag::PStrLoc | HeapCellValueTag::PStrOffset, l) => {
if l <= focus && focus < l + 2 {
// TopoSort doesn't consider focus ->
// focus to induce a cycle so in this case
// it must be checked manually.
return true;
}
topo_graph.insert(focus, (l .. l + 2).collect::<Vec<_>>());
}
(HeapCellValueTag::AttrVar | HeapCellValueTag::Var, h) => {
if focus != h {
topo_graph.insert(focus, vec![h]);
}
}
_ => {
}
);
if topo_graph.cycle_detected() {
break;
}
}
iter.found_cycle()
};
topo_graph.cycle_detected()
})();
self.heap.pop();
found_cycle