diff --git a/compiler/can/src/def.rs b/compiler/can/src/def.rs index 79f71f6608..4e9b349f7b 100644 --- a/compiler/can/src/def.rs +++ b/compiler/can/src/def.rs @@ -148,7 +148,7 @@ pub fn canonicalize_defs<'a>( // Any time we have an Annotation followed immediately by a Body, // check to see if their patterns are equivalent. If they are, // turn it into a TypedBody. Otherwise, give an error. - let pending_def = match &loc_def.value { + let (new_output, pending_def) = match &loc_def.value { Annotation(pattern, annotation) | Nested(Annotation(pattern, annotation)) => { match iter.peek() { Some(Located { @@ -189,6 +189,8 @@ pub fn canonicalize_defs<'a>( _ => to_pending_def(env, var_store, &loc_def.value, &mut scope, pattern_type), }; + output.union(new_output); + // Record the ast::Expr for later. We'll do another pass through these // once we have the entire scope assembled. If we were to canonicalize // the exprs right now, they wouldn't have symbols in scope from defs @@ -212,8 +214,8 @@ pub fn canonicalize_defs<'a>( let mut can_vars: Vec> = Vec::with_capacity(vars.len()); - let mut is_phantom = false; + for loc_lowercase in vars { if let Some(var) = can_ann .introduced_variables @@ -1288,13 +1290,13 @@ fn to_pending_def<'a>( def: &'a ast::Def<'a>, scope: &mut Scope, pattern_type: PatternType, -) -> PendingDef<'a> { +) -> (Output, PendingDef<'a>) { use roc_parse::ast::Def::*; match def { Annotation(loc_pattern, loc_ann) => { // This takes care of checking for shadowing and adding idents to scope. - let loc_can_pattern = canonicalize_pattern( + let (output, loc_can_pattern) = canonicalize_pattern( env, var_store, scope, @@ -1303,11 +1305,14 @@ fn to_pending_def<'a>( loc_pattern.region, ); - PendingDef::AnnotationOnly(loc_pattern, loc_can_pattern, loc_ann) + ( + output, + PendingDef::AnnotationOnly(loc_pattern, loc_can_pattern, loc_ann), + ) } Body(loc_pattern, loc_expr) => { // This takes care of checking for shadowing and adding idents to scope. - let loc_can_pattern = canonicalize_pattern( + let (output, loc_can_pattern) = canonicalize_pattern( env, var_store, scope, @@ -1316,7 +1321,10 @@ fn to_pending_def<'a>( loc_pattern.region, ); - PendingDef::Body(loc_pattern, loc_can_pattern, loc_expr) + ( + output, + PendingDef::Body(loc_pattern, loc_can_pattern, loc_expr), + ) } TypedBody(loc_pattern, loc_ann, loc_expr) => pending_typed_body( env, @@ -1358,19 +1366,22 @@ fn to_pending_def<'a>( region: loc_var.region, }); - return PendingDef::InvalidAlias; + return (Output::default(), PendingDef::InvalidAlias); } } } - PendingDef::Alias { - name: Located { - region: name.region, - value: symbol, + ( + Output::default(), + PendingDef::Alias { + name: Located { + region: name.region, + value: symbol, + }, + vars: can_rigids, + ann, }, - vars: can_rigids, - ann, - } + ) } Err((original_region, loc_shadowed_symbol)) => { @@ -1379,7 +1390,7 @@ fn to_pending_def<'a>( shadow: loc_shadowed_symbol, }); - PendingDef::InvalidAlias + (Output::default(), PendingDef::InvalidAlias) } } } @@ -1398,9 +1409,9 @@ fn pending_typed_body<'a>( var_store: &mut VarStore, scope: &mut Scope, pattern_type: PatternType, -) -> PendingDef<'a> { +) -> (Output, PendingDef<'a>) { // This takes care of checking for shadowing and adding idents to scope. - let loc_can_pattern = canonicalize_pattern( + let (output, loc_can_pattern) = canonicalize_pattern( env, var_store, scope, @@ -1409,7 +1420,10 @@ fn pending_typed_body<'a>( loc_pattern.region, ); - PendingDef::TypedBody(loc_pattern, loc_can_pattern, loc_ann, loc_expr) + ( + output, + PendingDef::TypedBody(loc_pattern, loc_can_pattern, loc_ann, loc_expr), + ) } /// Make aliases recursive diff --git a/compiler/can/src/expr.rs b/compiler/can/src/expr.rs index 21e031270d..ea14a43040 100644 --- a/compiler/can/src/expr.rs +++ b/compiler/can/src/expr.rs @@ -427,9 +427,10 @@ pub fn canonicalize_expr<'a>( let original_scope = scope; let mut scope = original_scope.clone(); let mut can_args = Vec::with_capacity(loc_arg_patterns.len()); + let mut output = Output::default(); for loc_pattern in loc_arg_patterns.into_iter() { - let can_arg = canonicalize_pattern( + let (new_output, can_arg) = canonicalize_pattern( env, var_store, &mut scope, @@ -438,16 +439,21 @@ pub fn canonicalize_expr<'a>( loc_pattern.region, ); + output.union(new_output); + can_args.push((var_store.fresh(), can_arg)); } - let (loc_body_expr, mut output) = canonicalize_expr( + let (loc_body_expr, new_output) = canonicalize_expr( env, var_store, &mut scope, loc_body_expr.region, &loc_body_expr.value, ); + + output.union(new_output); + // Now that we've collected all the references, check to see if any of the args we defined // went unreferenced. If any did, report them as unused arguments. for (sub_symbol, region) in scope.symbols() { @@ -713,14 +719,18 @@ fn canonicalize_when_branch<'a>( // TODO report symbols not bound in all patterns for loc_pattern in &branch.patterns { - patterns.push(canonicalize_pattern( + let (new_output, can_pattern) = canonicalize_pattern( env, var_store, &mut scope, WhenBranch, &loc_pattern.value, loc_pattern.region, - )); + ); + + output.union(new_output); + + patterns.push(can_pattern); } let (value, mut branch_output) = canonicalize_expr( diff --git a/compiler/can/src/pattern.rs b/compiler/can/src/pattern.rs index f1978acefd..70dbae9c67 100644 --- a/compiler/can/src/pattern.rs +++ b/compiler/can/src/pattern.rs @@ -1,5 +1,5 @@ use crate::env::Env; -use crate::expr::{canonicalize_expr, Expr}; +use crate::expr::{canonicalize_expr, Expr, Output}; use crate::num::{finish_parsing_base, finish_parsing_float, finish_parsing_int}; use crate::scope::Scope; use roc_module::ident::{Ident, Lowercase, TagName}; @@ -100,10 +100,11 @@ pub fn canonicalize_pattern<'a>( pattern_type: PatternType, pattern: &ast::Pattern<'a>, region: Region, -) -> Located { +) -> (Output, Located) { use roc_parse::ast::Pattern::*; use PatternType::*; + let mut output = Output::default(); let can_pattern = match pattern { Identifier(name) => match scope.introduce( (*name).into(), @@ -154,17 +155,18 @@ pub fn canonicalize_pattern<'a>( let mut can_patterns = Vec::with_capacity(patterns.len()); for loc_pattern in *patterns { - can_patterns.push(( - var_store.fresh(), - canonicalize_pattern( - env, - var_store, - scope, - pattern_type, - &loc_pattern.value, - loc_pattern.region, - ), - )); + let (new_output, can_pattern) = canonicalize_pattern( + env, + var_store, + scope, + pattern_type, + &loc_pattern.value, + loc_pattern.region, + ); + + output.union(new_output); + + can_patterns.push((var_store.fresh(), can_pattern)); } Pattern::AppliedTag { @@ -283,7 +285,7 @@ pub fn canonicalize_pattern<'a>( RequiredField(label, loc_guard) => { // a guard does not introduce the label into scope! let symbol = scope.ignore(label.into(), &mut env.ident_ids); - let can_guard = canonicalize_pattern( + let (new_output, can_guard) = canonicalize_pattern( env, var_store, scope, @@ -292,6 +294,8 @@ pub fn canonicalize_pattern<'a>( loc_guard.region, ); + output.union(new_output); + destructs.push(Located { region: loc_pattern.region, value: RecordDestruct { @@ -311,8 +315,7 @@ pub fn canonicalize_pattern<'a>( region, ) { Ok(symbol) => { - // TODO use output? - let (can_default, _output) = canonicalize_expr( + let (can_default, expr_output) = canonicalize_expr( env, var_store, scope, @@ -320,6 +323,8 @@ pub fn canonicalize_pattern<'a>( &loc_default.value, ); + output.union(expr_output); + destructs.push(Located { region: loc_pattern.region, value: RecordDestruct { @@ -375,10 +380,13 @@ pub fn canonicalize_pattern<'a>( } }; - Located { - region, - value: can_pattern, - } + ( + output, + Located { + region, + value: can_pattern, + }, + ) } /// When we detect an unsupported pattern type (e.g. 5 = 1 + 2 is unsupported because you can't