From d7109febe4b35caeebc72d654a960e5a13d7c47a Mon Sep 17 00:00:00 2001 From: Sam Zhou Date: Sat, 28 Oct 2023 14:55:24 -0700 Subject: [PATCH 1/2] [checker][pattern-matching] Add `nothing` as a convenience factory function --- crates/samlang-core/src/checker/pattern_matching.rs | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/crates/samlang-core/src/checker/pattern_matching.rs b/crates/samlang-core/src/checker/pattern_matching.rs index bebbde907..99a65b08f 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))) } @@ -405,6 +409,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()], From 72cd10d5c202fc19d070c63bcdc7d70755a002c4 Mon Sep 17 00:00:00 2001 From: Sam Zhou Date: Sat, 28 Oct 2023 15:00:07 -0700 Subject: [PATCH 2/2] [checker][pattern-matching] Take context by reference --- .../src/checker/pattern_matching.rs | 35 +++++++++++++------ 1 file changed, 24 insertions(+), 11 deletions(-) diff --git a/crates/samlang-core/src/checker/pattern_matching.rs b/crates/samlang-core/src/checker/pattern_matching.rs index 99a65b08f..9235bb6d0 100644 --- a/crates/samlang-core/src/checker/pattern_matching.rs +++ b/crates/samlang-core/src/checker/pattern_matching.rs @@ -65,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], @@ -72,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; } @@ -92,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)), ) @@ -112,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), ) { @@ -143,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())))), } } @@ -204,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) { @@ -221,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)] @@ -287,6 +297,7 @@ mod tests { impl PatternMatchingContext for MockingPatternMatchingContext { fn is_variant_signature_complete( + &self, _module_reference: ModuleReference, class_name: PStr, variant_name: &[PStr], @@ -308,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(), ), @@ -321,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, &[], @@ -448,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)]),