about summary refs log tree commit diff
diff options
context:
space:
mode:
authorMatthew Jasper <mjjasper1@gmail.com>2019-01-12 14:55:23 +0000
committerMatthew Jasper <mjjasper1@gmail.com>2019-01-19 16:30:45 +0000
commit65fe2516346f10dc8d670e9fdfbd4e4f99a5b34b (patch)
tree58eca1afd783b7c256d0918893e3fcb1309c3dcb
parented871cb368f6b72dde644b0c21e0f9e62dba1810 (diff)
downloadrust-65fe2516346f10dc8d670e9fdfbd4e4f99a5b34b.tar.gz
rust-65fe2516346f10dc8d670e9fdfbd4e4f99a5b34b.zip
Handle lifetime annotations in unreachable code
We  equate the type in the annotation with the inferred type first so
that we have a fully inferred type to perform the well-formedness check
on.
-rw-r--r--src/librustc/ich/impls_ty.rs2
-rw-r--r--src/librustc/mir/tcx.rs13
-rw-r--r--src/librustc/mir/visit.rs4
-rw-r--r--src/librustc/traits/query/type_op/ascribe_user_type.rs15
-rw-r--r--src/librustc/ty/context.rs5
-rw-r--r--src/librustc_mir/borrow_check/nll/constraint_generation.rs11
-rw-r--r--src/librustc_mir/borrow_check/nll/renumber.rs17
-rw-r--r--src/librustc_mir/borrow_check/nll/type_check/mod.rs118
-rw-r--r--src/librustc_mir/build/expr/as_constant.rs5
-rw-r--r--src/librustc_mir/build/expr/as_place.rs12
-rw-r--r--src/librustc_mir/build/expr/as_rvalue.rs2
-rw-r--r--src/librustc_mir/build/matches/mod.rs13
-rw-r--r--src/librustc_mir/hair/pattern/mod.rs17
-rw-r--r--src/librustc_traits/type_op.rs43
-rw-r--r--src/test/ui/issue-54943.rs6
-rw-r--r--src/test/ui/issue-54943.stderr11
-rw-r--r--src/test/ui/nll/ty-outlives/projection-where-clause-env-wrong-bound.stderr2
-rw-r--r--src/test/ui/nll/ty-outlives/projection-where-clause-none.stderr2
-rw-r--r--src/test/ui/nll/ty-outlives/wf-unreachable.rs54
-rw-r--r--src/test/ui/nll/ty-outlives/wf-unreachable.stderr73
-rw-r--r--src/test/ui/nll/user-annotations/downcast-infer.rs11
-rw-r--r--src/test/ui/regions/regions-assoc-type-in-supertrait-outlives-container.ast.stderr20
-rw-r--r--src/test/ui/regions/regions-assoc-type-in-supertrait-outlives-container.mir.stderr13
-rw-r--r--src/test/ui/regions/regions-assoc-type-in-supertrait-outlives-container.rs6
-rw-r--r--src/test/ui/regions/regions-free-region-ordering-caller.ast.stderr32
-rw-r--r--src/test/ui/regions/regions-free-region-ordering-caller.mir.stderr33
-rw-r--r--src/test/ui/regions/regions-free-region-ordering-caller.rs12
-rw-r--r--src/test/ui/regions/regions-free-region-ordering-caller1.nll.stderr19
-rw-r--r--src/test/ui/regions/regions-outlives-projection-container-hrtb.ast.stderr37
-rw-r--r--src/test/ui/regions/regions-outlives-projection-container-hrtb.mir.stderr24
-rw-r--r--src/test/ui/regions/regions-outlives-projection-container-hrtb.rs9
-rw-r--r--src/test/ui/regions/regions-outlives-projection-container-wc.ast.stderr20
-rw-r--r--src/test/ui/regions/regions-outlives-projection-container-wc.mir.stderr13
-rw-r--r--src/test/ui/regions/regions-outlives-projection-container-wc.rs6
34 files changed, 514 insertions, 166 deletions
diff --git a/src/librustc/ich/impls_ty.rs b/src/librustc/ich/impls_ty.rs
index 9b613e3e1ab..79c2b89522d 100644
--- a/src/librustc/ich/impls_ty.rs
+++ b/src/librustc/ich/impls_ty.rs
@@ -1242,7 +1242,7 @@ impl_stable_hash_for!(
 
 impl_stable_hash_for!(
     struct ty::CanonicalUserTypeAnnotation<'tcx> {
-        user_ty, span
+        user_ty, span, inferred_ty
     }
 );
 
diff --git a/src/librustc/mir/tcx.rs b/src/librustc/mir/tcx.rs
index c5b884525da..649370059f0 100644
--- a/src/librustc/mir/tcx.rs
+++ b/src/librustc/mir/tcx.rs
@@ -75,8 +75,7 @@ impl<'a, 'gcx, 'tcx> PlaceTy<'tcx> {
                          elem: &PlaceElem<'tcx>)
                          -> PlaceTy<'tcx>
     {
-        self.projection_ty_core(tcx, elem, |_, _, ty| -> Result<Ty<'tcx>, ()> { Ok(ty) })
-            .unwrap()
+        self.projection_ty_core(tcx, elem, |_, _, ty| ty)
     }
 
     /// `place_ty.projection_ty_core(tcx, elem, |...| { ... })`
@@ -84,12 +83,12 @@ impl<'a, 'gcx, 'tcx> PlaceTy<'tcx> {
     /// `Ty` or downcast variant corresponding to that projection.
     /// The `handle_field` callback must map a `Field` to its `Ty`,
     /// (which should be trivial when `T` = `Ty`).
-    pub fn projection_ty_core<V, T, E>(
+    pub fn projection_ty_core<V, T>(
         self,
         tcx: TyCtxt<'a, 'gcx, 'tcx>,
         elem: &ProjectionElem<'tcx, V, T>,
-        mut handle_field: impl FnMut(&Self, &Field, &T) -> Result<Ty<'tcx>, E>)
-        -> Result<PlaceTy<'tcx>, E>
+        mut handle_field: impl FnMut(&Self, &Field, &T) -> Ty<'tcx>)
+        -> PlaceTy<'tcx>
     where
         V: ::std::fmt::Debug, T: ::std::fmt::Debug
     {
@@ -140,10 +139,10 @@ impl<'a, 'gcx, 'tcx> PlaceTy<'tcx> {
                     }
                 },
             ProjectionElem::Field(ref f, ref fty) =>
-                PlaceTy::Ty { ty: handle_field(&self, f, fty)? },
+                PlaceTy::Ty { ty: handle_field(&self, f, fty) },
         };
         debug!("projection_ty self: {:?} elem: {:?} yields: {:?}", self, elem, answer);
-        Ok(answer)
+        answer
     }
 }
 
diff --git a/src/librustc/mir/visit.rs b/src/librustc/mir/visit.rs
index 49a1e5046aa..598303f2932 100644
--- a/src/librustc/mir/visit.rs
+++ b/src/librustc/mir/visit.rs
@@ -887,6 +887,7 @@ macro_rules! make_mir_visitor {
                 ty: & $($mutability)* CanonicalUserTypeAnnotation<'tcx>,
             ) {
                 self.visit_span(& $($mutability)* ty.span);
+                self.visit_ty(& $($mutability)* ty.inferred_ty, TyContext::UserTy(ty.span));
             }
 
             fn super_ty(&mut self, _ty: & $($mutability)* Ty<'tcx>) {
@@ -967,6 +968,9 @@ pub enum TyContext {
         source_info: SourceInfo,
     },
 
+    /// The inferred type of a user type annotation.
+    UserTy(Span),
+
     /// The return type of the function.
     ReturnTy(SourceInfo),
 
diff --git a/src/librustc/traits/query/type_op/ascribe_user_type.rs b/src/librustc/traits/query/type_op/ascribe_user_type.rs
index b2f30564de9..15f627b3ee8 100644
--- a/src/librustc/traits/query/type_op/ascribe_user_type.rs
+++ b/src/librustc/traits/query/type_op/ascribe_user_type.rs
@@ -1,28 +1,23 @@
 use infer::canonical::{Canonical, Canonicalized, CanonicalizedQueryResponse, QueryResponse};
 use traits::query::Fallible;
 use hir::def_id::DefId;
-use mir::ProjectionKind;
-use ty::{self, ParamEnvAnd, Ty, TyCtxt};
+use ty::{ParamEnvAnd, Ty, TyCtxt};
 use ty::subst::UserSubsts;
 
 #[derive(Copy, Clone, Debug, Hash, PartialEq, Eq)]
 pub struct AscribeUserType<'tcx> {
     pub mir_ty: Ty<'tcx>,
-    pub variance: ty::Variance,
     pub def_id: DefId,
     pub user_substs: UserSubsts<'tcx>,
-    pub projs: &'tcx ty::List<ProjectionKind<'tcx>>,
 }
 
 impl<'tcx> AscribeUserType<'tcx> {
     pub fn new(
         mir_ty: Ty<'tcx>,
-        variance: ty::Variance,
         def_id: DefId,
         user_substs: UserSubsts<'tcx>,
-        projs: &'tcx ty::List<ProjectionKind<'tcx>>,
     ) -> Self {
-        Self { mir_ty, variance, def_id, user_substs, projs }
+        Self { mir_ty,  def_id, user_substs }
     }
 }
 
@@ -52,19 +47,19 @@ impl<'gcx: 'tcx, 'tcx> super::QueryTypeOp<'gcx, 'tcx> for AscribeUserType<'tcx>
 
 BraceStructTypeFoldableImpl! {
     impl<'tcx> TypeFoldable<'tcx> for AscribeUserType<'tcx> {
-        mir_ty, variance, def_id, user_substs, projs
+        mir_ty, def_id, user_substs
     }
 }
 
 BraceStructLiftImpl! {
     impl<'a, 'tcx> Lift<'tcx> for AscribeUserType<'a> {
         type Lifted = AscribeUserType<'tcx>;
-        mir_ty, variance, def_id, user_substs, projs
+        mir_ty, def_id, user_substs
     }
 }
 
 impl_stable_hash_for! {
     struct AscribeUserType<'tcx> {
-        mir_ty, variance, def_id, user_substs, projs
+        mir_ty, def_id, user_substs
     }
 }
diff --git a/src/librustc/ty/context.rs b/src/librustc/ty/context.rs
index 59835afc841..4c8f8141116 100644
--- a/src/librustc/ty/context.rs
+++ b/src/librustc/ty/context.rs
@@ -813,18 +813,19 @@ pub type CanonicalUserTypeAnnotations<'tcx> =
 pub struct CanonicalUserTypeAnnotation<'tcx> {
     pub user_ty: CanonicalUserType<'tcx>,
     pub span: Span,
+    pub inferred_ty: Ty<'tcx>,
 }
 
 BraceStructTypeFoldableImpl! {
     impl<'tcx> TypeFoldable<'tcx> for CanonicalUserTypeAnnotation<'tcx> {
-        user_ty, span
+        user_ty, span, inferred_ty
     }
 }
 
 BraceStructLiftImpl! {
     impl<'a, 'tcx> Lift<'tcx> for CanonicalUserTypeAnnotation<'a> {
         type Lifted = CanonicalUserTypeAnnotation<'tcx>;
-        user_ty, span
+        user_ty, span, inferred_ty
     }
 }
 
diff --git a/src/librustc_mir/borrow_check/nll/constraint_generation.rs b/src/librustc_mir/borrow_check/nll/constraint_generation.rs
index e1c2b611d01..588f46cb77f 100644
--- a/src/librustc_mir/borrow_check/nll/constraint_generation.rs
+++ b/src/librustc_mir/borrow_check/nll/constraint_generation.rs
@@ -7,7 +7,7 @@ use rustc::infer::InferCtxt;
 use rustc::mir::visit::TyContext;
 use rustc::mir::visit::Visitor;
 use rustc::mir::{BasicBlock, BasicBlockData, Location, Mir, Place, Rvalue};
-use rustc::mir::{Statement, Terminator};
+use rustc::mir::{SourceInfo, Statement, Terminator};
 use rustc::mir::UserTypeProjection;
 use rustc::ty::fold::TypeFoldable;
 use rustc::ty::subst::Substs;
@@ -66,11 +66,12 @@ impl<'cg, 'cx, 'gcx, 'tcx> Visitor<'tcx> for ConstraintGeneration<'cg, 'cx, 'gcx
     /// call. Make them live at the location where they appear.
     fn visit_ty(&mut self, ty: &ty::Ty<'tcx>, ty_context: TyContext) {
         match ty_context {
-            TyContext::ReturnTy(source_info)
-            | TyContext::YieldTy(source_info)
-            | TyContext::LocalDecl { source_info, .. } => {
+            TyContext::ReturnTy(SourceInfo { span, .. })
+            | TyContext::YieldTy(SourceInfo { span, .. })
+            | TyContext::UserTy(span)
+            | TyContext::LocalDecl { source_info: SourceInfo { span, .. }, .. } => {
                 span_bug!(
-                    source_info.span,
+                    span,
                     "should not be visiting outside of the CFG: {:?}",
                     ty_context
                 );
diff --git a/src/librustc_mir/borrow_check/nll/renumber.rs b/src/librustc_mir/borrow_check/nll/renumber.rs
index ade06bce469..e6a974fd8cc 100644
--- a/src/librustc_mir/borrow_check/nll/renumber.rs
+++ b/src/librustc_mir/borrow_check/nll/renumber.rs
@@ -1,8 +1,5 @@
 use rustc::ty::subst::Substs;
-use rustc::ty::{
-    self, ClosureSubsts, GeneratorSubsts, Ty, TypeFoldable,
-    UserTypeAnnotationIndex, CanonicalUserTypeAnnotation
-};
+use rustc::ty::{self, ClosureSubsts, GeneratorSubsts, Ty, TypeFoldable};
 use rustc::mir::{Location, Mir};
 use rustc::mir::visit::{MutVisitor, TyContext};
 use rustc::infer::{InferCtxt, NLLRegionVariableOrigin};
@@ -58,18 +55,6 @@ impl<'a, 'gcx, 'tcx> MutVisitor<'tcx> for NLLVisitor<'a, 'gcx, 'tcx> {
         debug!("visit_ty: ty={:?}", ty);
     }
 
-    fn visit_user_type_annotation(
-        &mut self,
-        _index: UserTypeAnnotationIndex,
-        _ty: &mut CanonicalUserTypeAnnotation,
-    ) {
-        // User type annotations represent the types that the user
-        // wrote in the progarm. We don't want to erase the regions
-        // from these types: rather, we want to add them as
-        // constraints at type-check time.
-        debug!("visit_user_type_annotation: skipping renumber");
-    }
-
     fn visit_substs(&mut self, substs: &mut &'tcx Substs<'tcx>, location: Location) {
         debug!("visit_substs(substs={:?}, location={:?})", substs, location);
 
diff --git a/src/librustc_mir/borrow_check/nll/type_check/mod.rs b/src/librustc_mir/borrow_check/nll/type_check/mod.rs
index 82ffafa4ce9..9ed1d49d05b 100644
--- a/src/librustc_mir/borrow_check/nll/type_check/mod.rs
+++ b/src/librustc_mir/borrow_check/nll/type_check/mod.rs
@@ -748,7 +748,7 @@ struct TypeChecker<'a, 'gcx: 'tcx, 'tcx: 'a> {
     /// annotations. Part of the reason for this setup is that it allows us to enforce basic
     /// WF criteria on the types even if the code that referenced them is dead
     /// code (see #54943).
-    instantiated_type_annotations: FxHashMap<UserTypeAnnotationIndex, UserType<'tcx>>,
+    instantiated_type_annotations: FxHashMap<UserTypeAnnotationIndex, Ty<'tcx>>,
 }
 
 struct BorrowCheckContext<'a, 'tcx: 'a> {
@@ -920,17 +920,58 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> {
              self.mir.user_type_annotations
         );
         for annotation_index in self.mir.user_type_annotations.indices() {
-            let CanonicalUserTypeAnnotation { span, ref user_ty } =
+            let CanonicalUserTypeAnnotation { span, ref user_ty, inferred_ty } =
                 self.mir.user_type_annotations[annotation_index];
-            let (mut annotation, _) = self.infcx.instantiate_canonical_with_fresh_inference_vars(
+            let (annotation, _) = self.infcx.instantiate_canonical_with_fresh_inference_vars(
                 span, user_ty
             );
             match annotation {
-                UserType::Ty(ref mut ty) =>
-                    *ty = self.normalize(ty, Locations::All(span)),
-                _ => {},
+                UserType::Ty(mut ty) => {
+                    ty = self.normalize(ty, Locations::All(span));
+
+                    if let Err(terr) = self.eq_types(
+                        ty,
+                        inferred_ty,
+                        Locations::All(span),
+                        ConstraintCategory::BoringNoLocation,
+                    ) {
+                        span_mirbug!(
+                            self,
+                            self.mir.user_type_annotations[annotation_index],
+                            "bad user type ({:?} = {:?}): {:?}",
+                            ty,
+                            inferred_ty,
+                            terr
+                        );
+                    }
+
+                    self.prove_predicate(
+                        ty::Predicate::WellFormed(inferred_ty),
+                        Locations::All(span),
+                        ConstraintCategory::TypeAnnotation,
+                    );
+                },
+                UserType::TypeOf(def_id, user_substs) => {
+                    if let Err(terr) = self.fully_perform_op(
+                        Locations::All(span),
+                        ConstraintCategory::BoringNoLocation,
+                        self.param_env.and(type_op::ascribe_user_type::AscribeUserType::new(
+                            inferred_ty, def_id, user_substs,
+                        )),
+                    ) {
+                        span_mirbug!(
+                            self,
+                            self.mir.user_type_annotations[annotation_index],
+                            "bad user type AscribeUserType({:?}, {:?} {:?}): {:?}",
+                            inferred_ty,
+                            def_id,
+                            user_substs,
+                            terr
+                        );
+                    }
+                },
             }
-            self.instantiated_type_annotations.insert(annotation_index, annotation);
+            self.instantiated_type_annotations.insert(annotation_index, inferred_ty);
         }
         debug!(
             "instantiate_user_type_annotations: instantiated_type_annotations={:?}",
@@ -1067,58 +1108,23 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> {
             a, v, user_ty, locations,
         );
 
-        let type_annotation = self.instantiated_type_annotations[&user_ty.base];
-        match type_annotation {
-            UserType::Ty(ty) => {
-                // The `TypeRelating` code assumes that "unresolved inference
-                // variables" appear in the "a" side, so flip `Contravariant`
-                // ambient variance to get the right relationship.
-                let v1 = ty::Contravariant.xform(v);
-                let tcx = self.infcx.tcx;
+        let annotated_type = self.instantiated_type_annotations[&user_ty.base];
+        let mut curr_projected_ty = PlaceTy::from_ty(annotated_type);
 
-                // We need to follow any provided projetions into the type.
-                //
-                // if we hit a ty var as we descend, then just skip the
-                // attempt to relate the mir local with any type.
-                #[derive(Debug)] struct HitTyVar;
-                let mut curr_projected_ty: Result<PlaceTy, HitTyVar>;
-
-                curr_projected_ty = Ok(PlaceTy::from_ty(ty));
-                for proj in &user_ty.projs {
-                    let projected_ty = if let Ok(projected_ty) = curr_projected_ty {
-                        projected_ty
-                    } else {
-                        break;
-                    };
-                    curr_projected_ty = projected_ty.projection_ty_core(
-                        tcx, proj, |this, field, &()| {
-                            if this.to_ty(tcx).is_ty_var() {
-                                Err(HitTyVar)
-                            } else {
-                                let ty = this.field_ty(tcx, field);
-                                Ok(self.normalize(ty, locations))
-                            }
-                        });
-                }
-                debug!("user_ty base: {:?} freshened: {:?} projs: {:?} yields: {:?}",
-                       user_ty.base, ty, user_ty.projs, curr_projected_ty);
+        let tcx = self.infcx.tcx;
 
-                if let Ok(projected_ty) = curr_projected_ty {
-                    let ty = projected_ty.to_ty(tcx);
-                    self.relate_types(ty, v1, a, locations, category)?;
-                }
-            }
-            UserType::TypeOf(def_id, user_substs) => {
-                let projs = self.infcx.tcx.intern_projs(&user_ty.projs);
-                self.fully_perform_op(
-                    locations,
-                    category,
-                    self.param_env.and(type_op::ascribe_user_type::AscribeUserType::new(
-                        a, v, def_id, user_substs, projs,
-                    )),
-                )?;
-            }
+        for proj in &user_ty.projs {
+            let projected_ty = curr_projected_ty.projection_ty_core(tcx, proj, |this, field, &()| {
+                let ty = this.field_ty(tcx, field);
+                self.normalize(ty, locations)
+            });
+            curr_projected_ty = projected_ty;
         }
+        debug!("user_ty base: {:?} freshened: {:?} projs: {:?} yields: {:?}",
+                user_ty.base, annotated_type, user_ty.projs, curr_projected_ty);
+
+        let ty = curr_projected_ty.to_ty(tcx);
+        self.relate_types(a, v, ty, locations, category)?;
 
         Ok(())
     }
diff --git a/src/librustc_mir/build/expr/as_constant.rs b/src/librustc_mir/build/expr/as_constant.rs
index 4f812f53745..31e0c0daa3f 100644
--- a/src/librustc_mir/build/expr/as_constant.rs
+++ b/src/librustc_mir/build/expr/as_constant.rs
@@ -31,10 +31,11 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
                 value,
             } => this.as_constant(value),
             ExprKind::Literal { literal, user_ty } => {
-                let user_ty = user_ty.map(|ty| {
+                let user_ty = user_ty.map(|user_ty| {
                     this.canonical_user_type_annotations.push(CanonicalUserTypeAnnotation {
                         span,
-                        user_ty: ty,
+                        user_ty,
+                        inferred_ty: ty,
                     })
                 });
                 Constant {
diff --git a/src/librustc_mir/build/expr/as_place.rs b/src/librustc_mir/build/expr/as_place.rs
index 5429ce2a2e3..6bd61ab53fd 100644
--- a/src/librustc_mir/build/expr/as_place.rs
+++ b/src/librustc_mir/build/expr/as_place.rs
@@ -134,7 +134,11 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
                 let place = unpack!(block = this.as_place(block, source));
                 if let Some(user_ty) = user_ty {
                     let annotation_index = this.canonical_user_type_annotations.push(
-                        CanonicalUserTypeAnnotation { span: source_info.span, user_ty }
+                        CanonicalUserTypeAnnotation {
+                            span: source_info.span,
+                            user_ty,
+                            inferred_ty: expr.ty,
+                        }
                     );
                     this.cfg.push(
                         block,
@@ -157,7 +161,11 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
                 );
                 if let Some(user_ty) = user_ty {
                     let annotation_index = this.canonical_user_type_annotations.push(
-                        CanonicalUserTypeAnnotation { span: source_info.span, user_ty }
+                        CanonicalUserTypeAnnotation {
+                            span: source_info.span,
+                            user_ty,
+                            inferred_ty: expr.ty,
+                        }
                     );
                     this.cfg.push(
                         block,
diff --git a/src/librustc_mir/build/expr/as_rvalue.rs b/src/librustc_mir/build/expr/as_rvalue.rs
index 501a10cfbb9..3de2f475786 100644
--- a/src/librustc_mir/build/expr/as_rvalue.rs
+++ b/src/librustc_mir/build/expr/as_rvalue.rs
@@ -331,10 +331,12 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
                         .collect()
                 };
 
+                let inferred_ty = expr.ty;
                 let user_ty = user_ty.map(|ty| {
                     this.canonical_user_type_annotations.push(CanonicalUserTypeAnnotation {
                         span: source_info.span,
                         user_ty: ty,
+                        inferred_ty,
                     })
                 });
                 let adt = box AggregateKind::Adt(
diff --git a/src/librustc_mir/build/matches/mod.rs b/src/librustc_mir/build/matches/mod.rs
index 61d1216fd3e..2f1e8c03f2f 100644
--- a/src/librustc_mir/build/matches/mod.rs
+++ b/src/librustc_mir/build/matches/mod.rs
@@ -303,7 +303,9 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
 
                 let ty_source_info = self.source_info(user_ty_span);
                 let user_ty = box pat_ascription_ty.user_ty(
-                    &mut self.canonical_user_type_annotations, ty_source_info.span
+                    &mut self.canonical_user_type_annotations,
+                    place.ty(&self.local_decls, self.hir.tcx()).to_ty(self.hir.tcx()),
+                    ty_source_info.span,
                 );
                 self.cfg.push(
                     block,
@@ -572,11 +574,12 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
                 // of `user_ty` on any bindings contained with subpattern.
                 let annotation = CanonicalUserTypeAnnotation {
                     span: user_ty_span,
-                    user_ty: user_ty.base,
+                    user_ty: user_ty.user_ty,
+                    inferred_ty: subpattern.ty,
                 };
                 let projection = UserTypeProjection {
                     base: self.canonical_user_type_annotations.push(annotation),
-                    projs: user_ty.projs.clone(),
+                    projs: Vec::new(),
                 };
                 let subpattern_user_ty = pattern_user_ty.push_projection(&projection, user_ty_span);
                 self.visit_bindings(subpattern, subpattern_user_ty, f)
@@ -1340,7 +1343,9 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
             );
 
             let user_ty = box ascription.user_ty.clone().user_ty(
-                &mut self.canonical_user_type_annotations, source_info.span
+                &mut self.canonical_user_type_annotations,
+                ascription.source.ty(&self.local_decls, self.hir.tcx()).to_ty(self.hir.tcx()),
+                source_info.span
             );
             self.cfg.push(
                 block,
diff --git a/src/librustc_mir/hair/pattern/mod.rs b/src/librustc_mir/hair/pattern/mod.rs
index 8a5e6a581b3..9dcccba1a06 100644
--- a/src/librustc_mir/hair/pattern/mod.rs
+++ b/src/librustc_mir/hair/pattern/mod.rs
@@ -12,7 +12,7 @@ use hair::util::UserAnnotatedTyHelpers;
 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, UserType};
 use rustc::ty::{CanonicalUserType, CanonicalUserTypeAnnotation, CanonicalUserTypeAnnotations};
@@ -60,26 +60,29 @@ pub struct Pattern<'tcx> {
 
 #[derive(Clone, Debug)]
 pub struct PatternTypeProjection<'tcx> {
-    pub base: CanonicalUserType<'tcx>,
-    pub projs: Vec<ProjectionElem<'tcx, (), ()>>,
+    pub user_ty: CanonicalUserType<'tcx>,
 }
 
 impl<'tcx> PatternTypeProjection<'tcx> {
     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(CanonicalUserTypeAnnotation{ span, user_ty: self.base }),
-            projs: self.projs
+            base: annotations.push(CanonicalUserTypeAnnotation {
+                span,
+                user_ty: self.user_ty,
+                inferred_ty,
+            }),
+            projs: Vec::new(),
         }
     }
 }
diff --git a/src/librustc_traits/type_op.rs b/src/librustc_traits/type_op.rs
index 52fcb5b80f4..526637e108d 100644
--- a/src/librustc_traits/type_op.rs
+++ b/src/librustc_traits/type_op.rs
@@ -2,8 +2,6 @@ use rustc::infer::at::ToTrace;
 use rustc::infer::canonical::{Canonical, QueryResponse};
 use rustc::infer::InferCtxt;
 use rustc::hir::def_id::DefId;
-use rustc::mir::ProjectionKind;
-use rustc::mir::tcx::PlaceTy;
 use rustc::traits::query::type_op::ascribe_user_type::AscribeUserType;
 use rustc::traits::query::type_op::eq::Eq;
 use rustc::traits::query::type_op::normalize::Normalize;
@@ -44,17 +42,16 @@ fn type_op_ascribe_user_type<'tcx>(
     tcx.infer_ctxt()
         .enter_canonical_trait_query(&canonicalized, |infcx, fulfill_cx, key| {
             let (
-                param_env, AscribeUserType { mir_ty, variance, def_id, user_substs, projs }
+                param_env, AscribeUserType { mir_ty, def_id, user_substs }
             ) = key.into_parts();
 
             debug!(
-                "type_op_ascribe_user_type: mir_ty={:?} variance={:?} def_id={:?} \
-                 user_substs={:?} projs={:?}",
-                mir_ty, variance, def_id, user_substs, projs
+                "type_op_ascribe_user_type: mir_ty={:?} def_id={:?} user_substs={:?}",
+                mir_ty, def_id, user_substs
             );
 
             let mut cx = AscribeUserTypeCx { infcx, param_env, fulfill_cx };
-            cx.relate_mir_and_user_ty(mir_ty, variance, def_id, user_substs, projs)?;
+            cx.relate_mir_and_user_ty(mir_ty, def_id, user_substs)?;
 
             Ok(())
         })
@@ -112,10 +109,8 @@ impl AscribeUserTypeCx<'me, 'gcx, 'tcx> {
     fn relate_mir_and_user_ty(
         &mut self,
         mir_ty: Ty<'tcx>,
-        variance: Variance,
         def_id: DefId,
         user_substs: UserSubsts<'tcx>,
-        projs: &[ProjectionKind<'tcx>],
     ) -> Result<(), NoSolution> {
         let UserSubsts {
             user_self_ty,
@@ -128,35 +123,7 @@ impl AscribeUserTypeCx<'me, 'gcx, 'tcx> {
         debug!("relate_type_and_user_type: ty of def-id is {:?}", ty);
         let ty = self.normalize(ty);
 
-        // We need to follow any provided projetions into the type.
-        //
-        // if we hit a ty var as we descend, then just skip the
-        // attempt to relate the mir local with any type.
-
-        struct HitTyVar;
-        let mut curr_projected_ty: Result<PlaceTy, HitTyVar>;
-        curr_projected_ty = Ok(PlaceTy::from_ty(ty));
-        for proj in projs {
-            let projected_ty = if let Ok(projected_ty) = curr_projected_ty {
-                projected_ty
-            } else {
-                break;
-            };
-            curr_projected_ty = projected_ty.projection_ty_core(
-                tcx, proj, |this, field, &()| {
-                    if this.to_ty(tcx).is_ty_var() {
-                        Err(HitTyVar)
-                    } else {
-                        let ty = this.field_ty(tcx, field);
-                        Ok(self.normalize(ty))
-                    }
-                });
-        }
-
-        if let Ok(projected_ty) = curr_projected_ty {
-            let ty = projected_ty.to_ty(tcx);
-            self.relate(mir_ty, variance, ty)?;
-        }
+        self.relate(mir_ty, Variance::Invariant, ty)?;
 
         // Prove the predicates coming along with `def_id`.
         //
diff --git a/src/test/ui/issue-54943.rs b/src/test/ui/issue-54943.rs
index c720f627975..ce4e0106743 100644
--- a/src/test/ui/issue-54943.rs
+++ b/src/test/ui/issue-54943.rs
@@ -1,7 +1,3 @@
-// compile-pass
-// FIXME(#54943) This test targets the scenario where proving the WF requirements of a user
-// type annotation requires checking dead code. This test should actually fail to compile.
-
 #![feature(nll)]
 #![allow(warnings)]
 
@@ -11,7 +7,7 @@ fn boo<'a>() {
     return;
 
     let x = foo::<&'a u32>();
-    //~^ ERROR the type `&'a u32` does not fulfill the required lifetime [E0477]
+    //~^ ERROR lifetime may not live long enough
 }
 
 fn main() {}
diff --git a/src/test/ui/issue-54943.stderr b/src/test/ui/issue-54943.stderr
new file mode 100644
index 00000000000..aa68177bcdb
--- /dev/null
+++ b/src/test/ui/issue-54943.stderr
@@ -0,0 +1,11 @@
+error: lifetime may not live long enough
+  --> $DIR/issue-54943.rs:9:13
+   |
+LL | fn boo<'a>() {
+   |        -- lifetime `'a` defined here
+...
+LL |     let x = foo::<&'a u32>();
+   |             ^^^^^^^^^^^^^^ requires that `'a` must outlive `'static`
+
+error: aborting due to previous error
+
diff --git a/src/test/ui/nll/ty-outlives/projection-where-clause-env-wrong-bound.stderr b/src/test/ui/nll/ty-outlives/projection-where-clause-env-wrong-bound.stderr
index acb978b5d5a..597b096dbe6 100644
--- a/src/test/ui/nll/ty-outlives/projection-where-clause-env-wrong-bound.stderr
+++ b/src/test/ui/nll/ty-outlives/projection-where-clause-env-wrong-bound.stderr
@@ -2,7 +2,7 @@ error[E0309]: the associated type `<T as MyTrait<'_>>::Output` may not live long
   --> $DIR/projection-where-clause-env-wrong-bound.rs:17:5
    |
 LL |     bar::<T::Output>() //~ ERROR may not live long enough
-   |     ^^^^^^^^^^^^^^^^^^
+   |     ^^^^^^^^^^^^^^^^
    |
    = help: consider adding an explicit lifetime bound `<T as MyTrait<'_>>::Output: 'a`...
 
diff --git a/src/test/ui/nll/ty-outlives/projection-where-clause-none.stderr b/src/test/ui/nll/ty-outlives/projection-where-clause-none.stderr
index 2d171a98789..3c2ac474778 100644
--- a/src/test/ui/nll/ty-outlives/projection-where-clause-none.stderr
+++ b/src/test/ui/nll/ty-outlives/projection-where-clause-none.stderr
@@ -2,7 +2,7 @@ error[E0309]: the parameter type `T` may not live long enough
   --> $DIR/projection-where-clause-none.rs:16:5
    |
 LL |     bar::<T::Output>() //~ ERROR the parameter type `T` may not live long enough
-   |     ^^^^^^^^^^^^^^^^^^
+   |     ^^^^^^^^^^^^^^^^
    |
    = help: consider adding an explicit lifetime bound `T: 'a`...
 
diff --git a/src/test/ui/nll/ty-outlives/wf-unreachable.rs b/src/test/ui/nll/ty-outlives/wf-unreachable.rs
new file mode 100644
index 00000000000..a2e3ab41614
--- /dev/null
+++ b/src/test/ui/nll/ty-outlives/wf-unreachable.rs
@@ -0,0 +1,54 @@
+// Test that we check that user type annotations are well-formed, even in dead
+// code.
+
+#![feature(nll)]
+
+fn uninit<'a>() {
+    return;
+    let x: &'static &'a ();                         //~ ERROR lifetime may not live long enough
+}
+
+fn var_type<'a>() {
+    return;
+    let x: &'static &'a () = &&();                  //~ ERROR lifetime may not live long enough
+}
+
+fn uninit_infer<'a>() {
+    let x: &'static &'a _;                          //~ ERROR lifetime may not live long enough
+    x = && ();
+}
+
+fn infer<'a>() {
+    return;
+    let x: &'static &'a _ = &&();                   //~ ERROR lifetime may not live long enough
+}
+
+fn uninit_no_var<'a>() {
+    return;
+    let _: &'static &'a ();                         //~ ERROR lifetime may not live long enough
+}
+
+fn no_var<'a>() {
+    return;
+    let _: &'static &'a () = &&();                  //~ ERROR lifetime may not live long enough
+}
+
+fn infer_no_var<'a>() {
+    return;
+    let _: &'static &'a _ = &&();                   //~ ERROR lifetime may not live long enough
+}
+
+trait X<'a, 'b> {}
+
+struct C<'a, 'b, T: X<'a, 'b>>(T, &'a (), &'b ());
+
+impl X<'_, '_> for i32 {}
+impl<'a> X<'a, 'a> for () {}
+
+// This type annotation is not well-formed because we substitute `()` for `_`.
+fn required_substs<'a>() {
+    return;
+    let _: C<'static, 'a, _> = C((), &(), &());     //~ ERROR lifetime may not live long enough
+}
+
+fn main() {}
diff --git a/src/test/ui/nll/ty-outlives/wf-unreachable.stderr b/src/test/ui/nll/ty-outlives/wf-unreachable.stderr
new file mode 100644
index 00000000000..14642a1e615
--- /dev/null
+++ b/src/test/ui/nll/ty-outlives/wf-unreachable.stderr
@@ -0,0 +1,73 @@
+error: lifetime may not live long enough
+  --> $DIR/wf-unreachable.rs:8:12
+   |
+LL | fn uninit<'a>() {
+   |           -- lifetime `'a` defined here
+LL |     return;
+LL |     let x: &'static &'a ();                         //~ ERROR lifetime may not live long enough
+   |            ^^^^^^^^^^^^^^^ type annotation requires that `'a` must outlive `'static`
+
+error: lifetime may not live long enough
+  --> $DIR/wf-unreachable.rs:13:12
+   |
+LL | fn var_type<'a>() {
+   |             -- lifetime `'a` defined here
+LL |     return;
+LL |     let x: &'static &'a () = &&();                  //~ ERROR lifetime may not live long enough
+   |            ^^^^^^^^^^^^^^^ type annotation requires that `'a` must outlive `'static`
+
+error: lifetime may not live long enough
+  --> $DIR/wf-unreachable.rs:17:12
+   |
+LL | fn uninit_infer<'a>() {
+   |                 -- lifetime `'a` defined here
+LL |     let x: &'static &'a _;                          //~ ERROR lifetime may not live long enough
+   |            ^^^^^^^^^^^^^^ type annotation requires that `'a` must outlive `'static`
+
+error: lifetime may not live long enough
+  --> $DIR/wf-unreachable.rs:23:12
+   |
+LL | fn infer<'a>() {
+   |          -- lifetime `'a` defined here
+LL |     return;
+LL |     let x: &'static &'a _ = &&();                   //~ ERROR lifetime may not live long enough
+   |            ^^^^^^^^^^^^^^ type annotation requires that `'a` must outlive `'static`
+
+error: lifetime may not live long enough
+  --> $DIR/wf-unreachable.rs:28:12
+   |
+LL | fn uninit_no_var<'a>() {
+   |                  -- lifetime `'a` defined here
+LL |     return;
+LL |     let _: &'static &'a ();                         //~ ERROR lifetime may not live long enough
+   |            ^^^^^^^^^^^^^^^ type annotation requires that `'a` must outlive `'static`
+
+error: lifetime may not live long enough
+  --> $DIR/wf-unreachable.rs:33:12
+   |
+LL | fn no_var<'a>() {
+   |           -- lifetime `'a` defined here
+LL |     return;
+LL |     let _: &'static &'a () = &&();                  //~ ERROR lifetime may not live long enough
+   |            ^^^^^^^^^^^^^^^ type annotation requires that `'a` must outlive `'static`
+
+error: lifetime may not live long enough
+  --> $DIR/wf-unreachable.rs:38:12
+   |
+LL | fn infer_no_var<'a>() {
+   |                 -- lifetime `'a` defined here
+LL |     return;
+LL |     let _: &'static &'a _ = &&();                   //~ ERROR lifetime may not live long enough
+   |            ^^^^^^^^^^^^^^ type annotation requires that `'a` must outlive `'static`
+
+error: lifetime may not live long enough
+  --> $DIR/wf-unreachable.rs:51:12
+   |
+LL | fn required_substs<'a>() {
+   |                    -- lifetime `'a` defined here
+LL |     return;
+LL |     let _: C<'static, 'a, _> = C((), &(), &());     //~ ERROR lifetime may not live long enough
+   |            ^^^^^^^^^^^^^^^^^ type annotation requires that `'a` must outlive `'static`
+
+error: aborting due to 8 previous errors
+
diff --git a/src/test/ui/nll/user-annotations/downcast-infer.rs b/src/test/ui/nll/user-annotations/downcast-infer.rs
new file mode 100644
index 00000000000..23b76bb1964
--- /dev/null
+++ b/src/test/ui/nll/user-annotations/downcast-infer.rs
@@ -0,0 +1,11 @@
+// compile-pass
+
+// Check that we don't try to downcast `_` when type-checking the annotation.
+fn main() {
+    let x = Some(Some(Some(1)));
+
+    match x {
+        Some::<Option<_>>(Some(Some(v))) => (),
+        _ => (),
+    }
+}
diff --git a/src/test/ui/regions/regions-assoc-type-in-supertrait-outlives-container.ast.stderr b/src/test/ui/regions/regions-assoc-type-in-supertrait-outlives-container.ast.stderr
new file mode 100644
index 00000000000..76ead4e94ef
--- /dev/null
+++ b/src/test/ui/regions/regions-assoc-type-in-supertrait-outlives-container.ast.stderr
@@ -0,0 +1,20 @@
+error[E0491]: in type `&'a WithAssoc<TheType<'b>>`, reference has a longer lifetime than the data it references
+  --> $DIR/regions-assoc-type-in-supertrait-outlives-container.rs:45:13
+   |
+LL |     let _x: &'a WithAssoc<TheType<'b>> = loop { };
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+note: the pointer is valid for the lifetime 'a as defined on the function body at 37:15
+  --> $DIR/regions-assoc-type-in-supertrait-outlives-container.rs:37:15
+   |
+LL | fn with_assoc<'a,'b>() {
+   |               ^^
+note: but the referenced data is only valid for the lifetime 'b as defined on the function body at 37:18
+  --> $DIR/regions-assoc-type-in-supertrait-outlives-container.rs:37:18
+   |
+LL | fn with_assoc<'a,'b>() {
+   |                  ^^
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0491`.
diff --git a/src/test/ui/regions/regions-assoc-type-in-supertrait-outlives-container.mir.stderr b/src/test/ui/regions/regions-assoc-type-in-supertrait-outlives-container.mir.stderr
new file mode 100644
index 00000000000..ad94d375b5b
--- /dev/null
+++ b/src/test/ui/regions/regions-assoc-type-in-supertrait-outlives-container.mir.stderr
@@ -0,0 +1,13 @@
+error: lifetime may not live long enough
+  --> $DIR/regions-assoc-type-in-supertrait-outlives-container.rs:45:13
+   |
+LL | fn with_assoc<'a,'b>() {
+   |               -- -- lifetime `'b` defined here
+   |               |
+   |               lifetime `'a` defined here
+...
+LL |     let _x: &'a WithAssoc<TheType<'b>> = loop { };
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^ type annotation requires that `'b` must outlive `'a`
+
+error: aborting due to previous error
+
diff --git a/src/test/ui/regions/regions-assoc-type-in-supertrait-outlives-container.rs b/src/test/ui/regions/regions-assoc-type-in-supertrait-outlives-container.rs
index df7c1e0c7c7..1d534921992 100644
--- a/src/test/ui/regions/regions-assoc-type-in-supertrait-outlives-container.rs
+++ b/src/test/ui/regions/regions-assoc-type-in-supertrait-outlives-container.rs
@@ -3,6 +3,9 @@
 // outlive the location in which the type appears, even when the
 // associted type is in a supertype. Issue #22246.
 
+// revisions: ast mir
+//[mir]compile-flags: -Z borrowck=mir
+
 #![allow(dead_code)]
 
 ///////////////////////////////////////////////////////////////////////////
@@ -40,7 +43,8 @@ fn with_assoc<'a,'b>() {
     // FIXME (#54943) NLL doesn't enforce WF condition in unreachable code if
     // `_x` is changed to `_`
     let _x: &'a WithAssoc<TheType<'b>> = loop { };
-    //~^ ERROR reference has a longer lifetime
+    //[ast]~^ ERROR reference has a longer lifetime
+    //[mir]~^^ ERROR lifetime may not live long enough
 }
 
 fn main() {
diff --git a/src/test/ui/regions/regions-free-region-ordering-caller.ast.stderr b/src/test/ui/regions/regions-free-region-ordering-caller.ast.stderr
new file mode 100644
index 00000000000..73266ab50fa
--- /dev/null
+++ b/src/test/ui/regions/regions-free-region-ordering-caller.ast.stderr
@@ -0,0 +1,32 @@
+error[E0623]: lifetime mismatch
+  --> $DIR/regions-free-region-ordering-caller.rs:11:12
+   |
+LL | fn call2<'a, 'b>(a: &'a usize, b: &'b usize) {
+   |                     ---------     ---------
+   |                     |
+   |                     these two types are declared with different lifetimes...
+LL |     let z: Option<&'b &'a usize> = None;//[ast]~ ERROR E0623
+   |            ^^^^^^^^^^^^^^^^^^^^^ ...but data from `a` flows into `b` here
+
+error[E0623]: lifetime mismatch
+  --> $DIR/regions-free-region-ordering-caller.rs:17:12
+   |
+LL | fn call3<'a, 'b>(a: &'a usize, b: &'b usize) {
+   |                     ---------     ---------
+   |                     |
+   |                     these two types are declared with different lifetimes...
+LL |     let y: Paramd<'a> = Paramd { x: a };
+LL |     let z: Option<&'b Paramd<'a>> = None;//[ast]~ ERROR E0623
+   |            ^^^^^^^^^^^^^^^^^^^^^^ ...but data from `a` flows into `b` here
+
+error[E0623]: lifetime mismatch
+  --> $DIR/regions-free-region-ordering-caller.rs:22:12
+   |
+LL | fn call4<'a, 'b>(a: &'a usize, b: &'b usize) {
+   |                     ---------     --------- these two types are declared with different lifetimes...
+LL |     let z: Option<&'a &'b usize> = None;//[ast]~ ERROR E0623
+   |            ^^^^^^^^^^^^^^^^^^^^^ ...but data from `b` flows into `a` here
+
+error: aborting due to 3 previous errors
+
+For more information about this error, try `rustc --explain E0623`.
diff --git a/src/test/ui/regions/regions-free-region-ordering-caller.mir.stderr b/src/test/ui/regions/regions-free-region-ordering-caller.mir.stderr
new file mode 100644
index 00000000000..abec468c9ea
--- /dev/null
+++ b/src/test/ui/regions/regions-free-region-ordering-caller.mir.stderr
@@ -0,0 +1,33 @@
+error: lifetime may not live long enough
+  --> $DIR/regions-free-region-ordering-caller.rs:11:12
+   |
+LL | fn call2<'a, 'b>(a: &'a usize, b: &'b usize) {
+   |          --  -- lifetime `'b` defined here
+   |          |
+   |          lifetime `'a` defined here
+LL |     let z: Option<&'b &'a usize> = None;//[ast]~ ERROR E0623
+   |            ^^^^^^^^^^^^^^^^^^^^^ type annotation requires that `'a` must outlive `'b`
+
+error: lifetime may not live long enough
+  --> $DIR/regions-free-region-ordering-caller.rs:17:12
+   |
+LL | fn call3<'a, 'b>(a: &'a usize, b: &'b usize) {
+   |          --  -- lifetime `'b` defined here
+   |          |
+   |          lifetime `'a` defined here
+LL |     let y: Paramd<'a> = Paramd { x: a };
+LL |     let z: Option<&'b Paramd<'a>> = None;//[ast]~ ERROR E0623
+   |            ^^^^^^^^^^^^^^^^^^^^^^ type annotation requires that `'a` must outlive `'b`
+
+error: lifetime may not live long enough
+  --> $DIR/regions-free-region-ordering-caller.rs:22:12
+   |
+LL | fn call4<'a, 'b>(a: &'a usize, b: &'b usize) {
+   |          --  -- lifetime `'b` defined here
+   |          |
+   |          lifetime `'a` defined here
+LL |     let z: Option<&'a &'b usize> = None;//[ast]~ ERROR E0623
+   |            ^^^^^^^^^^^^^^^^^^^^^ type annotation requires that `'b` must outlive `'a`
+
+error: aborting due to 3 previous errors
+
diff --git a/src/test/ui/regions/regions-free-region-ordering-caller.rs b/src/test/ui/regions/regions-free-region-ordering-caller.rs
index e26799fcc47..621e6e78b46 100644
--- a/src/test/ui/regions/regions-free-region-ordering-caller.rs
+++ b/src/test/ui/regions/regions-free-region-ordering-caller.rs
@@ -2,19 +2,25 @@
 // than the thing it points at and ensure that they result in
 // errors. See also regions-free-region-ordering-callee.rs
 
+// revisions: ast mir
+//[mir]compile-flags: -Z borrowck=mir
+
 struct Paramd<'a> { x: &'a usize }
 
 fn call2<'a, 'b>(a: &'a usize, b: &'b usize) {
-    let z: Option<&'b &'a usize> = None;//~ ERROR E0623
+    let z: Option<&'b &'a usize> = None;//[ast]~ ERROR E0623
+    //[mir]~^ ERROR lifetime may not live long enough
 }
 
 fn call3<'a, 'b>(a: &'a usize, b: &'b usize) {
     let y: Paramd<'a> = Paramd { x: a };
-    let z: Option<&'b Paramd<'a>> = None;//~ ERROR E0623
+    let z: Option<&'b Paramd<'a>> = None;//[ast]~ ERROR E0623
+    //[mir]~^ ERROR lifetime may not live long enough
 }
 
 fn call4<'a, 'b>(a: &'a usize, b: &'b usize) {
-    let z: Option<&'a &'b usize> = None;//~ ERROR E0623
+    let z: Option<&'a &'b usize> = None;//[ast]~ ERROR E0623
+    //[mir]~^ ERROR lifetime may not live long enough
 }
 
 fn main() {}
diff --git a/src/test/ui/regions/regions-free-region-ordering-caller1.nll.stderr b/src/test/ui/regions/regions-free-region-ordering-caller1.nll.stderr
index 92c21fcb4ae..539343a6829 100644
--- a/src/test/ui/regions/regions-free-region-ordering-caller1.nll.stderr
+++ b/src/test/ui/regions/regions-free-region-ordering-caller1.nll.stderr
@@ -12,6 +12,21 @@ LL |     let z: &'a & usize = &(&y);
 LL | }
    | - temporary value is freed at the end of this statement
 
-error: aborting due to previous error
+error[E0597]: `y` does not live long enough
+  --> $DIR/regions-free-region-ordering-caller1.rs:9:27
+   |
+LL | fn call1<'a>(x: &'a usize) {
+   |          -- lifetime `'a` defined here
+...
+LL |     let z: &'a & usize = &(&y);
+   |            -----------    ^^^^ borrowed value does not live long enough
+   |            |
+   |            type annotation requires that `y` is borrowed for `'a`
+...
+LL | }
+   | - `y` dropped here while still borrowed
+
+error: aborting due to 2 previous errors
 
-For more information about this error, try `rustc --explain E0716`.
+Some errors occurred: E0597, E0716.
+For more information about an error, try `rustc --explain E0597`.
diff --git a/src/test/ui/regions/regions-outlives-projection-container-hrtb.ast.stderr b/src/test/ui/regions/regions-outlives-projection-container-hrtb.ast.stderr
new file mode 100644
index 00000000000..d8330184008
--- /dev/null
+++ b/src/test/ui/regions/regions-outlives-projection-container-hrtb.ast.stderr
@@ -0,0 +1,37 @@
+error[E0491]: in type `&'a WithHrAssoc<TheType<'b>>`, reference has a longer lifetime than the data it references
+  --> $DIR/regions-outlives-projection-container-hrtb.rs:35:12
+   |
+LL |     let _: &'a WithHrAssoc<TheType<'b>> = loop { };
+   |            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+note: the pointer is valid for the lifetime 'a as defined on the function body at 32:15
+  --> $DIR/regions-outlives-projection-container-hrtb.rs:32:15
+   |
+LL | fn with_assoc<'a,'b>() {
+   |               ^^
+note: but the referenced data is only valid for the lifetime 'b as defined on the function body at 32:18
+  --> $DIR/regions-outlives-projection-container-hrtb.rs:32:18
+   |
+LL | fn with_assoc<'a,'b>() {
+   |                  ^^
+
+error[E0491]: in type `&'a WithHrAssocSub<TheType<'b>>`, reference has a longer lifetime than the data it references
+  --> $DIR/regions-outlives-projection-container-hrtb.rs:57:12
+   |
+LL |     let _: &'a WithHrAssocSub<TheType<'b>> = loop { };
+   |            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+note: the pointer is valid for the lifetime 'a as defined on the function body at 53:19
+  --> $DIR/regions-outlives-projection-container-hrtb.rs:53:19
+   |
+LL | fn with_assoc_sub<'a,'b>() {
+   |                   ^^
+note: but the referenced data is only valid for the lifetime 'b as defined on the function body at 53:22
+  --> $DIR/regions-outlives-projection-container-hrtb.rs:53:22
+   |
+LL | fn with_assoc_sub<'a,'b>() {
+   |                      ^^
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0491`.
diff --git a/src/test/ui/regions/regions-outlives-projection-container-hrtb.mir.stderr b/src/test/ui/regions/regions-outlives-projection-container-hrtb.mir.stderr
new file mode 100644
index 00000000000..5028663ba6d
--- /dev/null
+++ b/src/test/ui/regions/regions-outlives-projection-container-hrtb.mir.stderr
@@ -0,0 +1,24 @@
+error: lifetime may not live long enough
+  --> $DIR/regions-outlives-projection-container-hrtb.rs:35:12
+   |
+LL | fn with_assoc<'a,'b>() {
+   |               -- -- lifetime `'b` defined here
+   |               |
+   |               lifetime `'a` defined here
+...
+LL |     let _: &'a WithHrAssoc<TheType<'b>> = loop { };
+   |            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type annotation requires that `'b` must outlive `'a`
+
+error: lifetime may not live long enough
+  --> $DIR/regions-outlives-projection-container-hrtb.rs:57:12
+   |
+LL | fn with_assoc_sub<'a,'b>() {
+   |                   -- -- lifetime `'b` defined here
+   |                   |
+   |                   lifetime `'a` defined here
+...
+LL |     let _: &'a WithHrAssocSub<TheType<'b>> = loop { };
+   |            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type annotation requires that `'b` must outlive `'a`
+
+error: aborting due to 2 previous errors
+
diff --git a/src/test/ui/regions/regions-outlives-projection-container-hrtb.rs b/src/test/ui/regions/regions-outlives-projection-container-hrtb.rs
index 3483f24ecbf..2871d962c42 100644
--- a/src/test/ui/regions/regions-outlives-projection-container-hrtb.rs
+++ b/src/test/ui/regions/regions-outlives-projection-container-hrtb.rs
@@ -1,6 +1,9 @@
 // Test that structs with higher-ranked where clauses don't generate
 // "outlives" requirements. Issue #22246.
 
+// revisions: ast mir
+//[mir]compile-flags: -Z borrowck=mir
+
 #![allow(dead_code)]
 
 
@@ -30,7 +33,8 @@ fn with_assoc<'a,'b>() {
     // We get an error because 'b:'a does not hold:
 
     let _: &'a WithHrAssoc<TheType<'b>> = loop { };
-    //~^ ERROR reference has a longer lifetime
+    //[ast]~^ ERROR reference has a longer lifetime
+    //[mir]~^^ ERROR lifetime may not live long enough
 }
 
 ///////////////////////////////////////////////////////////////////////////
@@ -51,7 +55,8 @@ fn with_assoc_sub<'a,'b>() {
     // below to be well-formed, it is not related to the HR relation.
 
     let _: &'a WithHrAssocSub<TheType<'b>> = loop { };
-    //~^ ERROR reference has a longer lifetime
+    //[ast]~^ ERROR reference has a longer lifetime
+    //[mir]~^^ ERROR lifetime may not live long enough
 }
 
 
diff --git a/src/test/ui/regions/regions-outlives-projection-container-wc.ast.stderr b/src/test/ui/regions/regions-outlives-projection-container-wc.ast.stderr
new file mode 100644
index 00000000000..9e31065ca4e
--- /dev/null
+++ b/src/test/ui/regions/regions-outlives-projection-container-wc.ast.stderr
@@ -0,0 +1,20 @@
+error[E0491]: in type `&'a WithAssoc<TheType<'b>>`, reference has a longer lifetime than the data it references
+  --> $DIR/regions-outlives-projection-container-wc.rs:37:12
+   |
+LL |     let _: &'a WithAssoc<TheType<'b>> = loop { };
+   |            ^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+note: the pointer is valid for the lifetime 'a as defined on the function body at 31:15
+  --> $DIR/regions-outlives-projection-container-wc.rs:31:15
+   |
+LL | fn with_assoc<'a,'b>() {
+   |               ^^
+note: but the referenced data is only valid for the lifetime 'b as defined on the function body at 31:18
+  --> $DIR/regions-outlives-projection-container-wc.rs:31:18
+   |
+LL | fn with_assoc<'a,'b>() {
+   |                  ^^
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0491`.
diff --git a/src/test/ui/regions/regions-outlives-projection-container-wc.mir.stderr b/src/test/ui/regions/regions-outlives-projection-container-wc.mir.stderr
new file mode 100644
index 00000000000..880fe17b740
--- /dev/null
+++ b/src/test/ui/regions/regions-outlives-projection-container-wc.mir.stderr
@@ -0,0 +1,13 @@
+error: lifetime may not live long enough
+  --> $DIR/regions-outlives-projection-container-wc.rs:37:12
+   |
+LL | fn with_assoc<'a,'b>() {
+   |               -- -- lifetime `'b` defined here
+   |               |
+   |               lifetime `'a` defined here
+...
+LL |     let _: &'a WithAssoc<TheType<'b>> = loop { };
+   |            ^^^^^^^^^^^^^^^^^^^^^^^^^^ type annotation requires that `'b` must outlive `'a`
+
+error: aborting due to previous error
+
diff --git a/src/test/ui/regions/regions-outlives-projection-container-wc.rs b/src/test/ui/regions/regions-outlives-projection-container-wc.rs
index 91a0d8590ff..37622211327 100644
--- a/src/test/ui/regions/regions-outlives-projection-container-wc.rs
+++ b/src/test/ui/regions/regions-outlives-projection-container-wc.rs
@@ -3,6 +3,9 @@
 // outlive the location in which the type appears, even when the
 // constraint is in a where clause not a bound. Issue #22246.
 
+// revisions: ast mir
+//[mir]compile-flags: -Z borrowck=mir
+
 #![allow(dead_code)]
 
 ///////////////////////////////////////////////////////////////////////////
@@ -32,7 +35,8 @@ fn with_assoc<'a,'b>() {
     // which is &'b (), must outlive 'a.
 
     let _: &'a WithAssoc<TheType<'b>> = loop { };
-    //~^ ERROR reference has a longer lifetime
+    //[ast]~^ ERROR reference has a longer lifetime
+    //[mir]~^^ ERROR lifetime may not live long enough
 }
 
 fn main() {