about summary refs log tree commit diff
diff options
context:
space:
mode:
authorNadrieril <nadrieril+git@gmail.com>2019-11-09 10:03:18 +0000
committerNadrieril <nadrieril+git@gmail.com>2019-11-15 16:14:34 +0000
commit75a50886aa17e4b22841c9eafdd3506b3b92e62b (patch)
treeb3825e78f53eca1a218482d31714565cf8bc3bba
parentc6c862574de4245698452f46025163434a9fbbe1 (diff)
downloadrust-75a50886aa17e4b22841c9eafdd3506b3b92e62b.tar.gz
rust-75a50886aa17e4b22841c9eafdd3506b3b92e62b.zip
Avoid converting through Constructor when subtracting ranges
-rw-r--r--src/librustc_mir/hair/pattern/_match.rs67
1 files changed, 29 insertions, 38 deletions
diff --git a/src/librustc_mir/hair/pattern/_match.rs b/src/librustc_mir/hair/pattern/_match.rs
index b84af467d0c..37bd5057944 100644
--- a/src/librustc_mir/hair/pattern/_match.rs
+++ b/src/librustc_mir/hair/pattern/_match.rs
@@ -763,35 +763,30 @@ impl<'tcx> Constructor<'tcx> {
                 remaining_ctors
             }
             ConstantRange(..) | ConstantValue(..) => {
-                if let Some(_self_range) = IntRange::from_ctor(tcx, param_env, self) {
-                    let mut remaining_ctors = vec![self.clone()];
-                    for other_ctor in other_ctors {
-                        if other_ctor == self {
-                            // If a constructor appears in a `match` arm, we can
+                if let Some(self_range) = IntRange::from_ctor(tcx, param_env, self) {
+                    let mut remaining_ranges = vec![self_range.clone()];
+                    let other_ranges = other_ctors
+                        .into_iter()
+                        .filter_map(|c| IntRange::from_ctor(tcx, param_env, c));
+                    for other_range in other_ranges {
+                        if other_range == self_range {
+                            // If the `self` range appears directly in a `match` arm, we can
                             // eliminate it straight away.
-                            remaining_ctors = vec![]
-                        } else if let Some(interval) =
-                            IntRange::from_ctor(tcx, param_env, other_ctor)
-                        {
-                            // Refine the required constructors for the type by subtracting
-                            // the range defined by the current constructor pattern.
-                            remaining_ctors =
-                                interval.subtract_from(tcx, param_env, remaining_ctors);
+                            remaining_ranges = vec![];
+                        } else {
+                            // Otherwise explicitely compute the remaining ranges.
+                            remaining_ranges = other_range.subtract_from(remaining_ranges);
                         }
 
-                        // If the constructor patterns that have been considered so far
-                        // already cover the entire range of values, then we know the
-                        // constructor is not missing, and we can move on to the next one.
-                        if remaining_ctors.is_empty() {
+                        // If the ranges that have been considered so far already cover the entire
+                        // range of values, we can return early.
+                        if remaining_ranges.is_empty() {
                             break;
                         }
                     }
 
-                    // If a constructor has not been matched, then it is missing.
-                    // We add `remaining_ctors` instead of `self`, because then we can
-                    // provide more detailed error information about precisely which
-                    // ranges have been omitted.
-                    remaining_ctors
+                    // Convert the ranges back into constructors
+                    remaining_ranges.into_iter().map(|range| range.into_ctor(tcx)).collect()
                 } else {
                     if other_ctors.iter().any(|c| {
                         c == self
@@ -1418,38 +1413,27 @@ impl<'tcx> IntRange<'tcx> {
 
     /// Returns a collection of ranges that spans the values covered by `ranges`, subtracted
     /// by the values covered by `self`: i.e., `ranges \ self` (in set notation).
-    fn subtract_from(
-        self,
-        tcx: TyCtxt<'tcx>,
-        param_env: ty::ParamEnv<'tcx>,
-        ranges: Vec<Constructor<'tcx>>,
-    ) -> Vec<Constructor<'tcx>> {
-        let ranges = ranges
-            .into_iter()
-            .filter_map(|r| IntRange::from_ctor(tcx, param_env, &r).map(|i| i.range));
+    fn subtract_from(self, ranges: Vec<IntRange<'tcx>>) -> Vec<IntRange<'tcx>> {
         let mut remaining_ranges = vec![];
         let ty = self.ty;
         let span = self.span;
         let (lo, hi) = self.range.into_inner();
         for subrange in ranges {
-            let (subrange_lo, subrange_hi) = subrange.into_inner();
+            let (subrange_lo, subrange_hi) = subrange.range.into_inner();
             if lo > subrange_hi || subrange_lo > hi {
                 // The pattern doesn't intersect with the subrange at all,
                 // so the subrange remains untouched.
-                remaining_ranges
-                    .push(IntRange { range: subrange_lo..=subrange_hi, ty, span }.into_ctor(tcx));
+                remaining_ranges.push(IntRange { range: subrange_lo..=subrange_hi, ty, span });
             } else {
                 if lo > subrange_lo {
                     // The pattern intersects an upper section of the
                     // subrange, so a lower section will remain.
-                    remaining_ranges
-                        .push(IntRange { range: subrange_lo..=(lo - 1), ty, span }.into_ctor(tcx));
+                    remaining_ranges.push(IntRange { range: subrange_lo..=(lo - 1), ty, span });
                 }
                 if hi < subrange_hi {
                     // The pattern intersects a lower section of the
                     // subrange, so an upper section will remain.
-                    remaining_ranges
-                        .push(IntRange { range: (hi + 1)..=subrange_hi, ty, span }.into_ctor(tcx));
+                    remaining_ranges.push(IntRange { range: (hi + 1)..=subrange_hi, ty, span });
                 }
             }
         }
@@ -1491,6 +1475,13 @@ impl<'tcx> IntRange<'tcx> {
     }
 }
 
+// Ignore spans when comparing, they don't carry semantic information as they are only for lints.
+impl<'tcx> std::cmp::PartialEq for IntRange<'tcx> {
+    fn eq(&self, other: &Self) -> bool {
+        self.range == other.range && self.ty == other.ty
+    }
+}
+
 // A struct to compute a set of constructors equivalent to `all_ctors \ used_ctors`.
 struct MissingConstructors<'tcx> {
     tcx: TyCtxt<'tcx>,