prevent duplicate definitions

patterns that bind multiple symbols, like `{ x, y } = someDef` would insert the definition twice (once for x, once for y).
that can lead to problems in codegen, and means the work for this definition is done twice.

Now we use the region of the pattern as a key, to ensure the pattern and its associated expression is only processed once.
This commit is contained in:
Folkert 2020-01-12 01:20:09 +01:00
parent ceba17ed98
commit e5a9a016cd
3 changed files with 19 additions and 4 deletions

View file

@ -418,6 +418,15 @@ fn group_to_declaration(
result
};
// patterns like
//
// { x, y } = someDef
//
// Can Bind multiple symbols, when not incorrectly recursive (which is guaranteed in this function)
// normally `someDef` would be inserted twice. We use the region of the pattern as a unique key
// for a definition, so every definition is only inserted (thus typechecked, code-gen'd) once
let mut seen_pattern_regions: ImSet<Region> = ImSet::default();
for cycle in strongly_connected_components(&group, filtered_successors) {
if cycle.len() == 1 {
let symbol = &cycle[0];
@ -433,7 +442,10 @@ fn group_to_declaration(
new_def.loc_expr.value = Closure(fn_var, name, recursion, args, body);
}
declarations.push(Declare(new_def));
if !seen_pattern_regions.contains(&new_def.loc_pattern.region) {
declarations.push(Declare(new_def.clone()));
}
seen_pattern_regions.insert(new_def.loc_pattern.region);
}
} else {
// Topological sort gives us the reverse of the sorting we want!
@ -451,7 +463,10 @@ fn group_to_declaration(
new_def.loc_expr.value = Closure(fn_var, name, recursion, args, body);
}
can_defs.push(new_def);
if !seen_pattern_regions.contains(&new_def.loc_pattern.region) {
can_defs.push(new_def.clone());
}
seen_pattern_regions.insert(new_def.loc_pattern.region);
}
}
declarations.push(DeclareRec(can_defs));

View file

@ -3,7 +3,7 @@ use std::fmt;
/// TODO replace Located with this
pub type Loc<T> = Located<T>;
#[derive(Copy, Clone, Eq, PartialEq, PartialOrd, Ord)]
#[derive(Copy, Clone, Eq, PartialEq, PartialOrd, Ord, Hash)]
pub struct Region {
pub start_line: u32,
pub end_line: u32,

View file

@ -25,7 +25,7 @@ mod test_infer {
// and variables actually used in constraints
let (declared, used) = roc::types::variable_usage(&constraint);
if false && declared.flex_vars.len() + declared.rigid_vars.len() != used.len() {
if declared.flex_vars.len() + declared.rigid_vars.len() != used.len() {
dbg!(&constraint);
dbg!(expr);
println!("VARIABLE USAGE PROBLEM");