mirror of
https://github.com/roc-lang/roc.git
synced 2025-10-04 00:54:36 +00:00
Fix bug with inferring functions in Let
This commit is contained in:
parent
10631d0dd0
commit
c2f3f6c789
3 changed files with 35 additions and 22 deletions
|
@ -38,16 +38,17 @@ pub fn constrain(
|
||||||
List(elems) => { list(elems, bound_vars, subs, expected, region) },
|
List(elems) => { list(elems, bound_vars, subs, expected, region) },
|
||||||
Var(symbol) => Lookup(symbol, expected, region),
|
Var(symbol) => Lookup(symbol, expected, region),
|
||||||
Assign(assignments, ret_expr) => {
|
Assign(assignments, ret_expr) => {
|
||||||
|
let ret_con = constrain(bound_vars, subs, *ret_expr, expected);
|
||||||
|
|
||||||
if assignments.len() > 1 {
|
if assignments.len() > 1 {
|
||||||
panic!("TODO can't handle multiple assignments yet");
|
panic!("TODO can't handle multiple assignments yet");
|
||||||
} else {
|
|
||||||
let ret_con = constrain(bound_vars, subs, *ret_expr, expected);
|
|
||||||
let (loc_pattern, loc_expr) = assignments.first().unwrap_or_else(|| {
|
|
||||||
panic!("assignments.first() failed")
|
|
||||||
});
|
|
||||||
|
|
||||||
constrain_def(loc_pattern.clone(), loc_expr.clone(), bound_vars, subs, ret_con)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for (loc_pattern, loc_expr) in assignments {
|
||||||
|
return constrain_def(loc_pattern, loc_expr, bound_vars, subs, ret_con);
|
||||||
|
}
|
||||||
|
|
||||||
|
unreachable!();
|
||||||
}
|
}
|
||||||
_ => { panic!("TODO constraints for {:?}", loc_expr.value) }
|
_ => { panic!("TODO constraints for {:?}", loc_expr.value) }
|
||||||
}
|
}
|
||||||
|
@ -136,21 +137,26 @@ pub fn constrain_def(
|
||||||
vars: Vec::with_capacity(1),
|
vars: Vec::with_capacity(1),
|
||||||
reversed_constraints: Vec::with_capacity(1)
|
reversed_constraints: Vec::with_capacity(1)
|
||||||
};
|
};
|
||||||
let (mut vars, arg_types) =
|
let (vars, _) =
|
||||||
patterns_to_variables(std::iter::once(loc_pattern.clone()), subs, &mut state);
|
patterns_to_variables(std::iter::once(loc_pattern.clone()), subs, &mut state);
|
||||||
|
let region = loc_pattern.region;
|
||||||
|
|
||||||
let ret_var = subs.mk_flex_var();
|
// Set up types for the expr we're assigned to.
|
||||||
let ret_type = Type::Variable(ret_var);
|
let expr_var = subs.mk_flex_var();
|
||||||
|
let expr_type = Type::Variable(expr_var);
|
||||||
|
|
||||||
vars.push(ret_var);
|
// These types are *only* for the current pattern. In contrast, the ones
|
||||||
|
// in PatternState represent
|
||||||
let mut assignment_types: ImMap<Symbol, Located<Type>> = ImMap::default();
|
let mut lookup_types: ImMap<Symbol, Located<Type>> = ImMap::default();
|
||||||
|
|
||||||
|
// Any time there's a lookup on this symbol in the outer Let,
|
||||||
|
// it should result in this expression's type. After all, this
|
||||||
|
// is the type to which this symbol is assigned!
|
||||||
match loc_pattern.value {
|
match loc_pattern.value {
|
||||||
Pattern::Identifier(symbol) => {
|
Pattern::Identifier(symbol) => {
|
||||||
let loc_type = Located {region: loc_pattern.region, value: ret_type.clone()};
|
let value = expr_type.clone();
|
||||||
|
|
||||||
assignment_types.insert(symbol, loc_type);
|
lookup_types.insert(symbol, Located {region, value});
|
||||||
},
|
},
|
||||||
_ => panic!("TODO constrain patterns other than Identifier")
|
_ => panic!("TODO constrain patterns other than Identifier")
|
||||||
}
|
}
|
||||||
|
@ -161,14 +167,15 @@ pub fn constrain_def(
|
||||||
rigid_vars: Vec::new(),
|
rigid_vars: Vec::new(),
|
||||||
flex_vars: vars,
|
flex_vars: vars,
|
||||||
assignments_constraint:
|
assignments_constraint:
|
||||||
|
// This nested constraint represents the actually constrained expr.
|
||||||
Let(Box::new(LetConstraint {
|
Let(Box::new(LetConstraint {
|
||||||
rigid_vars: Vec::new(),
|
rigid_vars: Vec::new(),
|
||||||
flex_vars: state.vars,
|
flex_vars: state.vars,
|
||||||
assignment_types: state.assignment_types,
|
assignment_types: state.assignment_types,
|
||||||
assignments_constraint: And(state.reversed_constraints),
|
assignments_constraint: And(state.reversed_constraints),
|
||||||
ret_constraint: constrain(bound_vars, subs, loc_expr, NoExpectation(ret_type))
|
ret_constraint: constrain(bound_vars, subs, loc_expr, NoExpectation(expr_type))
|
||||||
})),
|
})),
|
||||||
assignment_types,
|
assignment_types: lookup_types,
|
||||||
ret_constraint,
|
ret_constraint,
|
||||||
}))
|
}))
|
||||||
}
|
}
|
||||||
|
|
|
@ -27,8 +27,9 @@ pub fn infer_expr(subs: &mut Subs, loc_expr: Located<Expr>, procedures: MutMap<S
|
||||||
// Next, constrain the expression.
|
// Next, constrain the expression.
|
||||||
let variable = subs.mk_flex_var();
|
let variable = subs.mk_flex_var();
|
||||||
let expected = NoExpectation(Variable(variable));
|
let expected = NoExpectation(Variable(variable));
|
||||||
|
let constraint = constrain(&bound_vars, subs, loc_expr, expected);
|
||||||
|
|
||||||
constraints.push(constrain(&bound_vars, subs, loc_expr, expected));
|
constraints.push(constraint);
|
||||||
|
|
||||||
solve(&env, subs, Constraint::And(constraints));
|
solve(&env, subs, Constraint::And(constraints));
|
||||||
|
|
||||||
|
|
13
src/solve.rs
13
src/solve.rs
|
@ -60,10 +60,16 @@ pub fn solve(env: &Env, subs: &mut Subs, constraint: Constraint) {
|
||||||
// Add a variable for each assignment to the env.
|
// Add a variable for each assignment to the env.
|
||||||
let mut new_env = env.clone();
|
let mut new_env = env.clone();
|
||||||
|
|
||||||
for (name, loc_type) in let_con.assignment_types {
|
for (symbol, loc_type) in let_con.assignment_types {
|
||||||
let var = type_to_variable(subs, loc_type.value);
|
// We must not overwrite existing symbols! If we do,
|
||||||
|
// we will overwrite procedure entries, which were
|
||||||
|
// inserted earlier in solving. (If we allowed
|
||||||
|
// shadowing, we'd need to do something fancier here.)
|
||||||
|
if !new_env.contains_key(&symbol) {
|
||||||
|
let var = type_to_variable(subs, loc_type.value);
|
||||||
|
|
||||||
new_env.insert(name, var);
|
new_env.insert(symbol, var);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Now solve the body, using the new env which includes
|
// Now solve the body, using the new env which includes
|
||||||
|
@ -96,7 +102,6 @@ fn type_to_variable(subs: &mut Subs, typ: Type) -> Variable {
|
||||||
|
|
||||||
subs.fresh(Descriptor::from(content))
|
subs.fresh(Descriptor::from(content))
|
||||||
},
|
},
|
||||||
|
|
||||||
Function(arg_types, ret_type) => {
|
Function(arg_types, ret_type) => {
|
||||||
let arg_vars = arg_types.into_iter().map(|arg_type| {
|
let arg_vars = arg_types.into_iter().map(|arg_type| {
|
||||||
type_to_variable(subs, arg_type)
|
type_to_variable(subs, arg_type)
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue