diff --git a/src/can/def.rs b/src/can/def.rs index f8d3bc182b..d93b837e98 100644 --- a/src/can/def.rs +++ b/src/can/def.rs @@ -870,7 +870,7 @@ pub fn can_defs_with_return<'a>( for declaration in decls.into_iter().rev() { loc_expr = Located { region: Region::zero(), - value: decl_to_let(declaration, loc_expr), + value: decl_to_let(var_store, declaration, loc_expr), }; } @@ -880,10 +880,12 @@ pub fn can_defs_with_return<'a>( } } -fn decl_to_let(decl: Declaration, loc_ret: Located) -> Expr { +fn decl_to_let(var_store: &VarStore, decl: Declaration, loc_ret: Located) -> Expr { match decl { - Declaration::Declare(def) => Expr::LetNonRec(Box::new(def), Box::new(loc_ret)), - Declaration::DeclareRec(defs) => Expr::LetRec(defs, Box::new(loc_ret)), + Declaration::Declare(def) => { + Expr::LetNonRec(Box::new(def), Box::new(loc_ret), var_store.fresh()) + } + Declaration::DeclareRec(defs) => Expr::LetRec(defs, Box::new(loc_ret), var_store.fresh()), Declaration::InvalidCycle(symbols, regions) => { Expr::RuntimeError(RuntimeError::CircularDef(symbols, regions)) } diff --git a/src/can/expr.rs b/src/can/expr.rs index 5450996f1f..ebb82603c1 100644 --- a/src/can/expr.rs +++ b/src/can/expr.rs @@ -56,8 +56,8 @@ pub enum Expr { loc_cond: Box>, branches: Vec<(Located, Located)>, }, - LetRec(Vec, Box>), - LetNonRec(Box, Box>), + LetRec(Vec, Box>, Variable), + LetNonRec(Box, Box>, Variable), /// This is *only* for calling functions, not for tag application. /// The Tag variant contains any applied values inside it. diff --git a/src/constrain/expr.rs b/src/constrain/expr.rs index d4b6fff847..66c8f71fb0 100644 --- a/src/constrain/expr.rs +++ b/src/constrain/expr.rs @@ -393,17 +393,28 @@ pub fn constrain_expr( ), ) } - LetRec(defs, loc_ret) => constrain_defs_with_return( - rigids, - defs, - expected, - Info::with_capacity(defs.len()), - Info::with_capacity(defs.len()), - loc_ret, - ), - LetNonRec(def, loc_ret) => { - let body_con = constrain_expr(rigids, loc_ret.region, &loc_ret.value, expected); - constrain_def(rigids, &mut SendMap::default(), def, body_con) + LetRec(defs, loc_ret, var) => And(vec![ + constrain_defs_with_return( + rigids, + defs, + expected.clone(), + Info::with_capacity(defs.len()), + Info::with_capacity(defs.len()), + loc_ret, + ), + // Record the type of tne entire def-expression in the variable. + // Code gen will need that later! + Eq(Type::Variable(*var), expected, loc_ret.region), + ]), + LetNonRec(def, loc_ret, var) => { + let body_con = constrain_expr(rigids, loc_ret.region, &loc_ret.value, expected.clone()); + + And(vec![ + constrain_def(rigids, &mut SendMap::default(), def, body_con), + // Record the type of tne entire def-expression in the variable. + // Code gen will need that later! + Eq(Type::Variable(*var), expected, loc_ret.region), + ]) } Tag(_, _) => { panic!("TODO constrain Tag"); diff --git a/src/gen/mod.rs b/src/gen/mod.rs index 3fc5f3fb11..0b288394de 100644 --- a/src/gen/mod.rs +++ b/src/gen/mod.rs @@ -197,7 +197,7 @@ fn compile_expr<'ctx, 'env>( panic!("TODO support when-expressions of more than 2 branches."); } } - LetNonRec(ref def, ref loc_ret) => { + LetNonRec(ref def, ref loc_ret, _) => { match &def.loc_pattern.value { Pattern::Identifier(symbol) => { let expr = &def.loc_expr.value; @@ -241,8 +241,11 @@ fn content_from_expr(scope: &Scope<'_>, subs: &Subs, expr: &Expr) -> Content { use crate::can::expr::Expr::*; match expr { - Int(var, _) => subs.get_without_compacting(*var).content, - Float(var, _) => subs.get_without_compacting(*var).content, + Int(var, _) + | Float(var, _) + | When { expr_var: var, .. } + | LetNonRec(_, _, var) + | LetRec(_, _, var) => subs.get_without_compacting(*var).content, Str(_) | BlockStr(_) => Content::Structure(FlatType::Apply { module_name: "Str".into(), name: "Str".into(), @@ -253,7 +256,10 @@ fn content_from_expr(scope: &Scope<'_>, subs: &Subs, expr: &Expr) -> Content { .. } => { let (content, _) = scope.get(resolved_symbol).unwrap_or_else(|| { - panic!("Couldn't find {:?} in scope {:?}", resolved_symbol, scope) + panic!( + "Code gen problem: Couldn't find {:?} in scope {:?}", + resolved_symbol, scope + ) }); content.clone() diff --git a/src/uniqueness/mod.rs b/src/uniqueness/mod.rs index 25f8306e43..4e592951cc 100644 --- a/src/uniqueness/mod.rs +++ b/src/uniqueness/mod.rs @@ -474,11 +474,11 @@ pub fn canonicalize_expr( ), ) } - LetRec(defs, loc_ret) => ( + LetRec(defs, loc_ret, _) => ( Output::default(), can_defs(rigids, var_store, var_usage, defs, expected, loc_ret), ), - LetNonRec(def, loc_ret) => { + LetNonRec(def, loc_ret, _) => { let (_, body_con) = canonicalize_expr( rigids, var_store, diff --git a/tests/test_canonicalize.rs b/tests/test_canonicalize.rs index 695c53fde2..b43e665af6 100644 --- a/tests/test_canonicalize.rs +++ b/tests/test_canonicalize.rs @@ -262,14 +262,14 @@ mod test_canonicalize { fn get_closure(expr: &Expr, i: usize) -> roc::can::expr::Recursive { match expr { - LetRec(assignments, _) => match &assignments.get(i).map(|def| &def.loc_expr.value) { + LetRec(assignments, _, _) => match &assignments.get(i).map(|def| &def.loc_expr.value) { Some(Closure(_, recursion, _, _)) => recursion.clone(), Some(other @ _) => { panic!("assignment at {} is not a closure, but a {:?}", i, other) } None => panic!("Looking for assignment at {} but the list is too short", i), }, - LetNonRec(def, body) => { + LetNonRec(def, body, _) => { if i > 0 { // recurse in the body (not the def!) get_closure(&body.value, i - 1)