about summary refs log tree commit diff
path: root/compiler/rustc_pattern_analysis/tests/exhaustiveness.rs
diff options
context:
space:
mode:
Diffstat (limited to 'compiler/rustc_pattern_analysis/tests/exhaustiveness.rs')
-rw-r--r--compiler/rustc_pattern_analysis/tests/exhaustiveness.rs112
1 files changed, 106 insertions, 6 deletions
diff --git a/compiler/rustc_pattern_analysis/tests/exhaustiveness.rs b/compiler/rustc_pattern_analysis/tests/exhaustiveness.rs
index 3b8f346ef19..14ca0d057f0 100644
--- a/compiler/rustc_pattern_analysis/tests/exhaustiveness.rs
+++ b/compiler/rustc_pattern_analysis/tests/exhaustiveness.rs
@@ -11,16 +11,30 @@ use rustc_pattern_analysis::usefulness::PlaceValidity;
 mod common;
 
 /// Analyze a match made of these patterns.
-fn check(patterns: Vec<DeconstructedPat<Cx>>) -> Vec<WitnessPat<Cx>> {
-    let ty = *patterns[0].ty();
+fn run(
+    ty: Ty,
+    patterns: Vec<DeconstructedPat<Cx>>,
+    exhaustive_witnesses: bool,
+) -> Vec<WitnessPat<Cx>> {
     let arms: Vec<_> =
         patterns.iter().map(|pat| MatchArm { pat, has_guard: false, arm_data: () }).collect();
-    let report =
-        compute_match_usefulness(arms.as_slice(), ty, PlaceValidity::ValidOnly, usize::MAX)
-            .unwrap();
+    let report = compute_match_usefulness(
+        arms.as_slice(),
+        ty,
+        PlaceValidity::ValidOnly,
+        usize::MAX,
+        exhaustive_witnesses,
+    )
+    .unwrap();
     report.non_exhaustiveness_witnesses
 }
 
+/// Analyze a match made of these patterns. Panics if there are no patterns
+fn check(patterns: Vec<DeconstructedPat<Cx>>) -> Vec<WitnessPat<Cx>> {
+    let ty = *patterns[0].ty();
+    run(ty, patterns, true)
+}
+
 #[track_caller]
 fn assert_exhaustive(patterns: Vec<DeconstructedPat<Cx>>) {
     let witnesses = check(patterns);
@@ -35,6 +49,26 @@ fn assert_non_exhaustive(patterns: Vec<DeconstructedPat<Cx>>) {
     assert!(!witnesses.is_empty())
 }
 
+use WhichWitnesses::*;
+enum WhichWitnesses {
+    AllOfThem,
+    OnlySome,
+}
+
+#[track_caller]
+/// We take the type as input to support empty matches.
+fn assert_witnesses(
+    which: WhichWitnesses,
+    ty: Ty,
+    patterns: Vec<DeconstructedPat<Cx>>,
+    expected: Vec<&str>,
+) {
+    let exhaustive_wit = matches!(which, AllOfThem);
+    let witnesses = run(ty, patterns, exhaustive_wit);
+    let witnesses: Vec<_> = witnesses.iter().map(|w| format!("{w:?}")).collect();
+    assert_eq!(witnesses, expected)
+}
+
 #[test]
 fn test_int_ranges() {
     let ty = Ty::U8;
@@ -59,6 +93,8 @@ fn test_int_ranges() {
 
 #[test]
 fn test_nested() {
+    // enum E { A(bool), B(bool) }
+    // ty = (E, E)
     let ty = Ty::BigStruct { arity: 2, ty: &Ty::BigEnum { arity: 2, ty: &Ty::Bool } };
     assert_non_exhaustive(pats!(ty;
         Struct(Variant.0, _),
@@ -79,9 +115,73 @@ fn test_nested() {
 }
 
 #[test]
+fn test_witnesses() {
+    // TY = Option<bool>
+    const TY: Ty = Ty::Enum(&[Ty::Bool, UNIT]);
+    // ty = (Option<bool>, Option<bool>)
+    let ty = Ty::Tuple(&[TY, TY]);
+    assert_witnesses(AllOfThem, ty, vec![], vec!["(_, _)"]);
+    assert_witnesses(
+        OnlySome,
+        ty,
+        pats!(ty;
+            (Variant.0(false), Variant.0(false)),
+        ),
+        vec!["(Enum::Variant1(_), _)"],
+    );
+    assert_witnesses(
+        AllOfThem,
+        ty,
+        pats!(ty;
+            (Variant.0(false), Variant.0(false)),
+        ),
+        vec![
+            "(Enum::Variant0(false), Enum::Variant0(true))",
+            "(Enum::Variant0(false), Enum::Variant1(_))",
+            "(Enum::Variant0(true), _)",
+            "(Enum::Variant1(_), _)",
+        ],
+    );
+    assert_witnesses(
+        OnlySome,
+        ty,
+        pats!(ty;
+            (_, Variant.0(false)),
+        ),
+        vec!["(_, Enum::Variant1(_))"],
+    );
+    assert_witnesses(
+        AllOfThem,
+        ty,
+        pats!(ty;
+            (_, Variant.0(false)),
+        ),
+        vec!["(_, Enum::Variant0(true))", "(_, Enum::Variant1(_))"],
+    );
+
+    let ty = Ty::NonExhaustiveEnum(&[UNIT, UNIT, UNIT]);
+    assert_witnesses(
+        OnlySome,
+        ty,
+        pats!(ty;
+            Variant.0,
+        ),
+        vec!["_"],
+    );
+    assert_witnesses(
+        AllOfThem,
+        ty,
+        pats!(ty;
+            Variant.0,
+        ),
+        vec!["Enum::Variant1(_)", "Enum::Variant2(_)", "_"],
+    );
+}
+
+#[test]
 fn test_empty() {
     // `TY = Result<bool, !>`
-    const TY: Ty = Ty::Enum(&[Ty::Bool, Ty::Enum(&[])]);
+    const TY: Ty = Ty::Enum(&[Ty::Bool, NEVER]);
     assert_exhaustive(pats!(TY;
         Variant.0,
     ));