]> git.proxmox.com Git - rustc.git/blobdiff - src/librustc_mir/hair/pattern/_match.rs
New upstream version 1.34.2+dfsg1
[rustc.git] / src / librustc_mir / hair / pattern / _match.rs
index 188a1120442983dfba44c786cb5a4b6047a04590..10bef53e249c4430993e3581013d81d776b1d11a 100644 (file)
@@ -6,8 +6,8 @@
 ///
 /// The algorithm implemented here is a modified version of the one described in:
 /// http://moscova.inria.fr/~maranget/papers/warn/index.html
-/// However, to save future implementors from reading the original paper, I'm going
-/// to summarise the algorithm here to hopefully save time and be a little clearer
+/// However, to save future implementors from reading the original paper, we
+/// summarise the algorithm here to hopefully save time and be a little clearer
 /// (without being so rigorous).
 ///
 /// The core of the algorithm revolves about a "usefulness" check. In particular, we
@@ -172,7 +172,7 @@ use rustc::ty::{self, Ty, TyCtxt, TypeFoldable, Const};
 use rustc::ty::layout::{Integer, IntegerExt, VariantIdx, Size};
 
 use rustc::mir::Field;
-use rustc::mir::interpret::{ConstValue, Pointer, Scalar};
+use rustc::mir::interpret::{ConstValue, Scalar};
 use rustc::util::common::ErrorReported;
 
 use syntax::attr::{SignedInt, UnsignedInt};
@@ -214,20 +214,22 @@ impl<'a, 'tcx> LiteralExpander<'a, 'tcx> {
         match (val, &crty.sty, &rty.sty) {
             // the easy case, deref a reference
             (ConstValue::Scalar(Scalar::Ptr(p)), x, y) if x == y => ConstValue::ByRef(
-                p.alloc_id,
+                p,
                 self.tcx.alloc_map.lock().unwrap_memory(p.alloc_id),
-                p.offset,
             ),
             // unsize array to slice if pattern is array but match value or other patterns are slice
             (ConstValue::Scalar(Scalar::Ptr(p)), ty::Array(t, n), ty::Slice(u)) => {
                 assert_eq!(t, u);
-                ConstValue::ScalarPair(
+                ConstValue::Slice(
                     Scalar::Ptr(p),
-                    n.map_evaluated(|val| val.val.try_to_scalar()).unwrap(),
+                    n.map_evaluated(|val| val.val.try_to_scalar())
+                        .unwrap()
+                        .to_usize(&self.tcx)
+                        .unwrap(),
                 )
             },
             // fat pointers stay the same
-            (ConstValue::ScalarPair(..), _, _) => val,
+            (ConstValue::Slice(..), _, _) => val,
             // FIXME(oli-obk): this is reachable for `const FOO: &&&u32 = &&&42;` being used
             _ => bug!("cannot deref {:#?}, {} -> {}", val, crty, rty),
         }
@@ -304,7 +306,7 @@ impl<'p, 'tcx> Matrix<'p, 'tcx> {
 /// + _     + [_, _, ..tail] +
 /// ++++++++++++++++++++++++++
 impl<'p, 'tcx> fmt::Debug for Matrix<'p, 'tcx> {
-    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
         write!(f, "\n")?;
 
         let &Matrix(ref m) = self;
@@ -348,7 +350,7 @@ pub struct MatchCheckCtxt<'a, 'tcx: 'a> {
     /// The module in which the match occurs. This is necessary for
     /// checking inhabited-ness of types because whether a type is (visibly)
     /// inhabited can depend on whether it was defined in the current module or
-    /// not. eg. `struct Foo { _private: ! }` cannot be seen to be empty
+    /// not. E.g., `struct Foo { _private: ! }` cannot be seen to be empty
     /// outside it's module and should not be matchable with an empty match
     /// statement.
     pub module: DefId,
@@ -427,13 +429,24 @@ pub enum Constructor<'tcx> {
 }
 
 impl<'tcx> Constructor<'tcx> {
-    fn variant_index_for_adt(&self, adt: &'tcx ty::AdtDef) -> VariantIdx {
+    fn variant_index_for_adt<'a>(
+        &self,
+        cx: &MatchCheckCtxt<'a, 'tcx>,
+        adt: &'tcx ty::AdtDef,
+    ) -> VariantIdx {
         match self {
             &Variant(vid) => adt.variant_index_with_id(vid),
             &Single => {
                 assert!(!adt.is_enum());
                 VariantIdx::new(0)
             }
+            &ConstantValue(c) => {
+                crate::const_eval::const_variant_index(
+                    cx.tcx,
+                    cx.param_env,
+                    c,
+                ).unwrap()
+            },
             _ => bug!("bad constructor {:?} for adt {:?}", self, adt)
         }
     }
@@ -567,7 +580,7 @@ impl<'tcx> Witness<'tcx> {
                             PatternKind::Variant {
                                 adt_def: adt,
                                 substs,
-                                variant_index: ctor.variant_index_for_adt(adt),
+                                variant_index: ctor.variant_index_for_adt(cx, adt),
                                 subpatterns: pats
                             }
                         } else {
@@ -620,8 +633,8 @@ impl<'tcx> Witness<'tcx> {
 /// but is instead bounded by the maximum fixed length of slice patterns in
 /// the column of patterns being analyzed.
 ///
-/// We make sure to omit constructors that are statically impossible. eg for
-/// Option<!> we do not include Some(_) in the returned list of constructors.
+/// We make sure to omit constructors that are statically impossible. E.g., for
+/// `Option<!>`, we do not include `Some(_)` in the returned list of constructors.
 fn all_constructors<'a, 'tcx: 'a>(cx: &mut MatchCheckCtxt<'a, 'tcx>,
                                   pcx: PatternContext<'tcx>)
                                   -> Vec<Constructor<'tcx>>
@@ -777,9 +790,9 @@ fn max_slice_length<'p, 'a: 'p, 'tcx: 'a, I>(
                         max_fixed_len,
                         n.unwrap_usize(cx.tcx),
                     ),
-                    (ConstValue::ScalarPair(_, n), ty::Slice(_)) => max_fixed_len = cmp::max(
+                    (ConstValue::Slice(_, n), ty::Slice(_)) => max_fixed_len = cmp::max(
                         max_fixed_len,
-                        n.to_usize(&cx.tcx).unwrap(),
+                        n,
                     ),
                     _ => {},
                 }
@@ -857,18 +870,24 @@ impl<'tcx> IntRange<'tcx> {
     }
 
     fn from_pat(tcx: TyCtxt<'_, 'tcx, 'tcx>,
-                pat: &Pattern<'tcx>)
+                mut pat: &Pattern<'tcx>)
                 -> Option<IntRange<'tcx>> {
-        Self::from_ctor(tcx, &match pat.kind {
-            box PatternKind::Constant { value } => ConstantValue(value),
-            box PatternKind::Range(PatternRange { lo, hi, ty, end }) => ConstantRange(
-                lo.to_bits(tcx, ty::ParamEnv::empty().and(ty)).unwrap(),
-                hi.to_bits(tcx, ty::ParamEnv::empty().and(ty)).unwrap(),
-                ty,
-                end,
-            ),
-            _ => return None,
-        })
+        let range = loop {
+            match pat.kind {
+                box PatternKind::Constant { value } => break ConstantValue(value),
+                box PatternKind::Range(PatternRange { lo, hi, ty, end }) => break ConstantRange(
+                    lo.to_bits(tcx, ty::ParamEnv::empty().and(ty)).unwrap(),
+                    hi.to_bits(tcx, ty::ParamEnv::empty().and(ty)).unwrap(),
+                    ty,
+                    end,
+                ),
+                box PatternKind::AscribeUserType { ref subpattern, .. } => {
+                    pat = subpattern;
+                },
+                _ => return None,
+            }
+        };
+        Self::from_ctor(tcx, &range)
     }
 
     // The return value of `signed_bias` should be XORed with an endpoint to encode/decode it.
@@ -882,7 +901,7 @@ impl<'tcx> IntRange<'tcx> {
         }
     }
 
-    /// Convert a `RangeInclusive` to a `ConstantValue` or inclusive `ConstantRange`.
+    /// Converts a `RangeInclusive` to a `ConstantValue` or inclusive `ConstantRange`.
     fn range_to_ctor(
         tcx: TyCtxt<'_, 'tcx, 'tcx>,
         ty: Ty<'tcx>,
@@ -898,7 +917,7 @@ impl<'tcx> IntRange<'tcx> {
         }
     }
 
-    /// Return a collection of ranges that spans the values covered by `ranges`, subtracted
+    /// 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, 'tcx>,
@@ -1019,13 +1038,13 @@ fn compute_missing_ctors<'a, 'tcx: 'a>(
     }
 }
 
-/// Algorithm from http://moscova.inria.fr/~maranget/papers/warn/index.html
+/// Algorithm from http://moscova.inria.fr/~maranget/papers/warn/index.html.
 /// The algorithm from the paper has been modified to correctly handle empty
 /// types. The changes are:
 ///   (0) We don't exit early if the pattern matrix has zero rows. We just
 ///       continue to recurse over columns.
 ///   (1) all_constructors will only return constructors that are statically
-///       possible. eg. it will only return Ok for Result<T, !>
+///       possible. E.g., it will only return `Ok` for `Result<T, !>`.
 ///
 /// This finds whether a (row) vector `v` of patterns is 'useful' in relation
 /// to a set of such vectors `m` - this is defined as there being a set of
@@ -1033,8 +1052,8 @@ fn compute_missing_ctors<'a, 'tcx: 'a>(
 ///
 /// All the patterns at each column of the `matrix ++ v` matrix must
 /// have the same type, except that wildcard (PatternKind::Wild) patterns
-/// with type TyErr are also allowed, even if the "type of the column"
-/// is not TyErr. That is used to represent private fields, as using their
+/// with type `TyErr` are also allowed, even if the "type of the column"
+/// is not `TyErr`. That is used to represent private fields, as using their
 /// real type would assert that they are inhabited.
 ///
 /// This is used both for reachability checking (if a pattern isn't useful in
@@ -1101,7 +1120,7 @@ pub fn is_useful<'p, 'a: 'p, 'tcx: 'a>(cx: &mut MatchCheckCtxt<'a, 'tcx>,
     } else {
         debug!("is_useful - expanding wildcard");
 
-        let used_ctors: Vec<Constructor> = rows.iter().flat_map(|row| {
+        let used_ctors: Vec<Constructor<'_>> = rows.iter().flat_map(|row| {
             pat_constructors(cx, row[0], pcx).unwrap_or(vec![])
         }).collect();
         debug!("used_ctors = {:#?}", used_ctors);
@@ -1285,10 +1304,10 @@ fn is_useful_specialized<'p, 'a: 'p, 'tcx: 'a>(
 /// Slice patterns, however, can match slices of different lengths. For instance,
 /// `[a, b, ..tail]` can match a slice of length 2, 3, 4 and so on.
 ///
-/// Returns None in case of a catch-all, which can't be specialized.
+/// Returns `None` in case of a catch-all, which can't be specialized.
 fn pat_constructors<'tcx>(cx: &mut MatchCheckCtxt<'_, 'tcx>,
                           pat: &Pattern<'tcx>,
-                          pcx: PatternContext)
+                          pcx: PatternContext<'_>)
                           -> Option<Vec<Constructor<'tcx>>>
 {
     match *pat.kind {
@@ -1327,9 +1346,9 @@ fn pat_constructors<'tcx>(cx: &mut MatchCheckCtxt<'_, 'tcx>,
 /// This computes the arity of a constructor. The arity of a constructor
 /// is how many subpattern patterns of that constructor should be expanded to.
 ///
-/// For instance, a tuple pattern (_, 42, Some([])) has the arity of 3.
+/// For instance, a tuple pattern `(_, 42, Some([]))` has the arity of 3.
 /// A struct pattern's arity is the number of fields it contains, etc.
-fn constructor_arity(_cx: &MatchCheckCtxt, ctor: &Constructor, ty: Ty) -> u64 {
+fn constructor_arity(cx: &MatchCheckCtxt<'a, 'tcx>, ctor: &Constructor<'tcx>, ty: Ty<'tcx>) -> u64 {
     debug!("constructor_arity({:#?}, {:?})", ctor, ty);
     match ty.sty {
         ty::Tuple(ref fs) => fs.len() as u64,
@@ -1337,10 +1356,10 @@ fn constructor_arity(_cx: &MatchCheckCtxt, ctor: &Constructor, ty: Ty) -> u64 {
             Slice(length) => length,
             ConstantValue(_) => 0,
             _ => bug!("bad slice pattern {:?} {:?}", ctor, ty)
-        },
+        }
         ty::Ref(..) => 1,
         ty::Adt(adt, _) => {
-            adt.variants[ctor.variant_index_for_adt(adt)].fields.len() as u64
+            adt.variants[ctor.variant_index_for_adt(cx, adt)].fields.len() as u64
         }
         _ => 0
     }
@@ -1351,7 +1370,7 @@ fn constructor_arity(_cx: &MatchCheckCtxt, ctor: &Constructor, ty: Ty) -> u64 {
 ///
 /// For instance, a tuple pattern (43u32, 'a') has sub pattern types [u32, char].
 fn constructor_sub_pattern_tys<'a, 'tcx: 'a>(cx: &MatchCheckCtxt<'a, 'tcx>,
-                                             ctor: &Constructor,
+                                             ctor: &Constructor<'tcx>,
                                              ty: Ty<'tcx>) -> Vec<Ty<'tcx>>
 {
     debug!("constructor_sub_pattern_tys({:#?}, {:?})", ctor, ty);
@@ -1361,14 +1380,14 @@ fn constructor_sub_pattern_tys<'a, 'tcx: 'a>(cx: &MatchCheckCtxt<'a, 'tcx>,
             Slice(length) => (0..length).map(|_| ty).collect(),
             ConstantValue(_) => vec![],
             _ => bug!("bad slice pattern {:?} {:?}", ctor, ty)
-        },
+        }
         ty::Ref(_, rty, _) => vec![rty],
         ty::Adt(adt, substs) => {
             if adt.is_box() {
                 // Use T as the sub pattern type of Box<T>.
                 vec![substs.type_at(0)]
             } else {
-                adt.variants[ctor.variant_index_for_adt(adt)].fields.iter().map(|field| {
+                adt.variants[ctor.variant_index_for_adt(cx, adt)].fields.iter().map(|field| {
                     let is_visible = adt.is_enum()
                         || field.vis.is_accessible_from(cx.module, cx.tcx);
                     if is_visible {
@@ -1408,7 +1427,7 @@ fn slice_pat_covered_by_const<'tcx>(
     suffix: &[Pattern<'tcx>]
 ) -> Result<bool, ErrorReported> {
     let data: &[u8] = match (const_val.val, &const_val.ty.sty) {
-        (ConstValue::ByRef(id, alloc, offset), ty::Array(t, n)) => {
+        (ConstValue::ByRef(ptr, alloc), ty::Array(t, n)) => {
             if *t != tcx.types.u8 {
                 // FIXME(oli-obk): can't mix const patterns with slice patterns and get
                 // any sort of exhaustiveness/unreachable check yet
@@ -1416,12 +1435,11 @@ fn slice_pat_covered_by_const<'tcx>(
                 // are definitely unreachable.
                 return Ok(false);
             }
-            let ptr = Pointer::new(id, offset);
             let n = n.assert_usize(tcx).unwrap();
             alloc.get_bytes(&tcx, ptr, Size::from_bytes(n)).unwrap()
         },
         // a slice fat pointer to a zero length slice
-        (ConstValue::ScalarPair(Scalar::Bits { .. }, n), ty::Slice(t)) => {
+        (ConstValue::Slice(Scalar::Bits { .. }, 0), ty::Slice(t)) => {
             if *t != tcx.types.u8 {
                 // FIXME(oli-obk): can't mix const patterns with slice patterns and get
                 // any sort of exhaustiveness/unreachable check yet
@@ -1429,11 +1447,10 @@ fn slice_pat_covered_by_const<'tcx>(
                 // are definitely unreachable.
                 return Ok(false);
             }
-            assert_eq!(n.to_usize(&tcx).unwrap(), 0);
             &[]
         },
         //
-        (ConstValue::ScalarPair(Scalar::Ptr(ptr), n), ty::Slice(t)) => {
+        (ConstValue::Slice(Scalar::Ptr(ptr), n), ty::Slice(t)) => {
             if *t != tcx.types.u8 {
                 // FIXME(oli-obk): can't mix const patterns with slice patterns and get
                 // any sort of exhaustiveness/unreachable check yet
@@ -1441,7 +1458,6 @@ fn slice_pat_covered_by_const<'tcx>(
                 // are definitely unreachable.
                 return Ok(false);
             }
-            let n = n.to_usize(&tcx).unwrap();
             tcx.alloc_map
                 .lock()
                 .unwrap_memory(ptr.alloc_id)
@@ -1602,7 +1618,7 @@ fn split_grouped_constructors<'p, 'a: 'p, 'tcx: 'a>(
     split_ctors
 }
 
-/// Check whether there exists any shared value in either `ctor` or `pat` by intersecting them.
+/// Checks whether there exists any shared value in either `ctor` or `pat` by intersecting them.
 fn constructor_intersects_pattern<'p, 'a: 'p, 'tcx: 'a>(
     tcx: TyCtxt<'a, 'tcx, 'tcx>,
     ctor: &Constructor<'tcx>,
@@ -1760,8 +1776,8 @@ fn specialize<'p, 'a: 'p, 'tcx: 'a>(
                     let (opt_ptr, n, ty) = match value.ty.sty {
                         ty::TyKind::Array(t, n) => {
                             match value.val {
-                                ConstValue::ByRef(id, alloc, offset) => (
-                                    Some((Pointer::new(id, offset), alloc)),
+                                ConstValue::ByRef(ptr, alloc) => (
+                                    Some((ptr, alloc)),
                                     n.unwrap_usize(cx.tcx),
                                     t,
                                 ),
@@ -1773,12 +1789,12 @@ fn specialize<'p, 'a: 'p, 'tcx: 'a>(
                         },
                         ty::TyKind::Slice(t) => {
                             match value.val {
-                                ConstValue::ScalarPair(ptr, n) => (
+                                ConstValue::Slice(ptr, n) => (
                                     ptr.to_ptr().ok().map(|ptr| (
                                         ptr,
                                         cx.tcx.alloc_map.lock().unwrap_memory(ptr.alloc_id),
                                     )),
-                                    n.to_bits(cx.tcx.data_layout.pointer_size).unwrap() as u64,
+                                    n,
                                     t,
                                 ),
                                 _ => span_bug!(