about summary refs log tree commit diff
diff options
context:
space:
mode:
authorNadrieril <nadrieril+git@gmail.com>2019-11-07 18:52:13 +0000
committerNadrieril <nadrieril+git@gmail.com>2019-11-15 16:14:34 +0000
commit81db2ee902566dfe8d1324f7849ea202028f68fd (patch)
treedf1981cae99aab39ae35a3da942bf00b3112c401
parentf3752ee5d5777ed68231710a6410823f24417bdc (diff)
downloadrust-81db2ee902566dfe8d1324f7849ea202028f68fd.tar.gz
rust-81db2ee902566dfe8d1324f7849ea202028f68fd.zip
Special-case range inclusion when the range is integral but non-exhaustive
-rw-r--r--src/librustc_mir/hair/pattern/_match.rs27
1 files changed, 27 insertions, 0 deletions
diff --git a/src/librustc_mir/hair/pattern/_match.rs b/src/librustc_mir/hair/pattern/_match.rs
index 87d5795484e..4f4d814dee9 100644
--- a/src/librustc_mir/hair/pattern/_match.rs
+++ b/src/librustc_mir/hair/pattern/_match.rs
@@ -641,6 +641,15 @@ impl<'tcx> Constructor<'tcx> {
         IntRange::should_treat_range_exhaustively(tcx, ty)
     }
 
+    fn is_integral_range(&self) -> bool {
+        let ty = match self {
+            ConstantValue(value, _) => value.ty,
+            ConstantRange(_, _, ty, _, _) => ty,
+            _ => return false,
+        };
+        IntRange::is_integral(ty)
+    }
+
     fn variant_index_for_adt<'a>(
         &self,
         cx: &MatchCheckCtxt<'a, 'tcx>,
@@ -1471,6 +1480,12 @@ impl<'tcx> IntRange<'tcx> {
         }
     }
 
+    fn is_subrange(&self, other: &Self) -> bool {
+        let (lo, hi) = (*self.range.start(), *self.range.end());
+        let (other_lo, other_hi) = (*other.range.start(), *other.range.end());
+        other_lo <= lo && hi <= other_hi
+    }
+
     fn suspicious_intersection(&self, other: &Self) -> bool {
         // `false` in the following cases:
         // 1     ----      // 1  ----------   // 1 ----        // 1       ----
@@ -2300,6 +2315,8 @@ fn specialize_one_pattern<'p, 'a: 'p, 'q: 'p, 'tcx>(
                     IntRange::from_pat(cx.tcx, cx.param_env, pat),
                 ) {
                     (Some(ctor), Some(pat)) => ctor.intersection(&pat).map(|_| {
+                        // Constructor splitting should ensure that all intersections we encounter
+                        // are actually inclusions.
                         let (pat_lo, pat_hi) = pat.range.into_inner();
                         let (ctor_lo, ctor_hi) = ctor.range.into_inner();
                         assert!(pat_lo <= ctor_lo && ctor_hi <= pat_hi);
@@ -2307,6 +2324,16 @@ fn specialize_one_pattern<'p, 'a: 'p, 'q: 'p, 'tcx>(
                     }),
                     _ => None,
                 }
+            } else if constructor.is_integral_range() {
+                // If we have an integer range that should not be matched exhaustively, fallback to
+                // checking for inclusion.
+                match (
+                    IntRange::from_ctor(cx.tcx, cx.param_env, constructor),
+                    IntRange::from_pat(cx.tcx, cx.param_env, pat),
+                ) {
+                    (Some(ctor), Some(pat)) if ctor.is_subrange(&pat) => Some(PatStack::default()),
+                    _ => None,
+                }
             } else {
                 // Fallback for non-ranges and ranges that involve
                 // floating-point numbers, which are not conveniently handled