diff --git a/crates/compiler/can/src/constraint.rs b/crates/compiler/can/src/constraint.rs index 2200a5f9df..7e8842901c 100644 --- a/crates/compiler/can/src/constraint.rs +++ b/crates/compiler/can/src/constraint.rs @@ -211,10 +211,14 @@ impl Constraints { EitherIndex::from_right(index) } - pub fn push_expected_type(&mut self, expected: Expected) -> Index>> { + pub fn push_expected_type(&mut self, expected: Expected) -> ExpectedTypeIndex { Index::push_new(&mut self.expectations, expected.map(Cell::new)) } + pub fn push_pat_expected_type(&mut self, expected: PExpected) -> PExpectedTypeIndex { + Index::push_new(&mut self.pattern_expectations, expected.map(Cell::new)) + } + #[inline(always)] pub fn push_category(&mut self, category: Category) -> Index { match category { @@ -256,13 +260,11 @@ impl Constraints { pub fn equal_types( &mut self, - typ: Type, - expected: Expected, + type_index: TypeOrVar, + expected_index: ExpectedTypeIndex, category: Category, region: Region, ) -> Constraint { - let type_index = self.push_type(typ); - let expected_index = Index::push_new(&mut self.expectations, expected.map(Cell::new)); let category_index = Self::push_category(self, category); Constraint::Eq(Eq(type_index, expected_index, category_index, region)) @@ -271,12 +273,11 @@ impl Constraints { pub fn equal_types_var( &mut self, var: Variable, - expected: Expected, + expected_index: ExpectedTypeIndex, category: Category, region: Region, ) -> Constraint { let type_index = Self::push_type_variable(var); - let expected_index = Index::push_new(&mut self.expectations, expected.map(Cell::new)); let category_index = Self::push_category(self, category); Constraint::Eq(Eq(type_index, expected_index, category_index, region)) @@ -284,14 +285,12 @@ impl Constraints { pub fn equal_types_with_storage( &mut self, - typ: Type, - expected: Expected, + type_index: TypeOrVar, + expected_index: ExpectedTypeIndex, category: Category, region: Region, storage_var: Variable, ) -> Constraint { - let type_index = self.push_type(typ); - let expected_index = Index::push_new(&mut self.expectations, expected.map(Cell::new)); let category_index = Self::push_category(self, category); let equal = Constraint::Eq(Eq(type_index, expected_index, category_index, region)); @@ -311,14 +310,11 @@ impl Constraints { pub fn equal_pattern_types( &mut self, - typ: Type, - expected: PExpected, + type_index: TypeOrVar, + expected_index: PExpectedTypeIndex, category: PatternCategory, region: Region, ) -> Constraint { - let type_index = self.push_type(typ); - let expected_index = - Index::push_new(&mut self.pattern_expectations, expected.map(Cell::new)); let category_index = Self::push_pattern_category(self, category); Constraint::Pattern(type_index, expected_index, category_index, region) @@ -326,44 +322,34 @@ impl Constraints { pub fn pattern_presence( &mut self, - typ: Type, - expected: PExpected, + type_index: TypeOrVar, + expected_index: PExpectedTypeIndex, category: PatternCategory, region: Region, ) -> Constraint { - let type_index = self.push_type(typ); - let expected_index = - Index::push_new(&mut self.pattern_expectations, expected.map(Cell::new)); let category_index = Index::push_new(&mut self.pattern_categories, category); Constraint::PatternPresence(type_index, expected_index, category_index, region) } - pub fn is_open_type(&mut self, typ: Type) -> Constraint { - let type_index = self.push_type(typ); - + pub fn is_open_type(&mut self, type_index: TypeOrVar) -> Constraint { Constraint::IsOpenType(type_index) } - pub fn includes_tag( + pub fn includes_tag( &mut self, - typ: Type, + type_index: TypeOrVar, tag_name: TagName, - types: I, + payloads: Slice, category: PatternCategory, region: Region, - ) -> Constraint - where - I: IntoIterator, - { - let type_index = Index::push_new(&mut self.types, Cell::new(typ)); + ) -> Constraint { let category_index = Index::push_new(&mut self.pattern_categories, category); - let types_slice = Slice::extend_new(&mut self.types, types.into_iter().map(Cell::new)); let includes_tag = IncludesTag { type_index, tag_name, - types: types_slice, + types: payloads, pattern_category: category_index, region, }; @@ -373,7 +359,7 @@ impl Constraints { Constraint::IncludesTag(includes_tag_index) } - fn variable_slice(&mut self, it: I) -> Slice + pub fn variable_slice(&mut self, it: I) -> Slice where I: IntoIterator, { @@ -572,14 +558,10 @@ impl Constraints { pub fn lookup( &mut self, symbol: Symbol, - expected: Expected, + expected_index: ExpectedTypeIndex, region: Region, ) -> Constraint { - Constraint::Lookup( - symbol, - Index::push_new(&mut self.expectations, expected.map(Cell::new)), - region, - ) + Constraint::Lookup(symbol, expected_index, region) } pub fn contains_save_the_environment(&self, constraint: &Constraint) -> bool { @@ -617,19 +599,6 @@ impl Constraints { } pub fn store( - &mut self, - typ: Type, - variable: Variable, - filename: &'static str, - line_number: u32, - ) -> Constraint { - let type_index = self.push_type(typ); - let string_index = Index::push_new(&mut self.strings, filename); - - Constraint::Store(type_index, variable, string_index, line_number) - } - - pub fn store_index( &mut self, type_index: TypeOrVar, variable: Variable, @@ -804,9 +773,9 @@ pub struct LetConstraint { #[derive(Debug, Clone)] pub struct IncludesTag { - pub type_index: TypeIndex, + pub type_index: TypeOrVar, pub tag_name: TagName, - pub types: Slice>, + pub types: Slice, pub pattern_category: Index, pub region: Region, } diff --git a/crates/compiler/constrain/src/builtins.rs b/crates/compiler/constrain/src/builtins.rs index b0fd06a1b0..bc96ff1d0b 100644 --- a/crates/compiler/constrain/src/builtins.rs +++ b/crates/compiler/constrain/src/builtins.rs @@ -32,8 +32,10 @@ pub fn add_numeric_bound_constr( NumericBound::FloatExact(width) => { let actual_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); let because_suffix = - constraints.equal_types(Variable(num_var), expected, category, region); + constraints.equal_types(type_index, expected_index, category, region); num_constraints.extend([because_suffix]); @@ -42,8 +44,10 @@ pub fn add_numeric_bound_constr( NumericBound::IntExact(width) => { let actual_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); let because_suffix = - constraints.equal_types(Variable(num_var), expected, category, region); + constraints.equal_types(type_index, expected_index, category, region); num_constraints.extend([because_suffix]); @@ -52,7 +56,9 @@ pub fn add_numeric_bound_constr( NumericBound::Range(range) => { let actual_type = Variable(precision_var); let expected = Expected::NoExpectation(RangedNumber(range)); - let constr = constraints.equal_types(actual_type, expected, category, region); + let type_index = constraints.push_type(actual_type); + let expected_index = constraints.push_expected_type(expected); + let constr = constraints.equal_types(type_index, expected_index, category, region); num_constraints.extend([constr]); @@ -84,14 +90,19 @@ pub fn int_literal( Category::Num, ); + 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, + )); + constrs.extend([ - constraints.equal_types( - num_type.clone(), - ForReason(reason, num_int(Type::Variable(precision_var)), region), - Category::Int, - region, - ), - constraints.equal_types(num_type, expected, Category::Int, region), + 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) + }, ]); // TODO the precision_var is not part of the exists here; for float it is. Which is correct? @@ -121,14 +132,24 @@ pub fn single_quote_literal( Category::Character, ); + 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, + )); + constrs.extend([ constraints.equal_types( - num_type.clone(), - ForReason(reason, num_int(Type::Variable(precision_var)), region), + num_type_index, + expect_precision_var, Category::Character, region, ), - constraints.equal_types(num_type, expected, Category::Character, region), + { + let expected_index = constraints.push_expected_type(expected); + constraints.equal_types(num_type_index, expected_index, Category::Character, region) + }, ]); let and_constraint = constraints.and_constraint(constrs); @@ -157,14 +178,19 @@ pub fn float_literal( Category::Frac, ); + 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, + )); + constrs.extend([ - constraints.equal_types( - num_type.clone(), - ForReason(reason, num_float(Type::Variable(precision_var)), region), - Category::Frac, - region, - ), - constraints.equal_types(num_type, expected, Category::Frac, region), + 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) + }, ]); let and_constraint = constraints.and_constraint(constrs); @@ -190,7 +216,9 @@ pub fn num_literal( Category::Num, ); - constrs.extend([constraints.equal_types(num_type, expected, Category::Num, region)]); + 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)]); let and_constraint = constraints.and_constraint(constrs); constraints.exists([num_var], and_constraint) diff --git a/crates/compiler/constrain/src/expr.rs b/crates/compiler/constrain/src/expr.rs index 899a273dca..c75d858e1f 100644 --- a/crates/compiler/constrain/src/expr.rs +++ b/crates/compiler/constrain/src/expr.rs @@ -151,6 +151,10 @@ 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( [], @@ -211,7 +215,9 @@ pub fn constrain_expr( rec_constraints.push(field_con); } - let record_type = Type::Record(field_types, TypeExtension::Closed); + 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, @@ -256,33 +262,33 @@ pub fn constrain_expr( let record_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)); let fields_con = constraints.equal_types_var( *record_var, - NoExpectation(fields_type), + fields_type_expected, Category::Record, region, ); + let expected_record = constraints.push_expected_type(expected); let record_con = - constraints.equal_types_var(*record_var, expected, Category::Record, region); + constraints.equal_types_var(*record_var, expected_record, Category::Record, region); vars.push(*record_var); vars.push(*ext_var); - let con = constraints.lookup( - *symbol, - ForReason( - Reason::RecordUpdateKeys( - *symbol, - updates - .iter() - .map(|(key, field)| (key.clone(), field.region)) - .collect(), - ), - record_type, - region, + let record_being_updated_expectation = constraints.push_expected_type(ForReason( + Reason::RecordUpdateKeys( + *symbol, + updates + .iter() + .map(|(key, field)| (key.clone(), field.region)) + .collect(), ), + record_type, region, - ); + )); + + let con = constraints.lookup(*symbol, record_being_updated_expectation, region); // ensure constraints are solved in this order, gives better errors cons.insert(0, fields_con); @@ -292,7 +298,11 @@ pub fn constrain_expr( let and_constraint = constraints.and_constraint(cons); constraints.exists(vars, and_constraint) } - Str(_) => constraints.equal_types(str_type(), expected, Category::Str, region), + Str(_) => { + let str_index = constraints.push_type(str_type()); + let expected_index = constraints.push_expected_type(expected); + constraints.equal_types(str_index, expected_index, Category::Str, region) + } SingleQuote(num_var, precision_var, _, bound) => single_quote_literal( constraints, *num_var, @@ -306,9 +316,11 @@ pub fn constrain_expr( loc_elems, } => { 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( - empty_list_type(*elem_var), - expected, + elem_type_index, + expected_index, Category::List, region, ); @@ -336,9 +348,11 @@ pub fn constrain_expr( list_constraints.push(constraint); } + 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( - list_type(list_elem_type), - expected, + elem_type_index, + expected_index, Category::List, region, )); @@ -407,11 +421,13 @@ pub fn constrain_expr( arg_cons.push(arg_con); } - let expected_fn_type = ForReason( + 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_final_type = constraints.push_expected_type(expected); let category = Category::CallResult(opt_symbol, *called_via); @@ -419,7 +435,7 @@ pub fn constrain_expr( fn_con, constraints.equal_types_var(*fn_var, expected_fn_type, category.clone(), fn_region), constraints.and_constraint(arg_cons), - constraints.equal_types_var(*ret_var, expected, category, region), + constraints.equal_types_var(*ret_var, expected_final_type, category, region), ]; let and_constraint = constraints.and_constraint(and_cons); @@ -427,26 +443,25 @@ pub fn constrain_expr( } Var(symbol, variable) => { // Save the expectation in the variable, then lookup the symbol's type in the environment - let store_expected = - constraints.store(expected.get_type_ref().clone(), *variable, file!(), line!()); - let lookup_constr = - constraints.lookup(*symbol, expected.replace(Type::Variable(*variable)), region); + let expected_type = constraints.push_type(expected.get_type_ref().clone()); + let store_expected = constraints.store(expected_type, *variable, file!(), line!()); + + let store_into_var = + constraints.push_expected_type(expected.replace(Type::Variable(*variable))); + + let lookup_constr = constraints.lookup(*symbol, store_into_var, 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 store_expected = constraints.store( - expected.get_type_ref().clone(), - specialization_var, - file!(), - line!(), - ); - let lookup_constr = constraints.lookup( - symbol, - Expected::NoExpectation(Type::Variable(specialization_var)), - region, - ); + let expected_type = constraints.push_type(expected.get_type_ref().clone()); + 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); // Make sure we attempt to resolve the specialization, if we can. if let Some(specialization_id) = specialization_id { @@ -527,11 +542,9 @@ pub fn constrain_expr( { vars.push(*var); - all_constraints.push(constraints.lookup( - *symbol, - NoExpectation(Type::Variable(*var)), - Region::zero(), - )); + let store_into = + constraints.push_expected_type(NoExpectation(Type::Variable(*var))); + all_constraints.push(constraints.lookup(*symbol, store_into, Region::zero())); } constraints.exists_many(vars, all_constraints) @@ -579,11 +592,10 @@ pub fn constrain_expr( { vars.push(*var); - all_constraints.push(constraints.lookup( - *symbol, - NoExpectation(Type::Variable(*var)), - Region::zero(), - )); + let store_into = + constraints.push_expected_type(NoExpectation(Type::Variable(*var))); + + all_constraints.push(constraints.lookup(*symbol, store_into, Region::zero())); } constraints.exists_many(vars, all_constraints) @@ -603,9 +615,10 @@ pub fn constrain_expr( // 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 cond_var_is_bool_con = constraints.equal_types_var( *cond_var, - expect_bool(first_cond_region), + expected_bool, Category::If, first_cond_region, ); @@ -662,9 +675,11 @@ pub fn constrain_expr( ), ); + let expected_result_type = constraints.push_expected_type(NoExpectation(tipe)); + let ast_con = constraints.equal_types_var( *branch_var, - NoExpectation(tipe), + expected_result_type, Category::Storage(std::file!(), std::line!()), region, ); @@ -717,6 +732,8 @@ pub fn constrain_expr( ), ); + let expected = constraints.push_expected_type(expected); + branch_cons.push(constraints.equal_types_var( *branch_var, expected, @@ -910,6 +927,8 @@ 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); @@ -939,19 +958,22 @@ pub fn constrain_expr( 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 = Expected::NoExpectation(record_type); + let record_expected = + constraints.push_expected_type(NoExpectation(record_type.clone())); let category = Category::Access(field.clone()); - let record_con = constraints.equal_types_var( - *record_var, - record_expected.clone(), - category.clone(), - region, - ); + let record_con = + constraints.equal_types_var(*record_var, record_expected, category.clone(), region); - let constraint = - constrain_expr(constraints, env, region, &loc_expr.value, record_expected); + let constraint = constrain_expr( + constraints, + env, + region, + &loc_expr.value, + NoExpectation(record_type), + ); + let expected = constraints.push_expected_type(expected); let eq = constraints.equal_types_var(field_var, expected, category, region); constraints.exists_many( @@ -980,38 +1002,46 @@ pub fn constrain_expr( let category = Category::Accessor(field.clone()); - let record_expected = Expected::NoExpectation(record_type.clone()); + let record_expected = + constraints.push_expected_type(NoExpectation(record_type.clone())); let record_con = constraints.equal_types_var(*record_var, record_expected, category.clone(), region); - let lambda_set = Type::ClosureTag { + let lambda_set = constraints.push_expected_type(NoExpectation(Type::ClosureTag { name: *closure_name, captures: vec![], ambient_function: *function_var, - }; + })); let closure_type = Type::Variable(*closure_var); - let function_type = Type::Function( + let function_type_index = constraints.push_type(Type::Function( vec![record_type], Box::new(closure_type), Box::new(field_type), - ); + )); let cons = [ - constraints.equal_types_var( - *closure_var, - NoExpectation(lambda_set), - category.clone(), - region, - ), - constraints.equal_types(function_type.clone(), expected, category.clone(), region), - constraints.equal_types( - function_type, - NoExpectation(Variable(*function_var)), - category, - region, - ), + constraints.equal_types_var(*closure_var, lambda_set, category.clone(), region), + { + let expected_index = constraints.push_expected_type(expected); + constraints.equal_types( + function_type_index, + expected_index, + category.clone(), + region, + ) + }, + { + let function_var_index = + constraints.push_expected_type(NoExpectation(Variable(*function_var))); + constraints.equal_types( + function_type_index, + function_var_index, + category, + region, + ) + }, record_con, ]; @@ -1083,12 +1113,15 @@ pub fn constrain_expr( types.push(Type::Variable(*var)); } + let tag_union_type = constraints.push_type(Type::TagUnion( + 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( - Type::TagUnion( - vec![(name.clone(), types)], - TypeExtension::from_type(Type::Variable(*ext_var)), - ), - expected.clone(), + tag_union_type, + expected, Category::TagApply { tag_name: name.clone(), args_count: arguments.len(), @@ -1109,13 +1142,15 @@ pub fn constrain_expr( name, closure_name, } => { + let function_or_tag_union = constraints.push_type(Type::FunctionOrTagUnion( + name.clone(), + *closure_name, + TypeExtension::from_type(Type::Variable(*ext_var)), + )); + let expected = constraints.push_expected_type(expected); let union_con = constraints.equal_types_with_storage( - Type::FunctionOrTagUnion( - name.clone(), - *closure_name, - TypeExtension::from_type(Type::Variable(*ext_var)), - ), - expected.clone(), + function_or_tag_union, + expected, Category::TagApply { tag_name: name.clone(), args_count: 0, @@ -1137,7 +1172,7 @@ pub fn constrain_expr( let (arg_var, arg_loc_expr) = &**argument; let arg_type = Type::Variable(*arg_var); - let opaque_type = Type::Alias { + let opaque_type = constraints.push_type(Type::Alias { symbol: *name, type_arguments: type_arguments .iter() @@ -1149,7 +1184,7 @@ pub fn constrain_expr( lambda_set_variables: lambda_set_variables.clone(), actual: Box::new(arg_type.clone()), kind: AliasKind::Opaque, - }; + }); // Constrain the argument let arg_con = constrain_expr( @@ -1162,6 +1197,7 @@ pub fn constrain_expr( // 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, @@ -1173,12 +1209,17 @@ pub fn constrain_expr( // Link the entire wrapped opaque type (with the now-constrained argument) to the type // variables of the opaque type // TODO: better expectation here - let link_type_variables_con = constraints.equal_types( - arg_type, - Expected::NoExpectation((**specialized_def_type).clone()), - Category::OpaqueArg, - arg_loc_expr.region, - ); + 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())); + constraints.equal_types( + type_index, + expected_index, + Category::OpaqueArg, + arg_loc_expr.region, + ) + }; let mut vars = vec![*arg_var, *opaque_var]; // Also add the fresh variables we created for the type argument and lambda sets @@ -1216,50 +1257,59 @@ pub fn constrain_expr( kind: AliasKind::Opaque, }; + let expected_opaque_type = constraints.push_expected_type(NoExpectation(opaque_type)); + // Tie the opaque type to the opaque_var let opaque_con = constraints.equal_types_var( *opaque_var, - Expected::NoExpectation(opaque_type), + expected_opaque_type, Category::OpaqueWrap(*opaque_name), region, ); // Tie the type of the value wrapped by the opaque to the opaque's type variables. - let link_type_variables_con = constraints.equal_types( - argument_type.clone(), - Expected::NoExpectation((*specialized_def_type).clone()), - Category::OpaqueArg, - region, - ); + 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())); + constraints.equal_types( + arg_type_index, + expected_specialized, + Category::OpaqueArg, + region, + ) + }; - let lambda_set = Type::ClosureTag { + let lambda_set = constraints.push_expected_type(NoExpectation(Type::ClosureTag { name: *function_name, captures: vec![], ambient_function: *function_var, - }; + })); let closure_type = Type::Variable(*closure_var); let opaque_type = Type::Variable(*opaque_var); - let function_type = Type::Function( + let function_type = constraints.push_expected_type(NoExpectation(Type::Function( vec![argument_type], Box::new(closure_type), Box::new(opaque_type), - ); + ))); + + let expected = constraints.push_expected_type(expected); let cons = [ opaque_con, link_type_variables_con, constraints.equal_types_var( *closure_var, - NoExpectation(lambda_set), + lambda_set, Category::OpaqueWrap(*opaque_name), region, ), constraints.equal_types_var( *function_var, - Expected::NoExpectation(function_type), + function_type, Category::OpaqueWrap(*opaque_name), region, ), @@ -1314,6 +1364,7 @@ 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); @@ -1354,6 +1405,7 @@ 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); @@ -1362,6 +1414,7 @@ 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, @@ -1441,12 +1494,17 @@ fn constrain_function_def( signature.clone(), ); - def_pattern_state.constraints.push(constraints.equal_types( - Type::Variable(expr_var), - annotation_expected, - Category::Storage(std::file!(), std::line!()), - Region::span_across(&annotation.region, &loc_body_expr.region), - )); + { + 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, + expected_index, + Category::Storage(std::file!(), std::line!()), + Region::span_across(&annotation.region, &loc_body_expr.region), + )); + } def_pattern_state }; @@ -1477,10 +1535,12 @@ fn constrain_function_def( let ret_constraint = attach_resolution_constraints(constraints, env, ret_constraint); + let signature_index = constraints.push_type(signature); + let cons = [ ret_constraint, // Store type into AST vars. We use Store so errors aren't reported twice - constraints.store(signature, expr_var, std::file!(), std::line!()), + constraints.store(signature_index, expr_var, std::file!(), std::line!()), ]; let expr_con = constraints.and_constraint(cons); @@ -1514,6 +1574,7 @@ fn constrain_function_def( let closure_var = function_def.closure_type; let ret_type = *ret_type.clone(); + let ret_type_index = constraints.push_type(ret_type.clone()); vars.push(ret_var); vars.push(closure_var); @@ -1544,12 +1605,16 @@ fn constrain_function_def( signature.clone(), ); - def_pattern_state.constraints.push(constraints.equal_types( - Type::Variable(expr_var), - annotation_expected, - Category::Storage(std::file!(), std::line!()), - Region::span_across(&annotation.region, &loc_body_expr.region), - )); + { + 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, + expected_index, + Category::Storage(std::file!(), std::line!()), + Region::span_across(&annotation.region, &loc_body_expr.region), + )); + } constrain_typed_function_arguments_simple( constraints, @@ -1577,7 +1642,7 @@ fn constrain_function_def( AnnotationSource::TypedBody { region: annotation.region, }, - ret_type.clone(), + ret_type, ); let ret_constraint = constrain_expr( @@ -1592,8 +1657,15 @@ fn constrain_function_def( vars.push(expr_var); let defs_constraint = constraints.and_constraint(argument_pattern_state.constraints); - let signature_closure_type = *signature_closure_type.clone(); - let signature_index = constraints.push_type(signature.clone()); + let signature_closure_type = constraints.push_expected_type(Expected::FromAnnotation( + loc_pattern, + arity, + AnnotationSource::TypedBody { + region: annotation.region, + }, + *signature_closure_type.clone(), + )); + let signature_index = constraints.push_type(signature); let cons = [ constraints.let_constraint( [], @@ -1604,19 +1676,12 @@ fn constrain_function_def( ), constraints.equal_types_var( closure_var, - Expected::FromAnnotation( - loc_pattern, - arity, - AnnotationSource::TypedBody { - region: annotation.region, - }, - signature_closure_type, - ), + signature_closure_type, Category::ClosureSize, region, ), - constraints.store_index(signature_index, expr_var, std::file!(), std::line!()), - constraints.store(ret_type, ret_var, std::file!(), std::line!()), + constraints.store(signature_index, expr_var, std::file!(), std::line!()), + constraints.store(ret_type_index, ret_var, std::file!(), std::line!()), closure_constraint, ]; @@ -1728,10 +1793,12 @@ fn constrain_destructure_def( annotation_expected, ); + let signature_index = constraints.push_type(signature); + let cons = [ ret_constraint, // Store type into AST vars. We use Store so errors aren't reported twice - constraints.store(signature, expr_var, std::file!(), std::line!()), + constraints.store(signature_index, expr_var, std::file!(), std::line!()), ]; let expr_con = constraints.and_constraint(cons); @@ -1824,10 +1891,12 @@ fn constrain_value_def( ); 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 - constraints.store(signature.clone(), expr_var, std::file!(), std::line!()), + constraints.store(signature_index, expr_var, std::file!(), std::line!()), ]; let expr_con = constraints.and_constraint(cons); @@ -1927,13 +1996,17 @@ fn constrain_when_branch_help( state.headers.extend(partial_state.headers); } else { // Make sure the bound variables in the patterns on the same branch agree in their types. - for (sym, typ1) in state.headers.iter() { - if let Some(typ2) = partial_state.headers.get(sym) { + 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 this_typ = constraints + .push_expected_type(Expected::NoExpectation(this_bound_typ.value.clone())); + state.constraints.push(constraints.equal_types( - typ1.value.clone(), - Expected::NoExpectation(typ2.value.clone()), + whole_typ, + this_typ, Category::When, - typ2.region, + this_bound_typ.region, )); } @@ -2016,7 +2089,9 @@ fn constrain_empty_record( region: Region, expected: Expected, ) -> Constraint { - constraints.equal_types(Type::EmptyRec, expected, Category::Record, region) + 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) } /// Constrain top-level module declarations @@ -2214,12 +2289,16 @@ fn constrain_typed_def( signature.clone(), ); - def_pattern_state.constraints.push(constraints.equal_types( - expr_type.clone(), - annotation_expected, - Category::Storage(std::file!(), std::line!()), - Region::span_across(&annotation.region, &def.loc_expr.region), - )); + { + let type_index = constraints.push_type(expr_type.clone()); + let expected_index = constraints.push_expected_type(annotation_expected); + def_pattern_state.constraints.push(constraints.equal_types( + type_index, + expected_index, + Category::Storage(std::file!(), std::line!()), + Region::span_across(&annotation.region, &def.loc_expr.region), + )); + } // when a def is annotated, and its body is a closure, treat this // as a named function (in elm terms) for error messages. @@ -2256,6 +2335,7 @@ fn constrain_typed_def( let ret_var = *ret_var; let closure_var = *closure_var; let ret_type = *ret_type.clone(); + let ret_type_index = constraints.push_type(ret_type.clone()); vars.push(ret_var); vars.push(closure_var); @@ -2286,7 +2366,7 @@ fn constrain_typed_def( AnnotationSource::TypedBody { region: annotation.region, }, - ret_type.clone(), + ret_type, ); let ret_constraint = constrain_expr( @@ -2301,7 +2381,14 @@ fn constrain_typed_def( vars.push(*fn_var); let defs_constraint = constraints.and_constraint(argument_pattern_state.constraints); - let signature_closure_type = *signature_closure_type.clone(); + 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_index = constraints.push_type(signature); let cons = [ constraints.let_constraint( @@ -2313,20 +2400,13 @@ fn constrain_typed_def( ), constraints.equal_types_var( closure_var, - Expected::FromAnnotation( - def.loc_pattern.clone(), - arity, - AnnotationSource::TypedBody { - region: annotation.region, - }, - signature_closure_type, - ), + signature_closure_type, Category::ClosureSize, region, ), - constraints.store_index(signature_index, *fn_var, std::file!(), std::line!()), - constraints.store_index(signature_index, expr_var, std::file!(), std::line!()), - constraints.store(ret_type, ret_var, std::file!(), std::line!()), + constraints.store(signature_index, *fn_var, std::file!(), std::line!()), + constraints.store(signature_index, expr_var, std::file!(), std::line!()), + constraints.store(ret_type_index, ret_var, std::file!(), std::line!()), closure_constraint, ]; @@ -2417,9 +2497,11 @@ 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_expected = + constraints.push_expected_type(Expected::NoExpectation(ann.clone())); let pattern_con = constraints.equal_types_var( *pattern_var, - Expected::NoExpectation(ann.clone()), + ann_expected, Category::Storage(std::file!(), std::line!()), loc_pattern.region, ); @@ -2452,11 +2534,13 @@ fn constrain_typed_function_arguments( { // Store the actual type in a variable. + let ann_expected = + constraints.push_expected_type(Expected::NoExpectation(ann.clone())); argument_pattern_state .constraints .push(constraints.equal_types_var( annotation_var, - Expected::NoExpectation(ann.clone()), + ann_expected, Category::Storage(file!(), line!()), Region::zero(), )); @@ -2537,9 +2621,11 @@ 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_expected = + constraints.push_expected_type(Expected::NoExpectation(ann.clone())); let pattern_con = constraints.equal_types_var( *pattern_var, - Expected::NoExpectation(ann.clone()), + ann_expected, Category::Storage(std::file!(), std::line!()), loc_pattern.region, ); @@ -2572,11 +2658,13 @@ fn constrain_typed_function_arguments_simple( { // Store the actual type in a variable. + let expected_annotation = + constraints.push_expected_type(Expected::NoExpectation(ann.clone())); argument_pattern_state .constraints .push(constraints.equal_types_var( annotation_var, - Expected::NoExpectation(ann.clone()), + expected_annotation, Category::Storage(file!(), line!()), Region::zero(), )); @@ -2758,27 +2846,22 @@ fn constrain_closure_size( captured_types.push(Type::Variable(*var)); // make the variable equal to the looked-up type of symbol - captured_symbols_constraints.push(constraints.lookup( - *symbol, - Expected::NoExpectation(Type::Variable(*var)), - Region::zero(), - )); + let store_into = + constraints.push_expected_type(Expected::NoExpectation(Type::Variable(*var))); + captured_symbols_constraints.push(constraints.lookup(*symbol, store_into, Region::zero())); } - // pick a more efficient representation if we don't actually capture anything - let closure_type = Type::ClosureTag { - name, - captures: captured_types, - ambient_function, + let finalizer = { + // pick a more efficient representation if we don't actually capture anything + let closure_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) }; - let finalizer = constraints.equal_types_var( - closure_var, - NoExpectation(closure_type), - Category::ClosureSize, - region, - ); - captured_symbols_constraints.push(finalizer); constraints.and_constraint(captured_symbols_constraints) @@ -3005,6 +3088,7 @@ fn constraint_recursive_function( let ret_var = function_def.return_type; let closure_var = function_def.closure_type; let ret_type = *ret_type.clone(); + let ret_type_index = constraints.push_type(ret_type.clone()); vars.push(ret_var); vars.push(closure_var); @@ -3056,7 +3140,7 @@ fn constraint_recursive_function( env, loc_body_expr.region, &loc_body_expr.value, - NoExpectation(ret_type.clone()), + NoExpectation(ret_type), ); let expr_con = attach_resolution_constraints(constraints, env, expr_con); @@ -3072,11 +3156,15 @@ fn constraint_recursive_function( state_constraints, expr_con, ), - constraints.equal_types(fn_type, expected, Category::Lambda, region), + { + let type_index = constraints.push_type(fn_type); + let expected_index = constraints.push_expected_type(expected); + constraints.equal_types(type_index, expected_index, Category::Lambda, region) + }, // "fn_var is equal to the closure's type" - fn_var is used in code gen // Store type into AST vars. We use Store so errors aren't reported twice - constraints.store_index(signature_index, expr_var, std::file!(), std::line!()), - constraints.store(ret_type, ret_var, std::file!(), std::line!()), + constraints.store(signature_index, expr_var, std::file!(), std::line!()), + constraints.store(ret_type_index, ret_var, std::file!(), std::line!()), closure_constraint, ]; @@ -3197,11 +3285,13 @@ 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 constraints.store( - signature.clone(), + signature_index, expr_var, std::file!(), std::line!(), @@ -3430,6 +3520,7 @@ fn rec_defs_help( let ret_var = *ret_var; let closure_var = *closure_var; let ret_type = *ret_type.clone(); + let ret_type_index = constraints.push_type(ret_type.clone()); vars.push(ret_var); vars.push(closure_var); @@ -3455,11 +3546,11 @@ fn rec_defs_help( &mut vars, ); - let fn_type = Type::Function( + let fn_type_index = constraints.push_type(Type::Function( pattern_types, Box::new(Type::Variable(closure_var)), Box::new(ret_type.clone()), - ); + )); let body_type = NoExpectation(ret_type.clone()); let expr_con = constrain_expr( constraints, @@ -3474,6 +3565,7 @@ fn rec_defs_help( let signature_index = constraints.push_type(signature); let state_constraints = constraints.and_constraint(state.constraints); + let expected_index = constraints.push_expected_type(expected); let cons = [ constraints.let_constraint( [], @@ -3483,26 +3575,21 @@ fn rec_defs_help( expr_con, ), constraints.equal_types( - fn_type.clone(), - expected.clone(), + fn_type_index, + expected_index, Category::Lambda, region, ), // "fn_var is equal to the closure's type" - fn_var is used in code gen // Store type into AST vars. We use Store so errors aren't reported twice - constraints.store_index( - signature_index, - *fn_var, - std::file!(), - std::line!(), - ), - constraints.store_index( + constraints.store(signature_index, *fn_var, std::file!(), std::line!()), + constraints.store( signature_index, expr_var, std::file!(), std::line!(), ), - constraints.store(ret_type, ret_var, std::file!(), std::line!()), + constraints.store(ret_type_index, ret_var, std::file!(), std::line!()), closure_constraint, ]; @@ -3541,10 +3628,17 @@ fn rec_defs_help( let ret_constraint = attach_resolution_constraints(constraints, env, ret_constraint); + let signature_index = constraints.push_type(signature); + let cons = [ ret_constraint, // Store type into AST vars. We use Store so errors aren't reported twice - constraints.store(signature, expr_var, std::file!(), std::line!()), + constraints.store( + signature_index, + expr_var, + std::file!(), + std::line!(), + ), ]; let def_con = constraints.and_constraint(cons); diff --git a/crates/compiler/constrain/src/module.rs b/crates/compiler/constrain/src/module.rs index 148067074b..76f9047d36 100644 --- a/crates/compiler/constrain/src/module.rs +++ b/crates/compiler/constrain/src/module.rs @@ -69,18 +69,16 @@ 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 provided_eq_requires_constr = constraints.lookup( - loc_symbol.value, - Expected::FromAnnotation( - loc_symbol.map(|&s| Pattern::Identifier(s)), - arity, - AnnotationSource::RequiredSymbol { - region: loc_type.region, - }, - loc_type.value, - ), - loc_type.region, - ); + 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, + )); + let provided_eq_requires_constr = + constraints.lookup(loc_symbol.value, expected, loc_type.region); constraints.and_constraint([provided_eq_requires_constr, constraint]) } }) @@ -122,11 +120,14 @@ 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_expectation = + constraints.push_expected_type(Expected::NoExpectation(signature.clone())); + def_pattern_state .constraints .push(constraints.equal_types_var( signature_var, - Expected::NoExpectation(signature.clone()), + signature_expectation, Category::Storage(file!(), line!()), Region::zero(), )); diff --git a/crates/compiler/constrain/src/pattern.rs b/crates/compiler/constrain/src/pattern.rs index da11ed9bfb..2b0f1625a2 100644 --- a/crates/compiler/constrain/src/pattern.rs +++ b/crates/compiler/constrain/src/pattern.rs @@ -182,9 +182,11 @@ pub fn constrain_pattern( // _ -> "" // so, we know that "x" (in this case, a tag union) must be open. if could_be_a_tag_union(expected.get_type_ref()) { + let type_index = constraints.push_type(expected.get_type()); + state .delayed_is_open_constraints - .push(constraints.is_open_type(expected.get_type())); + .push(constraints.is_open_type(type_index)); } } UnsupportedPattern(_) | MalformedPattern(_, _) | OpaqueNotInScope(..) => { @@ -193,9 +195,11 @@ 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()); + state .delayed_is_open_constraints - .push(constraints.is_open_type(expected.get_type_ref().clone())); + .push(constraints.is_open_type(type_index)); } state.headers.insert( @@ -212,9 +216,9 @@ pub fn constrain_pattern( specializes: _, } => { if could_be_a_tag_union(expected.get_type_ref()) { - state - .constraints - .push(constraints.is_open_type(expected.get_type_ref().clone())); + let type_index = constraints.push_type(expected.get_type_ref().clone()); + + state.constraints.push(constraints.is_open_type(type_index)); } state.headers.insert( @@ -238,6 +242,9 @@ pub fn constrain_pattern( region, Category::Num, ); + 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, @@ -259,18 +266,19 @@ pub fn constrain_pattern( region, Category::Int, ); + 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)); - state.constraints.push(constraints.equal_types( - num_type.clone(), // TODO check me if something breaks! - Expected::NoExpectation(int_type), - Category::Int, - region, - )); + state.constraints.push({ + let expected_index = + constraints.push_expected_type(Expected::NoExpectation(int_type)); + constraints.equal_types(num_type, expected_index, Category::Int, region) + }); // 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, @@ -294,17 +302,18 @@ pub fn constrain_pattern( // 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! - state.constraints.push(constraints.equal_types( - num_type.clone(), // TODO check me if something breaks! - Expected::NoExpectation(float_type), - Category::Frac, - region, - )); + state.constraints.push({ + let expected_index = + constraints.push_expected_type(Expected::NoExpectation(float_type)); + constraints.equal_types(num_type_index, expected_index, Category::Frac, region) + }); // 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, // TODO check me if something breaks! + num_type_index, expected, PatternCategory::Float, region, @@ -312,8 +321,10 @@ 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( - builtins::str_type(), + str_type, expected, PatternCategory::Str, region, @@ -336,16 +347,23 @@ pub fn constrain_pattern( // Link the free num var with the int var and our expectation. let int_type = builtins::num_int(Type::Variable(precision_var)); - state.constraints.push(constraints.equal_types( - num_type.clone(), // TODO check me if something breaks! - Expected::NoExpectation(int_type), - Category::Int, - region, - )); + let num_type_index = constraints.push_type(num_type); + + state.constraints.push({ + let expected_index = + constraints.push_expected_type(Expected::NoExpectation(int_type)); + constraints.equal_types( + num_type_index, // TODO check me if something breaks! + expected_index, + Category::Int, + region, + ) + }); // 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, + num_type_index, expected, PatternCategory::Character, region, @@ -385,13 +403,17 @@ pub fn constrain_pattern( let field_type = match typ { DestructType::Guard(guard_var, loc_guard) => { - state.constraints.push(constraints.pattern_presence( - Type::Variable(*guard_var), - PExpected::ForReason( + let guard_type = constraints.push_type(Type::Variable(*guard_var)); + let expected_pat = + constraints.push_pat_expected_type(PExpected::ForReason( PReason::PatternGuard, pat_type.clone(), loc_guard.region, - ), + )); + + state.constraints.push(constraints.pattern_presence( + guard_type, + expected_pat, PatternCategory::PatternGuard, region, )); @@ -409,13 +431,17 @@ pub fn constrain_pattern( RecordField::Demanded(pat_type) } DestructType::Optional(expr_var, loc_expr) => { - state.constraints.push(constraints.pattern_presence( - Type::Variable(*expr_var), - PExpected::ForReason( + let expr_type = constraints.push_type(Type::Variable(*expr_var)); + let expected_pat = + constraints.push_pat_expected_type(PExpected::ForReason( PReason::OptionalField, pat_type.clone(), loc_expr.region, - ), + )); + + state.constraints.push(constraints.pattern_presence( + expr_type, + expected_pat, PatternCategory::PatternDefault, region, )); @@ -452,15 +478,20 @@ pub fn constrain_pattern( let record_type = Type::Record(field_types, TypeExtension::from_type(ext_type)); + let whole_var_index = constraints.push_type(Type::Variable(*whole_var)); + let expected_record = + constraints.push_expected_type(Expected::NoExpectation(record_type)); let whole_con = constraints.equal_types( - Type::Variable(*whole_var), - Expected::NoExpectation(record_type), + whole_var_index, + expected_record, Category::Storage(std::file!(), std::line!()), region, ); + let expected = constraints.push_pat_expected_type(expected); + let record_con = constraints.pattern_presence( - Type::Variable(*whole_var), + whole_var_index, expected, PatternCategory::Record, region, @@ -475,12 +506,12 @@ pub fn constrain_pattern( tag_name, arguments, } => { - let mut argument_types = Vec::with_capacity(arguments.len()); + let argument_types = constraints.variable_slice(arguments.iter().map(|(var, _)| *var)); + for (index, (pattern_var, loc_pattern)) in arguments.iter().enumerate() { state.vars.push(*pattern_var); let pattern_type = Type::Variable(*pattern_var); - argument_types.push(pattern_type.clone()); let expected = PExpected::ForReason( PReason::TagArg { @@ -501,21 +532,20 @@ pub fn constrain_pattern( } let pat_category = PatternCategory::Ctor(tag_name.clone()); + let expected_type = constraints.push_type(expected.get_type_ref().clone()); let whole_con = constraints.includes_tag( - expected.clone().get_type(), + expected_type, tag_name.clone(), - argument_types.clone(), + argument_types, pat_category.clone(), region, ); - let tag_con = constraints.pattern_presence( - Type::Variable(*whole_var), - expected, - pat_category, - region, - ); + 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); state.vars.push(*whole_var); state.vars.push(*ext_var); @@ -561,9 +591,12 @@ pub fn constrain_pattern( ); // Next, link `whole_var` to the opaque type of "@Id who" + let whole_var_index = constraints.push_type(Type::Variable(*whole_var)); + let expected_opaque = + constraints.push_expected_type(Expected::NoExpectation(opaque_type)); let whole_con = constraints.equal_types( - Type::Variable(*whole_var), - Expected::NoExpectation(opaque_type), + whole_var_index, + expected_opaque, Category::Storage(std::file!(), std::line!()), region, ); @@ -581,16 +614,21 @@ pub fn constrain_pattern( // This must **always** be a presence constraint, that is enforcing // `[A k1, B k1] += typeof (A s)`, because we are in a destructure position and not // all constructors are covered in this branch! + let arg_pattern_type = constraints.push_type(arg_pattern_type); + let specialized_type = constraints + .push_pat_expected_type(PExpected::NoExpectation((**specialized_def_type).clone())); let link_type_variables_con = constraints.pattern_presence( arg_pattern_type, - PExpected::NoExpectation((**specialized_def_type).clone()), + specialized_type, PatternCategory::Opaque(*opaque), loc_arg_pattern.region, ); // 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( - Type::Variable(*whole_var), + whole_type, expected, PatternCategory::Opaque(*opaque), region, diff --git a/crates/compiler/solve/src/solve.rs b/crates/compiler/solve/src/solve.rs index 60fbc8c506..784fd3c2f4 100644 --- a/crates/compiler/solve/src/solve.rs +++ b/crates/compiler/solve/src/solve.rs @@ -1323,40 +1323,29 @@ fn solve( region, } = includes_tag; - let typ_cell = &constraints.types[type_index.index()]; - let tys_cells = &constraints.types[types.indices()]; let pattern_category = &constraints.pattern_categories[pattern_category.index()]; - let actual = type_cell_to_var( + let actual = either_type_index_to_var( + constraints, subs, rank, + pools, problems, abilities_store, obligation_cache, - pools, aliases, - typ_cell, + *type_index, ); - let tys = { - let mut tys = Vec::with_capacity(tys_cells.len()); - for cell in tys_cells { - let actual = type_cell_to_var( - subs, - rank, - problems, - abilities_store, - obligation_cache, - pools, - aliases, - cell, - ); - tys.push(Type::Variable(actual)); - } - tys - }; + let payload_types = constraints.variables[types.indices()] + .iter() + .map(|v| Type::Variable(*v)) + .collect(); - let tag_ty = Type::TagUnion(vec![(tag_name.clone(), tys)], TypeExtension::Closed); + let tag_ty = Type::TagUnion( + vec![(tag_name.clone(), payload_types)], + TypeExtension::Closed, + ); let includes = type_to_var( subs, rank,