Merge pull request #80 from rtfeldman/let-rec-style

"Let Rec" style def constraints
This commit is contained in:
Richard Feldman 2019-12-22 22:26:53 -08:00 committed by GitHub
commit aaae923e59
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
7 changed files with 39 additions and 46 deletions

View file

@ -937,37 +937,32 @@ pub fn can_defs_with_return<'a>(
output.rigids = output.rigids.union(found_rigids); output.rigids = output.rigids.union(found_rigids);
// Rigid constraint for the def expr as a whole // Rigid constraint for the def expr as a whole.
// This is a "LetRec" constraint; it supports recursion.
// (The only advantage of "Let" over "LetRec" is if you want to
// shadow things, and Roc disallows shadowing anyway.)
let constraint = Let(Box::new(LetConstraint { let constraint = Let(Box::new(LetConstraint {
rigid_vars: rigid_info.vars, rigid_vars: rigid_info.vars,
flex_vars: Vec::new(), flex_vars: Vec::new(),
def_types: rigid_info.def_types, def_types: rigid_info.def_types,
defs_constraint: defs_constraint: True,
// Flex constraint ret_constraint: Let(Box::new(LetConstraint {
Let(Box::new(LetConstraint {
rigid_vars: Vec::new(), rigid_vars: Vec::new(),
flex_vars: flex_info.vars, flex_vars: flex_info.vars,
def_types: flex_info.def_types.clone(), def_types: flex_info.def_types.clone(),
defs_constraint: defs_constraint: Let(Box::new(LetConstraint {
// Final flex constraints
Let(Box::new(LetConstraint {
rigid_vars: Vec::new(),
flex_vars: Vec::new(), flex_vars: Vec::new(),
rigid_vars: Vec::new(),
def_types: flex_info.def_types, def_types: flex_info.def_types,
defs_constraint: True, defs_constraint: True,
ret_constraint: And(flex_info.constraints) ret_constraint: And(flex_info.constraints),
})), })),
ret_constraint: And(vec![And(rigid_info.constraints), ret_con]) ret_constraint: And(vec![And(rigid_info.constraints), ret_con]),
})), })),
ret_constraint: True,
})); }));
match can_defs { match can_defs {
Ok(defs) => ( Ok(defs) => (Defs(defs, Box::new(ret_expr)), output, constraint),
Defs(var_store.fresh(), defs, Box::new(ret_expr)),
output,
constraint,
),
Err(err) => (RuntimeError(err), output, constraint), Err(err) => (RuntimeError(err), output, constraint),
} }
} }

View file

@ -74,7 +74,7 @@ pub enum Expr {
Box<Located<Expr>>, Box<Located<Expr>>,
Vec<(Located<Pattern>, Located<Expr>)>, Vec<(Located<Pattern>, Located<Expr>)>,
), ),
Defs(Variable, Vec<Def>, Box<Located<Expr>>), Defs(Vec<Def>, Box<Located<Expr>>),
/// This is *only* for calling functions, not for tag application. /// This is *only* for calling functions, not for tag application.
/// The Tag variant contains any applied values inside it. /// The Tag variant contains any applied values inside it.

View file

@ -75,7 +75,7 @@ pub fn run(
vars_by_symbol: vars_by_symbol.clone(), vars_by_symbol: vars_by_symbol.clone(),
mark: Mark::none().next(), mark: Mark::none().next(),
}; };
let rank = Rank::outermost(); let rank = Rank::toplevel();
solve( solve(
vars_by_symbol, vars_by_symbol,
@ -565,7 +565,7 @@ fn adjust_rank(
} else if mark == visit_mark { } else if mark == visit_mark {
desc.rank desc.rank
} else { } else {
let min_rank = desc.rank.min(group_rank); let min_rank = group_rank.min(desc.rank);
// TODO from elm-compiler: how can min_rank ever be group_rank? // TODO from elm-compiler: how can min_rank ever be group_rank?
desc.rank = min_rank; desc.rank = min_rank;
@ -593,7 +593,7 @@ fn adjust_rank_content(
Structure(flat_type) => { Structure(flat_type) => {
match flat_type { match flat_type {
Apply { args, .. } => { Apply { args, .. } => {
let mut rank = Rank::outermost(); let mut rank = Rank::toplevel();
for var in args { for var in args {
rank = rank.max(adjust_rank(subs, young_mark, visit_mark, group_rank, var)); rank = rank.max(adjust_rank(subs, young_mark, visit_mark, group_rank, var));
@ -614,7 +614,7 @@ fn adjust_rank_content(
EmptyRecord => { EmptyRecord => {
// from elm-compiler: THEORY: an empty record never needs to get generalized // from elm-compiler: THEORY: an empty record never needs to get generalized
Rank::outermost() Rank::toplevel()
} }
Record(fields, ext_var) => { Record(fields, ext_var) => {
@ -631,9 +631,9 @@ fn adjust_rank_content(
} }
Alias(_, _, args, _) => { Alias(_, _, args, _) => {
let mut rank = Rank::outermost(); let mut rank = Rank::toplevel();
// from elm-compiler: THEORY: anything in the real_var would be Rank::outermost() // from elm-compiler: THEORY: anything in the real_var would be Rank::toplevel()
for (_, var) in args { for (_, var) in args {
rank = rank.max(adjust_rank(subs, young_mark, visit_mark, group_rank, var)); rank = rank.max(adjust_rank(subs, young_mark, visit_mark, group_rank, var));
} }

View file

@ -279,7 +279,7 @@ impl Rank {
Rank(0) Rank(0)
} }
pub fn outermost() -> Self { pub fn toplevel() -> Self {
Rank(1) Rank(1)
} }
@ -300,13 +300,7 @@ impl fmt::Display for Rank {
impl fmt::Debug for Rank { impl fmt::Debug for Rank {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
if self == &Rank::none() { self.0.fmt(f)
write!(f, "none")
} else if self == &Rank::outermost() {
write!(f, "outermost")
} else {
write!(f, "Rank({})", self.0)
}
} }
} }

View file

@ -46,6 +46,8 @@ impl fmt::Debug for Type {
match self { match self {
Type::EmptyRec => write!(f, "{{}}"), Type::EmptyRec => write!(f, "{{}}"),
Type::Function(args, ret) => { Type::Function(args, ret) => {
write!(f, "Fn(")?;
for (index, arg) in args.iter().enumerate() { for (index, arg) in args.iter().enumerate() {
if index > 0 { if index > 0 {
", ".fmt(f)?; ", ".fmt(f)?;
@ -56,7 +58,9 @@ impl fmt::Debug for Type {
write!(f, " -> ")?; write!(f, " -> ")?;
ret.fmt(f) ret.fmt(f)?;
write!(f, ")")
} }
Type::Variable(var) => write!(f, "<{:?}>", var), Type::Variable(var) => write!(f, "<{:?}>", var),

View file

@ -385,7 +385,7 @@ pub fn canonicalize_expr(
) )
} }
Defs(_, defs, loc_ret) => { Defs(defs, loc_ret) => {
// The body expression gets a new scope for canonicalization, // The body expression gets a new scope for canonicalization,
// so clone it. // so clone it.

View file

@ -232,7 +232,7 @@ mod test_canonicalize {
fn get_closure(expr: &Expr, i: usize) -> roc::can::expr::Recursive { fn get_closure(expr: &Expr, i: usize) -> roc::can::expr::Recursive {
match expr { match expr {
Defs(_, assignments, _) => match &assignments.get(i).map(|def| &def.expr.value) { Defs(assignments, _) => match &assignments.get(i).map(|def| &def.expr.value) {
Some(Closure(_, recursion, _, _)) => recursion.clone(), Some(Closure(_, recursion, _, _)) => recursion.clone(),
Some(other @ _) => { Some(other @ _) => {
panic!("assignment at {} is not a closure, but a {:?}", i, other) panic!("assignment at {} is not a closure, but a {:?}", i, other)