use custom type for TopologicalSort result

This commit is contained in:
Folkert 2022-04-22 19:28:46 +02:00
parent 48ce1c14bf
commit 28cb9bf36e
No known key found for this signature in database
GPG key ID: 1F17F6FFD112B97C
2 changed files with 32 additions and 8 deletions

View file

@ -8,6 +8,7 @@ use crate::expr::{canonicalize_expr, Output, Recursive};
use crate::pattern::{bindings_from_patterns, canonicalize_def_header_pattern, Pattern}; use crate::pattern::{bindings_from_patterns, canonicalize_def_header_pattern, Pattern};
use crate::procedure::References; use crate::procedure::References;
use crate::reference_matrix::ReferenceMatrix; use crate::reference_matrix::ReferenceMatrix;
use crate::reference_matrix::TopologicalSort;
use crate::scope::create_alias; use crate::scope::create_alias;
use crate::scope::Scope; use crate::scope::Scope;
use roc_collections::{default_hasher, ImEntry, ImMap, ImSet, MutMap, MutSet, SendMap}; use roc_collections::{default_hasher, ImEntry, ImMap, ImSet, MutMap, MutSet, SendMap};
@ -812,7 +813,7 @@ pub fn sort_can_defs(
// TODO also do the same `addDirects` check elm/compiler does, so we can // TODO also do the same `addDirects` check elm/compiler does, so we can
// report an error if a recursive definition can't possibly terminate! // report an error if a recursive definition can't possibly terminate!
match def_ids.references.topological_sort_into_groups() { match def_ids.references.topological_sort_into_groups() {
Ok(groups) => { TopologicalSort::Groups { groups } => {
let mut declarations = Vec::new(); let mut declarations = Vec::new();
// groups are in reversed order // groups are in reversed order
@ -828,7 +829,10 @@ pub fn sort_can_defs(
(Ok(declarations), output) (Ok(declarations), output)
} }
Err((mut groups, nodes_in_cycle)) => { TopologicalSort::HasCycles {
mut groups,
nodes_in_cycle,
} => {
let mut declarations = Vec::new(); let mut declarations = Vec::new();
let mut problems = Vec::new(); let mut problems = Vec::new();

View file

@ -50,13 +50,12 @@ impl ReferenceMatrix {
// //
// Thank you, Samuel! // Thank you, Samuel!
impl ReferenceMatrix { impl ReferenceMatrix {
#[allow(clippy::type_complexity)] pub fn topological_sort_into_groups(&self) -> TopologicalSort {
pub fn topological_sort_into_groups(&self) -> Result<Vec<Vec<u32>>, (Vec<Vec<u32>>, Vec<u32>)> {
let length = self.length; let length = self.length;
let bitvec = &self.bitvec; let bitvec = &self.bitvec;
if length == 0 { if length == 0 {
return Ok(Vec::new()); return TopologicalSort::Groups { groups: Vec::new() };
} }
let mut preds_map: Vec<i64> = vec![0; length]; let mut preds_map: Vec<i64> = vec![0; length];
@ -85,7 +84,11 @@ impl ReferenceMatrix {
if prev_group.is_empty() { if prev_group.is_empty() {
let remaining: Vec<u32> = (0u32..length as u32).collect(); let remaining: Vec<u32> = (0u32..length as u32).collect();
return Err((Vec::new(), remaining));
return TopologicalSort::HasCycles {
groups: Vec::new(),
nodes_in_cycle: remaining,
};
} }
while preds_map.iter().any(|x| *x > 0) { while preds_map.iter().any(|x| *x > 0) {
@ -114,12 +117,16 @@ impl ReferenceMatrix {
let remaining: Vec<u32> = (0u32..length as u32) let remaining: Vec<u32> = (0u32..length as u32)
.filter(|i| preds_map[*i as usize] > 0) .filter(|i| preds_map[*i as usize] > 0)
.collect(); .collect();
return Err((groups, remaining));
return TopologicalSort::HasCycles {
groups,
nodes_in_cycle: remaining,
};
} }
} }
groups.push(prev_group); groups.push(prev_group);
Ok(groups) TopologicalSort::Groups { groups }
} }
pub fn strongly_connected_components(&self, group: &[u32]) -> Vec<Vec<u32>> { pub fn strongly_connected_components(&self, group: &[u32]) -> Vec<Vec<u32>> {
@ -141,6 +148,19 @@ impl ReferenceMatrix {
} }
} }
pub(crate) enum TopologicalSort {
/// There were no cycles, all nodes have been partitioned into groups
Groups { groups: Vec<Vec<u32>> },
/// Cycles were found. All nodes that are not part of a cycle have been partitioned
/// into groups. The other elements are in the `cyclic` vector. However, there may be
/// many cycles, or just one big one. Use strongly-connected components to find out
/// exactly what the cycles are and how they fit into the groups.
HasCycles {
groups: Vec<Vec<u32>>,
nodes_in_cycle: Vec<u32>,
},
}
#[derive(Clone, Copy)] #[derive(Clone, Copy)]
enum Preorder { enum Preorder {
Empty, Empty,