Store and use Variable in Let/LetRec

This commit is contained in:
Richard Feldman 2020-01-02 19:44:44 -05:00
parent dcf79c469f
commit be9f784eca
6 changed files with 44 additions and 25 deletions

View file

@ -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>) -> Expr {
fn decl_to_let(var_store: &VarStore, decl: Declaration, loc_ret: Located<Expr>) -> 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))
}

View file

@ -56,8 +56,8 @@ pub enum Expr {
loc_cond: Box<Located<Expr>>,
branches: Vec<(Located<Pattern>, Located<Expr>)>,
},
LetRec(Vec<Def>, Box<Located<Expr>>),
LetNonRec(Box<Def>, Box<Located<Expr>>),
LetRec(Vec<Def>, Box<Located<Expr>>, Variable),
LetNonRec(Box<Def>, Box<Located<Expr>>, Variable),
/// This is *only* for calling functions, not for tag application.
/// The Tag variant contains any applied values inside it.

View file

@ -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");

View file

@ -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()

View file

@ -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,

View file

@ -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)