diff --git a/crates/compiler/constrain/src/pattern.rs b/crates/compiler/constrain/src/pattern.rs index 2246878701..993262cef1 100644 --- a/crates/compiler/constrain/src/pattern.rs +++ b/crates/compiler/constrain/src/pattern.rs @@ -3,7 +3,7 @@ use crate::expr::{constrain_expr, Env}; use roc_can::constraint::{Constraint, Constraints}; use roc_can::expected::{Expected, PExpected}; use roc_can::pattern::Pattern::{self, *}; -use roc_can::pattern::{DestructType, RecordDestruct}; +use roc_can::pattern::{DestructType, ListPatterns, RecordDestruct}; use roc_collections::all::{HumanIndex, SendMap}; use roc_collections::VecMap; use roc_module::ident::Lowercase; @@ -513,12 +513,46 @@ pub fn constrain_pattern( List { list_var, elem_var, - patterns: _, + patterns: + ListPatterns { + patterns, + opt_rest: _, + }, } => { + for loc_pat in patterns.iter() { + let expected = + PExpected::ForReason(PReason::ListElem, Type::Variable(*elem_var), region); + + constrain_pattern( + constraints, + env, + &loc_pat.value, + loc_pat.region, + expected, + state, + ); + } + + let list_var_index = constraints.push_type(Type::Variable(*list_var)); + let solved_list = constraints.push_type(Type::Apply( + Symbol::LIST_LIST, + vec![Loc::at(region, Type::Variable(*elem_var))], + region, + )); + let store_solved_list = constraints.store(solved_list, *list_var, file!(), line!()); + + let expected = constraints.push_pat_expected_type(expected); + let expected_constraint = constraints.pattern_presence( + list_var_index, + expected, + PatternCategory::List, + region, + ); + state.vars.push(*list_var); state.vars.push(*elem_var); - - todo!(); + state.constraints.push(store_solved_list); + state.constraints.push(expected_constraint); } AppliedTag { diff --git a/crates/compiler/types/src/types.rs b/crates/compiler/types/src/types.rs index 4ace381866..50fbfb6af1 100644 --- a/crates/compiler/types/src/types.rs +++ b/crates/compiler/types/src/types.rs @@ -2160,6 +2160,7 @@ pub enum PReason { tag_name: TagName, index: HumanIndex, }, + ListElem, PatternGuard, OptionalField, } diff --git a/crates/reporting/src/error/type.rs b/crates/reporting/src/error/type.rs index 7e819553e0..731a7084e7 100644 --- a/crates/reporting/src/error/type.rs +++ b/crates/reporting/src/error/type.rs @@ -1945,8 +1945,8 @@ fn to_pattern_report<'b>( severity: Severity::RuntimeError, } } - PReason::TagArg { .. } | PReason::PatternGuard => { - unreachable!("I didn't think this could trigger. Please tell Folkert about it!") + PReason::TagArg { .. } | PReason::PatternGuard | PReason::ListElem => { + internal_error!("We didn't think this could trigger. Please tell us about it on Zulip if it does!") } }, } diff --git a/crates/reporting/tests/test_reporting.rs b/crates/reporting/tests/test_reporting.rs index d3f5a4f7ee..445170fb9f 100644 --- a/crates/reporting/tests/test_reporting.rs +++ b/crates/reporting/tests/test_reporting.rs @@ -11821,4 +11821,30 @@ All branches in an `if` must have the same type! I would have to crash if I saw one of those! Add branches for them! "### ); + + test_report!( + #[ignore = "must implement exhaustiveness sketching for lists first"] + mismatch_within_list_pattern, + indoc!( + r#" + when [] is + [A, 1u8] -> "" + "# + ), + @r###" + "### + ); + + test_report!( + #[ignore = "must implement exhaustiveness sketching for lists first"] + mismatch_list_pattern_vs_condition, + indoc!( + r#" + when [A, B] is + ["foo", "bar"] -> "" + "# + ), + @r###" + "### + ); }