more rigid fixes?

This commit is contained in:
Folkert 2020-11-12 14:54:41 +01:00
parent f438cefd68
commit 7a719172bc

View File

@ -1376,23 +1376,7 @@ pub fn rec_defs_help(
let expr_var = def.expr_var;
let expr_type = Type::Variable(expr_var);
let pattern_expected = PExpected::NoExpectation(expr_type.clone());
let mut pattern_state = PatternState {
headers: SendMap::default(),
vars: flex_info.vars.clone(),
constraints: Vec::with_capacity(1),
};
constrain_pattern(
env,
&def.loc_pattern.value,
def.loc_pattern.region,
pattern_expected,
&mut pattern_state,
);
pattern_state.vars.push(expr_var);
let mut def_pattern_state = constrain_def_pattern(env, &def.loc_pattern, expr_type.clone());
let mut new_rigids = Vec::new();
match &def.annotation {
@ -1404,6 +1388,8 @@ pub fn rec_defs_help(
NoExpectation(expr_type),
);
def_pattern_state.vars.push(expr_var);
// TODO investigate if this let can be safely removed
let def_con = Let(Box::new(LetConstraint {
rigid_vars: Vec::new(),
@ -1413,9 +1399,9 @@ pub fn rec_defs_help(
ret_constraint: expr_con,
}));
flex_info.vars = pattern_state.vars;
flex_info.vars = def_pattern_state.vars;
flex_info.constraints.push(def_con);
flex_info.def_types.extend(pattern_state.headers);
flex_info.def_types.extend(def_pattern_state.headers);
}
Some(annotation) => {
@ -1428,7 +1414,7 @@ pub fn rec_defs_help(
&mut new_rigids,
&mut ftv,
&def.loc_pattern,
&mut pattern_state.headers,
&mut def_pattern_state.headers,
);
let annotation_expected = FromAnnotation(
@ -1440,43 +1426,176 @@ pub fn rec_defs_help(
signature.clone(),
);
let expr_con = constrain_expr(
&Env {
rigids: ftv,
home: env.home,
},
def.loc_expr.region,
&def.loc_expr.value,
annotation_expected.clone(),
);
// when a def is annotated, and it's body is a closure, treat this
// as a named function (in elm terms) for error messages.
//
// This means we get errors like "the first argument of `f` is weird"
// instead of the more generic "something is wrong with the body of `f`"
match (&def.loc_expr.value, &signature) {
(
Closure {
function_type: fn_var,
closure_type: closure_var,
closure_ext_var,
return_type: ret_var,
captured_symbols,
arguments,
loc_body,
name,
..
},
Type::Function(arg_types, _, _),
) => {
let expected = annotation_expected;
let region = def.loc_expr.region;
// ensure expected type unifies with annotated type
let storage_con = Eq(
expr_type,
annotation_expected.clone(),
Category::Storage(std::file!(), std::line!()),
def.loc_expr.region,
);
let loc_body_expr = &**loc_body;
let mut state = PatternState {
headers: SendMap::default(),
vars: Vec::with_capacity(arguments.len()),
constraints: Vec::with_capacity(1),
};
let mut vars = Vec::with_capacity(state.vars.capacity() + 1);
let mut pattern_types = Vec::with_capacity(state.vars.capacity());
let ret_var = *ret_var;
let closure_var = *closure_var;
let closure_ext_var = *closure_ext_var;
let ret_type = Type::Variable(ret_var);
// TODO investigate if this let can be safely removed
let def_con = Let(Box::new(LetConstraint {
rigid_vars: Vec::new(),
flex_vars: Vec::new(), // empty because Roc function defs have no args
def_types: SendMap::default(), // empty because Roc function defs have no args
defs_constraint: storage_con,
ret_constraint: expr_con,
}));
vars.push(ret_var);
vars.push(closure_var);
vars.push(closure_ext_var);
rigid_info.vars.extend(&new_rigids);
let it = arguments.iter().zip(arg_types.iter()).enumerate();
for (index, ((pattern_var, loc_pattern), loc_ann)) in it {
{
// ensure type matches the one in the annotation
let opt_label =
if let Pattern::Identifier(label) = def.loc_pattern.value {
Some(label)
} else {
None
};
let pattern_type: &Type = loc_ann;
rigid_info.constraints.push(Let(Box::new(LetConstraint {
rigid_vars: new_rigids,
flex_vars: pattern_state.vars,
def_types: SendMap::default(), // no headers introduced (at this level)
defs_constraint: def_con,
ret_constraint: True,
})));
rigid_info.def_types.extend(pattern_state.headers);
let pattern_expected = PExpected::ForReason(
PReason::TypedArg {
index: Index::zero_based(index),
opt_name: opt_label,
},
pattern_type.clone(),
loc_pattern.region,
);
constrain_pattern(
env,
&loc_pattern.value,
loc_pattern.region,
pattern_expected,
&mut state,
);
}
{
// NOTE: because we perform an equality with part of the signature
// this constraint must be to the def_pattern_state's constraints
def_pattern_state.vars.push(*pattern_var);
pattern_types.push(Type::Variable(*pattern_var));
let pattern_con = Eq(
Type::Variable(*pattern_var),
Expected::NoExpectation(loc_ann.clone()),
Category::Storage(std::file!(), std::line!()),
loc_pattern.region,
);
def_pattern_state.constraints.push(pattern_con);
}
}
let closure_constraint = constrain_closure_size(
*name,
region,
captured_symbols,
closure_var,
closure_ext_var,
&mut vars,
);
let fn_type = Type::Function(
pattern_types,
Box::new(Type::Variable(closure_var)),
Box::new(ret_type.clone()),
);
let body_type = NoExpectation(ret_type);
let expr_con = constrain_expr(
env,
loc_body_expr.region,
&loc_body_expr.value,
body_type,
);
vars.push(*fn_var);
// let expr_con = constrain_expr(
// &Env {
// rigids: ftv,
// home: env.home,
// },
// def.loc_expr.region,
// &def.loc_expr.value,
// annotation_expected.clone(),
// );
//
// // ensure expected type unifies with annotated type
// let storage_con = Eq(
// expr_type,
// annotation_expected.clone(),
// Category::Storage(std::file!(), std::line!()),
// def.loc_expr.region,
// );
//
// def_pattern_state.vars.push(expr_var);
// // Open question: where should this constraint live?
// // rigid_info.vars.push(expr_var);
// rigid_info.constraints.push(storage_con);
// TODO investigate if this let can be safely removed
let def_con = exists(
vars,
And(vec![
Let(Box::new(LetConstraint {
rigid_vars: Vec::new(),
flex_vars: state.vars,
def_types: state.headers,
defs_constraint: And(state.constraints),
ret_constraint: expr_con,
})),
Eq(fn_type.clone(), expected, Category::Lambda, region),
// "fn_var is equal to the closure's type" - fn_var is used in code gen
Eq(
Type::Variable(*fn_var),
NoExpectation(fn_type),
Category::Storage(std::file!(), std::line!()),
region,
),
closure_constraint,
]),
);
rigid_info.vars.extend(&new_rigids);
rigid_info.constraints.push(Let(Box::new(LetConstraint {
rigid_vars: new_rigids,
flex_vars: def_pattern_state.vars,
def_types: SendMap::default(), // no headers introduced (at this level)
defs_constraint: def_con,
ret_constraint: True,
})));
rigid_info.def_types.extend(def_pattern_state.headers);
}
_ => todo!(),
}
}
}
}