diff --git a/compiler/can/src/constraint_soa.rs b/compiler/can/src/constraint_soa.rs index 9d24540cf1..e79ac4fae0 100644 --- a/compiler/can/src/constraint_soa.rs +++ b/compiler/can/src/constraint_soa.rs @@ -1,5 +1,6 @@ use crate::expected::{Expected, PExpected}; use roc_collections::soa::{Index, Slice}; +use roc_module::ident::TagName; use roc_module::symbol::Symbol; use roc_region::all::{Loc, Region}; use roc_types::types::{Category, PatternCategory, Type}; @@ -15,6 +16,7 @@ pub struct Constraints { pattern_categories: Vec, expectations: Vec>, pattern_expectations: Vec>, + includes_tags: Vec, } impl Constraints { @@ -52,13 +54,9 @@ impl Constraints { category: Category, region: Region, ) -> Constraint { - let type_index = Index::new(self.types.len() as _); - let expected_index = Index::new(self.expectations.len() as _); - let category_index = Index::new(self.categories.len() as _); - - self.types.push(typ); - self.expectations.push(expected); - self.categories.push(category); + let type_index = Index::push_new(&mut self.types, typ); + let expected_index = Index::push_new(&mut self.expectations, expected); + let category_index = Index::push_new(&mut self.categories, category); Constraint::Eq(type_index, expected_index, category_index, region) } @@ -70,17 +68,61 @@ impl Constraints { category: PatternCategory, region: Region, ) -> Constraint { - let type_index = Index::new(self.types.len() as _); - let expected_index = Index::new(self.pattern_expectations.len() as _); - let category_index = Index::new(self.pattern_categories.len() as _); - - self.types.push(typ); - self.pattern_expectations.push(expected); - self.pattern_categories.push(category); + let type_index = Index::push_new(&mut self.types, typ); + let expected_index = Index::push_new(&mut self.pattern_expectations, expected); + let category_index = Index::push_new(&mut self.pattern_categories, category); Constraint::Pattern(type_index, expected_index, category_index, region) } + pub fn pattern_presence( + &mut self, + typ: Type, + expected: PExpected, + category: PatternCategory, + region: Region, + ) -> Constraint { + let type_index = Index::push_new(&mut self.types, typ); + let expected_index = Index::push_new(&mut self.pattern_expectations, expected); + 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 = Index::push_new(&mut self.types, typ); + + Constraint::IsOpenType(type_index) + } + + pub fn includes_tag( + &mut self, + typ: Type, + tag_name: TagName, + types: I, + category: PatternCategory, + region: Region, + ) -> Constraint + where + I: IntoIterator, + { + let type_index = Index::push_new(&mut self.types, typ); + let category_index = Index::push_new(&mut self.pattern_categories, category); + let types_slice = Slice::extend_new(&mut self.types, types); + + let includes_tag = IncludesTag { + type_index, + tag_name, + types: types_slice, + pattern_category: category_index, + region, + }; + + let includes_tag_index = Index::push_new(&mut self.includes_tags, includes_tag); + + Constraint::IncludesTag(includes_tag_index) + } + fn variable_slice(&mut self, it: I) -> Slice where I: IntoIterator, @@ -133,6 +175,29 @@ impl Constraints { Constraint::Let(let_index) } + pub fn exists_many(&mut self, flex_vars: I, defs_constraint: C) -> Constraint + where + I: IntoIterator, + C: IntoIterator, + { + let defs_and_ret_constraint = Index::new(self.constraints.len() as _); + + self.and_constraint(defs_constraint); + self.constraints.push(Constraint::True); + + let let_contraint = LetConstraint { + rigid_vars: Slice::default(), + flex_vars: self.variable_slice(flex_vars), + def_types: Slice::default(), + defs_and_ret_constraint, + }; + + let let_index = Index::new(self.let_constraints.len() as _); + self.let_constraints.push(let_contraint); + + Constraint::Let(let_index) + } + pub fn let_constraint( &mut self, rigid_vars: I1, @@ -191,7 +256,7 @@ impl Constraints { region, ) } - pub fn contains_save_the_environment(&self, constraint: Constraint) -> bool { + pub fn contains_save_the_environment(&self, constraint: &Constraint) -> bool { todo!() } @@ -228,6 +293,15 @@ pub enum Constraint { SaveTheEnvironment, Let(Index), And(Slice), + /// Presence constraints + IsOpenType(Index), // Theory; always applied to a variable? if yes the use that + IncludesTag(Index), + PatternPresence( + Index, + Index>, + Index, + Region, + ), } #[derive(Debug, Clone, PartialEq)] @@ -237,3 +311,12 @@ pub struct LetConstraint { pub def_types: Slice<(Symbol, Loc)>, pub defs_and_ret_constraint: Index<(Constraint, Constraint)>, } + +#[derive(Debug, Clone, PartialEq)] +pub struct IncludesTag { + pub type_index: Index, + pub tag_name: TagName, + pub types: Slice, + pub pattern_category: Index, + pub region: Region, +} diff --git a/compiler/collections/src/soa.rs b/compiler/collections/src/soa.rs index ad5bae89d0..7c5b7e4d61 100644 --- a/compiler/collections/src/soa.rs +++ b/compiler/collections/src/soa.rs @@ -47,6 +47,19 @@ impl Slice { } } + pub fn extend_new(vector: &mut Vec, values: I) -> Slice + where + I: IntoIterator, + { + let start = vector.len() as u32; + + vector.extend(values); + + let end = vector.len() as u32; + + Self::new(start, (end - start) as u16) + } + pub const fn len(&self) -> usize { self.length as _ } diff --git a/compiler/constrain/src/builtins.rs b/compiler/constrain/src/builtins.rs index f036400799..44ae773491 100644 --- a/compiler/constrain/src/builtins.rs +++ b/compiler/constrain/src/builtins.rs @@ -61,7 +61,8 @@ pub fn add_numeric_bound_constr_soa( 1 => { let actual_type = Variable(range[0]); let expected = Expected::ForReason(Reason::NumericLiteralSuffix, actual_type, region); - let because_suffix = constraints.equal_types(actual_type, expected, category, region); + let because_suffix = + constraints.equal_types(total_num_type.clone(), expected, category, region); num_constraints.extend([because_suffix]); diff --git a/compiler/constrain/src/soa_expr.rs b/compiler/constrain/src/soa_expr.rs index 7be8bdeaf8..9d8bd17b19 100644 --- a/compiler/constrain/src/soa_expr.rs +++ b/compiler/constrain/src/soa_expr.rs @@ -411,33 +411,28 @@ pub fn constrain_expr( &mut vars, ); - constraints.exists( - vars, - constraints.and_constraint([ - constraints.let_constraint( - Vec::new(), - pattern_state.vars, - pattern_state.headers, - constraints.and_constraint(pattern_state.constraints), - ret_constraint, - ), - // "the closure's type is equal to expected type" - constraints.equal_types( - function_type.clone(), - expected, - Category::Lambda, - region, - ), - // "fn_var is equal to the closure's type" - fn_var is used in code gen - constraints.equal_types( - Type::Variable(*fn_var), - NoExpectation(function_type), - Category::Storage(std::file!(), std::line!()), - region, - ), - closure_constraint, - ]), - ) + let pattern_state_constraints = constraints.and_constraint(pattern_state.constraints); + let cons = [ + constraints.let_constraint( + [], + pattern_state.vars, + pattern_state.headers, + pattern_state_constraints, + ret_constraint, + ), + // "the closure's type is equal to expected type" + constraints.equal_types(function_type.clone(), expected, Category::Lambda, region), + // "fn_var is equal to the closure's type" - fn_var is used in code gen + constraints.equal_types( + Type::Variable(*fn_var), + NoExpectation(function_type), + Category::Storage(std::file!(), std::line!()), + region, + ), + closure_constraint, + ]; + + constraints.exists_many(vars, cons) } Expect(loc_cond, continuation) => { @@ -462,7 +457,7 @@ pub fn constrain_expr( expected, ); - constraints.exists([], constraints.and_constraint([cond_con, continuation_con])) + constraints.exists_many([], [cond_con, continuation_con]) } If { @@ -548,10 +543,7 @@ pub fn constrain_expr( branch_cons.push(ast_con); branch_cons.push(else_con); - constraints.exists( - [*cond_var, *branch_var], - constraints.and_constraint(branch_cons), - ) + constraints.exists_many([*cond_var, *branch_var], branch_cons) } _ => { for (index, (loc_cond, loc_body)) in branches.iter().enumerate() { @@ -604,10 +596,7 @@ pub fn constrain_expr( )); branch_cons.push(else_con); - constraints.exists( - [*cond_var, *branch_var], - constraints.and_constraint(branch_cons), - ) + constraints.exists_many([*cond_var, *branch_var], branch_cons) } } } @@ -677,10 +666,7 @@ pub fn constrain_expr( region, )); - return constraints.exists( - [cond_var, *expr_var], - constraints.and_constraint(branch_constraints), - ); + return constraints.exists_many([cond_var, *expr_var], branch_constraints); } _ => { @@ -691,6 +677,7 @@ pub fn constrain_expr( let pattern_region = Region::across_all(when_branch.patterns.iter().map(|v| &v.region)); let branch_con = constrain_when_branch( + constraints, env, region, when_branch, @@ -713,23 +700,26 @@ pub fn constrain_expr( branch_cons.push(branch_con); } - branch_constraints.push(constraints.and_constraint([ - // Record the original conditional expression's constraint. - // Each branch's pattern must have the same type - // as the condition expression did. - constraints.and_constraint(branch_cons), - // The return type of each branch must equal - // the return type of the entire when-expression. - constraints.equal_types(branch_type, expected, Category::When, region), - ])); + // Deviation: elm adds another layer of And nesting + // + // Record the original conditional expression's constraint. + // Each branch's pattern must have the same type + // as the condition expression did. + // + // The return type of each branch must equal the return type of + // the entire when-expression. + branch_cons.push(constraints.equal_types( + branch_type, + expected, + Category::When, + region, + )); + branch_constraints.push(constraints.and_constraint(branch_cons)); } } // exhautiveness checking happens when converting to mono::Expr - constraints.exists( - [cond_var, *expr_var], - constraints.and_constraint(branch_constraints), - ) + constraints.exists_many([cond_var, *expr_var], branch_constraints) } Access { record_var, @@ -771,13 +761,10 @@ pub fn constrain_expr( record_expected, ); - constraints.exists( + let eq = constraints.equal_types(field_type, expected, category, region); + constraints.exists_many( [*record_var, field_var, ext_var], - constraints.and_constraint([ - constraint, - constraints.equal_types(field_type, expected, category, region), - record_con, - ]), + [constraint, eq, record_con], ) } Accessor { @@ -820,23 +807,20 @@ pub fn constrain_expr( Box::new(field_type), ); - constraints.exists( + let cons = [ + constraints.equal_types(function_type.clone(), expected, category.clone(), region), + constraints.equal_types( + function_type, + NoExpectation(Variable(*function_var)), + category, + region, + ), + record_con, + ]; + + constraints.exists_many( [*record_var, *function_var, *closure_var, field_var, ext_var], - constraints.and_constraint([ - constraints.equal_types( - function_type.clone(), - expected, - category.clone(), - region, - ), - constraints.equal_types( - function_type, - NoExpectation(Variable(*function_var)), - category, - region, - ), - record_con, - ]), + cons, ) } LetRec(defs, loc_ret, var) => { @@ -848,20 +832,19 @@ pub fn constrain_expr( expected.clone(), ); - constraints.exists( - [*var], - constraints.and_constraint([ - constrain_recursive_defs(env, defs, body_con), - // Record the type of tne entire def-expression in the variable. - // Code gen will need that later! - constraints.equal_types( - Type::Variable(*var), - expected, - Category::Storage(std::file!(), std::line!()), - loc_ret.region, - ), - ]), - ) + let cons = [ + constrain_recursive_defs(constraints, env, defs, body_con), + // Record the type of tne entire def-expression in the variable. + // Code gen will need that later! + constraints.equal_types( + Type::Variable(*var), + expected, + Category::Storage(std::file!(), std::line!()), + loc_ret.region, + ), + ]; + + constraints.exists_many([*var], cons) } LetNonRec(def, loc_ret, var) => { let mut stack = Vec::with_capacity(1); @@ -884,20 +867,19 @@ pub fn constrain_expr( ); while let Some((def, var, ret_region)) = stack.pop() { - body_con = constraints.exists( - [*var], - constraints.and_constraint([ - constrain_def(env, def, body_con), - // Record the type of the entire def-expression in the variable. - // Code gen will need that later! - constraints.equal_types( - Type::Variable(*var), - expected.clone(), - Category::Storage(std::file!(), std::line!()), - ret_region, - ), - ]), - ) + let cons = [ + constrain_def(constraints, env, def, body_con), + // Record the type of the entire def-expression in the variable. + // Code gen will need that later! + constraints.equal_types( + Type::Variable(*var), + expected.clone(), + Category::Storage(std::file!(), std::line!()), + ret_region, + ), + ]; + + body_con = constraints.exists_many([*var], cons) } body_con @@ -950,7 +932,7 @@ pub fn constrain_expr( arg_cons.push(union_con); arg_cons.push(ast_con); - constraints.exists(vars, constraints.and_constraint(arg_cons)) + constraints.exists_many(vars, arg_cons) } ZeroArgumentTag { variant_var, @@ -1002,7 +984,7 @@ pub fn constrain_expr( arg_cons.push(union_con); arg_cons.push(ast_con); - constraints.exists(vars, constraints.and_constraint(arg_cons)) + constraints.exists_many(vars, arg_cons) } OpaqueRef { @@ -1069,9 +1051,9 @@ pub fn constrain_expr( v.0.expect_variable("all lambda sets should be fresh variables here") })); - constraints.exists( + constraints.exists_many( vars, - constraints.and([arg_con, opaque_con, link_type_variables_con, storage_con]), + [arg_con, opaque_con, link_type_variables_con, storage_con], ) } @@ -1109,12 +1091,8 @@ pub fn constrain_expr( let category = Category::LowLevelOpResult(*op); - constraints.exists( - vars, - constraints.and_constraint(arg_cons.into_iter().chain(std::iter::once( - constraints.equal_types(ret_type, expected, category, region), - ))), - ) + let eq = constraints.equal_types(ret_type, expected, category, region); + constraints.exists_many(vars, arg_cons.into_iter().chain(std::iter::once(eq))) } ForeignCall { args, @@ -1154,12 +1132,8 @@ pub fn constrain_expr( let category = Category::ForeignCall; - constraints.exists( - vars, - constraints.and_constraint(arg_cons.into_iter().chain(std::iter::once( - constraints.equal_types(ret_type, expected, category, region), - ))), - ) + let eq = constraints.equal_types(ret_type, expected, category, region); + constraints.exists_many(vars, arg_cons.into_iter().chain(std::iter::once(eq))) } RuntimeError(_) => { // Runtime Errors have no constraints because they're going to crash. @@ -1195,6 +1169,7 @@ fn constrain_when_branch( // then unify that variable with the expectation? for loc_pattern in &when_branch.patterns { constrain_pattern( + constraints, env, &loc_pattern.value, loc_pattern.region, @@ -1217,25 +1192,23 @@ fn constrain_when_branch( ); // must introduce the headers from the pattern before constraining the guard - constraints.let_constraint( + let state_constraints = constraints.and_constraint(state.constraints); + let inner = constraints.let_constraint( [], - state.vars, - state.headers, - constraints.and_constraint(state.constraints), - constraints.let_constraint( - [], - [], - SendMap::default(), - guard_constraint, - ret_constraint, - ), - ) + [], + SendMap::default(), + guard_constraint, + ret_constraint, + ); + + constraints.let_constraint([], state.vars, state.headers, state_constraints, inner) } else { + let state_constraints = constraints.and_constraint(state.constraints); constraints.let_constraint( [], state.vars, state.headers, - constraints.and_constraint(state.constraints), + state_constraints, ret_constraint, ) } @@ -1300,7 +1273,7 @@ pub fn constrain_decls( constraint = constrain_def(constraints, &env, def, constraint); } Declaration::DeclareRec(defs) => { - constraint = constrain_recursive_defs(&env, defs, constraint); + constraint = constrain_recursive_defs(constraints, &env, defs, constraint); } Declaration::InvalidCycle(_) => { // invalid cycles give a canonicalization error. we skip them here. @@ -1310,7 +1283,7 @@ pub fn constrain_decls( } // this assert make the "root" of the constraint wasn't dropped - debug_assert!(constraints.contains_save_the_environment(constraint)); + debug_assert!(constraints.contains_save_the_environment(&constraint)); constraint } @@ -1484,6 +1457,7 @@ fn constrain_def( } let closure_constraint = constrain_closure_size( + constraints, *name, region, captured_symbols, @@ -1512,40 +1486,35 @@ fn constrain_def( vars.push(*fn_var); let defs_constraint = constraints.and_constraint(state.constraints); - constraints.exists( - vars, - constraints.and_constraint([ - constraints.let_constraint( - [], - state.vars, - state.headers, - defs_constraint, - ret_constraint, + let cons = [ + constraints.let_constraint( + [], + state.vars, + state.headers, + defs_constraint, + ret_constraint, + ), + constraints.equal_types( + Type::Variable(closure_var), + Expected::FromAnnotation( + def.loc_pattern.clone(), + arity, + AnnotationSource::TypedBody { + region: annotation.region, + }, + *signature_closure_type.clone(), ), - constraints.equal_types( - Type::Variable(closure_var), - Expected::FromAnnotation( - def.loc_pattern.clone(), - arity, - AnnotationSource::TypedBody { - region: annotation.region, - }, - *signature_closure_type.clone(), - ), - Category::ClosureSize, - region, - ), - constraints.store( - signature.clone(), - *fn_var, - std::file!(), - std::line!(), - ), - constraints.store(signature, expr_var, std::file!(), std::line!()), - constraints.store(ret_type, ret_var, std::file!(), std::line!()), - closure_constraint, - ]), - ) + Category::ClosureSize, + region, + ), + constraints.store(signature.clone(), *fn_var, std::file!(), std::line!()), + constraints.store(signature, expr_var, std::file!(), std::line!()), + constraints.store(ret_type, ret_var, std::file!(), std::line!()), + closure_constraint, + ]; + + let and_constraint = constraints.and_constraint(cons); + constraints.exists(vars, and_constraint) } _ => { @@ -1559,7 +1528,7 @@ fn constrain_def( expected, ); - constraints.and_constraint([ + let cons = [ constraints.let_constraint( [], [], @@ -1569,7 +1538,8 @@ fn constrain_def( ), // Store type into AST vars. We use Store so errors aren't reported twice constraints.store(signature, expr_var, std::file!(), std::line!()), - ]) + ]; + constraints.and_constraint(cons) } } } @@ -1586,17 +1556,21 @@ fn constrain_def( } }; + let and_constraint = constraints.and_constraint(def_pattern_state.constraints); + + let def_con = constraints.let_constraint( + [], + [], + SendMap::default(), // empty, because our functions have no arguments! + and_constraint, + expr_con, + ); + constraints.let_constraint( new_rigids, def_pattern_state.vars, def_pattern_state.headers, - constraints.let_constraint( - [], - [], - SendMap::default(), // empty, because our functions have no arguments! - constraints.and_constraint(def_pattern_state.constraints), - expr_con, - ), + def_con, body_con, ) } @@ -1706,8 +1680,14 @@ fn instantiate_rigids( annotation } -fn constrain_recursive_defs(env: &Env, defs: &[Def], body_con: Constraint) -> Constraint { +fn constrain_recursive_defs( + constraints: &mut Constraints, + env: &Env, + defs: &[Def], + body_con: Constraint, +) -> Constraint { rec_defs_help( + constraints, env, defs, body_con, @@ -1897,35 +1877,36 @@ pub fn rec_defs_help( vars.push(*fn_var); - let def_con = constraints.exists( - vars, - constraints.and_constraint([ - constraints.let_constraint( - [], - state.vars, - state.headers, - constraints.and_constraint(state.constraints), - expr_con, - ), - constraints.equal_types( - fn_type.clone(), - expected.clone(), - 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( - signature.clone(), - *fn_var, - std::file!(), - std::line!(), - ), - constraints.store(signature, expr_var, std::file!(), std::line!()), - constraints.store(ret_type, ret_var, std::file!(), std::line!()), - closure_constraint, - ]), - ); + let state_constraints = constraints.and_constraint(state.constraints); + let cons = [ + constraints.let_constraint( + [], + state.vars, + state.headers, + state_constraints, + expr_con, + ), + constraints.equal_types( + fn_type.clone(), + expected.clone(), + 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( + signature.clone(), + *fn_var, + std::file!(), + std::line!(), + ), + constraints.store(signature, expr_var, std::file!(), std::line!()), + constraints.store(ret_type, ret_var, std::file!(), std::line!()), + closure_constraint, + ]; + + let and_constraint = constraints.and_constraint(cons); + let def_con = constraints.exists(vars, and_constraint); rigid_info.vars.extend(&new_rigids); @@ -1949,7 +1930,7 @@ pub fn rec_defs_help( expected, ); - let def_con = constraints.and_constraint([ + let cons = [ constraints.let_constraint( [], [], @@ -1959,7 +1940,8 @@ pub fn rec_defs_help( ), // Store type into AST vars. We use Store so errors aren't reported twice constraints.store(signature, expr_var, std::file!(), std::line!()), - ]); + ]; + let def_con = constraints.and_constraint(cons); rigid_info.vars.extend(&new_rigids); @@ -1977,25 +1959,36 @@ pub fn rec_defs_help( } } + let flex_constraints = constraints.and_constraint(flex_info.constraints); + let inner_inner = constraints.let_constraint( + [], + [], + flex_info.def_types.clone(), + Constraint::True, + flex_constraints, + ); + + let rigid_constraints = { + let mut temp = rigid_info.constraints; + temp.push(body_con); + + constraints.and_constraint(temp) + }; + + let inner = constraints.let_constraint( + [], + flex_info.vars, + flex_info.def_types, + inner_inner, + rigid_constraints, + ); + constraints.let_constraint( rigid_info.vars, [], rigid_info.def_types, Constraint::True, - constraints.let_constraint( - [], - flex_info.vars, - flex_info.def_types.clone(), - constraints.let_constraint( - [], - [], - flex_info.def_types, - Constraint::True, - constraints.and_constraint(flex_info.constraints), - ), - constraints - .and_constraint([constraints.and_constraint(rigid_info.constraints), body_con]), - ), + inner, ) } diff --git a/compiler/constrain/src/soa_pattern.rs b/compiler/constrain/src/soa_pattern.rs index adbdc3d68a..721a1488d7 100644 --- a/compiler/constrain/src/soa_pattern.rs +++ b/compiler/constrain/src/soa_pattern.rs @@ -1,6 +1,6 @@ use crate::builtins; use crate::soa_expr::{constrain_expr, Env}; -use roc_can::constraint_soa::{Constraint, Constraints, PresenceConstraint}; +use roc_can::constraint_soa::{Constraint, Constraints}; use roc_can::expected::{Expected, PExpected}; use roc_can::pattern::Pattern::{self, *}; use roc_can::pattern::{DestructType, RecordDestruct}; @@ -168,20 +168,18 @@ pub fn constrain_pattern( // A -> "" // _ -> "" // so, we know that "x" (in this case, a tag union) must be open. - state.constraints.push(Constraint::Present( - expected.get_type(), - PresenceConstraint::IsOpen, - )); + state + .constraints + .push(constraints.is_open_type(expected.get_type())); } UnsupportedPattern(_) | MalformedPattern(_, _) | OpaqueNotInScope(..) => { // Erroneous patterns don't add any constraints. } Identifier(symbol) | Shadowed(_, _, symbol) => { - state.constraints.push(Constraint::Present( - expected.get_type_ref().clone(), - PresenceConstraint::IsOpen, - )); + state + .constraints + .push(constraints.is_open_type(expected.get_type_ref().clone())); state.headers.insert( *symbol, Loc { @@ -205,18 +203,19 @@ pub fn constrain_pattern( Category::Num, ); - state.constraints.push(Constraint::Pattern( - region, - PatternCategory::Num, + state.constraints.push(constraints.equal_pattern_types( num_type, expected, + PatternCategory::Num, + region, )); } &IntLiteral(num_var, precision_var, _, _, bound) => { // First constraint on the free num var; this improves the resolved type quality in // case the bound is an alias. - let num_type = builtins::add_numeric_bound_constr( + let num_type = builtins::add_numeric_bound_constr_soa( + constraints, &mut state.constraints, Type::Variable(num_var), bound, @@ -266,29 +265,29 @@ pub fn constrain_pattern( )); // Also constrain the pattern against the num var, again to reuse aliases if they're present. - state.constraints.push(Constraint::Pattern( - region, - PatternCategory::Float, + state.constraints.push(constraints.equal_pattern_types( num_type, // TODO check me if something breaks! expected, + PatternCategory::Float, + region, )); } StrLiteral(_) => { - state.constraints.push(Constraint::Pattern( - region, - PatternCategory::Str, + state.constraints.push(constraints.equal_pattern_types( builtins::str_type(), expected, + PatternCategory::Str, + region, )); } SingleQuote(_) => { - state.constraints.push(Constraint::Pattern( - region, - PatternCategory::Character, + state.constraints.push(constraints.equal_pattern_types( builtins::num_u32(), expected, + PatternCategory::Character, + region, )); } @@ -325,36 +324,39 @@ pub fn constrain_pattern( let field_type = match typ { DestructType::Guard(guard_var, loc_guard) => { - state.constraints.push(Constraint::Present( + state.constraints.push(constraints.pattern_presence( Type::Variable(*guard_var), - PresenceConstraint::Pattern( - region, - PatternCategory::PatternGuard, - PExpected::ForReason( - PReason::PatternGuard, - pat_type.clone(), - loc_guard.region, - ), + PExpected::ForReason( + PReason::PatternGuard, + pat_type.clone(), + loc_guard.region, ), + PatternCategory::PatternGuard, + region, )); state.vars.push(*guard_var); - constrain_pattern(env, &loc_guard.value, loc_guard.region, expected, state); + constrain_pattern( + constraints, + env, + &loc_guard.value, + loc_guard.region, + expected, + state, + ); RecordField::Demanded(pat_type) } DestructType::Optional(expr_var, loc_expr) => { - state.constraints.push(Constraint::Present( + state.constraints.push(constraints.pattern_presence( Type::Variable(*expr_var), - PresenceConstraint::Pattern( - region, - PatternCategory::PatternDefault, - PExpected::ForReason( - PReason::OptionalField, - pat_type.clone(), - loc_expr.region, - ), + PExpected::ForReason( + PReason::OptionalField, + pat_type.clone(), + loc_expr.region, ), + PatternCategory::PatternDefault, + region, )); state.vars.push(*expr_var); @@ -365,8 +367,13 @@ pub fn constrain_pattern( loc_expr.region, ); - let expr_con = - constrain_expr(env, loc_expr.region, &loc_expr.value, expr_expected); + let expr_con = constrain_expr( + constraints, + env, + loc_expr.region, + &loc_expr.value, + expr_expected, + ); state.constraints.push(expr_con); RecordField::Optional(pat_type) @@ -391,9 +398,11 @@ pub fn constrain_pattern( region, ); - let record_con = Constraint::Present( + let record_con = constraints.pattern_presence( Type::Variable(*whole_var), - PresenceConstraint::Pattern(region, PatternCategory::Record, expected), + expected, + PatternCategory::Record, + region, ); state.constraints.push(whole_con); @@ -420,24 +429,31 @@ pub fn constrain_pattern( pattern_type, region, ); - constrain_pattern(env, &loc_pattern.value, loc_pattern.region, expected, state); + constrain_pattern( + constraints, + env, + &loc_pattern.value, + loc_pattern.region, + expected, + state, + ); } let pat_category = PatternCategory::Ctor(tag_name.clone()); - let whole_con = Constraint::Present( + let whole_con = constraints.includes_tag( expected.clone().get_type(), - PresenceConstraint::IncludesTag( - tag_name.clone(), - argument_types.clone(), - region, - pat_category.clone(), - ), + tag_name.clone(), + argument_types.clone(), + pat_category.clone(), + region, ); - let tag_con = Constraint::Present( + let tag_con = constraints.pattern_presence( Type::Variable(*whole_var), - PresenceConstraint::Pattern(region, pat_category, expected), + expected, + pat_category, + region, ); state.vars.push(*whole_var); @@ -469,6 +485,7 @@ pub fn constrain_pattern( // First, add a constraint for the argument "who" let arg_pattern_expected = PExpected::NoExpectation(arg_pattern_type.clone()); constrain_pattern( + constraints, env, &loc_arg_pattern.value, loc_arg_pattern.region, @@ -495,9 +512,11 @@ pub fn constrain_pattern( ); // Next, link `whole_var` (the type of "@Id who") to the expected type - let opaque_pattern_con = Constraint::Present( + let opaque_pattern_con = constraints.pattern_presence( Type::Variable(*whole_var), - PresenceConstraint::Pattern(region, PatternCategory::Opaque(*opaque), expected), + expected, + PatternCategory::Opaque(*opaque), + region, ); state diff --git a/reporting/src/error/type.rs b/reporting/src/error/type.rs index d633d5e6c4..65a0936977 100644 --- a/reporting/src/error/type.rs +++ b/reporting/src/error/type.rs @@ -1372,7 +1372,7 @@ fn to_pattern_report<'b>( } } PReason::WhenMatch { index } => { - if index == Index::FIRST { + if index == HumanIndex::FIRST { let doc = alloc.stack(vec![ alloc .text("The 1st pattern in this ") @@ -1384,7 +1384,7 @@ fn to_pattern_report<'b>( found, expected_type, add_pattern_category( - HumanIndexlloc, + alloc, alloc.text("The first pattern is trying to match"), &category, ),