mirror of
https://github.com/roc-lang/roc.git
synced 2025-10-02 08:11:12 +00:00
Merge pull request #80 from rtfeldman/let-rec-style
"Let Rec" style def constraints
This commit is contained in:
commit
aaae923e59
7 changed files with 39 additions and 46 deletions
|
@ -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),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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.
|
||||||
|
|
12
src/solve.rs
12
src/solve.rs
|
@ -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));
|
||||||
}
|
}
|
||||||
|
|
10
src/subs.rs
10
src/subs.rs
|
@ -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)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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),
|
||||||
|
|
||||||
|
|
|
@ -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.
|
||||||
|
|
||||||
|
|
|
@ -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)
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue