Merge pull request #4486 from roc-lang/more-prep-constraining

Lift constraining expectation indices up a level
This commit is contained in:
Ayaz 2022-11-08 13:47:57 -06:00 committed by GitHub
commit 8179e29bf8
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 216 additions and 215 deletions

View File

@ -676,6 +676,22 @@ impl Constraints {
roc_error_macros::assert_sizeof_default!(Constraint, 3 * 8);
roc_error_macros::assert_sizeof_aarch64!(Constraint, 3 * 8);
impl std::ops::Index<ExpectedTypeIndex> for Constraints {
type Output = Expected<TypeOrVar>;
fn index(&self, index: ExpectedTypeIndex) -> &Self::Output {
&self.expectations[index.index()]
}
}
impl std::ops::Index<PExpectedTypeIndex> for Constraints {
type Output = PExpected<TypeOrVar>;
fn index(&self, index: PExpectedTypeIndex) -> &Self::Output {
&self.pattern_expectations[index.index()]
}
}
#[derive(Clone, Copy, Debug)]
pub struct Eq(
pub TypeOrVar,

View File

@ -1,5 +1,5 @@
use arrayvec::ArrayVec;
use roc_can::constraint::{Constraint, Constraints, TypeOrVar};
use roc_can::constraint::{Constraint, Constraints, ExpectedTypeIndex};
use roc_can::expected::Expected::{self, *};
use roc_can::num::{FloatBound, FloatWidth, IntBound, IntLitWidth, NumBound, SignDemand};
use roc_module::symbol::Symbol;
@ -71,7 +71,7 @@ pub fn int_literal(
constraints: &mut Constraints,
num_var: Variable,
precision_var: Variable,
expected: Expected<TypeOrVar>,
expected: ExpectedTypeIndex,
region: Region,
bound: IntBound,
) -> Constraint {
@ -97,10 +97,7 @@ pub fn int_literal(
constrs.extend([
constraints.equal_types(num_type_index, expect_precision_var, Category::Int, region),
{
let expected_index = constraints.push_expected_type(expected);
constraints.equal_types(num_type_index, expected_index, Category::Int, region)
},
constraints.equal_types(num_type_index, expected, Category::Int, region),
]);
// TODO the precision_var is not part of the exists here; for float it is. Which is correct?
@ -112,7 +109,7 @@ pub fn single_quote_literal(
constraints: &mut Constraints,
num_var: Variable,
precision_var: Variable,
expected: Expected<TypeOrVar>,
expected: ExpectedTypeIndex,
region: Region,
bound: SingleQuoteBound,
) -> Constraint {
@ -143,10 +140,7 @@ pub fn single_quote_literal(
Category::Character,
region,
),
{
let expected_index = constraints.push_expected_type(expected);
constraints.equal_types(num_type_index, expected_index, Category::Character, region)
},
constraints.equal_types(num_type_index, expected, Category::Character, region),
]);
let and_constraint = constraints.and_constraint(constrs);
@ -158,7 +152,7 @@ pub fn float_literal(
constraints: &mut Constraints,
num_var: Variable,
precision_var: Variable,
expected: Expected<TypeOrVar>,
expected: ExpectedTypeIndex,
region: Region,
bound: FloatBound,
) -> Constraint {
@ -183,10 +177,7 @@ pub fn float_literal(
constrs.extend([
constraints.equal_types(num_type_index, expect_precision_var, Category::Frac, region),
{
let expected_index = constraints.push_expected_type(expected);
constraints.equal_types(num_type_index, expected_index, Category::Frac, region)
},
constraints.equal_types(num_type_index, expected, Category::Frac, region),
]);
let and_constraint = constraints.and_constraint(constrs);
@ -197,7 +188,7 @@ pub fn float_literal(
pub fn num_literal(
constraints: &mut Constraints,
num_var: Variable,
expected: Expected<TypeOrVar>,
expected: ExpectedTypeIndex,
region: Region,
bound: NumBound,
) -> Constraint {
@ -213,8 +204,7 @@ pub fn num_literal(
);
let type_index = constraints.push_type(num_type);
let expected_index = constraints.push_expected_type(expected);
constrs.extend([constraints.equal_types(type_index, expected_index, Category::Num, region)]);
constrs.extend([constraints.equal_types(type_index, expected, Category::Num, region)]);
let and_constraint = constraints.and_constraint(constrs);
constraints.exists([num_var], and_constraint)

View File

@ -6,7 +6,9 @@ use crate::builtins::{
};
use crate::pattern::{constrain_pattern, PatternState};
use roc_can::annotation::IntroducedVariables;
use roc_can::constraint::{Constraint, Constraints, OpportunisticResolve, TypeOrVar};
use roc_can::constraint::{
Constraint, Constraints, ExpectedTypeIndex, OpportunisticResolve, TypeOrVar,
};
use roc_can::def::Def;
use roc_can::exhaustive::{sketch_pattern_to_rows, sketch_when_branches, ExhaustiveContext};
use roc_can::expected::Expected::{self, *};
@ -74,7 +76,8 @@ fn constrain_untyped_args(
let pattern_type = Variable(*pattern_var);
let pattern_type_index = constraints.push_type(Variable(*pattern_var));
let pattern_expected = PExpected::NoExpectation(pattern_type_index);
let pattern_expected =
constraints.push_pat_expected_type(PExpected::NoExpectation(pattern_type_index));
pattern_types.push(pattern_type);
@ -101,7 +104,7 @@ fn constrain_untyped_closure(
constraints: &mut Constraints,
env: &mut Env,
region: Region,
expected: Expected<TypeOrVar>,
expected: ExpectedTypeIndex,
fn_var: Variable,
closure_var: Variable,
@ -121,7 +124,7 @@ fn constrain_untyped_closure(
vars.push(closure_var);
vars.push(fn_var);
let body_type = NoExpectation(return_type_index);
let body_type = constraints.push_expected_type(NoExpectation(return_type_index));
let ret_constraint = constrain_expr(
constraints,
env,
@ -150,7 +153,6 @@ fn constrain_untyped_closure(
let pattern_state_constraints = constraints.and_constraint(pattern_state.constraints);
let function_type = constraints.push_type(function_type);
let expected = constraints.push_expected_type(expected);
let cons = [
constraints.let_constraint(
@ -178,7 +180,7 @@ pub fn constrain_expr(
env: &mut Env,
region: Region,
expr: &Expr,
expected: Expected<TypeOrVar>,
expected: ExpectedTypeIndex,
) -> Constraint {
match expr {
&Int(var, precision, _, _, bound) => {
@ -214,7 +216,6 @@ pub fn constrain_expr(
let record_type =
constraints.push_type(Type::Record(field_types, TypeExtension::Closed));
let expected = constraints.push_expected_type(expected);
let record_con = constraints.equal_types_with_storage(
record_type,
@ -268,7 +269,7 @@ pub fn constrain_expr(
Category::Record,
region,
);
let expected_record = constraints.push_expected_type(expected);
let expected_record = expected;
let record_con =
constraints.equal_types_var(*record_var, expected_record, Category::Record, region);
@ -299,7 +300,7 @@ pub fn constrain_expr(
}
Str(_) => {
let str_index = constraints.push_type(str_type());
let expected_index = constraints.push_expected_type(expected);
let expected_index = expected;
constraints.equal_types(str_index, expected_index, Category::Str, region)
}
SingleQuote(num_var, precision_var, _, bound) => single_quote_literal(
@ -316,13 +317,7 @@ pub fn constrain_expr(
} => {
if loc_elems.is_empty() {
let elem_type_index = constraints.push_type(empty_list_type(*elem_var));
let expected_index = constraints.push_expected_type(expected);
let eq = constraints.equal_types(
elem_type_index,
expected_index,
Category::List,
region,
);
let eq = constraints.equal_types(elem_type_index, expected, Category::List, region);
constraints.exists(vec![*elem_var], eq)
} else {
let list_elem_type = Type::Variable(*elem_var);
@ -330,13 +325,13 @@ pub fn constrain_expr(
let mut list_constraints = Vec::with_capacity(1 + loc_elems.len());
for (index, loc_elem) in loc_elems.iter().enumerate() {
let elem_expected = ForReason(
let elem_expected = constraints.push_expected_type(ForReason(
Reason::ElemInList {
index: HumanIndex::zero_based(index),
},
list_elem_type_index,
loc_elem.region,
);
));
let constraint = constrain_expr(
constraints,
env,
@ -349,10 +344,9 @@ pub fn constrain_expr(
}
let elem_type_index = constraints.push_type(list_type(list_elem_type));
let expected_index = constraints.push_expected_type(expected);
list_constraints.push(constraints.equal_types(
elem_type_index,
expected_index,
expected,
Category::List,
region,
));
@ -373,7 +367,7 @@ pub fn constrain_expr(
let fn_type_index = constraints.push_type(Variable(*fn_var));
let fn_region = loc_fn.region;
let fn_expected = NoExpectation(fn_type_index);
let fn_expected = constraints.push_expected_type(NoExpectation(fn_type_index));
let fn_reason = Reason::FnCall {
name: opt_symbol,
@ -408,7 +402,8 @@ pub fn constrain_expr(
name: opt_symbol,
arg_index: HumanIndex::zero_based(index),
};
let expected_arg = ForReason(reason, arg_type_index, region);
let expected_arg =
constraints.push_expected_type(ForReason(reason, arg_type_index, region));
let arg_con = constrain_expr(
constraints,
env,
@ -430,7 +425,7 @@ pub fn constrain_expr(
let expected_fn_type =
constraints.push_expected_type(ForReason(fn_reason, expected_fn_index, region));
let expected_final_type = constraints.push_expected_type(expected);
let expected_final_type = expected;
let category = Category::CallResult(opt_symbol, *called_via);
@ -446,20 +441,17 @@ pub fn constrain_expr(
}
Var(symbol, variable) => {
// Save the expectation in the variable, then lookup the symbol's type in the environment
let expected_type = *expected.get_type_ref();
let expected_type = *constraints[expected].get_type_ref();
let store_expected = constraints.store(expected_type, *variable, file!(), line!());
let stored_index = constraints.push_type(Variable(*variable));
let stored_type = constraints.push_expected_type(expected.replace(stored_index));
let lookup_constr = constraints.lookup(*symbol, stored_type, region);
let lookup_constr = constraints.lookup(*symbol, expected, region);
constraints.and_constraint([store_expected, lookup_constr])
}
&AbilityMember(symbol, specialization_id, specialization_var) => {
// Save the expectation in the `specialization_var` so we know what to specialize, then
// lookup the member in the environment.
let expected_type = *expected.get_type_ref();
let expected_type = *constraints[expected].get_type_ref();
let store_expected =
constraints.store(expected_type, specialization_var, file!(), line!());
@ -513,7 +505,11 @@ pub fn constrain_expr(
} => {
let expected_bool = {
let bool_type = constraints.push_type(Type::Variable(Variable::BOOL));
Expected::ForReason(Reason::ExpectCondition, bool_type, loc_condition.region)
constraints.push_expected_type(Expected::ForReason(
Reason::ExpectCondition,
bool_type,
loc_condition.region,
))
};
let cond_con = constrain_expr(
@ -564,7 +560,11 @@ pub fn constrain_expr(
} => {
let expected_bool = {
let bool_type = constraints.push_type(Type::Variable(Variable::BOOL));
Expected::ForReason(Reason::ExpectCondition, bool_type, loc_condition.region)
constraints.push_expected_type(Expected::ForReason(
Reason::ExpectCondition,
bool_type,
loc_condition.region,
))
};
let cond_con = constrain_expr(
@ -616,16 +616,17 @@ pub fn constrain_expr(
} => {
let expect_bool = |constraints: &mut Constraints, region| {
let bool_type = constraints.push_type(Type::Variable(Variable::BOOL));
Expected::ForReason(Reason::IfCondition, bool_type, region)
constraints.push_expected_type(Expected::ForReason(
Reason::IfCondition,
bool_type,
region,
))
};
let mut branch_cons = Vec::with_capacity(2 * branches.len() + 3);
// TODO why does this cond var exist? is it for error messages?
let first_cond_region = branches[0].0.region;
let expected_bool = {
let expected = expect_bool(constraints, first_cond_region);
constraints.push_expected_type(expected)
};
let expected_bool = expect_bool(constraints, first_cond_region);
let cond_var_is_bool_con = constraints.equal_types_var(
*cond_var,
expected_bool,
@ -635,6 +636,7 @@ pub fn constrain_expr(
branch_cons.push(cond_var_is_bool_con);
let expected = constraints[expected].clone();
match expected {
FromAnnotation(name, arity, ann_source, tipe) => {
let num_branches = branches.len() + 1;
@ -648,42 +650,45 @@ pub fn constrain_expr(
expected_bool,
);
let expected_then = constraints.push_expected_type(FromAnnotation(
name.clone(),
arity,
AnnotationSource::TypedIfBranch {
index: HumanIndex::zero_based(index),
num_branches,
region: ann_source.region(),
},
tipe,
));
let then_con = constrain_expr(
constraints,
env,
loc_body.region,
&loc_body.value,
FromAnnotation(
name.clone(),
arity,
AnnotationSource::TypedIfBranch {
index: HumanIndex::zero_based(index),
num_branches,
region: ann_source.region(),
},
tipe,
),
expected_then,
);
branch_cons.push(cond_con);
branch_cons.push(then_con);
}
let expected_else = constraints.push_expected_type(FromAnnotation(
name,
arity,
AnnotationSource::TypedIfBranch {
index: HumanIndex::zero_based(branches.len()),
num_branches,
region: ann_source.region(),
},
tipe,
));
let else_con = constrain_expr(
constraints,
env,
final_else.region,
&final_else.value,
FromAnnotation(
name,
arity,
AnnotationSource::TypedIfBranch {
index: HumanIndex::zero_based(branches.len()),
num_branches,
region: ann_source.region(),
},
tipe,
),
expected_else,
);
let expected_result_type = constraints.push_expected_type(NoExpectation(tipe));
@ -713,37 +718,39 @@ pub fn constrain_expr(
expected_bool,
);
let expected_then = constraints.push_expected_type(ForReason(
Reason::IfBranch {
index: HumanIndex::zero_based(index),
total_branches: branches.len(),
},
branch_var_index,
loc_body.region,
));
let then_con = constrain_expr(
constraints,
env,
loc_body.region,
&loc_body.value,
ForReason(
Reason::IfBranch {
index: HumanIndex::zero_based(index),
total_branches: branches.len(),
},
branch_var_index,
loc_body.region,
),
expected_then,
);
branch_cons.push(cond_con);
branch_cons.push(then_con);
}
let expected_else = constraints.push_expected_type(ForReason(
Reason::IfBranch {
index: HumanIndex::zero_based(branches.len()),
total_branches: branches.len() + 1,
},
branch_var_index,
final_else.region,
));
let else_con = constrain_expr(
constraints,
env,
final_else.region,
&final_else.value,
ForReason(
Reason::IfBranch {
index: HumanIndex::zero_based(branches.len()),
total_branches: branches.len() + 1,
},
branch_var_index,
final_else.region,
),
expected_else,
);
let expected = constraints.push_expected_type(expected);
@ -853,7 +860,7 @@ pub fn constrain_expr(
when_branch,
expected_pattern,
branch_expr_reason(
&expected,
&constraints[expected],
HumanIndex::zero_based(index),
when_branch.value.region,
),
@ -901,12 +908,14 @@ pub fn constrain_expr(
// First, solve the condition type.
let real_cond_var = *real_cond_var;
let real_cond_type = constraints.push_type(Type::Variable(real_cond_var));
let expected_real_cond =
constraints.push_expected_type(Expected::NoExpectation(real_cond_type));
let cond_constraint = constrain_expr(
constraints,
env,
loc_cond.region,
&loc_cond.value,
Expected::NoExpectation(real_cond_type),
expected_real_cond,
);
pattern_cons.push(cond_constraint);
@ -939,8 +948,6 @@ pub fn constrain_expr(
body_constraints,
);
let expected = constraints.push_expected_type(expected);
let result_con =
constraints.equal_types_var(body_var, expected, Category::When, region);
@ -980,14 +987,9 @@ pub fn constrain_expr(
let record_con =
constraints.equal_types_var(*record_var, record_expected, category.clone(), region);
let constraint = constrain_expr(
constraints,
env,
region,
&loc_expr.value,
NoExpectation(record_type),
);
let expected = constraints.push_expected_type(expected);
let expected_record = constraints.push_expected_type(NoExpectation(record_type));
let constraint =
constrain_expr(constraints, env, region, &loc_expr.value, expected_record);
let eq = constraints.equal_types_var(field_var, expected, category, region);
constraints.exists_many(
@ -1045,15 +1047,7 @@ pub fn constrain_expr(
category.clone(),
region,
),
{
let expected_index = constraints.push_expected_type(expected);
constraints.equal_types(
function_type_index,
expected_index,
category.clone(),
region,
)
},
constraints.equal_types(function_type_index, expected, category.clone(), region),
{
let store_fn_var_index = constraints.push_type(Variable(*function_var));
let store_fn_var_expected =
@ -1074,13 +1068,8 @@ pub fn constrain_expr(
)
}
LetRec(defs, loc_ret, cycle_mark) => {
let body_con = constrain_expr(
constraints,
env,
loc_ret.region,
&loc_ret.value,
expected.clone(),
);
let body_con =
constrain_expr(constraints, env, loc_ret.region, &loc_ret.value, expected);
constrain_recursive_defs(constraints, env, defs, body_con, *cycle_mark)
}
@ -1096,13 +1085,8 @@ pub fn constrain_expr(
loc_ret = new_loc_ret;
}
let mut body_con = constrain_expr(
constraints,
env,
loc_ret.region,
&loc_ret.value,
expected.clone(),
);
let mut body_con =
constrain_expr(constraints, env, loc_ret.region, &loc_ret.value, expected);
while let Some(def) = stack.pop() {
body_con = constrain_def(constraints, env, def, body_con)
@ -1124,12 +1108,13 @@ pub fn constrain_expr(
for (var, loc_expr) in arguments {
let var_index = constraints.push_type(Variable(*var));
let expected_arg = constraints.push_expected_type(NoExpectation(var_index));
let arg_con = constrain_expr(
constraints,
env,
loc_expr.region,
&loc_expr.value,
Expected::NoExpectation(var_index),
expected_arg,
);
arg_cons.push(arg_con);
@ -1141,7 +1126,6 @@ pub fn constrain_expr(
vec![(name.clone(), types)],
TypeExtension::from_type(Type::Variable(*ext_var)),
));
let expected = constraints.push_expected_type(expected);
let union_con = constraints.equal_types_with_storage(
tag_union_type,
@ -1171,7 +1155,6 @@ pub fn constrain_expr(
*closure_name,
TypeExtension::from_type(Type::Variable(*ext_var)),
));
let expected = constraints.push_expected_type(expected);
let union_con = constraints.equal_types_with_storage(
function_or_tag_union,
expected,
@ -1213,17 +1196,18 @@ pub fn constrain_expr(
});
// Constrain the argument
let expected_arg =
constraints.push_expected_type(Expected::NoExpectation(arg_type_index));
let arg_con = constrain_expr(
constraints,
env,
arg_loc_expr.region,
&arg_loc_expr.value,
Expected::NoExpectation(arg_type_index),
expected_arg,
);
// Link the entire wrapped opaque type (with the now-constrained argument) to the
// expected type
let expected = constraints.push_expected_type(expected);
let opaque_con = constraints.equal_types_with_storage(
opaque_type,
expected,
@ -1331,8 +1315,6 @@ pub fn constrain_expr(
constraints.push_expected_type(NoExpectation(fn_type))
};
let expected = constraints.push_expected_type(expected);
let cons = [
opaque_con,
link_type_variables_con,
@ -1385,7 +1367,8 @@ pub fn constrain_expr(
op: *op,
arg_index: HumanIndex::zero_based(index),
};
let expected_arg = ForReason(reason, arg_type, Region::zero());
let expected_arg =
constraints.push_expected_type(ForReason(reason, arg_type, Region::zero()));
let arg_con = constrain_expr(constraints, env, Region::zero(), arg, expected_arg);
arg_types.push(arg_type);
@ -1400,7 +1383,6 @@ pub fn constrain_expr(
}
let category = Category::LowLevelOpResult(*op);
let expected = constraints.push_expected_type(expected);
// Deviation: elm uses an additional And here
let eq = constraints.equal_types_var(*ret_var, expected, category, region);
@ -1427,7 +1409,8 @@ pub fn constrain_expr(
foreign_symbol: foreign_symbol.clone(),
arg_index: HumanIndex::zero_based(index),
};
let expected_arg = ForReason(reason, arg_type, Region::zero());
let expected_arg =
constraints.push_expected_type(ForReason(reason, arg_type, Region::zero()));
let arg_con = constrain_expr(constraints, env, Region::zero(), arg, expected_arg);
arg_types.push(arg_type);
@ -1442,7 +1425,6 @@ pub fn constrain_expr(
}
let category = Category::ForeignCall;
let expected = constraints.push_expected_type(expected);
// Deviation: elm uses an additional And here
let eq = constraints.equal_types_var(*ret_var, expected, category, region);
@ -1451,7 +1433,6 @@ pub fn constrain_expr(
}
TypedHole(var) => {
// store the expected type for this position
let expected = constraints.push_expected_type(expected);
constraints.equal_types_var(
*var,
expected,
@ -1465,8 +1446,7 @@ pub fn constrain_expr(
// Instead, trivially equate the expected type to itself. This will never yield
// unification errors but it will catch errors in type translation, including ability
// obligations.
let trivial_type = *expected.get_type_ref();
let expected = constraints.push_expected_type(expected);
let trivial_type = *constraints[expected].get_type_ref();
constraints.equal_types(trivial_type, expected, Category::Unknown, region)
}
}
@ -1554,14 +1534,14 @@ fn constrain_function_def(
def_pattern_state
};
let annotation_expected = FromAnnotation(
let annotation_expected = constraints.push_expected_type(FromAnnotation(
loc_pattern,
arity,
AnnotationSource::TypedBody {
region: annotation.region,
},
signature_index,
);
));
let ret_constraint = constrain_untyped_closure(
constraints,
@ -1678,14 +1658,14 @@ fn constrain_function_def(
&mut vars,
);
let annotation_expected = FromAnnotation(
let annotation_expected = constraints.push_expected_type(FromAnnotation(
loc_pattern.clone(),
arity,
AnnotationSource::TypedBody {
region: annotation.region,
},
ret_type_index,
);
));
let ret_constraint = constrain_expr(
constraints,
@ -1745,11 +1725,12 @@ fn constrain_function_def(
None => {
let expr_type = constraints.push_type(Variable(expr_var));
let expected_expr = constraints.push_expected_type(NoExpectation(expr_type));
let expr_con = constrain_untyped_closure(
constraints,
env,
loc_function_def.region,
NoExpectation(expr_type),
expected_expr,
expr_var,
function_def.closure_type,
function_def.return_type,
@ -1823,14 +1804,14 @@ fn constrain_destructure_def(
let signature_index = constraints.push_type(signature);
let annotation_expected = FromAnnotation(
let annotation_expected = constraints.push_expected_type(FromAnnotation(
loc_pattern.clone(),
arity,
AnnotationSource::TypedBody {
region: annotation.region,
},
signature_index,
);
));
// This will fill in inference variables in the `signature` as well, so that we can
// then take the signature as the source-of-truth without having to worry about
@ -1862,12 +1843,13 @@ fn constrain_destructure_def(
None => {
let expr_type = constraints.push_type(Variable(expr_var));
let expected_type = constraints.push_expected_type(NoExpectation(expr_type));
let expr_con = constrain_expr(
constraints,
env,
loc_expr.region,
&loc_expr.value,
NoExpectation(expr_type),
expected_type,
);
constrain_function_def_make_constraint(
@ -1920,14 +1902,14 @@ fn constrain_value_def(
let signature_index = constraints.push_type(signature);
let annotation_expected = FromAnnotation(
let annotation_expected = constraints.push_expected_type(FromAnnotation(
loc_pattern,
arity,
AnnotationSource::TypedBody {
region: annotation.region,
},
signature_index,
);
));
// This will fill in inference variables in the `signature` as well, so that we can
// then take the signature as the source-of-truth without having to worry about
@ -1962,12 +1944,13 @@ fn constrain_value_def(
None => {
let expr_type = constraints.push_type(Type::Variable(expr_var));
let expected_type = constraints.push_expected_type(NoExpectation(expr_type));
let expr_con = constrain_expr(
constraints,
env,
loc_expr.region,
&loc_expr.value,
NoExpectation(expr_type),
expected_type,
);
let expr_con = attach_resolution_constraints(constraints, env, expr_con);
@ -2005,6 +1988,7 @@ fn constrain_when_branch_help(
pattern_expected: impl Fn(HumanIndex, Region) -> PExpected<TypeOrVar>,
expr_expected: Expected<TypeOrVar>,
) -> ConstrainedBranch {
let expr_expected = constraints.push_expected_type(expr_expected);
let ret_constraint = constrain_expr(
constraints,
env,
@ -2021,8 +2005,10 @@ fn constrain_when_branch_help(
};
for (i, loc_pattern) in when_branch.patterns.iter().enumerate() {
let pattern_expected =
pattern_expected(HumanIndex::zero_based(i), loc_pattern.pattern.region);
let pattern_expected = constraints.push_pat_expected_type(pattern_expected(
HumanIndex::zero_based(i),
loc_pattern.pattern.region,
));
let mut partial_state = PatternState::default();
constrain_pattern(
@ -2076,14 +2062,14 @@ fn constrain_when_branch_help(
let (pattern_constraints, delayed_is_open_constraints, body_constraints) =
if let Some(loc_guard) = &when_branch.guard {
let bool_index = constraints.push_type(Variable(Variable::BOOL));
let expected_guard = constraints.push_expected_type(Expected::ForReason(
Reason::WhenGuard,
bool_index,
loc_guard.region,
));
let guard_constraint = constrain_expr(
constraints,
env,
region,
&loc_guard.value,
Expected::ForReason(Reason::WhenGuard, bool_index, loc_guard.region),
);
let guard_constraint =
constrain_expr(constraints, env, region, &loc_guard.value, expected_guard);
// must introduce the headers from the pattern before constraining the guard
let delayed_is_open_constraints = state.delayed_is_open_constraints;
@ -2117,7 +2103,7 @@ fn constrain_field(
loc_expr: &Loc<Expr>,
) -> (Type, Constraint) {
let field_type = constraints.push_type(Variable(field_var));
let field_expected = NoExpectation(field_type);
let field_expected = constraints.push_expected_type(NoExpectation(field_type));
let constraint = constrain_expr(
constraints,
env,
@ -2133,11 +2119,10 @@ fn constrain_field(
fn constrain_empty_record(
constraints: &mut Constraints,
region: Region,
expected: Expected<TypeOrVar>,
expected: ExpectedTypeIndex,
) -> Constraint {
let record_type_index = constraints.push_type(Type::EmptyRec);
let expected_index = constraints.push_expected_type(expected);
constraints.equal_types(record_type_index, expected_index, Category::Record, region)
constraints.equal_types(record_type_index, expected, Category::Record, region)
}
/// Constrain top-level module declarations
@ -2174,8 +2159,11 @@ pub fn constrain_decls(
let loc_expr = &declarations.expressions[index];
let bool_type = constraints.push_type(Variable(Variable::BOOL));
let expected =
Expected::ForReason(Reason::ExpectCondition, bool_type, loc_expr.region);
let expected = constraints.push_expected_type(Expected::ForReason(
Reason::ExpectCondition,
bool_type,
loc_expr.region,
));
let expect_constraint = constrain_expr(
constraints,
@ -2191,8 +2179,11 @@ pub fn constrain_decls(
let loc_expr = &declarations.expressions[index];
let bool_type = constraints.push_type(Variable(Variable::BOOL));
let expected =
Expected::ForReason(Reason::ExpectCondition, bool_type, loc_expr.region);
let expected = constraints.push_expected_type(Expected::ForReason(
Reason::ExpectCondition,
bool_type,
loc_expr.region,
));
let expect_constraint = constrain_expr(
constraints,
@ -2267,7 +2258,7 @@ pub(crate) fn constrain_def_pattern(
loc_pattern: &Loc<Pattern>,
expr_type: TypeOrVar,
) -> PatternState {
let pattern_expected = PExpected::NoExpectation(expr_type);
let pattern_expected = constraints.push_pat_expected_type(PExpected::NoExpectation(expr_type));
let mut state = PatternState {
headers: VecMap::default(),
@ -2404,14 +2395,14 @@ fn constrain_typed_def(
&mut vars,
);
let body_type = FromAnnotation(
let body_type = constraints.push_expected_type(FromAnnotation(
def.loc_pattern.clone(),
arguments.len(),
AnnotationSource::TypedBody {
region: annotation.region,
},
ret_type_index,
);
));
let ret_constraint = constrain_expr(
constraints,
@ -2470,14 +2461,14 @@ fn constrain_typed_def(
}
_ => {
let annotation_expected = FromAnnotation(
let annotation_expected = constraints.push_expected_type(FromAnnotation(
def.loc_pattern.clone(),
arity,
AnnotationSource::TypedBody {
region: annotation.region,
},
expr_type_index,
);
));
let ret_constraint = constrain_expr(
constraints,
@ -2524,14 +2515,14 @@ fn constrain_typed_function_arguments(
if loc_pattern.value.surely_exhaustive() {
// OPT: we don't need to perform any type-level exhaustiveness checking.
// Check instead only that the pattern unifies with the annotation type.
let pattern_expected = PExpected::ForReason(
let pattern_expected = constraints.push_pat_expected_type(PExpected::ForReason(
PReason::TypedArg {
index: HumanIndex::zero_based(index),
opt_name: opt_label,
},
ann_index,
loc_pattern.region,
);
));
constrain_pattern(
constraints,
@ -2571,7 +2562,8 @@ fn constrain_typed_function_arguments(
{
// First, solve the type that the pattern is expecting to match in this
// position.
let pattern_expected = PExpected::NoExpectation(pattern_var_index);
let pattern_expected =
constraints.push_pat_expected_type(PExpected::NoExpectation(pattern_var_index));
constrain_pattern(
constraints,
env,
@ -2651,14 +2643,14 @@ fn constrain_typed_function_arguments_simple(
if loc_pattern.value.surely_exhaustive() {
// OPT: we don't need to perform any type-level exhaustiveness checking.
// Check instead only that the pattern unifies with the annotation type.
let pattern_expected = PExpected::ForReason(
let pattern_expected = constraints.push_pat_expected_type(PExpected::ForReason(
PReason::TypedArg {
index: HumanIndex::zero_based(index),
opt_name: Some(symbol),
},
ann_index,
loc_pattern.region,
);
));
constrain_pattern(
constraints,
@ -2698,7 +2690,8 @@ fn constrain_typed_function_arguments_simple(
{
// First, solve the type that the pattern is expecting to match in this
// position.
let pattern_expected = PExpected::NoExpectation(pattern_var_index);
let pattern_expected =
constraints.push_pat_expected_type(PExpected::NoExpectation(pattern_var_index));
constrain_pattern(
constraints,
env,
@ -2781,12 +2774,13 @@ fn constrain_def(
def_pattern_state.vars.push(expr_var);
// no annotation, so no extra work with rigids
let expected = constraints.push_expected_type(NoExpectation(expr_type_index));
let expr_con = constrain_expr(
constraints,
env,
def.loc_expr.region,
&def.loc_expr.value,
NoExpectation(expr_type_index),
expected,
);
let expr_con = attach_resolution_constraints(constraints, env, expr_con);
@ -3077,11 +3071,12 @@ fn constraint_recursive_function(
None => {
let expr_type_index = constraints.push_type(Type::Variable(expr_var));
let expected_expr = constraints.push_expected_type(NoExpectation(expr_type_index));
let expr_con = constrain_untyped_closure(
constraints,
env,
loc_function_def.region,
NoExpectation(expr_type_index),
expected_expr,
expr_var,
function_def.closure_type,
function_def.return_type,
@ -3203,12 +3198,13 @@ fn constraint_recursive_function(
));
let expr_con = {
let expected = constraints.push_expected_type(NoExpectation(ret_type_index));
constrain_expr(
constraints,
env,
loc_body_expr.region,
&loc_body_expr.value,
NoExpectation(ret_type_index),
expected,
)
};
let expr_con = attach_resolution_constraints(constraints, env, expr_con);
@ -3289,12 +3285,14 @@ pub fn rec_defs_help_simple(
match opt_annotation {
None => {
let expected =
constraints.push_expected_type(NoExpectation(expr_var_index));
let expr_con = constrain_expr(
constraints,
env,
loc_expr.region,
&loc_expr.value,
NoExpectation(expr_var_index),
expected,
);
let expr_con = attach_resolution_constraints(constraints, env, expr_con);
@ -3339,7 +3337,7 @@ pub fn rec_defs_help_simple(
signature_index,
);
let expected = annotation_expected;
let expected = constraints.push_expected_type(annotation_expected);
let ret_constraint = constrain_expr(
constraints,
@ -3501,12 +3499,13 @@ fn rec_defs_help(
match &def.annotation {
None => {
let expected = constraints.push_expected_type(NoExpectation(expr_type_index));
let expr_con = constrain_expr(
constraints,
env,
def.loc_expr.region,
&def.loc_expr.value,
NoExpectation(expr_type_index),
expected,
);
let expr_con = attach_resolution_constraints(constraints, env, expr_con);
@ -3617,7 +3616,8 @@ fn rec_defs_help(
Box::new(Type::Variable(closure_var)),
Box::new(*ret_type.clone()),
));
let body_type = NoExpectation(ret_type_index);
let body_type =
constraints.push_expected_type(NoExpectation(ret_type_index));
let expr_con = constrain_expr(
constraints,
env,
@ -3684,7 +3684,7 @@ fn rec_defs_help(
}
}
_ => {
let expected = annotation_expected;
let expected = constraints.push_expected_type(annotation_expected);
let ret_constraint = constrain_expr(
constraints,
@ -3815,7 +3815,7 @@ fn constrain_field_update(
) -> (Variable, Type, Constraint) {
let field_type = constraints.push_type(Variable(var));
let reason = Reason::RecordUpdateValue(field);
let expected = ForReason(reason, field_type, region);
let expected = constraints.push_expected_type(ForReason(reason, field_type, region));
let con = constrain_expr(constraints, env, loc_expr.region, &loc_expr.value, expected);
(var, Variable(var), con)

View File

@ -1,6 +1,6 @@
use crate::builtins;
use crate::expr::{constrain_expr, Env};
use roc_can::constraint::{Constraint, Constraints, TypeOrVar};
use roc_can::constraint::{Constraint, Constraints, PExpectedTypeIndex, TypeOrVar};
use roc_can::expected::{Expected, PExpected};
use roc_can::pattern::Pattern::{self, *};
use roc_can::pattern::{DestructType, ListPatterns, RecordDestruct};
@ -187,7 +187,7 @@ pub fn constrain_pattern(
env: &mut Env,
pattern: &Pattern,
region: Region,
expected: PExpected<TypeOrVar>,
expected: PExpectedTypeIndex,
state: &mut PatternState,
) {
match pattern {
@ -198,12 +198,11 @@ pub fn constrain_pattern(
// A -> ""
// _ -> ""
// so, we know that "x" (in this case, a tag union) must be open.
if could_be_a_tag_union(constraints, *expected.get_type_ref()) {
let type_index = expected.get_type();
let expected_type = *constraints[expected].get_type_ref();
if could_be_a_tag_union(constraints, expected_type) {
state
.delayed_is_open_constraints
.push(constraints.is_open_type(type_index));
.push(constraints.is_open_type(expected_type));
}
}
UnsupportedPattern(_) | MalformedPattern(_, _) | OpaqueNotInScope(..) => {
@ -211,6 +210,7 @@ pub fn constrain_pattern(
}
Identifier(symbol) | Shadowed(_, _, symbol) => {
let expected = &constraints[expected];
let type_index = *expected.get_type_ref();
if could_be_a_tag_union(constraints, type_index) {
@ -232,6 +232,7 @@ pub fn constrain_pattern(
ident: symbol,
specializes: _,
} => {
let expected = &constraints[expected];
let type_index = *expected.get_type_ref();
if could_be_a_tag_union(constraints, type_index) {
@ -261,8 +262,6 @@ pub fn constrain_pattern(
);
let num_type = constraints.push_type(num_type);
let expected = constraints.push_pat_expected_type(expected);
state.constraints.push(constraints.equal_pattern_types(
num_type,
expected,
@ -295,7 +294,6 @@ pub fn constrain_pattern(
});
// Also constrain the pattern against the num var, again to reuse aliases if they're present.
let expected = constraints.push_pat_expected_type(expected);
state.constraints.push(constraints.equal_pattern_types(
num_type,
expected,
@ -329,7 +327,6 @@ pub fn constrain_pattern(
});
// Also constrain the pattern against the num var, again to reuse aliases if they're present.
let expected = constraints.push_pat_expected_type(expected);
state.constraints.push(constraints.equal_pattern_types(
num_type_index,
expected,
@ -340,7 +337,6 @@ pub fn constrain_pattern(
StrLiteral(_) => {
let str_type = constraints.push_type(builtins::str_type());
let expected = constraints.push_pat_expected_type(expected);
state.constraints.push(constraints.equal_pattern_types(
str_type,
expected,
@ -379,7 +375,6 @@ pub fn constrain_pattern(
});
// Also constrain the pattern against the num var, again to reuse aliases if they're present.
let expected = constraints.push_pat_expected_type(expected);
state.constraints.push(constraints.equal_pattern_types(
num_type_index,
expected,
@ -412,7 +407,8 @@ pub fn constrain_pattern(
{
let pat_type = Type::Variable(*var);
let pat_type_index = constraints.push_type(pat_type.clone());
let expected = PExpected::NoExpectation(pat_type_index);
let expected =
constraints.push_pat_expected_type(PExpected::NoExpectation(pat_type_index));
if !state.headers.contains_key(symbol) {
state
@ -467,11 +463,11 @@ pub fn constrain_pattern(
state.vars.push(*expr_var);
let expr_expected = Expected::ForReason(
let expr_expected = constraints.push_expected_type(Expected::ForReason(
Reason::RecordDefaultField(label.clone()),
pat_type_index,
loc_expr.region,
);
));
let expr_con = constrain_expr(
constraints,
@ -510,8 +506,6 @@ pub fn constrain_pattern(
region,
);
let expected = constraints.push_pat_expected_type(expected);
let record_con = constraints.pattern_presence(
whole_var_index,
expected,
@ -535,8 +529,11 @@ pub fn constrain_pattern(
let elem_var_index = constraints.push_type(Type::Variable(*elem_var));
for loc_pat in patterns.iter() {
let expected =
PExpected::ForReason(PReason::ListElem, elem_var_index, loc_pat.region);
let expected = constraints.push_pat_expected_type(PExpected::ForReason(
PReason::ListElem,
elem_var_index,
loc_pat.region,
));
constrain_pattern(
constraints,
@ -556,7 +553,6 @@ pub fn constrain_pattern(
));
let store_solved_list = constraints.store(solved_list, *list_var, file!(), line!());
let expected = constraints.push_pat_expected_type(expected);
let expected_constraint = constraints.pattern_presence(
list_var_index,
expected,
@ -583,14 +579,14 @@ pub fn constrain_pattern(
let pattern_type = constraints.push_type(Type::Variable(*pattern_var));
let expected = PExpected::ForReason(
let expected = constraints.push_pat_expected_type(PExpected::ForReason(
PReason::TagArg {
tag_name: tag_name.clone(),
index: HumanIndex::zero_based(index),
},
pattern_type,
region,
);
));
constrain_pattern(
constraints,
env,
@ -602,7 +598,7 @@ pub fn constrain_pattern(
}
let pat_category = PatternCategory::Ctor(tag_name.clone());
let expected_type = *expected.get_type_ref();
let expected_type = *constraints[expected].get_type_ref();
let whole_con = constraints.includes_tag(
expected_type,
@ -613,7 +609,6 @@ pub fn constrain_pattern(
);
let whole_type = constraints.push_type(Type::Variable(*whole_var));
let expected = constraints.push_pat_expected_type(expected);
let tag_con = constraints.pattern_presence(whole_type, expected, pat_category, region);
@ -652,7 +647,8 @@ pub fn constrain_pattern(
});
// First, add a constraint for the argument "who"
let arg_pattern_expected = PExpected::NoExpectation(arg_pattern_type_index);
let arg_pattern_expected = constraints
.push_pat_expected_type(PExpected::NoExpectation(arg_pattern_type_index));
constrain_pattern(
constraints,
env,
@ -700,7 +696,6 @@ pub fn constrain_pattern(
// Next, link `whole_var` (the type of "@Id who") to the expected type
let whole_type = constraints.push_type(Type::Variable(*whole_var));
let expected = constraints.push_pat_expected_type(expected);
let opaque_pattern_con = constraints.pattern_presence(
whole_type,
expected,

View File

@ -145,7 +145,7 @@ pub fn can_expr_with<'a>(
let mut var_store = VarStore::default();
let var = var_store.fresh();
let var_index = constraints.push_type(Type::Variable(var));
let expected = Expected::NoExpectation(var_index);
let expected = constraints.push_expected_type(Expected::NoExpectation(var_index));
let mut module_ids = ModuleIds::default();
// ensure the Test module is accessible in our tests