diff --git a/src/can/def.rs b/src/can/def.rs index 9fb50f75fd..bd659f6ac4 100644 --- a/src/can/def.rs +++ b/src/can/def.rs @@ -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 = 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)); diff --git a/src/region.rs b/src/region.rs index f2d267df29..b94f0249b8 100644 --- a/src/region.rs +++ b/src/region.rs @@ -3,7 +3,7 @@ use std::fmt; /// TODO replace Located with this pub type Loc = Located; -#[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, diff --git a/tests/test_infer.rs b/tests/test_infer.rs index b177d1e49b..b0c96fd833 100644 --- a/tests/test_infer.rs +++ b/tests/test_infer.rs @@ -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");