]> git.lizzy.rs Git - rust.git/blobdiff - src/librustc_mir/hair/pattern/mod.rs
Auto merge of #57714 - matthewjasper:wellformed-unreachable, r=pnkfelix
[rust.git] / src / librustc_mir / hair / pattern / mod.rs
index f52aeded19ae797bb6117786b2167543b846b8ef..06a50f35be1cf428280e52f5841dbf208a9d8646 100644 (file)
 use hair::constant::*;
 
 use rustc::mir::{fmt_const_val, Field, BorrowKind, Mutability};
-use rustc::mir::{ProjectionElem, UserTypeProjection};
+use rustc::mir::{UserTypeProjection};
 use rustc::mir::interpret::{Scalar, GlobalId, ConstValue, sign_extend};
-use rustc::ty::{self, Region, TyCtxt, AdtDef, Ty, Lift};
-use rustc::ty::{CanonicalUserTypeAnnotation, CanonicalUserTypeAnnotations, UserTypeAnnotation};
+use rustc::ty::{self, Region, TyCtxt, AdtDef, Ty, Lift, UserType};
+use rustc::ty::{CanonicalUserType, CanonicalUserTypeAnnotation, CanonicalUserTypeAnnotations};
 use rustc::ty::subst::{Substs, Kind};
 use rustc::ty::layout::VariantIdx;
 use rustc::hir::{self, PatKind, RangeEnd};
@@ -39,9 +39,9 @@ pub enum PatternError {
 }
 
 #[derive(Copy, Clone, Debug)]
-pub enum BindingMode<'tcx> {
+pub enum BindingMode {
     ByValue,
-    ByRef(Region<'tcx>, BorrowKind),
+    ByRef(BorrowKind),
 }
 
 #[derive(Clone, Debug)]
@@ -60,26 +60,29 @@ pub struct Pattern<'tcx> {
 
 #[derive(Clone, Debug)]
 pub struct PatternTypeProjection<'tcx> {
-    pub base: CanonicalUserTypeAnnotation<'tcx>,
-    pub projs: Vec<ProjectionElem<'tcx, (), ()>>,
+    pub user_ty: CanonicalUserType<'tcx>,
 }
 
 impl<'tcx> PatternTypeProjection<'tcx> {
-    pub(crate) fn from_user_type(user_annotation: CanonicalUserTypeAnnotation<'tcx>) -> Self {
+    pub(crate) fn from_user_type(user_annotation: CanonicalUserType<'tcx>) -> Self {
         Self {
-            base: user_annotation,
-            projs: Vec::new(),
+            user_ty: user_annotation,
         }
     }
 
     pub(crate) fn user_ty(
         self,
         annotations: &mut CanonicalUserTypeAnnotations<'tcx>,
+        inferred_ty: Ty<'tcx>,
         span: Span,
     ) -> UserTypeProjection<'tcx> {
         UserTypeProjection {
-            base: annotations.push((span, self.base)),
-            projs: self.projs
+            base: annotations.push(CanonicalUserTypeAnnotation {
+                span,
+                user_ty: self.user_ty,
+                inferred_ty,
+            }),
+            projs: Vec::new(),
         }
     }
 }
@@ -91,6 +94,25 @@ pub enum PatternKind<'tcx> {
     AscribeUserType {
         user_ty: PatternTypeProjection<'tcx>,
         subpattern: Pattern<'tcx>,
+        /// Variance to use when relating the type `user_ty` to the **type of the value being
+        /// matched**. Typically, this is `Variance::Covariant`, since the value being matched must
+        /// have a type that is some subtype of the ascribed type.
+        ///
+        /// Note that this variance does not apply for any bindings within subpatterns. The type
+        /// assigned to those bindings must be exactly equal to the `user_ty` given here.
+        ///
+        /// The only place where this field is not `Covariant` is when matching constants, where
+        /// we currently use `Contravariant` -- this is because the constant type just needs to
+        /// be "comparable" to the type of the input value. So, for example:
+        ///
+        /// ```text
+        /// match x { "foo" => .. }
+        /// ```
+        ///
+        /// requires that `&'static str <: T_x`, where `T_x` is the type of `x`. Really, we should
+        /// probably be checking for a `PartialEq` impl instead, but this preserves the behavior
+        /// of the old type-check for now. See #57280 for details.
+        variance: ty::Variance,
         user_ty_span: Span,
     },
 
@@ -98,7 +120,7 @@ pub enum PatternKind<'tcx> {
     Binding {
         mutability: Mutability,
         name: ast::Name,
-        mode: BindingMode<'tcx>,
+        mode: BindingMode,
         var: ast::NodeId,
         ty: Ty<'tcx>,
         subpattern: Option<Pattern<'tcx>>,
@@ -162,7 +184,7 @@ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
             PatternKind::Binding { mutability, name, mode, ref subpattern, .. } => {
                 let is_mut = match mode {
                     BindingMode::ByValue => mutability == Mutability::Mut,
-                    BindingMode::ByRef(_, bk) => {
+                    BindingMode::ByRef(bk) => {
                         write!(f, "ref ")?;
                         match bk { BorrowKind::Mut { .. } => true, _ => false }
                     }
@@ -493,12 +515,9 @@ fn lower_pattern_unadjusted(&mut self, pat: &'tcx hir::Pat) -> Pattern<'tcx> {
 
             PatKind::Binding(_, id, ident, ref sub) => {
                 let var_ty = self.tables.node_id_to_type(pat.hir_id);
-                let region = match var_ty.sty {
-                    ty::Ref(r, _, _) => Some(r),
-                    ty::Error => { // Avoid ICE
-                        return Pattern { span: pat.span, ty, kind: Box::new(PatternKind::Wild) };
-                    }
-                    _ => None,
+                if let ty::Error = var_ty.sty {
+                    // Avoid ICE
+                    return Pattern { span: pat.span, ty, kind: Box::new(PatternKind::Wild) };
                 };
                 let bm = *self.tables.pat_binding_modes().get(pat.hir_id)
                                                          .expect("missing binding mode");
@@ -509,10 +528,10 @@ fn lower_pattern_unadjusted(&mut self, pat: &'tcx hir::Pat) -> Pattern<'tcx> {
                         (Mutability::Not, BindingMode::ByValue),
                     ty::BindByReference(hir::MutMutable) =>
                         (Mutability::Not, BindingMode::ByRef(
-                            region.unwrap(), BorrowKind::Mut { allow_two_phase_borrow: false })),
+                            BorrowKind::Mut { allow_two_phase_borrow: false })),
                     ty::BindByReference(hir::MutImmutable) =>
                         (Mutability::Not, BindingMode::ByRef(
-                            region.unwrap(), BorrowKind::Shared)),
+                            BorrowKind::Shared)),
                 };
 
                 // A ref x pattern is the same node used for x, and as such it has
@@ -714,6 +733,7 @@ fn lower_variant_or_leaf(
                 },
                 user_ty: PatternTypeProjection::from_user_type(user_ty),
                 user_ty_span: span,
+                variance: ty::Variance::Covariant,
             };
         }
 
@@ -763,6 +783,9 @@ fn lower_path(&mut self,
                                         kind: Box::new(
                                             PatternKind::AscribeUserType {
                                                 subpattern: pattern,
+                                                /// Note that use `Contravariant` here. See the
+                                                /// `variance` field documentation for details.
+                                                variance: ty::Variance::Contravariant,
                                                 user_ty,
                                                 user_ty_span: span,
                                             }
@@ -865,7 +888,7 @@ fn const_to_pat(
         let adt_subpattern = |i, variant_opt| {
             let field = Field::new(i);
             let val = const_field(
-                self.tcx, self.param_env, instance,
+                self.tcx, self.param_env,
                 variant_opt, field, cv,
             ).expect("field access failed");
             self.const_to_pat(instance, val, id, span)
@@ -908,7 +931,7 @@ fn const_to_pat(
             },
             ty::Adt(adt_def, substs) if adt_def.is_enum() => {
                 let variant_index = const_variant_index(
-                    self.tcx, self.param_env, instance, cv
+                    self.tcx, self.param_env, cv
                 ).expect("const_variant_index failed");
                 let subpatterns = adt_subpatterns(
                     adt_def.variants[variant_index].fields.len(),
@@ -1019,8 +1042,8 @@ fn super_fold_with<F: PatternFolder<$lt_tcx>>(&self, _: &mut F) -> Self {
 
 CloneImpls!{ <'tcx>
     Span, Field, Mutability, ast::Name, ast::NodeId, usize, ty::Const<'tcx>,
-    Region<'tcx>, Ty<'tcx>, BindingMode<'tcx>, &'tcx AdtDef,
-    &'tcx Substs<'tcx>, &'tcx Kind<'tcx>, UserTypeAnnotation<'tcx>,
+    Region<'tcx>, Ty<'tcx>, BindingMode, &'tcx AdtDef,
+    &'tcx Substs<'tcx>, &'tcx Kind<'tcx>, UserType<'tcx>,
     UserTypeProjection<'tcx>, PatternTypeProjection<'tcx>
 }
 
@@ -1057,11 +1080,13 @@ fn super_fold_with<F: PatternFolder<'tcx>>(&self, folder: &mut F) -> Self {
             PatternKind::Wild => PatternKind::Wild,
             PatternKind::AscribeUserType {
                 ref subpattern,
+                variance,
                 ref user_ty,
                 user_ty_span,
             } => PatternKind::AscribeUserType {
                 subpattern: subpattern.fold_with(folder),
                 user_ty: user_ty.fold_with(folder),
+                variance,
                 user_ty_span,
             },
             PatternKind::Binding {