From 2a4fca7034c50e39552617f405a5ec38663da937 Mon Sep 17 00:00:00 2001 From: Ayaz Hafiz Date: Tue, 25 Oct 2022 11:01:53 -0500 Subject: [PATCH] First pass at expectations taking a type index --- crates/compiler/can/src/constraint.rs | 31 +- crates/compiler/constrain/src/builtins.rs | 48 ++- crates/compiler/constrain/src/expr.rs | 451 +++++++++++++--------- crates/compiler/constrain/src/module.rs | 7 +- crates/compiler/constrain/src/pattern.rs | 63 +-- crates/compiler/solve/src/solve.rs | 45 ++- crates/reporting/tests/helpers/mod.rs | 6 +- 7 files changed, 379 insertions(+), 272 deletions(-) diff --git a/crates/compiler/can/src/constraint.rs b/crates/compiler/can/src/constraint.rs index 3544681b1d..428c63f902 100644 --- a/crates/compiler/can/src/constraint.rs +++ b/crates/compiler/can/src/constraint.rs @@ -19,7 +19,7 @@ pub struct Constraints { pub let_constraints: Vec, pub categories: Vec, pub pattern_categories: Vec, - pub expectations: Vec>>, + pub expectations: Vec>, pub pattern_expectations: Vec>>, pub includes_tags: Vec, pub strings: Vec<&'static str>, @@ -59,7 +59,7 @@ impl Default for Constraints { } pub type TypeIndex = Index>; -pub type ExpectedTypeIndex = Index>>; +pub type ExpectedTypeIndex = Index>; pub type PExpectedTypeIndex = Index>>; pub type TypeOrVar = EitherIndex, Variable>; @@ -215,8 +215,8 @@ impl Constraints { EitherIndex::from_right(index) } - pub fn push_expected_type(&mut self, expected: Expected) -> ExpectedTypeIndex { - Index::push_new(&mut self.expectations, expected.map(Cell::new)) + pub fn push_expected_type(&mut self, expected: Expected) -> ExpectedTypeIndex { + Index::push_new(&mut self.expectations, expected) } pub fn push_pat_expected_type(&mut self, expected: PExpected) -> PExpectedTypeIndex { @@ -464,7 +464,7 @@ impl Constraints { where I1: IntoIterator, I2: IntoIterator, - I3: IntoIterator)>, + I3: IntoIterator)>, I3::IntoIter: ExactSizeIterator, { // defs and ret constraint are stored consequtively, so we only need to store one index @@ -473,27 +473,10 @@ impl Constraints { self.constraints.push(defs_constraint); self.constraints.push(ret_constraint); - let def_types = { - let types = def_types - .into_iter() - .map(|(sym, Loc { region, value })| { - let type_index = self.push_type(value); - ( - sym, - Loc { - region, - value: type_index, - }, - ) - }) - .collect::>(); - self.def_types_slice(types) - }; - let let_constraint = LetConstraint { rigid_vars: self.variable_slice(rigid_vars), flex_vars: self.variable_slice(flex_vars), - def_types, + def_types: self.def_types_slice(def_types), defs_and_ret_constraint, }; @@ -714,7 +697,7 @@ roc_error_macros::assert_sizeof_aarch64!(Constraint, 3 * 8); #[derive(Clone, Copy, Debug)] pub struct Eq( pub TypeOrVar, - pub Index>>, + pub ExpectedTypeIndex, pub Index, pub Region, ); diff --git a/crates/compiler/constrain/src/builtins.rs b/crates/compiler/constrain/src/builtins.rs index ad307261c2..3aee4ab16b 100644 --- a/crates/compiler/constrain/src/builtins.rs +++ b/crates/compiler/constrain/src/builtins.rs @@ -1,5 +1,5 @@ use arrayvec::ArrayVec; -use roc_can::constraint::{Constraint, Constraints}; +use roc_can::constraint::{Constraint, Constraints, TypeOrVar}; use roc_can::expected::Expected::{self, *}; use roc_can::num::{FloatBound, FloatWidth, IntBound, IntLitWidth, NumBound, SignDemand}; use roc_module::symbol::Symbol; @@ -30,7 +30,7 @@ pub fn add_numeric_bound_constr( num_num(Variable(num_var)) } NumericBound::FloatExact(width) => { - let actual_type = Variable(float_width_to_variable(width)); + let actual_type = constraints.push_type(Variable(float_width_to_variable(width))); let expected = Expected::ForReason(Reason::NumericLiteralSuffix, actual_type, region); let type_index = constraints.push_type(Variable(num_var)); let expected_index = constraints.push_expected_type(expected); @@ -42,7 +42,7 @@ pub fn add_numeric_bound_constr( Variable(num_var) } NumericBound::IntExact(width) => { - let actual_type = Variable(int_lit_width_to_variable(width)); + let actual_type = constraints.push_type(Variable(int_lit_width_to_variable(width))); let expected = Expected::ForReason(Reason::NumericLiteralSuffix, actual_type, region); let type_index = constraints.push_type(Variable(num_var)); let expected_index = constraints.push_expected_type(expected); @@ -54,11 +54,10 @@ pub fn add_numeric_bound_constr( Variable(num_var) } NumericBound::Range(range) => { - let actual_type = Variable(precision_var); - let expected = Expected::NoExpectation(RangedNumber(range)); - let type_index = constraints.push_type(actual_type); + let precision_type = constraints.push_type(Variable(precision_var)); + let expected = Expected::NoExpectation(constraints.push_type(RangedNumber(range))); let expected_index = constraints.push_expected_type(expected); - let constr = constraints.equal_types(type_index, expected_index, category, region); + let constr = constraints.equal_types(precision_type, expected_index, category, region); num_constraints.extend([constr]); @@ -72,7 +71,7 @@ pub fn int_literal( constraints: &mut Constraints, num_var: Variable, precision_var: Variable, - expected: Expected, + expected: Expected, region: Region, bound: IntBound, ) -> Constraint { @@ -91,11 +90,10 @@ pub fn int_literal( ); let num_type_index = constraints.push_type(num_type); - let expect_precision_var = constraints.push_expected_type(ForReason( - reason, - num_int(Type::Variable(precision_var)), - region, - )); + let int_precision_type = constraints.push_type(num_int(Type::Variable(precision_var))); + + let expect_precision_var = + constraints.push_expected_type(ForReason(reason, int_precision_type, region)); constrs.extend([ constraints.equal_types(num_type_index, expect_precision_var, Category::Int, region), @@ -114,7 +112,7 @@ pub fn single_quote_literal( constraints: &mut Constraints, num_var: Variable, precision_var: Variable, - expected: Expected, + expected: Expected, region: Region, bound: SingleQuoteBound, ) -> Constraint { @@ -133,11 +131,10 @@ pub fn single_quote_literal( ); let num_type_index = constraints.push_type(num_type); - let expect_precision_var = constraints.push_expected_type(ForReason( - reason, - num_int(Type::Variable(precision_var)), - region, - )); + let int_precision_type = constraints.push_type(num_int(Type::Variable(precision_var))); + + let expect_precision_var = + constraints.push_expected_type(ForReason(reason, int_precision_type, region)); constrs.extend([ constraints.equal_types( @@ -161,7 +158,7 @@ pub fn float_literal( constraints: &mut Constraints, num_var: Variable, precision_var: Variable, - expected: Expected, + expected: Expected, region: Region, bound: FloatBound, ) -> Constraint { @@ -179,11 +176,10 @@ pub fn float_literal( ); let num_type_index = constraints.push_type(num_type); - let expect_precision_var = constraints.push_expected_type(ForReason( - reason, - num_float(Type::Variable(precision_var)), - region, - )); + let float_precision_type = constraints.push_type(num_float(Type::Variable(precision_var))); + + let expect_precision_var = + constraints.push_expected_type(ForReason(reason, float_precision_type, region)); constrs.extend([ constraints.equal_types(num_type_index, expect_precision_var, Category::Frac, region), @@ -201,7 +197,7 @@ pub fn float_literal( pub fn num_literal( constraints: &mut Constraints, num_var: Variable, - expected: Expected, + expected: Expected, region: Region, bound: NumBound, ) -> Constraint { diff --git a/crates/compiler/constrain/src/expr.rs b/crates/compiler/constrain/src/expr.rs index 600e14bdd4..ee7194234f 100644 --- a/crates/compiler/constrain/src/expr.rs +++ b/crates/compiler/constrain/src/expr.rs @@ -6,7 +6,7 @@ use crate::builtins::{ }; use crate::pattern::{constrain_pattern, PatternState}; use roc_can::annotation::IntroducedVariables; -use roc_can::constraint::{Constraint, Constraints, OpportunisticResolve}; +use roc_can::constraint::{Constraint, Constraints, 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, *}; @@ -35,7 +35,7 @@ use roc_types::types::{ pub struct Info { pub vars: Vec, pub constraints: Vec, - pub def_types: VecMap>, + pub def_types: VecMap>, } impl Info { @@ -100,7 +100,7 @@ fn constrain_untyped_closure( constraints: &mut Constraints, env: &mut Env, region: Region, - expected: Expected, + expected: Expected, fn_var: Variable, closure_var: Variable, @@ -112,6 +112,7 @@ fn constrain_untyped_closure( ) -> Constraint { let closure_type = Type::Variable(closure_var); let return_type = Type::Variable(ret_var); + let return_type_index = constraints.push_type(Type::Variable(ret_var)); let (mut vars, pattern_state, function_type) = constrain_untyped_args( constraints, env, @@ -124,7 +125,7 @@ fn constrain_untyped_closure( vars.push(closure_var); vars.push(fn_var); - let body_type = NoExpectation(return_type); + let body_type = NoExpectation(return_type_index); let ret_constraint = constrain_expr( constraints, env, @@ -181,7 +182,7 @@ pub fn constrain_expr( env: &mut Env, region: Region, expr: &Expr, - expected: Expected, + expected: Expected, ) -> Constraint { match expr { &Int(var, precision, _, _, bound) => { @@ -257,9 +258,11 @@ pub fn constrain_expr( cons.push(con); } - let fields_type = - Type::Record(fields, TypeExtension::from_type(Type::Variable(*ext_var))); - let record_type = Type::Variable(*record_var); + let fields_type = constraints.push_type(Type::Record( + fields, + TypeExtension::from_type(Type::Variable(*ext_var)), + )); + let record_type = constraints.push_type(Type::Variable(*record_var)); // NOTE from elm compiler: fields_type is separate so that Error propagates better let fields_type_expected = constraints.push_expected_type(NoExpectation(fields_type)); @@ -327,6 +330,7 @@ pub fn constrain_expr( constraints.exists(vec![*elem_var], eq) } else { let list_elem_type = Type::Variable(*elem_var); + let list_elem_type_index = constraints.push_type(list_elem_type.clone()); let mut list_constraints = Vec::with_capacity(1 + loc_elems.len()); for (index, loc_elem) in loc_elems.iter().enumerate() { @@ -334,7 +338,7 @@ pub fn constrain_expr( Reason::ElemInList { index: HumanIndex::zero_based(index), }, - list_elem_type.clone(), + list_elem_type_index, loc_elem.region, ); let constraint = constrain_expr( @@ -371,9 +375,9 @@ pub fn constrain_expr( None }; - let fn_type = Variable(*fn_var); + let fn_type_index = constraints.push_type(Variable(*fn_var)); let fn_region = loc_fn.region; - let fn_expected = NoExpectation(fn_type); + let fn_expected = NoExpectation(fn_type_index); let fn_reason = Reason::FnCall { name: opt_symbol, @@ -402,12 +406,13 @@ pub fn constrain_expr( for (index, (arg_var, loc_arg)) in loc_args.iter().enumerate() { let region = loc_arg.region; let arg_type = Variable(*arg_var); + let arg_type_index = constraints.push_type(Variable(*arg_var)); let reason = Reason::FnArg { name: opt_symbol, arg_index: HumanIndex::zero_based(index), }; - let expected_arg = ForReason(reason, arg_type.clone(), region); + let expected_arg = ForReason(reason, arg_type_index, region); let arg_con = constrain_expr( constraints, env, @@ -421,11 +426,13 @@ pub fn constrain_expr( arg_cons.push(arg_con); } - let expected_fn_type = constraints.push_expected_type(ForReason( - fn_reason, - Function(arg_types, Box::new(closure_type), Box::new(ret_type)), - region, + let expected_fn_index = constraints.push_type(Function( + arg_types, + Box::new(closure_type), + Box::new(ret_type), )); + let expected_fn_type = + constraints.push_expected_type(ForReason(fn_reason, expected_fn_index, region)); let expected_final_type = constraints.push_expected_type(expected); @@ -443,25 +450,28 @@ 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 = constraints.push_type(expected.get_type_ref().clone()); + let expected_type = *expected.get_type_ref(); let store_expected = constraints.store(expected_type, *variable, file!(), line!()); - let store_into_var = - constraints.push_expected_type(expected.replace(Type::Variable(*variable))); + 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, store_into_var, region); + let lookup_constr = constraints.lookup(*symbol, stored_type, 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 = constraints.push_type(expected.get_type_ref().clone()); + let expected_type = *expected.get_type_ref(); let store_expected = constraints.store(expected_type, specialization_var, file!(), line!()); - let store_specialization_var = constraints - .push_expected_type(Expected::NoExpectation(Type::Variable(specialization_var))); - let lookup_constr = constraints.lookup(symbol, store_specialization_var, region); + + let stored_index = constraints.push_type(Variable(specialization_var)); + let stored_specialization_var = + constraints.push_expected_type(Expected::NoExpectation(stored_index)); + + let lookup_constr = constraints.lookup(symbol, stored_specialization_var, region); // Make sure we attempt to resolve the specialization, if we can. if let Some(specialization_id) = specialization_id { @@ -505,9 +515,9 @@ pub fn constrain_expr( loc_continuation, lookups_in_cond, } => { - let expect_bool = |region| { - let bool_type = Type::Variable(Variable::BOOL); - Expected::ForReason(Reason::ExpectCondition, bool_type, region) + let expected_bool = { + let bool_type = constraints.push_type(Type::Variable(Variable::BOOL)); + Expected::ForReason(Reason::ExpectCondition, bool_type, loc_condition.region) }; let cond_con = constrain_expr( @@ -515,7 +525,7 @@ pub fn constrain_expr( env, loc_condition.region, &loc_condition.value, - expect_bool(loc_condition.region), + expected_bool, ); let continuation_con = constrain_expr( @@ -542,8 +552,9 @@ pub fn constrain_expr( { vars.push(*var); - let store_into = - constraints.push_expected_type(NoExpectation(Type::Variable(*var))); + let var_index = constraints.push_type(Variable(*var)); + let store_into = constraints.push_expected_type(NoExpectation(var_index)); + all_constraints.push(constraints.lookup(*symbol, store_into, Region::zero())); } @@ -555,9 +566,9 @@ pub fn constrain_expr( loc_continuation, lookups_in_cond, } => { - let expect_bool = |region| { - let bool_type = Type::Variable(Variable::BOOL); - Expected::ForReason(Reason::ExpectCondition, bool_type, region) + let expected_bool = { + let bool_type = constraints.push_type(Type::Variable(Variable::BOOL)); + Expected::ForReason(Reason::ExpectCondition, bool_type, loc_condition.region) }; let cond_con = constrain_expr( @@ -565,7 +576,7 @@ pub fn constrain_expr( env, loc_condition.region, &loc_condition.value, - expect_bool(loc_condition.region), + expected_bool, ); let continuation_con = constrain_expr( @@ -592,8 +603,8 @@ pub fn constrain_expr( { vars.push(*var); - let store_into = - constraints.push_expected_type(NoExpectation(Type::Variable(*var))); + let var_index = constraints.push_type(Variable(*var)); + let store_into = constraints.push_expected_type(NoExpectation(var_index)); all_constraints.push(constraints.lookup(*symbol, store_into, Region::zero())); } @@ -607,15 +618,18 @@ pub fn constrain_expr( branches, final_else, } => { - let expect_bool = |region| { - let bool_type = Type::Variable(Variable::BOOL); + let expect_bool = |constraints: &mut Constraints, region| { + let bool_type = constraints.push_type(Type::Variable(Variable::BOOL)); 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 = constraints.push_expected_type(expect_bool(first_cond_region)); + let expected_bool = { + let expected = expect_bool(constraints, first_cond_region); + constraints.push_expected_type(expected) + }; let cond_var_is_bool_con = constraints.equal_types_var( *cond_var, expected_bool, @@ -629,12 +643,13 @@ pub fn constrain_expr( FromAnnotation(name, arity, ann_source, tipe) => { let num_branches = branches.len() + 1; for (index, (loc_cond, loc_body)) in branches.iter().enumerate() { + let expected_bool = expect_bool(constraints, loc_cond.region); let cond_con = constrain_expr( constraints, env, loc_cond.region, &loc_cond.value, - expect_bool(loc_cond.region), + expected_bool, ); let then_con = constrain_expr( @@ -690,13 +705,16 @@ pub fn constrain_expr( constraints.exists_many([*cond_var, *branch_var], branch_cons) } _ => { + let branch_var_index = constraints.push_type(Variable(*branch_var)); + for (index, (loc_cond, loc_body)) in branches.iter().enumerate() { + let expected_bool = expect_bool(constraints, loc_cond.region); let cond_con = constrain_expr( constraints, env, loc_cond.region, &loc_cond.value, - expect_bool(loc_cond.region), + expected_bool, ); let then_con = constrain_expr( @@ -709,7 +727,7 @@ pub fn constrain_expr( index: HumanIndex::zero_based(index), total_branches: branches.len(), }, - Type::Variable(*branch_var), + branch_var_index, loc_body.region, ), ); @@ -727,7 +745,7 @@ pub fn constrain_expr( index: HumanIndex::zero_based(branches.len()), total_branches: branches.len() + 1, }, - Type::Variable(*branch_var), + branch_var_index, final_else.region, ), ); @@ -757,9 +775,10 @@ pub fn constrain_expr( } => { let branches_cond_var = *branches_cond_var; let branches_cond_type = Variable(branches_cond_var); + let branches_cond_index = constraints.push_type(Variable(branches_cond_var)); let body_var = *expr_var; - let body_type = Variable(body_var); + let body_type_index = constraints.push_type(Variable(body_var)); let branches_region = { debug_assert!(!branches.is_empty()); @@ -767,7 +786,7 @@ pub fn constrain_expr( }; let branch_expr_reason = - |expected: &Expected, index, branch_region| match expected { + |expected: &Expected, index, branch_region| match expected { FromAnnotation(name, arity, ann_source, _typ) => { // NOTE deviation from elm. // @@ -780,15 +799,11 @@ pub fn constrain_expr( index, region: ann_source.region(), }, - body_type.clone(), + body_type_index, ) } - _ => ForReason( - Reason::WhenBranch { index }, - body_type.clone(), - branch_region, - ), + _ => ForReason(Reason::WhenBranch { index }, body_type_index, branch_region), }; // Our goal is to constrain and introduce variables in all pattern when branch patterns before @@ -890,7 +905,7 @@ pub fn constrain_expr( // // First, solve the condition type. let real_cond_var = *real_cond_var; - let real_cond_type = Type::Variable(real_cond_var); + let real_cond_type = constraints.push_type(Type::Variable(real_cond_var)); let cond_constraint = constrain_expr( constraints, env, @@ -904,7 +919,7 @@ pub fn constrain_expr( let sketched_rows = sketch_when_branches(branches_region, branches); let expected_by_branches = constraints.push_expected_type(Expected::ForReason( Reason::WhenBranches, - branches_cond_type, + branches_cond_index, branches_region, )); let cond_matches_branches_constraint = constraints.exhaustive( @@ -959,9 +974,11 @@ pub fn constrain_expr( let label = field.clone(); rec_field_types.insert(label, RecordField::Demanded(field_type)); - let record_type = Type::Record(rec_field_types, TypeExtension::from_type(ext_type)); - let record_expected = - constraints.push_expected_type(NoExpectation(record_type.clone())); + let record_type = constraints.push_type(Type::Record( + rec_field_types, + TypeExtension::from_type(ext_type), + )); + let record_expected = constraints.push_expected_type(NoExpectation(record_type)); let category = Category::Access(field.clone()); @@ -1001,19 +1018,22 @@ pub fn constrain_expr( let label = field.clone(); field_types.insert(label, RecordField::Demanded(field_type.clone())); let record_type = Type::Record(field_types, TypeExtension::from_type(ext_type)); + let record_type_index = constraints.push_type(record_type.clone()); let category = Category::Accessor(field.clone()); - let record_expected = - constraints.push_expected_type(NoExpectation(record_type.clone())); + let record_expected = constraints.push_expected_type(NoExpectation(record_type_index)); let record_con = constraints.equal_types_var(*record_var, record_expected, category.clone(), region); - let lambda_set = constraints.push_expected_type(NoExpectation(Type::ClosureTag { - name: *closure_name, - captures: vec![], - ambient_function: *function_var, - })); + let expected_lambda_set = { + let lambda_set_ty = constraints.push_type(Type::ClosureTag { + name: *closure_name, + captures: vec![], + ambient_function: *function_var, + }); + constraints.push_expected_type(NoExpectation(lambda_set_ty)) + }; let closure_type = Type::Variable(*closure_var); @@ -1024,7 +1044,12 @@ pub fn constrain_expr( )); let cons = [ - constraints.equal_types_var(*closure_var, lambda_set, category.clone(), region), + constraints.equal_types_var( + *closure_var, + expected_lambda_set, + category.clone(), + region, + ), { let expected_index = constraints.push_expected_type(expected); constraints.equal_types( @@ -1035,11 +1060,12 @@ pub fn constrain_expr( ) }, { - let function_var_index = - constraints.push_expected_type(NoExpectation(Variable(*function_var))); + let store_fn_var_index = constraints.push_type(Variable(*function_var)); + let store_fn_var_expected = + constraints.push_expected_type(NoExpectation(store_fn_var_index)); constraints.equal_types( function_type_index, - function_var_index, + store_fn_var_expected, category, region, ) @@ -1102,12 +1128,13 @@ pub fn constrain_expr( let mut arg_cons = Vec::with_capacity(arguments.len()); for (var, loc_expr) in arguments { + let var_index = constraints.push_type(Variable(*var)); let arg_con = constrain_expr( constraints, env, loc_expr.region, &loc_expr.value, - Expected::NoExpectation(Type::Variable(*var)), + Expected::NoExpectation(var_index), ); arg_cons.push(arg_con); @@ -1173,6 +1200,7 @@ pub fn constrain_expr( } => { let (arg_var, arg_loc_expr) = &**argument; let arg_type = Type::Variable(*arg_var); + let arg_type_index = constraints.push_type(Variable(*arg_var)); let opaque_type = constraints.push_type(Type::Alias { symbol: *name, @@ -1195,7 +1223,7 @@ pub fn constrain_expr( env, arg_loc_expr.region, &arg_loc_expr.value, - Expected::NoExpectation(arg_type.clone()), + Expected::NoExpectation(arg_type_index), ); // Link the entire wrapped opaque type (with the now-constrained argument) to the @@ -1213,11 +1241,12 @@ pub fn constrain_expr( // variables of the opaque type // TODO: better expectation here let link_type_variables_con = { - let type_index = constraints.push_type(arg_type); - let expected_index = constraints - .push_expected_type(Expected::NoExpectation((**specialized_def_type).clone())); + let specialized_type_index = + constraints.push_type((**specialized_def_type).clone()); + let expected_index = + constraints.push_expected_type(Expected::NoExpectation(specialized_type_index)); constraints.equal_types( - type_index, + arg_type_index, expected_index, Category::OpaqueArg, arg_loc_expr.region, @@ -1246,7 +1275,7 @@ pub fn constrain_expr( }) => { let argument_type = Type::Variable(*argument_var); - let opaque_type = Type::Alias { + let opaque_type = constraints.push_type(Type::Alias { symbol: *opaque_name, type_arguments: type_arguments .iter() @@ -1259,7 +1288,7 @@ pub fn constrain_expr( infer_ext_in_output_types: vec![], actual: Box::new(argument_type.clone()), kind: AliasKind::Opaque, - }; + }); let expected_opaque_type = constraints.push_expected_type(NoExpectation(opaque_type)); @@ -1274,8 +1303,9 @@ pub fn constrain_expr( // Tie the type of the value wrapped by the opaque to the opaque's type variables. let link_type_variables_con = { let arg_type_index = constraints.push_type(argument_type.clone()); - let expected_specialized = constraints - .push_expected_type(Expected::NoExpectation((*specialized_def_type).clone())); + let specialized_type_index = constraints.push_type((*specialized_def_type).clone()); + let expected_specialized = + constraints.push_expected_type(Expected::NoExpectation(specialized_type_index)); constraints.equal_types( arg_type_index, expected_specialized, @@ -1284,21 +1314,27 @@ pub fn constrain_expr( ) }; - let lambda_set = constraints.push_expected_type(NoExpectation(Type::ClosureTag { - name: *function_name, - captures: vec![], - ambient_function: *function_var, - })); + let lambda_set = { + let lambda_set_index = constraints.push_type(Type::ClosureTag { + name: *function_name, + captures: vec![], + ambient_function: *function_var, + }); + constraints.push_expected_type(NoExpectation(lambda_set_index)) + }; let closure_type = Type::Variable(*closure_var); let opaque_type = Type::Variable(*opaque_var); - let function_type = constraints.push_expected_type(NoExpectation(Type::Function( - vec![argument_type], - Box::new(closure_type), - Box::new(opaque_type), - ))); + let expected_function_type = { + let fn_type = constraints.push_type(Type::Function( + vec![argument_type], + Box::new(closure_type), + Box::new(opaque_type), + )); + constraints.push_expected_type(NoExpectation(fn_type)) + }; let expected = constraints.push_expected_type(expected); @@ -1313,7 +1349,7 @@ pub fn constrain_expr( ), constraints.equal_types_var( *function_var, - function_type, + expected_function_type, Category::OpaqueWrap(*opaque_name), region, ), @@ -1349,7 +1385,7 @@ pub fn constrain_expr( let mut arg_types = Vec::with_capacity(args.len()); let mut arg_cons = Vec::with_capacity(args.len()); - let mut add_arg = |index, arg_type: Type, arg| { + let mut add_arg = |constraints: &mut Constraints, index, arg_type: TypeOrVar, arg| { let reason = Reason::LowLevelOpArg { op: *op, arg_index: HumanIndex::zero_based(index), @@ -1363,8 +1399,9 @@ pub fn constrain_expr( for (index, (arg_var, arg)) in args.iter().enumerate() { vars.push(*arg_var); + let arg_var_index = constraints.push_type(Variable(*arg_var)); - add_arg(index, Variable(*arg_var), arg); + add_arg(constraints, index, arg_var_index, arg); } let category = Category::LowLevelOpResult(*op); @@ -1390,7 +1427,7 @@ pub fn constrain_expr( let mut arg_types = Vec::with_capacity(args.len()); let mut arg_cons = Vec::with_capacity(args.len()); - let mut add_arg = |index, arg_type: Type, arg| { + let mut add_arg = |constraints: &mut Constraints, index, arg_type: TypeOrVar, arg| { let reason = Reason::ForeignCallArg { foreign_symbol: foreign_symbol.clone(), arg_index: HumanIndex::zero_based(index), @@ -1404,8 +1441,9 @@ pub fn constrain_expr( for (index, (arg_var, arg)) in args.iter().enumerate() { vars.push(*arg_var); + let arg_var_index = constraints.push_type(Variable(*arg_var)); - add_arg(index, Variable(*arg_var), arg); + add_arg(constraints, index, arg_var_index, arg); } let category = Category::ForeignCall; @@ -1444,6 +1482,7 @@ fn constrain_function_def( let loc_expr = &declarations.expressions[index]; let loc_symbol = declarations.symbols[index]; let expr_var = declarations.variables[index]; + let expr_var_index = constraints.push_type(Type::Variable(expr_var)); let opt_annotation = &declarations.annotations[index]; let loc_function_def = &declarations.function_bodies[function_def_index.index()]; @@ -1483,7 +1522,8 @@ fn constrain_function_def( Loc { region: loc_function_def.region, // todo can we use Type::Variable(expr_var) here? - value: signature.clone(), + // TODO coalesce with other signatures + value: constraints.push_type(signature.clone()), }, ); @@ -1495,15 +1535,15 @@ fn constrain_function_def( AnnotationSource::TypedBody { region: annotation.region, }, - signature.clone(), + // TODO coalesce with other signatures + constraints.push_type(signature.clone()), ); { - let expr_type_index = constraints.push_type(Type::Variable(expr_var)); let expected_index = constraints.push_expected_type(annotation_expected); def_pattern_state.constraints.push(constraints.equal_types( - expr_type_index, + expr_var_index, expected_index, Category::Storage(std::file!(), std::line!()), Region::span_across(&annotation.region, &loc_body_expr.region), @@ -1519,7 +1559,8 @@ fn constrain_function_def( AnnotationSource::TypedBody { region: annotation.region, }, - signature.clone(), + // TODO coalesce with other signature indeces + constraints.push_type(signature.clone()), ); let ret_constraint = constrain_untyped_closure( @@ -1539,7 +1580,7 @@ fn constrain_function_def( let ret_constraint = attach_resolution_constraints(constraints, env, ret_constraint); - let signature_index = constraints.push_type(signature); + let signature_index = constraints.push_type(signature.clone()); let cons = [ ret_constraint, @@ -1594,7 +1635,7 @@ fn constrain_function_def( // annotation type may be instantiated into a fresh type variable that is // disassociated fromt the rest of the program. // Below, we'll check that the function actually matches the annotation. - value: Type::Variable(expr_var), + value: expr_var_index, }, ); @@ -1606,7 +1647,8 @@ fn constrain_function_def( AnnotationSource::TypedBody { region: annotation.region, }, - signature.clone(), + // TODO coalesce with other signature indices + constraints.push_type(signature.clone()), ); { @@ -1646,7 +1688,8 @@ fn constrain_function_def( AnnotationSource::TypedBody { region: annotation.region, }, - ret_type, + // TODO coalesce with other ret_type index + constraints.push_type(ret_type.clone()), ); let ret_constraint = constrain_expr( @@ -1661,14 +1704,18 @@ fn constrain_function_def( vars.push(expr_var); let defs_constraint = constraints.and_constraint(argument_pattern_state.constraints); - let signature_closure_type = constraints.push_expected_type(Expected::FromAnnotation( - loc_pattern, - arity, - AnnotationSource::TypedBody { - region: annotation.region, - }, - *signature_closure_type.clone(), - )); + let signature_closure_type = { + let signature_closure_type_index = + constraints.push_type(*signature_closure_type.clone()); + constraints.push_expected_type(Expected::FromAnnotation( + loc_pattern, + arity, + AnnotationSource::TypedBody { + region: annotation.region, + }, + signature_closure_type_index, + )) + }; let signature_index = constraints.push_type(signature); let cons = [ constraints.let_constraint( @@ -1701,7 +1748,7 @@ fn constrain_function_def( ) } None => { - let expr_type = Type::Variable(expr_var); + let expr_type = constraints.push_type(Variable(expr_var)); let expr_con = constrain_untyped_closure( constraints, @@ -1727,7 +1774,7 @@ fn constrain_function_def( body_con, loc_symbol, expr_var, - Type::Variable(expr_var), + expr_type, ) } } @@ -1764,6 +1811,7 @@ fn constrain_destructure_def( new_rigid_variables, new_infer_variables, } = instantiate_rigids( + constraints, &annotation.signature, &annotation.introduced_variables, loc_pattern, @@ -1783,7 +1831,8 @@ fn constrain_destructure_def( AnnotationSource::TypedBody { region: annotation.region, }, - signature.clone(), + // TODO coalesce with other signatures + constraints.push_type(signature.clone()), ); // This will fill in inference variables in the `signature` as well, so that we can @@ -1816,7 +1865,7 @@ fn constrain_destructure_def( ) } None => { - let expr_type = Type::Variable(expr_var); + let expr_type = constraints.push_type(Variable(expr_var)); let expr_con = constrain_expr( constraints, @@ -1850,6 +1899,8 @@ fn constrain_value_def( let expr_var = declarations.variables[index]; let opt_annotation = &declarations.annotations[index]; + dbg!(&opt_annotation); + match opt_annotation { Some(annotation) => { let arity = 1; @@ -1880,7 +1931,8 @@ fn constrain_value_def( AnnotationSource::TypedBody { region: annotation.region, }, - signature.clone(), + // TODO coalesce with other signature_index + constraints.push_type(signature.clone()), ); // This will fill in inference variables in the `signature` as well, so that we can @@ -1904,6 +1956,7 @@ fn constrain_value_def( ]; let expr_con = constraints.and_constraint(cons); + let signature_index = constraints.push_type(signature.clone()); constrain_value_def_make_constraint( constraints, new_rigid_variables, @@ -1912,11 +1965,12 @@ fn constrain_value_def( body_con, loc_symbol, expr_var, - signature, + // TODO coalesce + signature_index, ) } None => { - let expr_type = Type::Variable(expr_var); + let expr_type = constraints.push_type(Type::Variable(expr_var)); let expr_con = constrain_expr( constraints, @@ -1936,7 +1990,7 @@ fn constrain_value_def( body_con, loc_symbol, expr_var, - Type::Variable(expr_var), + expr_type, ) } } @@ -1944,7 +1998,7 @@ fn constrain_value_def( struct ConstrainedBranch { vars: Vec, - headers: VecMap>, + headers: VecMap>, pattern_constraints: Constraint, is_open_constrains: Vec, body_constraints: Constraint, @@ -1959,7 +2013,7 @@ fn constrain_when_branch_help( region: Region, when_branch: &WhenBranch, pattern_expected: impl Fn(HumanIndex, Region) -> PExpected, - expr_expected: Expected, + expr_expected: Expected, ) -> ConstrainedBranch { let ret_constraint = constrain_expr( constraints, @@ -2002,7 +2056,7 @@ fn constrain_when_branch_help( // Make sure the bound variables in the patterns on the same branch agree in their types. for (sym, all_branches_bound_typ) in state.headers.iter() { if let Some(this_bound_typ) = partial_state.headers.get(sym) { - let whole_typ = constraints.push_type(all_branches_bound_typ.value.clone()); + let whole_typ = all_branches_bound_typ.value; let this_typ = constraints .push_expected_type(Expected::NoExpectation(this_bound_typ.value.clone())); @@ -2031,16 +2085,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 guard_constraint = constrain_expr( constraints, env, region, &loc_guard.value, - Expected::ForReason( - Reason::WhenGuard, - Type::Variable(Variable::BOOL), - loc_guard.region, - ), + Expected::ForReason(Reason::WhenGuard, bool_index, loc_guard.region), ); // must introduce the headers from the pattern before constraining the guard @@ -2074,8 +2126,8 @@ fn constrain_field( field_var: Variable, loc_expr: &Loc, ) -> (Type, Constraint) { - let field_type = Variable(field_var); - let field_expected = NoExpectation(field_type.clone()); + let field_type = constraints.push_type(Variable(field_var)); + let field_expected = NoExpectation(field_type); let constraint = constrain_expr( constraints, env, @@ -2084,14 +2136,14 @@ fn constrain_field( field_expected, ); - (field_type, constraint) + (Variable(field_var), constraint) } #[inline(always)] fn constrain_empty_record( constraints: &mut Constraints, region: Region, - expected: Expected, + expected: Expected, ) -> Constraint { let record_type_index = constraints.push_type(Type::EmptyRec); let expected_index = constraints.push_expected_type(expected); @@ -2131,7 +2183,7 @@ pub fn constrain_decls( Expectation => { let loc_expr = &declarations.expressions[index]; - let bool_type = Type::Variable(Variable::BOOL); + let bool_type = constraints.push_type(Variable(Variable::BOOL)); let expected = Expected::ForReason(Reason::ExpectCondition, bool_type, loc_expr.region); @@ -2148,7 +2200,7 @@ pub fn constrain_decls( ExpectationFx => { let loc_expr = &declarations.expressions[index]; - let bool_type = Type::Variable(Variable::BOOL); + let bool_type = constraints.push_type(Variable(Variable::BOOL)); let expected = Expected::ForReason(Reason::ExpectCondition, bool_type, loc_expr.region); @@ -2256,6 +2308,7 @@ fn constrain_typed_def( ) -> Constraint { let expr_var = def.expr_var; let expr_type = Type::Variable(expr_var); + let expr_type_index = constraints.push_type(Variable(expr_var)); let mut def_pattern_state = constrain_def_pattern(constraints, env, &def.loc_pattern, expr_type.clone()); @@ -2271,6 +2324,7 @@ fn constrain_typed_def( new_rigid_variables, new_infer_variables, } = instantiate_rigids( + constraints, &annotation.signature, &annotation.introduced_variables, &def.loc_pattern, @@ -2284,13 +2338,16 @@ fn constrain_typed_def( rigids: ftv, }; + // TODO there is a signature_index below, can we coalesce it here? + let signature_index = constraints.push_type(signature.clone()); + let annotation_expected = FromAnnotation( def.loc_pattern.clone(), arity, AnnotationSource::TypedBody { region: annotation.region, }, - signature.clone(), + signature_index, ); { @@ -2370,7 +2427,7 @@ fn constrain_typed_def( AnnotationSource::TypedBody { region: annotation.region, }, - ret_type, + ret_type_index, ); let ret_constraint = constrain_expr( @@ -2385,14 +2442,18 @@ fn constrain_typed_def( vars.push(*fn_var); let defs_constraint = constraints.and_constraint(argument_pattern_state.constraints); - let signature_closure_type = constraints.push_expected_type(Expected::FromAnnotation( - def.loc_pattern.clone(), - arity, - AnnotationSource::TypedBody { - region: annotation.region, - }, - *signature_closure_type.clone(), - )); + let signature_closure_type = { + let signature_closure_type_index = + constraints.push_type(*signature_closure_type.clone()); + constraints.push_expected_type(Expected::FromAnnotation( + def.loc_pattern.clone(), + arity, + AnnotationSource::TypedBody { + region: annotation.region, + }, + signature_closure_type_index, + )) + }; let signature_index = constraints.push_type(signature); let cons = [ constraints.let_constraint( @@ -2433,7 +2494,7 @@ fn constrain_typed_def( AnnotationSource::TypedBody { region: annotation.region, }, - expr_type, + expr_type_index, ); let ret_constraint = constrain_expr( @@ -2501,8 +2562,10 @@ fn constrain_typed_function_arguments( // this constraint must be to the def_pattern_state's constraints def_pattern_state.vars.push(*pattern_var); + let ann_index = constraints.push_type(ann.clone()); + let ann_expected = - constraints.push_expected_type(Expected::NoExpectation(ann.clone())); + constraints.push_expected_type(Expected::NoExpectation(ann_index)); let pattern_con = constraints.equal_types_var( *pattern_var, ann_expected, @@ -2538,8 +2601,9 @@ fn constrain_typed_function_arguments( { // Store the actual type in a variable. + let ann_index = constraints.push_type(ann.clone()); let ann_expected = - constraints.push_expected_type(Expected::NoExpectation(ann.clone())); + constraints.push_expected_type(Expected::NoExpectation(ann_index)); argument_pattern_state .constraints .push(constraints.equal_types_var( @@ -2625,8 +2689,9 @@ fn constrain_typed_function_arguments_simple( // this constraint must be to the def_pattern_state's constraints def_pattern_state.vars.push(*pattern_var); + let ann_index = constraints.push_type(ann.clone()); let ann_expected = - constraints.push_expected_type(Expected::NoExpectation(ann.clone())); + constraints.push_expected_type(Expected::NoExpectation(ann_index)); let pattern_con = constraints.equal_types_var( *pattern_var, ann_expected, @@ -2662,8 +2727,9 @@ fn constrain_typed_function_arguments_simple( { // Store the actual type in a variable. + let ann_index = constraints.push_type(ann.clone()); let expected_annotation = - constraints.push_expected_type(Expected::NoExpectation(ann.clone())); + constraints.push_expected_type(Expected::NoExpectation(ann_index)); argument_pattern_state .constraints .push(constraints.equal_types_var( @@ -2725,6 +2791,7 @@ fn constrain_def( None => { let expr_var = def.expr_var; let expr_type = Type::Variable(expr_var); + let expr_type_index = constraints.push_type(Variable(expr_var)); let mut def_pattern_state = constrain_def_pattern(constraints, env, &def.loc_pattern, expr_type.clone()); @@ -2737,7 +2804,7 @@ fn constrain_def( env, def.loc_expr.region, &def.loc_expr.value, - NoExpectation(expr_type), + NoExpectation(expr_type_index), ); let expr_con = attach_resolution_constraints(constraints, env, expr_con); @@ -2786,7 +2853,7 @@ fn constrain_value_def_make_constraint( body_con: Constraint, symbol: Loc, expr_var: Variable, - expr_type: Type, + expr_type: TypeOrVar, ) -> Constraint { let def_con = constraints.let_constraint( [], @@ -2850,18 +2917,18 @@ fn constrain_closure_size( captured_types.push(Type::Variable(*var)); // make the variable equal to the looked-up type of symbol - let store_into = - constraints.push_expected_type(Expected::NoExpectation(Type::Variable(*var))); + let store_var_index = constraints.push_type(Variable(*var)); + let store_into = constraints.push_expected_type(Expected::NoExpectation(store_var_index)); captured_symbols_constraints.push(constraints.lookup(*symbol, store_into, Region::zero())); } let finalizer = { // pick a more efficient representation if we don't actually capture anything - let closure_type = Type::ClosureTag { + let closure_type = constraints.push_type(Type::ClosureTag { name, captures: captured_types, ambient_function, - }; + }); let clos_type = constraints.push_expected_type(NoExpectation(closure_type)); constraints.equal_types_var(closure_var, clos_type, Category::ClosureSize, region) }; @@ -2878,11 +2945,12 @@ pub struct InstantiateRigids { } fn instantiate_rigids( + constraints: &mut Constraints, annotation: &Type, introduced_vars: &IntroducedVariables, loc_pattern: &Loc, ftv: &mut MutMap, // rigids defined before the current annotation - headers: &mut VecMap>, + headers: &mut VecMap>, ) -> InstantiateRigids { let mut annotation = annotation.clone(); let mut new_rigid_variables: Vec = Vec::new(); @@ -2928,10 +2996,13 @@ fn instantiate_rigids( // Skipping all of this cloning here would be neat! let loc_annotation_ref = Loc::at(loc_pattern.region, &annotation); if let Pattern::Identifier(symbol) = loc_pattern.value { - headers.insert(symbol, Loc::at(loc_pattern.region, annotation.clone())); - } else if let Some(new_headers) = - crate::pattern::headers_from_annotation(&loc_pattern.value, &loc_annotation_ref) - { + let annotation_index = constraints.push_type(annotation.clone()); + headers.insert(symbol, Loc::at(loc_pattern.region, annotation_index)); + } else if let Some(new_headers) = crate::pattern::headers_from_annotation( + constraints, + &loc_pattern.value, + &loc_annotation_ref, + ) { headers.extend(new_headers) } @@ -3022,13 +3093,13 @@ fn constraint_recursive_function( match opt_annotation { None => { - let expr_type = Type::Variable(expr_var); + let expr_type_index = constraints.push_type(Type::Variable(expr_var)); let expr_con = constrain_untyped_closure( constraints, env, loc_function_def.region, - NoExpectation(expr_type), + NoExpectation(expr_type_index), expr_var, function_def.closure_type, function_def.return_type, @@ -3045,7 +3116,7 @@ fn constraint_recursive_function( flex_info.constraints.push(def_con); flex_info.def_types.insert( loc_symbol.value, - Loc::at(loc_symbol.region, Type::Variable(expr_var)), + Loc::at(loc_symbol.region, expr_type_index), ); } @@ -3074,7 +3145,8 @@ fn constraint_recursive_function( AnnotationSource::TypedBody { region: annotation.region, }, - signature.clone(), + // TODO coalesce with other signature_index + constraints.push_type(signature.clone()), ); let (arg_types, _signature_closure_type, ret_type) = match &signature { @@ -3109,7 +3181,8 @@ fn constraint_recursive_function( loc_symbol.value, Loc { region, - value: signature.clone(), + // TODO coalesce with other signature_index + value: constraints.push_type(signature.clone()), }, ); @@ -3145,18 +3218,23 @@ fn constraint_recursive_function( Box::new(ret_type.clone()), ); - let expr_con = constrain_expr( - constraints, - env, - loc_body_expr.region, - &loc_body_expr.value, - NoExpectation(ret_type), - ); + let expr_con = { + // TODO coalesce with other ret_type_index + let ret_type_index = constraints.push_type(ret_type.clone()); + constrain_expr( + constraints, + env, + loc_body_expr.region, + &loc_body_expr.value, + NoExpectation(ret_type_index), + ) + }; let expr_con = attach_resolution_constraints(constraints, env, expr_con); vars.push(expr_var); - let signature_index = constraints.push_type(signature); + let signature_index = constraints.push_type(signature.clone()); + let state_constraints = constraints.and_constraint(argument_pattern_state.constraints); let cons = [ constraints.let_constraint( @@ -3227,6 +3305,7 @@ pub fn rec_defs_help_simple( match declarations.declarations[index] { DeclarationTag::Value => { let expr_var = declarations.variables[index]; + let expr_var_index = constraints.push_type(Type::Variable(expr_var)); let opt_annotation = &declarations.annotations[index]; let loc_expr = &declarations.expressions[index]; @@ -3239,7 +3318,7 @@ pub fn rec_defs_help_simple( env, loc_expr.region, &loc_expr.value, - NoExpectation(Type::Variable(expr_var)), + NoExpectation(expr_var_index), ); let expr_con = attach_resolution_constraints(constraints, env, expr_con); @@ -3247,10 +3326,9 @@ pub fn rec_defs_help_simple( hybrid_and_flex_info.vars.push(expr_var); hybrid_and_flex_info.constraints.push(def_con); - hybrid_and_flex_info.def_types.insert( - loc_symbol.value, - Loc::at(loc_symbol.region, Type::Variable(expr_var)), - ); + hybrid_and_flex_info + .def_types + .insert(loc_symbol.value, Loc::at(loc_symbol.region, expr_var_index)); } Some(annotation) => { let arity = annotation.signature.arity(); @@ -3274,13 +3352,15 @@ pub fn rec_defs_help_simple( hybrid_and_flex_info.vars.extend(new_infer_variables); + let signature_index = constraints.push_type(signature.clone()); + let annotation_expected = FromAnnotation( loc_pattern.clone(), arity, AnnotationSource::TypedBody { region: annotation.region, }, - signature.clone(), + signature_index, ); let expected = annotation_expected; @@ -3295,8 +3375,6 @@ pub fn rec_defs_help_simple( let ret_constraint = attach_resolution_constraints(constraints, env, ret_constraint); - let signature_index = constraints.push_type(signature.clone()); - let cons = [ ret_constraint, // Store type into AST vars. We use Store so errors aren't reported twice @@ -3309,7 +3387,7 @@ pub fn rec_defs_help_simple( ]; let def_con = constraints.and_constraint(cons); - let loc_type = Loc::at(loc_symbol.region, signature); + let loc_type = Loc::at(loc_symbol.region, signature_index); if is_hybrid { hybrid_and_flex_info.vars.extend(&new_rigid_variables); hybrid_and_flex_info.constraints.push(def_con); @@ -3439,6 +3517,7 @@ fn rec_defs_help( for def in defs { let expr_var = def.expr_var; let expr_type = Type::Variable(expr_var); + let expr_type_index = constraints.push_type(Variable(expr_var)); let mut def_pattern_state = constrain_def_pattern(constraints, env, &def.loc_pattern, expr_type.clone()); @@ -3452,7 +3531,7 @@ fn rec_defs_help( env, def.loc_expr.region, &def.loc_expr.value, - NoExpectation(expr_type), + NoExpectation(expr_type_index), ); let expr_con = attach_resolution_constraints(constraints, env, expr_con); @@ -3474,6 +3553,7 @@ fn rec_defs_help( new_rigid_variables, new_infer_variables, } = instantiate_rigids( + constraints, &annotation.signature, &annotation.introduced_variables, &def.loc_pattern, @@ -3485,13 +3565,16 @@ fn rec_defs_help( hybrid_and_flex_info.vars.extend(new_infer_variables); + // TODO there is a signature_index below, can we coalesce? + let signature_index = constraints.push_type(signature.clone()); + let annotation_expected = FromAnnotation( def.loc_pattern.clone(), arity, AnnotationSource::TypedBody { region: annotation.region, }, - signature.clone(), + signature_index, ); // when a def is annotated, and it's body is a closure, treat this @@ -3561,7 +3644,7 @@ fn rec_defs_help( Box::new(Type::Variable(closure_var)), Box::new(ret_type.clone()), )); - let body_type = NoExpectation(ret_type.clone()); + let body_type = NoExpectation(ret_type_index); let expr_con = constrain_expr( constraints, env, @@ -3760,10 +3843,10 @@ fn constrain_field_update( field: Lowercase, loc_expr: &Loc, ) -> (Variable, Type, Constraint) { - let field_type = Type::Variable(var); + let field_type = constraints.push_type(Variable(var)); let reason = Reason::RecordUpdateValue(field); let expected = ForReason(reason, field_type.clone(), region); let con = constrain_expr(constraints, env, loc_expr.region, &loc_expr.value, expected); - (var, field_type, con) + (var, Variable(var), con) } diff --git a/crates/compiler/constrain/src/module.rs b/crates/compiler/constrain/src/module.rs index 76f9047d36..ba0455d6de 100644 --- a/crates/compiler/constrain/src/module.rs +++ b/crates/compiler/constrain/src/module.rs @@ -69,13 +69,15 @@ fn constrain_symbols_from_requires( // Otherwise, this symbol comes from an app module - we want to check that the type // provided by the app is in fact what the package module requires. let arity = loc_type.value.arity(); + let typ = loc_type.value; + let type_index = constraints.push_type(typ); let expected = constraints.push_expected_type(Expected::FromAnnotation( loc_symbol.map(|&s| Pattern::Identifier(s)), arity, AnnotationSource::RequiredSymbol { region: loc_type.region, }, - loc_type.value, + type_index, )); let provided_eq_requires_constr = constraints.lookup(loc_symbol.value, expected, loc_type.region); @@ -120,8 +122,9 @@ pub fn frontload_ability_constraints( let rigid_variables = vars.rigid_vars.iter().chain(vars.able_vars.iter()).copied(); let infer_variables = vars.flex_vars.iter().copied(); + let signature_index = constraints.push_type(signature.clone()); let signature_expectation = - constraints.push_expected_type(Expected::NoExpectation(signature.clone())); + constraints.push_expected_type(Expected::NoExpectation(signature_index)); def_pattern_state .constraints diff --git a/crates/compiler/constrain/src/pattern.rs b/crates/compiler/constrain/src/pattern.rs index f85c0a1c3f..76ed23bf5a 100644 --- a/crates/compiler/constrain/src/pattern.rs +++ b/crates/compiler/constrain/src/pattern.rs @@ -1,6 +1,6 @@ use crate::builtins; use crate::expr::{constrain_expr, Env}; -use roc_can::constraint::{Constraint, Constraints}; +use roc_can::constraint::{Constraint, Constraints, TypeOrVar}; use roc_can::expected::{Expected, PExpected}; use roc_can::pattern::Pattern::{self, *}; use roc_can::pattern::{DestructType, ListPatterns, RecordDestruct}; @@ -17,7 +17,7 @@ use roc_types::types::{ #[derive(Default, Debug)] pub struct PatternState { - pub headers: VecMap>, + pub headers: VecMap>, pub vars: Vec, pub constraints: Vec, pub delayed_is_open_constraints: Vec, @@ -31,14 +31,16 @@ pub struct PatternState { /// Would add `x => <42>` to the headers (i.e., symbol points to a type variable). If the /// definition has an annotation, we instead now add `x => Int`. pub fn headers_from_annotation( + constraints: &mut Constraints, pattern: &Pattern, annotation: &Loc<&Type>, -) -> Option>> { +) -> Option>> { let mut headers = VecMap::default(); // Check that the annotation structurally agrees with the pattern, preventing e.g. `{ x, y } : Int` // in such incorrect cases we don't put the full annotation in headers, just a variable, and let // inference generate a proper error. - let is_structurally_valid = headers_from_annotation_help(pattern, annotation, &mut headers); + let is_structurally_valid = + headers_from_annotation_help(constraints, pattern, annotation, &mut headers); if is_structurally_valid { Some(headers) @@ -48,9 +50,10 @@ pub fn headers_from_annotation( } fn headers_from_annotation_help( + constraints: &mut Constraints, pattern: &Pattern, annotation: &Loc<&Type>, - headers: &mut VecMap>, + headers: &mut VecMap>, ) -> bool { match pattern { Identifier(symbol) @@ -60,7 +63,8 @@ fn headers_from_annotation_help( ident: symbol, specializes: _, } => { - let typ = Loc::at(annotation.region, annotation.value.clone()); + let annotation_index = constraints.push_type(annotation.value.clone()); + let typ = Loc::at(annotation.region, annotation_index); headers.insert(*symbol, typ); true } @@ -87,9 +91,10 @@ fn headers_from_annotation_help( // `{ x ? 0 } = rec` or `{ x: 5 } -> ...` in all cases // the type of `x` within the binding itself is the same. if let Some(field_type) = fields.get(&destruct.label) { + let field_type_index = constraints.push_type(field_type.as_inner().clone()); headers.insert( destruct.symbol, - Loc::at(annotation.region, field_type.clone().into_inner()), + Loc::at(annotation.region, field_type_index), ); } else { return false; @@ -125,6 +130,7 @@ fn headers_from_annotation_help( .zip(arg_types.iter()) .all(|(arg_pattern, arg_type)| { headers_from_annotation_help( + constraints, &arg_pattern.1.value, &Loc::at(annotation.region, arg_type), headers, @@ -156,11 +162,13 @@ fn headers_from_annotation_help( && type_arguments.len() == pat_type_arguments.len() && lambda_set_variables.len() == pat_lambda_set_variables.len() => { - let typ = Loc::at(annotation.region, annotation.value.clone()); + let annotation_index = constraints.push_type(annotation.value.clone()); + let typ = Loc::at(annotation.region, annotation_index); headers.insert(*opaque, typ); let (_, argument_pat) = &**argument; headers_from_annotation_help( + constraints, &argument_pat.value, &Loc::at(annotation.region, actual), headers, @@ -203,9 +211,9 @@ pub fn constrain_pattern( } Identifier(symbol) | Shadowed(_, _, symbol) => { - if could_be_a_tag_union(expected.get_type_ref()) { - let type_index = constraints.push_type(expected.get_type_ref().clone()); + let type_index = constraints.push_type(expected.get_type_ref().clone()); + if could_be_a_tag_union(expected.get_type_ref()) { state .delayed_is_open_constraints .push(constraints.is_open_type(type_index)); @@ -215,7 +223,7 @@ pub fn constrain_pattern( *symbol, Loc { region, - value: expected.get_type(), + value: type_index, }, ); } @@ -224,9 +232,9 @@ pub fn constrain_pattern( ident: symbol, specializes: _, } => { - if could_be_a_tag_union(expected.get_type_ref()) { - let type_index = constraints.push_type(expected.get_type_ref().clone()); + let type_index = constraints.push_type(expected.get_type_ref().clone()); + if could_be_a_tag_union(expected.get_type_ref()) { state.constraints.push(constraints.is_open_type(type_index)); } @@ -234,7 +242,7 @@ pub fn constrain_pattern( *symbol, Loc { region, - value: expected.get_type(), + value: type_index, }, ); } @@ -278,7 +286,7 @@ pub fn constrain_pattern( let num_type = constraints.push_type(num_type); // Link the free num var with the int var and our expectation. - let int_type = builtins::num_int(Type::Variable(precision_var)); + let int_type = constraints.push_type(builtins::num_int(Type::Variable(precision_var))); state.constraints.push({ let expected_index = @@ -308,10 +316,11 @@ pub fn constrain_pattern( region, Category::Frac, ); + let num_type_index = constraints.push_type(num_type); // TODO check me if something breaks! // Link the free num var with the float var and our expectation. - let float_type = builtins::num_float(Type::Variable(precision_var)); - let num_type_index = constraints.push_type(num_type); // TODO check me if something breaks! + let float_type = + constraints.push_type(builtins::num_float(Type::Variable(precision_var))); state.constraints.push({ let expected_index = @@ -353,11 +362,11 @@ pub fn constrain_pattern( Category::Int, ); - // Link the free num var with the int var and our expectation. - let int_type = builtins::num_int(Type::Variable(precision_var)); - let num_type_index = constraints.push_type(num_type); + // Link the free num var with the int var and our expectation. + let int_type = constraints.push_type(builtins::num_int(Type::Variable(precision_var))); + state.constraints.push({ let expected_index = constraints.push_expected_type(Expected::NoExpectation(int_type)); @@ -402,12 +411,13 @@ pub fn constrain_pattern( } in destructs { let pat_type = Type::Variable(*var); + let pat_type_index = constraints.push_type(pat_type.clone()); let expected = PExpected::NoExpectation(pat_type.clone()); if !state.headers.contains_key(symbol) { state .headers - .insert(*symbol, Loc::at(region, pat_type.clone())); + .insert(*symbol, Loc::at(region, pat_type_index)); } let field_type = match typ { @@ -459,7 +469,7 @@ pub fn constrain_pattern( let expr_expected = Expected::ForReason( Reason::RecordDefaultField(label.clone()), - pat_type.clone(), + pat_type_index, loc_expr.region, ); @@ -485,7 +495,10 @@ pub fn constrain_pattern( state.vars.push(*var); } - let record_type = Type::Record(field_types, TypeExtension::from_type(ext_type)); + let record_type = constraints.push_type(Type::Record( + field_types, + TypeExtension::from_type(ext_type), + )); let whole_var_index = constraints.push_type(Type::Variable(*whole_var)); let expected_record = @@ -623,7 +636,7 @@ pub fn constrain_pattern( let (arg_pattern_var, loc_arg_pattern) = &**argument; let arg_pattern_type = Type::Variable(*arg_pattern_var); - let opaque_type = Type::Alias { + let opaque_type = constraints.push_type(Type::Alias { symbol: *opaque, type_arguments: type_arguments .iter() @@ -636,7 +649,7 @@ pub fn constrain_pattern( infer_ext_in_output_types: vec![], actual: Box::new(arg_pattern_type.clone()), kind: AliasKind::Opaque, - }; + }); // First, add a constraint for the argument "who" let arg_pattern_expected = PExpected::NoExpectation(arg_pattern_type.clone()); diff --git a/crates/compiler/solve/src/solve.rs b/crates/compiler/solve/src/solve.rs index a646a7b8eb..4c47cee1d1 100644 --- a/crates/compiler/solve/src/solve.rs +++ b/crates/compiler/solve/src/solve.rs @@ -947,15 +947,16 @@ fn solve( ); let expectation = &constraints.expectations[expectation_index.index()]; - let expected = type_cell_to_var( + let expected = either_type_index_to_var( + constraints, subs, rank, + pools, problems, abilities_store, obligation_cache, - pools, aliases, - expectation.get_type_ref(), + *expectation.get_type_ref(), ); match unify( @@ -1065,15 +1066,16 @@ fn solve( let actual = deep_copy_var_in(subs, rank, pools, var, arena); let expectation = &constraints.expectations[expectation_index.index()]; - let expected = type_cell_to_var( + let expected = either_type_index_to_var( + constraints, subs, rank, + pools, problems, abilities_store, obligation_cache, - pools, aliases, - expectation.get_type_ref(), + *expectation.get_type_ref(), ); match unify( @@ -1487,15 +1489,28 @@ fn solve( // 4. Condition and branch types aren't "almost equal", this is just a normal type // error. - let (real_var, real_region, expected_type, category_and_expected) = match eq { + let (real_var, real_region, branches_var, category_and_expected) = match eq { Ok(eq) => { let roc_can::constraint::Eq(real_var, expected, category, real_region) = constraints.eq[eq.index()]; let expected = &constraints.expectations[expected.index()]; + + let branches_var = either_type_index_to_var( + constraints, + subs, + rank, + pools, + problems, + abilities_store, + obligation_cache, + aliases, + *expected.get_type_ref(), + ); + ( real_var, real_region, - expected.get_type_ref(), + branches_var, Ok((category, expected)), ) } @@ -1507,10 +1522,22 @@ fn solve( real_region, ) = constraints.pattern_eq[peq.index()]; let expected = &constraints.pattern_expectations[expected.index()]; + + let branches_var = type_cell_to_var( + subs, + rank, + problems, + abilities_store, + obligation_cache, + pools, + aliases, + expected.get_type_ref(), + ); + ( real_var, real_region, - expected.get_type_ref(), + branches_var, Err((category, expected)), ) } diff --git a/crates/reporting/tests/helpers/mod.rs b/crates/reporting/tests/helpers/mod.rs index 7f0a6ea06c..22bd02d54e 100644 --- a/crates/reporting/tests/helpers/mod.rs +++ b/crates/reporting/tests/helpers/mod.rs @@ -140,9 +140,12 @@ pub fn can_expr_with<'a>( } }; + let mut constraints = Constraints::new(); + let mut var_store = VarStore::default(); let var = var_store.fresh(); - let expected = Expected::NoExpectation(Type::Variable(var)); + let var_index = constraints.push_type(Type::Variable(var)); + let expected = Expected::NoExpectation(var_index); let mut module_ids = ModuleIds::default(); // ensure the Test module is accessible in our tests @@ -169,7 +172,6 @@ pub fn can_expr_with<'a>( &loc_expr.value, ); - let mut constraints = Constraints::new(); let constraint = constrain_expr( &mut constraints, &mut roc_constrain::expr::Env {