properly sort recursive definitions

This commit is contained in:
Folkert 2020-11-12 00:32:45 +01:00
parent 21685b6f8f
commit 55b26277ca

View file

@ -292,8 +292,8 @@ pub fn canonicalize_defs<'a>(
} }
#[inline(always)] #[inline(always)]
pub fn sort_can_defs( pub fn sort_can_defs<'a>(
env: &mut Env<'_>, env: &mut Env<'a>,
defs: CanDefs, defs: CanDefs,
mut output: Output, mut output: Output,
) -> (Result<Vec<Declaration>, RuntimeError>, Output) { ) -> (Result<Vec<Declaration>, RuntimeError>, Output) {
@ -470,14 +470,17 @@ 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 topological_sort_into_groups(defined_symbols.as_slice(), all_successors_without_self) { match ven_graph::topological_sort_into_groups(
defined_symbols.as_slice(),
all_successors_without_self,
) {
Ok(groups) => { Ok(groups) => {
let mut declarations = Vec::new(); let mut declarations = Vec::new();
// groups are in reversed order // groups are in reversed order
for group in groups.into_iter().rev() { for group in groups.into_iter().rev() {
group_to_declaration( group_to_declaration(
group, &group,
&env.closures, &env.closures,
&mut all_successors_with_self, &mut all_successors_with_self,
&can_defs_by_symbol, &can_defs_by_symbol,
@ -487,21 +490,10 @@ pub fn sort_can_defs(
(Ok(declarations), output) (Ok(declarations), output)
} }
Err((groups, nodes_in_cycle)) => { Err((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();
// groups are in reversed order
for group in groups.into_iter().rev() {
group_to_declaration(
group,
&env.closures,
&mut all_successors_with_self,
&can_defs_by_symbol,
&mut declarations,
);
}
// nodes_in_cycle are symbols that form a syntactic cycle. That isn't always a problem, // nodes_in_cycle are symbols that form a syntactic cycle. That isn't always a problem,
// and in general it's impossible to decide whether it is. So we use a crude heuristic: // and in general it's impossible to decide whether it is. So we use a crude heuristic:
// //
@ -571,8 +563,50 @@ pub fn sort_can_defs(
declarations.push(Declaration::InvalidCycle(symbols_in_cycle, regions)); declarations.push(Declaration::InvalidCycle(symbols_in_cycle, regions));
} else { } else {
// slightly inefficient, because we know this becomes exactly one DeclareRec already // slightly inefficient, because we know this becomes exactly one DeclareRec already
groups.push(cycle);
}
}
// now we have a collection of groups whose dependencies are not cyclic.
// They are however not yet topologically sorted. Here we have to get a bit
// creative to get all the definitions in the correct sorted order.
let mut group_ids = Vec::with_capacity(groups.len());
let mut symbol_to_group_index = MutMap::default();
for (i, group) in groups.iter().enumerate() {
for symbol in group {
symbol_to_group_index.insert(*symbol, i);
}
group_ids.push(i);
}
let successors_of_group = |group_id: &usize| {
let mut result = ImSet::default();
// for each symbol in this group
for symbol in &groups[*group_id] {
// find its successors
for succ in all_successors_without_self(symbol) {
// and add its group to the result
result.insert(symbol_to_group_index[&succ]);
}
}
// don't introduce any cycles to self
result.remove(group_id);
result
};
match ven_graph::topological_sort_into_groups(&group_ids, successors_of_group) {
Ok(sorted_group_ids) => {
for sorted_group in sorted_group_ids.iter().rev() {
for group_id in sorted_group.iter().rev() {
let group = &groups[*group_id];
group_to_declaration( group_to_declaration(
cycle, group,
&env.closures, &env.closures,
&mut all_successors_with_self, &mut all_successors_with_self,
&can_defs_by_symbol, &can_defs_by_symbol,
@ -580,6 +614,9 @@ pub fn sort_can_defs(
); );
} }
} }
}
Err(_) => unreachable!("there should be no cycles now!"),
}
for problem in problems { for problem in problems {
env.problem(problem); env.problem(problem);
@ -591,7 +628,7 @@ pub fn sort_can_defs(
} }
fn group_to_declaration( fn group_to_declaration(
group: Vec<Symbol>, group: &[Symbol],
closures: &MutMap<Symbol, References>, closures: &MutMap<Symbol, References>,
successors: &mut dyn FnMut(&Symbol) -> ImSet<Symbol>, successors: &mut dyn FnMut(&Symbol) -> ImSet<Symbol>,
can_defs_by_symbol: &MutMap<Symbol, Def>, can_defs_by_symbol: &MutMap<Symbol, Def>,