diff --git a/crates/samlang-core/src/checker/pattern_matching.rs b/crates/samlang-core/src/checker/pattern_matching.rs index bebbde90..9235bb6d 100644 --- a/crates/samlang-core/src/checker/pattern_matching.rs +++ b/crates/samlang-core/src/checker/pattern_matching.rs @@ -50,6 +50,10 @@ impl AbstractPatternNode { })) } + pub(super) fn nothing() -> Self { + Self(Rc::new(AbstractPatternNodeInner::Or(Vec::with_capacity(0)))) + } + pub(super) fn or(possibilities: Vec) -> Self { Self(Rc::new(AbstractPatternNodeInner::Or(possibilities))) } @@ -61,6 +65,7 @@ struct PatternMatrix(Vec); pub(super) trait PatternMatchingContext { fn is_variant_signature_complete( + &self, module_reference: ModuleReference, class_name: PStr, variant_name: &[PStr], @@ -68,17 +73,23 @@ pub(super) trait PatternMatchingContext { } pub(super) fn is_additional_pattern_useful( + cx: &CX, existing_patterns: &[AbstractPatternNode], pattern: AbstractPatternNode, ) -> bool { - useful_internal::( + useful_internal( + cx, &PatternMatrix(existing_patterns.iter().map(|p| PatternVector(one(p.clone()))).collect_vec()), PatternVector(one(pattern)), ) } /// http://moscova.inria.fr/~maranget/papers/warn/warn.pdf -fn useful_internal(p: &PatternMatrix, q: PatternVector) -> bool { +fn useful_internal( + cx: &CX, + p: &PatternMatrix, + q: PatternVector, +) -> bool { if p.0.is_empty() { return true; } @@ -88,7 +99,8 @@ fn useful_internal(p: &PatternMatrix, q: PatternVect match q_first.0.as_ref() { AbstractPatternNodeInner::StructLike { variant, elements: rs } => { let rs_len = rs.len(); - useful_internal::( + useful_internal( + cx, &convert_into_specialized_matrix(p, *variant, rs_len), PatternVector(rs.clone().append(q_rest)), ) @@ -108,13 +120,14 @@ fn useful_internal(p: &PatternMatrix, q: PatternVect } } } - if is_signature_complete::(&root_constructors) { + if is_signature_complete(cx, &root_constructors) { for (variant, rs_len) in root_constructors { let mut new_q = q_rest.clone(); for _ in 0..rs_len { new_q = cons(AbstractPatternNode::wildcard(), new_q); } - if useful_internal::( + if useful_internal( + cx, &convert_into_specialized_matrix(p, variant, rs_len), PatternVector(new_q), ) { @@ -139,12 +152,12 @@ fn useful_internal(p: &PatternMatrix, q: PatternVect } } } - useful_internal::(&PatternMatrix(default_matrix_rows), PatternVector(q_rest)) + useful_internal(cx, &PatternMatrix(default_matrix_rows), PatternVector(q_rest)) } } AbstractPatternNodeInner::Or(possibilities) => possibilities .iter() - .any(|r| useful_internal::(p, PatternVector(cons(r.clone(), q_rest.clone())))), + .any(|r| useful_internal(cx, p, PatternVector(cons(r.clone(), q_rest.clone())))), } } @@ -200,6 +213,7 @@ fn convert_into_specialized_matrix( } fn is_signature_complete( + cx: &CX, root_constructors: &HashMap, usize>, ) -> bool { if root_constructors.contains_key(&None) { @@ -217,7 +231,7 @@ fn is_signature_complete( assert!(variants_grouped.len() == 1); let ((mod_ref, class_name), variants) = variants_grouped.pop().expect("Already checked it's non-empty."); - CX::is_variant_signature_complete(mod_ref, class_name, &variants) + cx.is_variant_signature_complete(mod_ref, class_name, &variants) } #[cfg(test)] @@ -283,6 +297,7 @@ mod tests { impl PatternMatchingContext for MockingPatternMatchingContext { fn is_variant_signature_complete( + &self, _module_reference: ModuleReference, class_name: PStr, variant_name: &[PStr], @@ -304,7 +319,8 @@ mod tests { } fn useful(matrix: &[&[P]], vector: &[P]) -> bool { - super::useful_internal::( + super::useful_internal( + &MockingPatternMatchingContext, &super::PatternMatrix( matrix.iter().map(|r| super::PatternVector(super::list(r.to_vec()))).collect(), ), @@ -317,7 +333,7 @@ mod tests { assert!(!format!("{:?}", OPTION_NONE).is_empty()); assert!(!format!("{:?}", P::wildcard()).is_empty()); assert_eq!(LETTERS, LETTERS_A.clone().class_name); - assert!(!MockingPatternMatchingContext::is_variant_signature_complete( + assert!(!MockingPatternMatchingContext.is_variant_signature_complete( ModuleReference::ROOT, PStr::PANIC, &[], @@ -405,6 +421,10 @@ mod tests { &[&[P::enum_(OPTION_NONE), P::wildcard()], &[P::wildcard(), P::enum_(OPTION_NONE)],], &[P::variant(OPTION_SOME, vec![P::wildcard()]), P::variant(OPTION_SOME, vec![P::wildcard()])] )); + assert!(!useful( + &[&[P::enum_(OPTION_NONE), P::wildcard()], &[P::wildcard(), P::enum_(OPTION_NONE)],], + &[P::nothing()] + )); assert!(!useful( &[ &[P::enum_(OPTION_NONE), P::wildcard()], @@ -440,7 +460,8 @@ mod tests { P::variant(OPTION_SOME, vec![P::wildcard()]) ])] )); - assert!(!super::is_additional_pattern_useful::( + assert!(!super::is_additional_pattern_useful( + &MockingPatternMatchingContext, &[ P::tuple(vec![P::enum_(OPTION_NONE), P::wildcard()]), P::tuple(vec![P::wildcard(), P::enum_(OPTION_NONE)]),