]> git.proxmox.com Git - rustc.git/blobdiff - src/librustc_mir/hair/pattern/mod.rs
New upstream version 1.31.0~beta.4+dfsg1
[rustc.git] / src / librustc_mir / hair / pattern / mod.rs
index 57519d6ad7d70908524d3a404be7aa5662a28202..f70e93182c8184cad14e16d71260a092c77d8908 100644 (file)
@@ -16,11 +16,14 @@ mod check_match;
 pub use self::check_match::check_crate;
 pub(crate) use self::check_match::check_match;
 
-use interpret::{const_field, const_variant_index};
+use const_eval::{const_field, const_variant_index};
+
+use hair::util::UserAnnotatedTyHelpers;
 
 use rustc::mir::{fmt_const_val, Field, BorrowKind, Mutability};
+use rustc::mir::{ProjectionElem, UserTypeAnnotation, UserTypeProjection, UserTypeProjections};
 use rustc::mir::interpret::{Scalar, GlobalId, ConstValue, sign_extend};
-use rustc::ty::{self, CanonicalTy, TyCtxt, AdtDef, Ty, Region};
+use rustc::ty::{self, Region, TyCtxt, AdtDef, Ty};
 use rustc::ty::subst::{Substs, Kind};
 use rustc::hir::{self, PatKind, RangeEnd};
 use rustc::hir::def::{Def, CtorKind};
@@ -62,13 +65,125 @@ pub struct Pattern<'tcx> {
     pub kind: Box<PatternKind<'tcx>>,
 }
 
+
+#[derive(Clone, Debug)]
+pub(crate) struct PatternTypeProjections<'tcx> {
+    contents: Vec<(PatternTypeProjection<'tcx>, Span)>,
+}
+
+impl<'tcx> PatternTypeProjections<'tcx> {
+    pub(crate) fn user_ty(self) -> UserTypeProjections<'tcx> {
+        UserTypeProjections::from_projections(
+            self.contents.into_iter().map(|(pat_ty_proj, span)| (pat_ty_proj.user_ty(), span)))
+    }
+
+    pub(crate) fn none() -> Self {
+        PatternTypeProjections { contents: vec![] }
+    }
+
+    pub(crate) fn ref_binding(&self) -> Self {
+        // FIXME(#47184): ignore for now
+        PatternTypeProjections { contents: vec![] }
+    }
+
+    fn map_projs(&self,
+                 mut f: impl FnMut(&PatternTypeProjection<'tcx>) -> PatternTypeProjection<'tcx>)
+                 -> Self
+    {
+        PatternTypeProjections {
+            contents: self.contents
+                .iter()
+                .map(|(proj, span)| (f(proj), *span))
+                .collect(), }
+    }
+
+    pub(crate) fn index(&self) -> Self { self.map_projs(|pat_ty_proj| pat_ty_proj.index()) }
+
+    pub(crate) fn subslice(&self, from: u32, to: u32) -> Self {
+        self.map_projs(|pat_ty_proj| pat_ty_proj.subslice(from, to))
+    }
+
+    pub(crate) fn deref(&self) -> Self { self.map_projs(|pat_ty_proj| pat_ty_proj.deref()) }
+
+    pub(crate) fn leaf(&self, field: Field) -> Self {
+        self.map_projs(|pat_ty_proj| pat_ty_proj.leaf(field))
+    }
+
+    pub(crate) fn variant(&self,
+                          adt_def: &'tcx AdtDef,
+                          variant_index: usize,
+                          field: Field) -> Self {
+        self.map_projs(|pat_ty_proj| pat_ty_proj.variant(adt_def, variant_index, field))
+    }
+
+    pub(crate) fn add_user_type(&self, user_ty: &PatternTypeProjection<'tcx>, sp: Span) -> Self {
+        let mut new = self.clone();
+        new.contents.push((user_ty.clone(), sp));
+        new
+    }
+}
+
+#[derive(Clone, Debug)]
+pub struct PatternTypeProjection<'tcx>(UserTypeProjection<'tcx>);
+
+impl<'tcx> PatternTypeProjection<'tcx> {
+    pub(crate) fn index(&self) -> Self {
+        let mut new = self.clone();
+        new.0.projs.push(ProjectionElem::Index(()));
+        new
+    }
+
+    pub(crate) fn subslice(&self, from: u32, to: u32) -> Self {
+        let mut new = self.clone();
+        new.0.projs.push(ProjectionElem::Subslice { from, to });
+        new
+    }
+
+    pub(crate) fn deref(&self) -> Self {
+        let mut new = self.clone();
+        new.0.projs.push(ProjectionElem::Deref);
+        new
+    }
+
+    pub(crate) fn leaf(&self, field: Field) -> Self {
+        let mut new = self.clone();
+        new.0.projs.push(ProjectionElem::Field(field, ()));
+        new
+    }
+
+    pub(crate) fn variant(&self,
+                          adt_def: &'tcx AdtDef,
+                          variant_index: usize,
+                          field: Field) -> Self {
+        let mut new = self.clone();
+        new.0.projs.push(ProjectionElem::Downcast(adt_def, variant_index));
+        new.0.projs.push(ProjectionElem::Field(field, ()));
+        new
+    }
+
+    pub(crate) fn from_canonical_ty(c_ty: ty::CanonicalTy<'tcx>) -> Self {
+        Self::from_user_type(UserTypeAnnotation::Ty(c_ty))
+    }
+
+    pub(crate) fn from_user_type(u_ty: UserTypeAnnotation<'tcx>) -> Self {
+        Self::from_user_type_proj(UserTypeProjection { base: u_ty, projs: vec![], })
+    }
+
+    pub(crate) fn from_user_type_proj(u_ty: UserTypeProjection<'tcx>) -> Self {
+        PatternTypeProjection(u_ty)
+    }
+
+    pub(crate) fn user_ty(self) -> UserTypeProjection<'tcx> { self.0 }
+}
+
 #[derive(Clone, Debug)]
 pub enum PatternKind<'tcx> {
     Wild,
 
     AscribeUserType {
-        user_ty: CanonicalTy<'tcx>,
+        user_ty: PatternTypeProjection<'tcx>,
         subpattern: Pattern<'tcx>,
+        user_ty_span: Span,
     },
 
     /// x, ref x, x @ P, etc
@@ -529,8 +644,9 @@ impl<'a, 'tcx> PatternContext<'a, 'tcx> {
                                        field: Field::new(i),
                                        pattern: self.lower_pattern(field),
                                    })
-                                   .collect();
-                self.lower_variant_or_leaf(def, pat.span, ty, subpatterns)
+                    .collect();
+
+                self.lower_variant_or_leaf(def, pat.hir_id, pat.span, ty, subpatterns)
             }
 
             PatKind::Struct(ref qpath, ref fields, _) => {
@@ -546,7 +662,7 @@ impl<'a, 'tcx> PatternContext<'a, 'tcx> {
                           })
                           .collect();
 
-                self.lower_variant_or_leaf(def, pat.span, ty, subpatterns)
+                self.lower_variant_or_leaf(def, pat.hir_id, pat.span, ty, subpatterns)
             }
         };
 
@@ -637,12 +753,12 @@ impl<'a, 'tcx> PatternContext<'a, 'tcx> {
     fn lower_variant_or_leaf(
         &mut self,
         def: Def,
+        hir_id: hir::HirId,
         span: Span,
         ty: Ty<'tcx>,
-        subpatterns: Vec<FieldPattern<'tcx>>)
-        -> PatternKind<'tcx>
-    {
-        match def {
+        subpatterns: Vec<FieldPattern<'tcx>>,
+    ) -> PatternKind<'tcx> {
+        let mut kind = match def {
             Def::Variant(variant_id) | Def::VariantCtor(variant_id, ..) => {
                 let enum_id = self.tcx.parent_def_id(variant_id).unwrap();
                 let adt_def = self.tcx.adt_def(enum_id);
@@ -675,7 +791,26 @@ impl<'a, 'tcx> PatternContext<'a, 'tcx> {
                 self.errors.push(PatternError::NonConstPath(span));
                 PatternKind::Wild
             }
+        };
+
+        if let Some(user_ty) = self.user_substs_applied_to_ty_of_hir_id(hir_id) {
+            let subpattern = Pattern {
+                span,
+                ty,
+                kind: Box::new(kind),
+            };
+
+            debug!("pattern user_ty = {:?} for pattern at {:?}", user_ty, span);
+
+            let pat_ty = PatternTypeProjection::from_user_type(user_ty);
+            kind = PatternKind::AscribeUserType {
+                subpattern,
+                user_ty: pat_ty,
+                user_ty_span: span,
+            };
         }
+
+        kind
     }
 
     /// Takes a HIR Path. If the path is a constant, evaluates it and feeds
@@ -729,7 +864,7 @@ impl<'a, 'tcx> PatternContext<'a, 'tcx> {
                     },
                 }
             }
-            _ => self.lower_variant_or_leaf(def, span, ty, vec![]),
+            _ => self.lower_variant_or_leaf(def, id, span, ty, vec![]),
         };
 
         Pattern {
@@ -894,6 +1029,17 @@ impl<'a, 'tcx> PatternContext<'a, 'tcx> {
     }
 }
 
+impl UserAnnotatedTyHelpers<'tcx, 'tcx> for PatternContext<'_, 'tcx> {
+    fn tcx(&self) -> TyCtxt<'_, 'tcx, 'tcx> {
+        self.tcx
+    }
+
+    fn tables(&self) -> &ty::TypeckTables<'tcx> {
+        self.tables
+    }
+}
+
+
 pub trait PatternFoldable<'tcx> : Sized {
     fn fold_with<F: PatternFolder<'tcx>>(&self, folder: &mut F) -> Self {
         self.super_fold_with(folder)
@@ -947,7 +1093,8 @@ macro_rules! CloneImpls {
 CloneImpls!{ <'tcx>
     Span, Field, Mutability, ast::Name, ast::NodeId, usize, &'tcx ty::Const<'tcx>,
     Region<'tcx>, Ty<'tcx>, BindingMode<'tcx>, &'tcx AdtDef,
-    &'tcx Substs<'tcx>, &'tcx Kind<'tcx>, CanonicalTy<'tcx>
+    &'tcx Substs<'tcx>, &'tcx Kind<'tcx>, UserTypeAnnotation<'tcx>,
+    UserTypeProjection<'tcx>, PatternTypeProjection<'tcx>
 }
 
 impl<'tcx> PatternFoldable<'tcx> for FieldPattern<'tcx> {
@@ -983,10 +1130,12 @@ impl<'tcx> PatternFoldable<'tcx> for PatternKind<'tcx> {
             PatternKind::Wild => PatternKind::Wild,
             PatternKind::AscribeUserType {
                 ref subpattern,
-                user_ty,
+                ref user_ty,
+                user_ty_span,
             } => PatternKind::AscribeUserType {
                 subpattern: subpattern.fold_with(folder),
                 user_ty: user_ty.fold_with(folder),
+                user_ty_span,
             },
             PatternKind::Binding {
                 mutability,
@@ -1124,13 +1273,6 @@ pub fn compare_const_vals<'a, 'tcx>(
                         len_b,
                     ),
                 ) if ptr_a.offset.bytes() == 0 && ptr_b.offset.bytes() == 0 => {
-                    let len_a = len_a.not_undef().ok();
-                    let len_b = len_b.not_undef().ok();
-                    if len_a.is_none() || len_b.is_none() {
-                        tcx.sess.struct_err("str slice len is undef").delay_as_bug();
-                    }
-                    let len_a = len_a?;
-                    let len_b = len_b?;
                     if let Ok(len_a) = len_a.to_bits(tcx.data_layout.pointer_size) {
                         if let Ok(len_b) = len_b.to_bits(tcx.data_layout.pointer_size) {
                             if len_a == len_b {