diff --git a/compiler/can/src/constraint.rs b/compiler/can/src/constraint.rs index 12beadab9b..03b758320f 100644 --- a/compiler/can/src/constraint.rs +++ b/compiler/can/src/constraint.rs @@ -13,6 +13,7 @@ use roc_types::{subs::Variable, types::VariableDetail}; pub enum PresenceConstraint { IncludesTag(TagName, Vec), IsOpen, + Pattern(Region, PatternCategory, PExpected), } #[derive(Debug, Clone, PartialEq)] @@ -20,13 +21,7 @@ pub enum Constraint { Eq(Type, Expected, Category, Region), Store(Type, Variable, &'static str, u32), Lookup(Symbol, Expected, Region), - Pattern( - Region, - PatternCategory, - Type, - PExpected, - bool, /* Treat the pattern as a presence constraint */ - ), + Pattern(Region, PatternCategory, Type, PExpected), True, // Used for things that always unify, e.g. blanks and runtime errors SaveTheEnvironment, Let(Box), @@ -83,7 +78,7 @@ impl Constraint { Constraint::Eq(_, _, _, _) => false, Constraint::Store(_, _, _, _) => false, Constraint::Lookup(_, _, _) => false, - Constraint::Pattern(_, _, _, _, _) => false, + Constraint::Pattern(_, _, _, _) => false, Constraint::True => false, Constraint::SaveTheEnvironment => true, Constraint::Let(boxed) => { @@ -142,7 +137,7 @@ fn validate_help(constraint: &Constraint, declared: &Declared, accum: &mut Varia subtract(declared, &typ.variables_detail(), accum); subtract(declared, &expected.get_type_ref().variables_detail(), accum); } - Constraint::Pattern(_, _, typ, expected, _) => { + Constraint::Pattern(_, _, typ, expected) => { subtract(declared, &typ.variables_detail(), accum); subtract(declared, &expected.get_type_ref().variables_detail(), accum); } @@ -170,6 +165,10 @@ fn validate_help(constraint: &Constraint, declared: &Declared, accum: &mut Varia } } PresenceConstraint::IsOpen => {} + PresenceConstraint::Pattern(_, _, expected) => { + subtract(declared, &typ.variables_detail(), accum); + subtract(declared, &expected.get_type_ref().variables_detail(), accum); + } } } } diff --git a/compiler/constrain/src/pattern.rs b/compiler/constrain/src/pattern.rs index e6acd4ea22..ba7d4f628f 100644 --- a/compiler/constrain/src/pattern.rs +++ b/compiler/constrain/src/pattern.rs @@ -118,6 +118,23 @@ fn headers_from_annotation_help( } } +fn make_pattern_constraint( + region: Region, + category: PatternCategory, + actual: Type, + expected: PExpected, + presence_con: bool, +) -> Constraint { + if presence_con { + Constraint::Present( + actual, + PresenceConstraint::Pattern(region, category, expected), + ) + } else { + Constraint::Pattern(region, category, actual, expected) + } +} + /// This accepts PatternState (rather than returning it) so that the caller can /// initialize the Vecs in PatternState using with_capacity /// based on its knowledge of their lengths. @@ -170,7 +187,6 @@ pub fn constrain_pattern( PatternCategory::Num, builtins::num_num(Type::Variable(*var)), expected, - false, )); } @@ -180,7 +196,6 @@ pub fn constrain_pattern( PatternCategory::Int, builtins::num_int(Type::Variable(*precision_var)), expected, - false, )); } @@ -190,7 +205,6 @@ pub fn constrain_pattern( PatternCategory::Float, builtins::num_float(Type::Variable(*precision_var)), expected, - false, )); } @@ -200,7 +214,6 @@ pub fn constrain_pattern( PatternCategory::Str, builtins::str_type(), expected, - false, )); } @@ -237,7 +250,7 @@ pub fn constrain_pattern( let field_type = match typ { DestructType::Guard(guard_var, loc_guard) => { - state.constraints.push(Constraint::Pattern( + state.constraints.push(make_pattern_constraint( region, PatternCategory::PatternGuard, Type::Variable(*guard_var), @@ -262,7 +275,7 @@ pub fn constrain_pattern( RecordField::Demanded(pat_type) } DestructType::Optional(expr_var, loc_expr) => { - state.constraints.push(Constraint::Pattern( + state.constraints.push(make_pattern_constraint( region, PatternCategory::PatternDefault, Type::Variable(*expr_var), @@ -308,7 +321,7 @@ pub fn constrain_pattern( region, ); - let record_con = Constraint::Pattern( + let record_con = make_pattern_constraint( region, PatternCategory::Record, Type::Variable(*whole_var), @@ -367,7 +380,7 @@ pub fn constrain_pattern( ) }; - let tag_con = Constraint::Pattern( + let tag_con = make_pattern_constraint( region, PatternCategory::Ctor(tag_name.clone()), Type::Variable(*whole_var), diff --git a/compiler/solve/src/solve.rs b/compiler/solve/src/solve.rs index a083a1f737..14fbb2160f 100644 --- a/compiler/solve/src/solve.rs +++ b/compiler/solve/src/solve.rs @@ -350,7 +350,8 @@ fn solve( state } - Pattern(region, category, typ, expectation, presence) => { + Pattern(region, category, typ, expectation) + | Present(typ, PresenceConstraint::Pattern(region, category, expectation)) => { let actual = type_to_var(subs, rank, pools, cached_aliases, typ); let expected = type_to_var( subs, @@ -360,7 +361,9 @@ fn solve( expectation.get_type_ref(), ); - match unify(subs, actual, expected, *presence) { + let presence_con = matches!(constraint, Present(_, _)); + + match unify(subs, actual, expected, presence_con) { Success(vars) => { introduce(subs, rank, pools, &vars); @@ -684,6 +687,9 @@ fn solve( } } } + PresenceConstraint::Pattern(_, _, _) => { + unreachable!("Handled in a previous branch") + } } } }