diff --git a/compiler/can/src/def.rs b/compiler/can/src/def.rs index cd7d5e2981..59b2c7c29d 100644 --- a/compiler/can/src/def.rs +++ b/compiler/can/src/def.rs @@ -192,17 +192,12 @@ fn sort_type_defs_before_introduction( } // find the strongly connected components and their relations - let nodes: Vec<_> = (0..capacity as u32).collect(); - - let mut output = Vec::with_capacity(capacity); - - for group in matrix.strongly_connected_components(&nodes).groups() { - for index in group.iter_ones() { - output.push(symbols[index]) - } - } - - output + matrix + .strongly_connected_components_all() + .groups() + .flat_map(|group| group.iter_ones()) + .map(|index| symbols[index]) + .collect() } #[inline(always)] @@ -790,14 +785,10 @@ pub(crate) fn sort_can_defs( }; } - let nodes: Vec<_> = (0..defs.len() as u32).collect(); - // We first perform SCC based on any reference, both variable usage and calls // considering both value definitions and function bodies. This will spot any // recursive relations between any 2 definitions. - let sccs = def_ordering - .references - .strongly_connected_components(&nodes); + let sccs = def_ordering.references.strongly_connected_components_all(); let mut declarations = Vec::new(); @@ -838,10 +829,9 @@ pub(crate) fn sort_can_defs( // boom = \{} -> boom {} // // In general we cannot spot faulty recursion (halting problem) so this is our best attempt - let nodes: Vec<_> = group.iter_ones().map(|v| v as u32).collect(); let direct_sccs = def_ordering .direct_references - .strongly_connected_components(&nodes); + .strongly_connected_components_subset(group); let declaration = if direct_sccs.groups().count() == 1 { // all defs are part of the same direct cycle, that is invalid! @@ -1571,8 +1561,7 @@ fn correct_mutual_recursive_type_alias<'a>( let mut solved_aliases = bitvec::vec::BitVec::::repeat(false, capacity); - let group: Vec<_> = (0u32..capacity as u32).collect(); - let sccs = matrix.strongly_connected_components(&group); + let sccs = matrix.strongly_connected_components_all(); // scratchpad to store aliases that are modified in the current iteration. // Only used when there is are more than one alias in a group. See below why diff --git a/compiler/can/src/reference_matrix.rs b/compiler/can/src/reference_matrix.rs index 13ba3caea2..cd06528109 100644 --- a/compiler/can/src/reference_matrix.rs +++ b/compiler/can/src/reference_matrix.rs @@ -129,8 +129,14 @@ impl ReferenceMatrix { TopologicalSort::Groups { groups } } - /// Get the strongly-connected components of the set of input nodes. - pub fn strongly_connected_components(&self, nodes: &[u32]) -> Sccs { + /// Get the strongly-connected components all nodes in the matrix + pub fn strongly_connected_components_all(&self) -> Sccs { + let bitvec = BitVec::repeat(true, self.length); + self.strongly_connected_components_subset(&bitvec) + } + + /// Get the strongly-connected components of a set of input nodes. + pub fn strongly_connected_components_subset(&self, nodes: &BitSlice) -> Sccs { let mut params = Params::new(self.length, nodes); 'outer: loop { @@ -176,15 +182,15 @@ struct Params { p: Vec, s: Vec, scc: Sccs, - scca: Vec, + scca: BitVec, } impl Params { - fn new(length: usize, group: &[u32]) -> Self { + fn new(length: usize, group: &BitSlice) -> Self { let mut preorders = vec![Preorder::Removed; length]; - for value in group { - preorders[*value as usize] = Preorder::Empty; + for index in group.iter_ones() { + preorders[index] = Preorder::Empty; } Self { @@ -196,7 +202,7 @@ impl Params { matrix: ReferenceMatrix::new(length), components: 0, }, - scca: Vec::new(), + scca: BitVec::repeat(false, length), } } } @@ -210,7 +216,7 @@ fn recurse_onto(length: usize, bitvec: &BitVec, v: usize, params: &mut Params) { params.p.push(v as u32); for w in bitvec[v * length..][..length].iter_ones() { - if !params.scca.contains(&(w as u32)) { + if !params.scca[w] { match params.preorders[w] { Preorder::Filled(pw) => loop { let index = *params.p.last().unwrap(); @@ -241,7 +247,7 @@ fn recurse_onto(length: usize, bitvec: &BitVec, v: usize, params: &mut Params) { .scc .matrix .set_row_col(params.scc.components, node as usize, true); - params.scca.push(node); + params.scca.set(node as usize, true); params.preorders[node as usize] = Preorder::Removed; if node as usize == v { break;