about summary refs log tree commit diff
diff options
context:
space:
mode:
authorAmin Arria <arria.amin@gmail.com>2020-03-25 20:07:01 -0300
committerAmin Arria <arria.amin@gmail.com>2020-03-26 12:34:22 -0300
commit5796e6e4618fd02bb7423b8f1a62f5b01ada63a7 (patch)
tree15556d671458c462cb12d8cd61e6867f25350158
parent3c1d9adb3cb3aad4233075fa296fc3c70b42cdb8 (diff)
downloadrust-5796e6e4618fd02bb7423b8f1a62f5b01ada63a7.tar.gz
rust-5796e6e4618fd02bb7423b8f1a62f5b01ada63a7.zip
Fix incorrect pattern warning "unreachable pattern"
- Added is_under_guard parameter to _match::is_useful and
  only add to the matrix if false
- Added comments explaining behavior
-rw-r--r--src/librustc_mir_build/hair/pattern/_match.rs42
-rw-r--r--src/librustc_mir_build/hair/pattern/check_match.rs7
2 files changed, 41 insertions, 8 deletions
diff --git a/src/librustc_mir_build/hair/pattern/_match.rs b/src/librustc_mir_build/hair/pattern/_match.rs
index 89063a4227f..b4a42aefca3 100644
--- a/src/librustc_mir_build/hair/pattern/_match.rs
+++ b/src/librustc_mir_build/hair/pattern/_match.rs
@@ -1619,12 +1619,17 @@ impl<'tcx> fmt::Debug for MissingConstructors<'tcx> {
 /// relation to preceding patterns, it is not reachable) and exhaustiveness
 /// checking (if a wildcard pattern is useful in relation to a matrix, the
 /// matrix isn't exhaustive).
+///
+/// `is_under_guard` is used to inform if the pattern has a guard. If it
+/// has one it must not be inserted into the matrix. This shouldn't be
+/// relied on for soundness.
 crate fn is_useful<'p, 'tcx>(
     cx: &mut MatchCheckCtxt<'p, 'tcx>,
     matrix: &Matrix<'p, 'tcx>,
     v: &PatStack<'p, 'tcx>,
     witness_preference: WitnessPreference,
     hir_id: HirId,
+    is_under_guard: bool,
     is_top_level: bool,
 ) -> Usefulness<'tcx, 'p> {
     let &Matrix(ref rows) = matrix;
@@ -1653,7 +1658,7 @@ crate fn is_useful<'p, 'tcx>(
         let mut unreachable_pats = Vec::new();
         let mut any_is_useful = false;
         for v in vs {
-            let res = is_useful(cx, &matrix, &v, witness_preference, hir_id, false);
+            let res = is_useful(cx, &matrix, &v, witness_preference, hir_id, is_under_guard, false);
             match res {
                 Useful(pats) => {
                     any_is_useful = true;
@@ -1664,7 +1669,10 @@ crate fn is_useful<'p, 'tcx>(
                     bug!("Encountered or-pat in `v` during exhaustiveness checking")
                 }
             }
-            matrix.push(v);
+            // If pattern has a guard don't add it to the matrix
+            if !is_under_guard {
+                matrix.push(v);
+            }
         }
         return if any_is_useful { Useful(unreachable_pats) } else { NotUseful };
     }
@@ -1712,7 +1720,18 @@ crate fn is_useful<'p, 'tcx>(
             Some(hir_id),
         )
         .into_iter()
-        .map(|c| is_useful_specialized(cx, matrix, v, c, pcx.ty, witness_preference, hir_id))
+        .map(|c| {
+            is_useful_specialized(
+                cx,
+                matrix,
+                v,
+                c,
+                pcx.ty,
+                witness_preference,
+                hir_id,
+                is_under_guard,
+            )
+        })
         .find(|result| result.is_useful())
         .unwrap_or(NotUseful)
     } else {
@@ -1746,14 +1765,24 @@ crate fn is_useful<'p, 'tcx>(
             split_grouped_constructors(cx.tcx, cx.param_env, pcx, all_ctors, matrix, DUMMY_SP, None)
                 .into_iter()
                 .map(|c| {
-                    is_useful_specialized(cx, matrix, v, c, pcx.ty, witness_preference, hir_id)
+                    is_useful_specialized(
+                        cx,
+                        matrix,
+                        v,
+                        c,
+                        pcx.ty,
+                        witness_preference,
+                        hir_id,
+                        is_under_guard,
+                    )
                 })
                 .find(|result| result.is_useful())
                 .unwrap_or(NotUseful)
         } else {
             let matrix = matrix.specialize_wildcard();
             let v = v.to_tail();
-            let usefulness = is_useful(cx, &matrix, &v, witness_preference, hir_id, false);
+            let usefulness =
+                is_useful(cx, &matrix, &v, witness_preference, hir_id, is_under_guard, false);
 
             // In this case, there's at least one "free"
             // constructor that is only matched against by
@@ -1810,6 +1839,7 @@ fn is_useful_specialized<'p, 'tcx>(
     lty: Ty<'tcx>,
     witness_preference: WitnessPreference,
     hir_id: HirId,
+    is_under_guard: bool,
 ) -> Usefulness<'tcx, 'p> {
     debug!("is_useful_specialized({:#?}, {:#?}, {:?})", v, ctor, lty);
 
@@ -1817,7 +1847,7 @@ fn is_useful_specialized<'p, 'tcx>(
         cx.pattern_arena.alloc_from_iter(ctor.wildcard_subpatterns(cx, lty));
     let matrix = matrix.specialize_constructor(cx, &ctor, ctor_wild_subpatterns);
     v.specialize_constructor(cx, &ctor, ctor_wild_subpatterns)
-        .map(|v| is_useful(cx, &matrix, &v, witness_preference, hir_id, false))
+        .map(|v| is_useful(cx, &matrix, &v, witness_preference, hir_id, is_under_guard, false))
         .map(|u| u.apply_constructor(cx, &ctor, lty))
         .unwrap_or(NotUseful)
 }
diff --git a/src/librustc_mir_build/hair/pattern/check_match.rs b/src/librustc_mir_build/hair/pattern/check_match.rs
index 9c86669cf9d..c2eeac60b8b 100644
--- a/src/librustc_mir_build/hair/pattern/check_match.rs
+++ b/src/librustc_mir_build/hair/pattern/check_match.rs
@@ -360,7 +360,7 @@ fn check_arms<'p, 'tcx>(
     let mut catchall = None;
     for (arm_index, (pat, id, has_guard)) in arms.iter().copied().enumerate() {
         let v = PatStack::from_pattern(pat);
-        match is_useful(cx, &seen, &v, LeaveOutWitness, id, true) {
+        match is_useful(cx, &seen, &v, LeaveOutWitness, id, has_guard, true) {
             NotUseful => {
                 match source {
                     hir::MatchSource::IfDesugar { .. } | hir::MatchSource::WhileDesugar => bug!(),
@@ -410,7 +410,10 @@ fn check_not_useful<'p, 'tcx>(
 ) -> Result<(), Vec<super::Pat<'tcx>>> {
     let wild_pattern = cx.pattern_arena.alloc(super::Pat::wildcard_from_ty(ty));
     let v = PatStack::from_pattern(wild_pattern);
-    match is_useful(cx, matrix, &v, ConstructWitness, hir_id, true) {
+
+    // false is given for `is_under_guard` argument due to the wildcard
+    // pattern not having a guard
+    match is_useful(cx, matrix, &v, ConstructWitness, hir_id, false, true) {
         NotUseful => Ok(()), // This is good, wildcard pattern isn't reachable.
         UsefulWithWitness(pats) => Err(if pats.is_empty() {
             bug!("Exhaustiveness check returned no witnesses")