about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--src/bootstrap/builder.rs3
-rw-r--r--src/librustc/ich/impls_ty.rs12
-rw-r--r--src/librustc/mir/mod.rs2
-rw-r--r--src/librustc/mir/tcx.rs13
-rw-r--r--src/librustc/mir/visit.rs21
-rw-r--r--src/librustc/traits/query/type_op/ascribe_user_type.rs15
-rw-r--r--src/librustc/ty/context.rs55
-rw-r--r--src/librustc/ty/mod.rs4
-rw-r--r--src/librustc_mir/borrow_check/nll/constraint_generation.rs11
-rw-r--r--src/librustc_mir/borrow_check/nll/renumber.rs18
-rw-r--r--src/librustc_mir/borrow_check/nll/type_check/mod.rs222
-rw-r--r--src/librustc_mir/build/expr/as_constant.rs9
-rw-r--r--src/librustc_mir/build/expr/as_place.rs14
-rw-r--r--src/librustc_mir/build/expr/as_rvalue.rs9
-rw-r--r--src/librustc_mir/build/matches/mod.rs18
-rw-r--r--src/librustc_mir/hair/cx/expr.rs4
-rw-r--r--src/librustc_mir/hair/mod.rs10
-rw-r--r--src/librustc_mir/hair/pattern/mod.rs25
-rw-r--r--src/librustc_mir/hair/util.rs6
-rw-r--r--src/librustc_mir/util/pretty.rs4
-rw-r--r--src/librustc_traits/type_op.rs43
-rw-r--r--src/librustc_typeck/check/mod.rs21
-rw-r--r--src/librustc_typeck/check/writeback.rs2
-rw-r--r--src/test/mir-opt/basic_assignment.rs2
-rw-r--r--src/test/mir-opt/retag.rs14
-rw-r--r--src/test/ui/issue-54943.rs6
-rw-r--r--src/test/ui/issue-54943.stderr11
-rw-r--r--src/test/ui/issues/issue-57866.rs26
-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/constant-in-expr-inherent-2.rs29
-rw-r--r--src/test/ui/nll/user-annotations/constant-in-expr-inherent-2.stderr50
-rw-r--r--src/test/ui/nll/user-annotations/downcast-infer.rs11
-rw-r--r--src/test/ui/nll/user-annotations/issue-57731-ascibed-coupled-types.rs40
-rw-r--r--src/test/ui/nll/user-annotations/issue-57731-ascibed-coupled-types.stderr38
-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
m---------src/tools/clippy14
51 files changed, 860 insertions, 297 deletions
diff --git a/src/bootstrap/builder.rs b/src/bootstrap/builder.rs
index c3dc9458839..a69ba207495 100644
--- a/src/bootstrap/builder.rs
+++ b/src/bootstrap/builder.rs
@@ -991,6 +991,9 @@ impl<'a> Builder<'a> {
 
         if self.config.incremental {
             cargo.env("CARGO_INCREMENTAL", "1");
+        } else {
+            // Don't rely on any default setting for incr. comp. in Cargo
+            cargo.env("CARGO_INCREMENTAL", "0");
         }
 
         if let Some(ref on_fail) = self.config.on_fail {
diff --git a/src/librustc/ich/impls_ty.rs b/src/librustc/ich/impls_ty.rs
index ef7fb0128ef..79c2b89522d 100644
--- a/src/librustc/ich/impls_ty.rs
+++ b/src/librustc/ich/impls_ty.rs
@@ -1240,16 +1240,22 @@ impl_stable_hash_for!(
     }
 );
 
-impl<'a, 'gcx> HashStable<StableHashingContext<'a>> for ty::UserTypeAnnotation<'gcx> {
+impl_stable_hash_for!(
+    struct ty::CanonicalUserTypeAnnotation<'tcx> {
+        user_ty, span, inferred_ty
+    }
+);
+
+impl<'a, 'gcx> HashStable<StableHashingContext<'a>> for ty::UserType<'gcx> {
     fn hash_stable<W: StableHasherResult>(&self,
                                           hcx: &mut StableHashingContext<'a>,
                                           hasher: &mut StableHasher<W>) {
         mem::discriminant(self).hash_stable(hcx, hasher);
         match *self {
-            ty::UserTypeAnnotation::Ty(ref ty) => {
+            ty::UserType::Ty(ref ty) => {
                 ty.hash_stable(hcx, hasher);
             }
-            ty::UserTypeAnnotation::TypeOf(ref def_id, ref substs) => {
+            ty::UserType::TypeOf(ref def_id, ref substs) => {
                 def_id.hash_stable(hcx, hasher);
                 substs.hash_stable(hcx, hasher);
             }
diff --git a/src/librustc/mir/mod.rs b/src/librustc/mir/mod.rs
index a1a6e890b12..f824ab7e5b3 100644
--- a/src/librustc/mir/mod.rs
+++ b/src/librustc/mir/mod.rs
@@ -31,7 +31,7 @@ use ty::subst::{Subst, Substs};
 use ty::layout::VariantIdx;
 use ty::{
     self, AdtDef, CanonicalUserTypeAnnotations, ClosureSubsts, GeneratorSubsts, Region, Ty, TyCtxt,
-    UserTypeAnnotationIndex, UserTypeAnnotation,
+    UserTypeAnnotationIndex,
 };
 use util::ppaux;
 
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 a0fae3aa927..598303f2932 100644
--- a/src/librustc/mir/visit.rs
+++ b/src/librustc/mir/visit.rs
@@ -1,7 +1,6 @@
 use hir::def_id::DefId;
-use infer::canonical::Canonical;
 use ty::subst::Substs;
-use ty::{ClosureSubsts, GeneratorSubsts, Region, Ty};
+use ty::{CanonicalUserTypeAnnotation, ClosureSubsts, GeneratorSubsts, Region, Ty};
 use mir::*;
 use syntax_pos::Span;
 
@@ -221,7 +220,7 @@ macro_rules! make_mir_visitor {
             fn visit_user_type_annotation(
                 &mut self,
                 index: UserTypeAnnotationIndex,
-                ty: & $($mutability)* Canonical<'tcx, UserTypeAnnotation<'tcx>>,
+                ty: & $($mutability)* CanonicalUserTypeAnnotation<'tcx>,
             ) {
                 self.super_user_type_annotation(index, ty);
             }
@@ -309,12 +308,15 @@ macro_rules! make_mir_visitor {
                     self.visit_local_decl(local, & $($mutability)* mir.local_decls[local]);
                 }
 
-                for index in mir.user_type_annotations.indices() {
-                    let (span, annotation) = & $($mutability)* mir.user_type_annotations[index];
+                macro_rules! type_annotations {
+                    (mut) => (mir.user_type_annotations.iter_enumerated_mut());
+                    () => (mir.user_type_annotations.iter_enumerated());
+                };
+
+                for (index, annotation) in type_annotations!($($mutability)*) {
                     self.visit_user_type_annotation(
                         index, annotation
                     );
-                    self.visit_span(span);
                 }
 
                 self.visit_span(&$($mutability)* mir.span);
@@ -882,8 +884,10 @@ macro_rules! make_mir_visitor {
             fn super_user_type_annotation(
                 &mut self,
                 _index: UserTypeAnnotationIndex,
-                _ty: & $($mutability)* Canonical<'tcx, UserTypeAnnotation<'tcx>>,
+                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>) {
@@ -964,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 e37eab622df..4c8f8141116 100644
--- a/src/librustc/ty/context.rs
+++ b/src/librustc/ty/context.rs
@@ -350,7 +350,7 @@ pub struct TypeckTables<'tcx> {
     /// canonical substitutions would include only `for<X> { Vec<X> }`.
     ///
     /// See also `AscribeUserType` statement in MIR.
-    user_provided_types: ItemLocalMap<CanonicalUserTypeAnnotation<'tcx>>,
+    user_provided_types: ItemLocalMap<CanonicalUserType<'tcx>>,
 
     /// Stores the canonicalized types provided by the user. See also
     /// `AscribeUserType` statement in MIR.
@@ -493,7 +493,7 @@ impl<'tcx> TypeckTables<'tcx> {
 
     pub fn user_provided_types(
         &self
-    ) -> LocalTableInContext<'_, CanonicalUserTypeAnnotation<'tcx>> {
+    ) -> LocalTableInContext<'_, CanonicalUserType<'tcx>> {
         LocalTableInContext {
             local_id_root: self.local_id_root,
             data: &self.user_provided_types
@@ -502,7 +502,7 @@ impl<'tcx> TypeckTables<'tcx> {
 
     pub fn user_provided_types_mut(
         &mut self
-    ) -> LocalTableInContextMut<'_, CanonicalUserTypeAnnotation<'tcx>> {
+    ) -> LocalTableInContextMut<'_, CanonicalUserType<'tcx>> {
         LocalTableInContextMut {
             local_id_root: self.local_id_root,
             data: &mut self.user_provided_types
@@ -800,25 +800,46 @@ impl<'a, 'gcx> HashStable<StableHashingContext<'a>> for TypeckTables<'gcx> {
 
 newtype_index! {
     pub struct UserTypeAnnotationIndex {
-        DEBUG_FORMAT = "UserTypeAnnotation({})",
+        DEBUG_FORMAT = "UserType({})",
         const START_INDEX = 0,
     }
 }
 
 /// Mapping of type annotation indices to canonical user type annotations.
 pub type CanonicalUserTypeAnnotations<'tcx> =
-    IndexVec<UserTypeAnnotationIndex, (Span, CanonicalUserTypeAnnotation<'tcx>)>;
+    IndexVec<UserTypeAnnotationIndex, CanonicalUserTypeAnnotation<'tcx>>;
+
+#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, RustcEncodable, RustcDecodable)]
+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, inferred_ty
+    }
+}
+
+BraceStructLiftImpl! {
+    impl<'a, 'tcx> Lift<'tcx> for CanonicalUserTypeAnnotation<'a> {
+        type Lifted = CanonicalUserTypeAnnotation<'tcx>;
+        user_ty, span, inferred_ty
+    }
+}
+
 
 /// Canonicalized user type annotation.
-pub type CanonicalUserTypeAnnotation<'gcx> = Canonical<'gcx, UserTypeAnnotation<'gcx>>;
+pub type CanonicalUserType<'gcx> = Canonical<'gcx, UserType<'gcx>>;
 
-impl CanonicalUserTypeAnnotation<'gcx> {
+impl CanonicalUserType<'gcx> {
     /// Returns `true` if this represents a substitution of the form `[?0, ?1, ?2]`,
     /// i.e. each thing is mapped to a canonical variable with the same index.
     pub fn is_identity(&self) -> bool {
         match self.value {
-            UserTypeAnnotation::Ty(_) => false,
-            UserTypeAnnotation::TypeOf(_, user_substs) => {
+            UserType::Ty(_) => false,
+            UserType::TypeOf(_, user_substs) => {
                 if user_substs.user_self_ty.is_some() {
                     return false;
                 }
@@ -853,7 +874,7 @@ impl CanonicalUserTypeAnnotation<'gcx> {
 /// from constants that are named via paths, like `Foo::<A>::new` and
 /// so forth.
 #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, RustcEncodable, RustcDecodable)]
-pub enum UserTypeAnnotation<'tcx> {
+pub enum UserType<'tcx> {
     Ty(Ty<'tcx>),
 
     /// The canonical type is the result of `type_of(def_id)` with the
@@ -862,17 +883,17 @@ pub enum UserTypeAnnotation<'tcx> {
 }
 
 EnumTypeFoldableImpl! {
-    impl<'tcx> TypeFoldable<'tcx> for UserTypeAnnotation<'tcx> {
-        (UserTypeAnnotation::Ty)(ty),
-        (UserTypeAnnotation::TypeOf)(def, substs),
+    impl<'tcx> TypeFoldable<'tcx> for UserType<'tcx> {
+        (UserType::Ty)(ty),
+        (UserType::TypeOf)(def, substs),
     }
 }
 
 EnumLiftImpl! {
-    impl<'a, 'tcx> Lift<'tcx> for UserTypeAnnotation<'a> {
-        type Lifted = UserTypeAnnotation<'tcx>;
-        (UserTypeAnnotation::Ty)(ty),
-        (UserTypeAnnotation::TypeOf)(def, substs),
+    impl<'a, 'tcx> Lift<'tcx> for UserType<'a> {
+        type Lifted = UserType<'tcx>;
+        (UserType::Ty)(ty),
+        (UserType::TypeOf)(def, substs),
     }
 }
 
diff --git a/src/librustc/ty/mod.rs b/src/librustc/ty/mod.rs
index dd315cf42ce..930bbc08885 100644
--- a/src/librustc/ty/mod.rs
+++ b/src/librustc/ty/mod.rs
@@ -73,8 +73,8 @@ pub use self::binding::BindingMode::*;
 pub use self::context::{TyCtxt, FreeRegionInfo, GlobalArenas, AllArenas, tls, keep_local};
 pub use self::context::{Lift, TypeckTables, CtxtInterners};
 pub use self::context::{
-    UserTypeAnnotationIndex, UserTypeAnnotation, CanonicalUserTypeAnnotation,
-    CanonicalUserTypeAnnotations,
+    UserTypeAnnotationIndex, UserType, CanonicalUserType,
+    CanonicalUserTypeAnnotation, CanonicalUserTypeAnnotations,
 };
 
 pub use self::instance::{Instance, InstanceDef};
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 5c24da7621b..e6a974fd8cc 100644
--- a/src/librustc_mir/borrow_check/nll/renumber.rs
+++ b/src/librustc_mir/borrow_check/nll/renumber.rs
@@ -1,9 +1,5 @@
-use rustc::infer::canonical::Canonical;
 use rustc::ty::subst::Substs;
-use rustc::ty::{
-    self, ClosureSubsts, GeneratorSubsts, Ty, TypeFoldable, UserTypeAnnotation,
-    UserTypeAnnotationIndex,
-};
+use rustc::ty::{self, ClosureSubsts, GeneratorSubsts, Ty, TypeFoldable};
 use rustc::mir::{Location, Mir};
 use rustc::mir::visit::{MutVisitor, TyContext};
 use rustc::infer::{InferCtxt, NLLRegionVariableOrigin};
@@ -59,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 Canonical<'tcx, UserTypeAnnotation<'tcx>>,
-    ) {
-        // 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 180aa1907e8..3e6aa358ee0 100644
--- a/src/librustc_mir/borrow_check/nll/type_check/mod.rs
+++ b/src/librustc_mir/borrow_check/nll/type_check/mod.rs
@@ -35,10 +35,10 @@ use rustc::traits::query::type_op::custom::CustomTypeOp;
 use rustc::traits::query::{Fallible, NoSolution};
 use rustc::traits::{ObligationCause, PredicateObligations};
 use rustc::ty::fold::TypeFoldable;
-use rustc::ty::subst::{Subst, Substs, UnpackedKind};
+use rustc::ty::subst::{Subst, Substs, UnpackedKind, UserSubsts};
 use rustc::ty::{
-    self, RegionVid, ToPolyTraitRef, Ty, TyCtxt, TyKind, UserTypeAnnotation,
-    UserTypeAnnotationIndex,
+    self, RegionVid, ToPolyTraitRef, Ty, TyCtxt, TyKind, UserType,
+    CanonicalUserTypeAnnotation, UserTypeAnnotationIndex,
 };
 use rustc_data_structures::fx::{FxHashMap, FxHashSet};
 use rustc_data_structures::indexed_vec::{IndexVec, Idx};
@@ -283,7 +283,7 @@ impl<'a, 'b, 'gcx, 'tcx> Visitor<'tcx> for TypeVerifier<'a, 'b, 'gcx, 'tcx> {
                 location.to_locations(),
                 ConstraintCategory::Boring,
             ) {
-                let annotation = self.cx.instantiated_type_annotations[&annotation_index];
+                let annotation = &self.mir.user_type_annotations[annotation_index];
                 span_mirbug!(
                     self,
                     constant,
@@ -293,6 +293,39 @@ impl<'a, 'b, 'gcx, 'tcx> Visitor<'tcx> for TypeVerifier<'a, 'b, 'gcx, 'tcx> {
                     terr,
                 );
             }
+        } else {
+            match *constant.literal {
+                ty::LazyConst::Unevaluated(def_id, substs) => {
+                    if let Err(terr) = self.cx.fully_perform_op(
+                        location.to_locations(),
+                        ConstraintCategory::Boring,
+                        self.cx.param_env.and(type_op::ascribe_user_type::AscribeUserType::new(
+                            constant.ty, def_id, UserSubsts { substs, user_self_ty: None },
+                        )),
+                    ) {
+                        span_mirbug!(
+                            self,
+                            constant,
+                            "bad constant type {:?} ({:?})",
+                            constant,
+                            terr
+                        );
+                    }
+                }
+                ty::LazyConst::Evaluated(lit) => {
+                    if let ty::FnDef(def_id, substs) = lit.ty.sty {
+                        let tcx = self.tcx();
+
+                        let instantiated_predicates = tcx
+                            .predicates_of(def_id)
+                            .instantiate(tcx, substs);
+                        self.cx.normalize_and_prove_instantiated_predicates(
+                            instantiated_predicates,
+                            location.to_locations(),
+                        );
+                    }
+                }
+            }
         }
     }
 
@@ -374,8 +407,9 @@ impl<'a, 'b, 'gcx, 'tcx> TypeVerifier<'a, 'b, 'gcx, 'tcx> {
         }
     }
 
-    /// Checks that the constant's `ty` field matches up with what
-    /// would be expected from its literal.
+    /// Checks that the constant's `ty` field matches up with what would be
+    /// expected from its literal. Unevaluated constants and well-formed
+    /// constraints are checked by `visit_constant`.
     fn sanitize_constant(&mut self, constant: &Constant<'tcx>, location: Location) {
         debug!(
             "sanitize_constant(constant={:?}, location={:?})",
@@ -387,35 +421,6 @@ impl<'a, 'b, 'gcx, 'tcx> TypeVerifier<'a, 'b, 'gcx, 'tcx> {
             ty::LazyConst::Unevaluated(..) => return,
         };
 
-        // FIXME(#46702) -- We need some way to get the predicates
-        // associated with the "pre-evaluated" form of the
-        // constant. For example, consider that the constant
-        // may have associated constant projections (`<Foo as
-        // Trait<'a, 'b>>::SOME_CONST`) that impose
-        // constraints on `'a` and `'b`. These constraints
-        // would be lost if we just look at the normalized
-        // value.
-        if let ty::FnDef(def_id, substs) = literal.ty.sty {
-            let tcx = self.tcx();
-            let type_checker = &mut self.cx;
-
-            // FIXME -- For now, use the substitutions from
-            // `value.ty` rather than `value.val`. The
-            // renumberer will rewrite them to independent
-            // sets of regions; in principle, we ought to
-            // derive the type of the `value.val` from "first
-            // principles" and equate with value.ty, but as we
-            // are transitioning to the miri-based system, we
-            // don't have a handy function for that, so for
-            // now we just ignore `value.val` regions.
-
-            let instantiated_predicates = tcx.predicates_of(def_id).instantiate(tcx, substs);
-            type_checker.normalize_and_prove_instantiated_predicates(
-                instantiated_predicates,
-                location.to_locations(),
-            );
-        }
-
         debug!("sanitize_constant: expected_ty={:?}", literal.ty);
 
         if let Err(terr) = self.cx.eq_types(
@@ -740,15 +745,6 @@ struct TypeChecker<'a, 'gcx: 'tcx, 'tcx: 'a> {
     reported_errors: FxHashSet<(Ty<'tcx>, Span)>,
     borrowck_context: Option<&'a mut BorrowCheckContext<'a, 'tcx>>,
     universal_region_relations: Option<&'a UniversalRegionRelations<'tcx>>,
-    /// For each user-type annotation (identified by a UserTypeAnnotationIndex), we create
-    /// an "instantiated" version at the beginning of type check, which replaces each
-    /// canonical variable with a fresh inference variable. These instantiated versions are
-    /// stored either in this field or in user_substs, depending on the kind of user-type
-    /// annotation. They are then referenced by the code which has the job of enforcing these
-    /// 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, UserTypeAnnotation<'tcx>>,
 }
 
 struct BorrowCheckContext<'a, 'tcx: 'a> {
@@ -905,36 +901,69 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> {
             borrowck_context,
             reported_errors: Default::default(),
             universal_region_relations,
-            instantiated_type_annotations: Default::default(),
         };
-        checker.instantiate_user_type_annotations();
+        checker.check_user_type_annotations();
         checker
     }
 
-    /// Instantiate canonical types from user type annotations in the `Mir` into the
-    /// `TypeChecker`. Used when relating user type annotations and when checking if
-    /// annotations are well-formed.
-    fn instantiate_user_type_annotations(&mut self) {
+    /// Equate the inferred type and the annotated type for user type annotations
+    fn check_user_type_annotations(&mut self) {
         debug!(
-            "instantiate_user_type_annotations: user_type_annotations={:?}",
+            "check_user_type_annotations: user_type_annotations={:?}",
              self.mir.user_type_annotations
         );
-        for annotation_index in self.mir.user_type_annotations.indices() {
-            let (span, canonical_annotation) = &self.mir.user_type_annotations[annotation_index];
-            let (mut annotation, _) = self.infcx.instantiate_canonical_with_fresh_inference_vars(
-                *span, &canonical_annotation
+        for user_annotation in &self.mir.user_type_annotations {
+            let CanonicalUserTypeAnnotation { span, ref user_ty, inferred_ty } = *user_annotation;
+            let (annotation, _) = self.infcx.instantiate_canonical_with_fresh_inference_vars(
+                span, user_ty
             );
             match annotation {
-                UserTypeAnnotation::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,
+                            user_annotation,
+                            "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,
+                            user_annotation,
+                            "bad user type AscribeUserType({:?}, {:?} {:?}): {:?}",
+                            inferred_ty,
+                            def_id,
+                            user_substs,
+                            terr
+                        );
+                    }
+                },
             }
-            self.instantiated_type_annotations.insert(annotation_index, annotation);
         }
-        debug!(
-            "instantiate_user_type_annotations: instantiated_type_annotations={:?}",
-            self.instantiated_type_annotations,
-        );
     }
 
     /// Given some operation `op` that manipulates types, proves
@@ -1066,58 +1095,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 {
-            UserTypeAnnotation::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.mir.user_type_annotations[user_ty.base].inferred_ty;
+        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)?;
-                }
-            }
-            UserTypeAnnotation::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(())
     }
@@ -1286,7 +1280,7 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> {
                         location.to_locations(),
                         ConstraintCategory::Boring,
                     ) {
-                        let annotation = self.instantiated_type_annotations[&annotation_index];
+                        let annotation = &mir.user_type_annotations[annotation_index];
                         span_mirbug!(
                             self,
                             stmt,
@@ -1345,7 +1339,7 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> {
                     Locations::All(stmt.source_info.span),
                     ConstraintCategory::TypeAnnotation,
                 ) {
-                    let annotation = self.instantiated_type_annotations[&projection.base];
+                    let annotation = &mir.user_type_annotations[projection.base];
                     span_mirbug!(
                         self,
                         stmt,
diff --git a/src/librustc_mir/build/expr/as_constant.rs b/src/librustc_mir/build/expr/as_constant.rs
index a431bfc61b3..31e0c0daa3f 100644
--- a/src/librustc_mir/build/expr/as_constant.rs
+++ b/src/librustc_mir/build/expr/as_constant.rs
@@ -3,6 +3,7 @@
 use build::Builder;
 use hair::*;
 use rustc::mir::*;
+use rustc::ty::CanonicalUserTypeAnnotation;
 
 impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
     /// Compile `expr`, yielding a compile-time constant. Assumes that
@@ -30,8 +31,12 @@ 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| {
-                    this.canonical_user_type_annotations.push((span, ty))
+                let user_ty = user_ty.map(|user_ty| {
+                    this.canonical_user_type_annotations.push(CanonicalUserTypeAnnotation {
+                        span,
+                        user_ty,
+                        inferred_ty: ty,
+                    })
                 });
                 Constant {
                     span,
diff --git a/src/librustc_mir/build/expr/as_place.rs b/src/librustc_mir/build/expr/as_place.rs
index 3ed00d57979..6bd61ab53fd 100644
--- a/src/librustc_mir/build/expr/as_place.rs
+++ b/src/librustc_mir/build/expr/as_place.rs
@@ -6,7 +6,7 @@ use build::{BlockAnd, BlockAndExtension, Builder};
 use hair::*;
 use rustc::mir::interpret::EvalErrorKind::BoundsCheck;
 use rustc::mir::*;
-use rustc::ty::Variance;
+use rustc::ty::{CanonicalUserTypeAnnotation, Variance};
 
 use rustc_data_structures::indexed_vec::Idx;
 
@@ -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(
-                        (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(
-                        (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 e0fc9093169..3de2f475786 100644
--- a/src/librustc_mir/build/expr/as_rvalue.rs
+++ b/src/librustc_mir/build/expr/as_rvalue.rs
@@ -9,7 +9,7 @@ use hair::*;
 use rustc::middle::region;
 use rustc::mir::interpret::EvalErrorKind;
 use rustc::mir::*;
-use rustc::ty::{self, Ty, UpvarSubsts};
+use rustc::ty::{self, CanonicalUserTypeAnnotation, Ty, UpvarSubsts};
 use syntax_pos::Span;
 
 impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
@@ -331,8 +331,13 @@ 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((expr_span, ty))
+                    this.canonical_user_type_annotations.push(CanonicalUserTypeAnnotation {
+                        span: source_info.span,
+                        user_ty: ty,
+                        inferred_ty,
+                    })
                 });
                 let adt = box AggregateKind::Adt(
                     adt_def,
diff --git a/src/librustc_mir/build/matches/mod.rs b/src/librustc_mir/build/matches/mod.rs
index d52ce9a67d2..2f1e8c03f2f 100644
--- a/src/librustc_mir/build/matches/mod.rs
+++ b/src/librustc_mir/build/matches/mod.rs
@@ -9,7 +9,7 @@ use build::{BlockAnd, BlockAndExtension, Builder};
 use build::{GuardFrame, GuardFrameLocal, LocalsForNode};
 use hair::*;
 use rustc::mir::*;
-use rustc::ty::{self, Ty};
+use rustc::ty::{self, CanonicalUserTypeAnnotation, Ty};
 use rustc::ty::layout::VariantIdx;
 use rustc_data_structures::bit_set::BitSet;
 use rustc_data_structures::fx::FxHashMap;
@@ -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,
@@ -570,10 +572,14 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
                 //
                 // Note that the variance doesn't apply here, as we are tracking the effect
                 // of `user_ty` on any bindings contained with subpattern.
-                let annotation = (user_ty_span, user_ty.base);
+                let annotation = CanonicalUserTypeAnnotation {
+                    span: user_ty_span,
+                    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)
@@ -1337,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/cx/expr.rs b/src/librustc_mir/hair/cx/expr.rs
index eb536fbcf69..8d64c9e9ada 100644
--- a/src/librustc_mir/hair/cx/expr.rs
+++ b/src/librustc_mir/hair/cx/expr.rs
@@ -278,7 +278,7 @@ fn make_mirror_unadjusted<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>,
                     let user_ty = user_provided_types.get(fun.hir_id)
                         .map(|u_ty| *u_ty)
                         .map(|mut u_ty| {
-                            if let UserTypeAnnotation::TypeOf(ref mut did, _) = &mut u_ty.value {
+                            if let UserType::TypeOf(ref mut did, _) = &mut u_ty.value {
                                 *did = adt_def.did;
                             }
                             u_ty
@@ -797,7 +797,7 @@ fn user_substs_applied_to_def(
     cx: &mut Cx<'a, 'gcx, 'tcx>,
     hir_id: hir::HirId,
     def: &Def,
-) -> Option<ty::CanonicalUserTypeAnnotation<'tcx>> {
+) -> Option<ty::CanonicalUserType<'tcx>> {
     debug!("user_substs_applied_to_def: def={:?}", def);
     let user_provided_type = match def {
         // A reference to something callable -- e.g., a fn, method, or
diff --git a/src/librustc_mir/hair/mod.rs b/src/librustc_mir/hair/mod.rs
index e902423cd30..f0f8acb31df 100644
--- a/src/librustc_mir/hair/mod.rs
+++ b/src/librustc_mir/hair/mod.rs
@@ -9,7 +9,7 @@ use rustc::hir::def_id::DefId;
 use rustc::infer::canonical::Canonical;
 use rustc::middle::region;
 use rustc::ty::subst::Substs;
-use rustc::ty::{AdtDef, UpvarSubsts, Ty, Const, LazyConst, UserTypeAnnotation};
+use rustc::ty::{AdtDef, UpvarSubsts, Ty, Const, LazyConst, UserType};
 use rustc::ty::layout::VariantIdx;
 use rustc::hir;
 use syntax::ast;
@@ -265,7 +265,7 @@ pub enum ExprKind<'tcx> {
 
         /// Optional user-given substs: for something like `let x =
         /// Bar::<T> { ... }`.
-        user_ty: Option<Canonical<'tcx, UserTypeAnnotation<'tcx>>>,
+        user_ty: Option<Canonical<'tcx, UserType<'tcx>>>,
 
         fields: Vec<FieldExprRef<'tcx>>,
         base: Option<FruInfo<'tcx>>
@@ -273,12 +273,12 @@ pub enum ExprKind<'tcx> {
     PlaceTypeAscription {
         source: ExprRef<'tcx>,
         /// Type that the user gave to this expression
-        user_ty: Option<Canonical<'tcx, UserTypeAnnotation<'tcx>>>,
+        user_ty: Option<Canonical<'tcx, UserType<'tcx>>>,
     },
     ValueTypeAscription {
         source: ExprRef<'tcx>,
         /// Type that the user gave to this expression
-        user_ty: Option<Canonical<'tcx, UserTypeAnnotation<'tcx>>>,
+        user_ty: Option<Canonical<'tcx, UserType<'tcx>>>,
     },
     Closure {
         closure_id: DefId,
@@ -288,7 +288,7 @@ pub enum ExprKind<'tcx> {
     },
     Literal {
         literal: &'tcx LazyConst<'tcx>,
-        user_ty: Option<Canonical<'tcx, UserTypeAnnotation<'tcx>>>,
+        user_ty: Option<Canonical<'tcx, UserType<'tcx>>>,
     },
     InlineAsm {
         asm: &'tcx hir::InlineAsm,
diff --git a/src/librustc_mir/hair/pattern/mod.rs b/src/librustc_mir/hair/pattern/mod.rs
index cdaffe5d456..06a50f35be1 100644
--- a/src/librustc_mir/hair/pattern/mod.rs
+++ b/src/librustc_mir/hair/pattern/mod.rs
@@ -12,10 +12,10 @@ 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};
-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};
@@ -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(),
         }
     }
 }
@@ -1040,7 +1043,7 @@ macro_rules! CloneImpls {
 CloneImpls!{ <'tcx>
     Span, Field, Mutability, ast::Name, ast::NodeId, usize, ty::Const<'tcx>,
     Region<'tcx>, Ty<'tcx>, BindingMode, &'tcx AdtDef,
-    &'tcx Substs<'tcx>, &'tcx Kind<'tcx>, UserTypeAnnotation<'tcx>,
+    &'tcx Substs<'tcx>, &'tcx Kind<'tcx>, UserType<'tcx>,
     UserTypeProjection<'tcx>, PatternTypeProjection<'tcx>
 }
 
diff --git a/src/librustc_mir/hair/util.rs b/src/librustc_mir/hair/util.rs
index f0f8263b64d..cb4a72387fa 100644
--- a/src/librustc_mir/hair/util.rs
+++ b/src/librustc_mir/hair/util.rs
@@ -1,5 +1,5 @@
 use rustc::hir;
-use rustc::ty::{self, CanonicalUserTypeAnnotation, TyCtxt, UserTypeAnnotation};
+use rustc::ty::{self, CanonicalUserType, TyCtxt, UserType};
 
 crate trait UserAnnotatedTyHelpers<'gcx: 'tcx, 'tcx> {
     fn tcx(&self) -> TyCtxt<'_, 'gcx, 'tcx>;
@@ -12,13 +12,13 @@ crate trait UserAnnotatedTyHelpers<'gcx: 'tcx, 'tcx> {
     fn user_substs_applied_to_ty_of_hir_id(
         &self,
         hir_id: hir::HirId,
-    ) -> Option<CanonicalUserTypeAnnotation<'tcx>> {
+    ) -> Option<CanonicalUserType<'tcx>> {
         let user_provided_types = self.tables().user_provided_types();
         let mut user_ty = *user_provided_types.get(hir_id)?;
         debug!("user_subts_applied_to_ty_of_hir_id: user_ty={:?}", user_ty);
         match &self.tables().node_id_to_type(hir_id).sty {
             ty::Adt(adt_def, ..) => {
-                if let UserTypeAnnotation::TypeOf(ref mut did, _) = &mut user_ty.value {
+                if let UserType::TypeOf(ref mut did, _) = &mut user_ty.value {
                     *did = adt_def.did;
                 }
                 Some(user_ty)
diff --git a/src/librustc_mir/util/pretty.rs b/src/librustc_mir/util/pretty.rs
index f4685e0ddc9..3a15356806a 100644
--- a/src/librustc_mir/util/pretty.rs
+++ b/src/librustc_mir/util/pretty.rs
@@ -634,8 +634,8 @@ fn write_user_type_annotations(mir: &Mir, w: &mut dyn Write) -> io::Result<()> {
     if !mir.user_type_annotations.is_empty() {
         writeln!(w, "| User Type Annotations")?;
     }
-    for (index, (span, annotation)) in mir.user_type_annotations.iter_enumerated() {
-        writeln!(w, "| {:?}: {:?} at {:?}", index.index(), annotation, span)?;
+    for (index, annotation) in mir.user_type_annotations.iter_enumerated() {
+        writeln!(w, "| {:?}: {:?} at {:?}", index.index(), annotation.user_ty, annotation.span)?;
     }
     if !mir.user_type_annotations.is_empty() {
         writeln!(w, "|")?;
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/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs
index ad4bc3cd839..240db801fb2 100644
--- a/src/librustc_typeck/check/mod.rs
+++ b/src/librustc_typeck/check/mod.rs
@@ -103,8 +103,8 @@ use rustc::middle::region;
 use rustc::mir::interpret::{ConstValue, GlobalId};
 use rustc::traits::{self, ObligationCause, ObligationCauseCode, TraitEngine};
 use rustc::ty::{
-    self, AdtKind, CanonicalUserTypeAnnotation, Ty, TyCtxt, GenericParamDefKind, Visibility,
-    ToPolyTraitRef, ToPredicate, RegionKind, UserTypeAnnotation
+    self, AdtKind, CanonicalUserType, Ty, TyCtxt, GenericParamDefKind, Visibility,
+    ToPolyTraitRef, ToPredicate, RegionKind, UserType
 };
 use rustc::ty::adjustment::{Adjust, Adjustment, AllowTwoPhase, AutoBorrow, AutoBorrowMutability};
 use rustc::ty::fold::TypeFoldable;
@@ -985,7 +985,7 @@ impl<'a, 'gcx, 'tcx> Visitor<'gcx> for GatherLocalsVisitor<'a, 'gcx, 'tcx> {
                 };
 
                 let c_ty = self.fcx.inh.infcx.canonicalize_user_type_annotation(
-                    &UserTypeAnnotation::Ty(revealed_ty)
+                    &UserType::Ty(revealed_ty)
                 );
                 debug!("visit_local: ty.hir_id={:?} o_ty={:?} revealed_ty={:?} c_ty={:?}",
                        ty.hir_id, o_ty, revealed_ty, c_ty);
@@ -2194,7 +2194,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                         user_self_ty: None, // not relevant here
                     };
 
-                    self.infcx.canonicalize_user_type_annotation(&UserTypeAnnotation::TypeOf(
+                    self.infcx.canonicalize_user_type_annotation(&UserType::TypeOf(
                         method.def_id,
                         user_substs,
                     ))
@@ -2239,7 +2239,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
 
         if !substs.is_noop() {
             let canonicalized = self.infcx.canonicalize_user_type_annotation(
-                &UserTypeAnnotation::TypeOf(def_id, UserSubsts {
+                &UserType::TypeOf(def_id, UserSubsts {
                     substs,
                     user_self_ty,
                 })
@@ -2252,7 +2252,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
     pub fn write_user_type_annotation(
         &self,
         hir_id: hir::HirId,
-        canonical_user_type_annotation: CanonicalUserTypeAnnotation<'tcx>,
+        canonical_user_type_annotation: CanonicalUserType<'tcx>,
     ) {
         debug!(
             "write_user_type_annotation: hir_id={:?} canonical_user_type_annotation={:?} tag={}",
@@ -2437,10 +2437,11 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
         // types that involve projections, since those can resolve to
         // `'static` bounds (modulo #54940, which hopefully will be
         // fixed by the time you see this comment, dear reader,
-        // although I have my doubts). Other sorts of things are
-        // already sufficiently enforced with erased regions. =)
-        if ty.has_free_regions() || ty.has_projections() {
-            let c_ty = self.infcx.canonicalize_response(&UserTypeAnnotation::Ty(ty));
+        // although I have my doubts). Also pass in types with inference
+        // types, because they may be repeated. Other sorts of things
+        // are already sufficiently enforced with erased regions. =)
+        if ty.has_free_regions() || ty.has_projections() || ty.has_infer_types() {
+            let c_ty = self.infcx.canonicalize_response(&UserType::Ty(ty));
             debug!("to_ty_saving_user_provided_ty: c_ty={:?}", c_ty);
             self.tables.borrow_mut().user_provided_types_mut().insert(ast_ty.hir_id, c_ty);
         }
diff --git a/src/librustc_typeck/check/writeback.rs b/src/librustc_typeck/check/writeback.rs
index c61159eb494..238b087fe32 100644
--- a/src/librustc_typeck/check/writeback.rs
+++ b/src/librustc_typeck/check/writeback.rs
@@ -404,7 +404,7 @@ impl<'cx, 'gcx, 'tcx> WritebackCx<'cx, 'gcx, 'tcx> {
                 .user_provided_types_mut()
                 .insert(hir_id, c_ty.clone());
 
-            if let ty::UserTypeAnnotation::TypeOf(_, user_substs) = c_ty.value {
+            if let ty::UserType::TypeOf(_, user_substs) = c_ty.value {
                 if self.rustc_dump_user_substs {
                     // This is a unit-testing mechanism.
                     let node_id = self.tcx().hir().hir_to_node_id(hir_id);
diff --git a/src/test/mir-opt/basic_assignment.rs b/src/test/mir-opt/basic_assignment.rs
index 88fd53d4ba5..1bbbe67a12c 100644
--- a/src/test/mir-opt/basic_assignment.rs
+++ b/src/test/mir-opt/basic_assignment.rs
@@ -37,7 +37,7 @@ fn main() {
 //        StorageLive(_4);
 //        _4 = std::option::Option<std::boxed::Box<u32>>::None;
 //        FakeRead(ForLet, _4);
-//        AscribeUserType(_4, o, UserTypeProjection { base: UserTypeAnnotation(1), projs: [] });
+//        AscribeUserType(_4, o, UserTypeProjection { base: UserType(1), projs: [] });
 //        StorageLive(_5);
 //        StorageLive(_6);
 //        _6 = move _4;
diff --git a/src/test/mir-opt/retag.rs b/src/test/mir-opt/retag.rs
index 5b00c5c4603..bb794409ae0 100644
--- a/src/test/mir-opt/retag.rs
+++ b/src/test/mir-opt/retag.rs
@@ -75,18 +75,18 @@ fn main() {
 //         _10 = move _8;
 //         Retag(_10);
 //         ...
-//         _14 = &mut (*_10);
-//         Retag(_14);
-//         _13 = move _14 as *mut i32 (Misc);
-//         Retag([raw] _13);
+//         _15 = &mut (*_10);
+//         Retag(_15);
+//         _14 = move _15 as *mut i32 (Misc);
+//         Retag([raw] _14);
 //         ...
-//         _17 = move _18(move _19) -> bb2;
+//         _18 = move _19(move _20) -> bb2;
 //     }
 //
 //     bb2: {
-//         Retag(_17);
+//         Retag(_18);
 //         ...
-//         _21 = const Test::foo_shr(move _22, move _24) -> bb3;
+//         _22 = const Test::foo_shr(move _23, move _25) -> bb3;
 //     }
 //
 //     bb3: {
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/issues/issue-57866.rs b/src/test/ui/issues/issue-57866.rs
new file mode 100644
index 00000000000..77c50e53868
--- /dev/null
+++ b/src/test/ui/issues/issue-57866.rs
@@ -0,0 +1,26 @@
+// compile-pass
+
+#![feature(type_alias_enum_variants)]
+
+enum Outer<T> {
+    A(T)
+}
+
+enum Inner {
+    A(i32)
+}
+
+type OuterAlias = Outer<Inner>;
+
+fn ice(x: OuterAlias) {
+    // Fine
+    match x {
+        OuterAlias::A(Inner::A(_)) => (),
+    }
+    // Not fine
+    match x {
+        OuterAlias::A(Inner::A(y)) => (),
+    }
+}
+
+fn main() {}
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/constant-in-expr-inherent-2.rs b/src/test/ui/nll/user-annotations/constant-in-expr-inherent-2.rs
new file mode 100644
index 00000000000..123be6b3e40
--- /dev/null
+++ b/src/test/ui/nll/user-annotations/constant-in-expr-inherent-2.rs
@@ -0,0 +1,29 @@
+// Test that we still check constants are well-formed, even when we there's no
+// type annotation to check.
+
+#![feature(nll)]
+
+const FUN: fn(&'static ()) = |_| {};
+struct A;
+impl A {
+    const ASSOCIATED_FUN: fn(&'static ()) = |_| {};
+}
+
+struct B<'a>(&'a ());
+impl B<'static> {
+    const ALSO_ASSOCIATED_FUN: fn(&'static ()) = |_| {};
+}
+
+trait Z: 'static {
+    const TRAIT_ASSOCIATED_FUN: fn(&'static Self) = |_| ();
+}
+
+impl Z for () {}
+
+fn main() {
+    let x = ();
+    FUN(&x);                        //~ ERROR `x` does not live long enough
+    A::ASSOCIATED_FUN(&x);          //~ ERROR `x` does not live long enough
+    B::ALSO_ASSOCIATED_FUN(&x);     //~ ERROR `x` does not live long enough
+    <_>::TRAIT_ASSOCIATED_FUN(&x);  //~ ERROR `x` does not live long enough
+}
diff --git a/src/test/ui/nll/user-annotations/constant-in-expr-inherent-2.stderr b/src/test/ui/nll/user-annotations/constant-in-expr-inherent-2.stderr
new file mode 100644
index 00000000000..57cfaa2db04
--- /dev/null
+++ b/src/test/ui/nll/user-annotations/constant-in-expr-inherent-2.stderr
@@ -0,0 +1,50 @@
+error[E0597]: `x` does not live long enough
+  --> $DIR/constant-in-expr-inherent-2.rs:25:9
+   |
+LL |     FUN(&x);                        //~ ERROR `x` does not live long enough
+   |     ----^^-
+   |     |   |
+   |     |   borrowed value does not live long enough
+   |     argument requires that `x` is borrowed for `'static`
+...
+LL | }
+   | - `x` dropped here while still borrowed
+
+error[E0597]: `x` does not live long enough
+  --> $DIR/constant-in-expr-inherent-2.rs:26:23
+   |
+LL |     A::ASSOCIATED_FUN(&x);          //~ ERROR `x` does not live long enough
+   |     ------------------^^-
+   |     |                 |
+   |     |                 borrowed value does not live long enough
+   |     argument requires that `x` is borrowed for `'static`
+...
+LL | }
+   | - `x` dropped here while still borrowed
+
+error[E0597]: `x` does not live long enough
+  --> $DIR/constant-in-expr-inherent-2.rs:27:28
+   |
+LL |     B::ALSO_ASSOCIATED_FUN(&x);     //~ ERROR `x` does not live long enough
+   |     -----------------------^^-
+   |     |                      |
+   |     |                      borrowed value does not live long enough
+   |     argument requires that `x` is borrowed for `'static`
+LL |     <_>::TRAIT_ASSOCIATED_FUN(&x);  //~ ERROR `x` does not live long enough
+LL | }
+   | - `x` dropped here while still borrowed
+
+error[E0597]: `x` does not live long enough
+  --> $DIR/constant-in-expr-inherent-2.rs:28:31
+   |
+LL |     <_>::TRAIT_ASSOCIATED_FUN(&x);  //~ ERROR `x` does not live long enough
+   |     --------------------------^^-
+   |     |                         |
+   |     |                         borrowed value does not live long enough
+   |     argument requires that `x` is borrowed for `'static`
+LL | }
+   | - `x` dropped here while still borrowed
+
+error: aborting due to 4 previous errors
+
+For more information about this error, try `rustc --explain E0597`.
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/nll/user-annotations/issue-57731-ascibed-coupled-types.rs b/src/test/ui/nll/user-annotations/issue-57731-ascibed-coupled-types.rs
new file mode 100644
index 00000000000..f4969bb4067
--- /dev/null
+++ b/src/test/ui/nll/user-annotations/issue-57731-ascibed-coupled-types.rs
@@ -0,0 +1,40 @@
+// Check that repeated type variables are correctly handled
+
+#![allow(unused)]
+#![feature(nll, type_ascription)]
+
+type PairUncoupled<'a, 'b, T> = (&'a T, &'b T);
+type PairCoupledTypes<T> = (T, T);
+type PairCoupledRegions<'a, T> = (&'a T, &'a T);
+
+fn uncoupled_wilds_rhs<'a>(_x: &'a u32, s: &'static u32) -> &'static u32 {
+    let ((y, _z),) = ((s, _x),): (PairUncoupled<_>,);
+    y // OK
+}
+
+fn coupled_wilds_rhs<'a>(_x: &'a u32, s: &'static u32) -> &'static u32 {
+    let ((y, _z),) = ((s, _x),): (PairCoupledTypes<_>,);
+    y //~ ERROR lifetime may not live long enough
+}
+
+fn coupled_regions_rhs<'a>(_x: &'a u32, s: &'static u32) -> &'static u32 {
+    let ((y, _z),) = ((s, _x),): (PairCoupledRegions<_>,);
+    y //~ ERROR lifetime may not live long enough
+}
+
+fn cast_uncoupled_wilds_rhs<'a>(_x: &'a u32, s: &'static u32) -> &'static u32 {
+    let ((y, _z),) = ((s, _x),) as (PairUncoupled<_>,);
+    y // OK
+}
+
+fn cast_coupled_wilds_rhs<'a>(_x: &'a u32, s: &'static u32) -> &'static u32 {
+    let ((y, _z),) = ((s, _x),) as (PairCoupledTypes<_>,);
+    y //~ ERROR lifetime may not live long enough
+}
+
+fn cast_coupled_regions_rhs<'a>(_x: &'a u32, s: &'static u32) -> &'static u32 {
+    let ((y, _z),) = ((s, _x),) as (PairCoupledRegions<_>,);
+    y //~ ERROR lifetime may not live long enough
+}
+
+fn main() {}
diff --git a/src/test/ui/nll/user-annotations/issue-57731-ascibed-coupled-types.stderr b/src/test/ui/nll/user-annotations/issue-57731-ascibed-coupled-types.stderr
new file mode 100644
index 00000000000..76be637220a
--- /dev/null
+++ b/src/test/ui/nll/user-annotations/issue-57731-ascibed-coupled-types.stderr
@@ -0,0 +1,38 @@
+error: lifetime may not live long enough
+  --> $DIR/issue-57731-ascibed-coupled-types.rs:17:5
+   |
+LL | fn coupled_wilds_rhs<'a>(_x: &'a u32, s: &'static u32) -> &'static u32 {
+   |                      -- lifetime `'a` defined here
+LL |     let ((y, _z),) = ((s, _x),): (PairCoupledTypes<_>,);
+LL |     y //~ ERROR lifetime may not live long enough
+   |     ^ returning this value requires that `'a` must outlive `'static`
+
+error: lifetime may not live long enough
+  --> $DIR/issue-57731-ascibed-coupled-types.rs:22:5
+   |
+LL | fn coupled_regions_rhs<'a>(_x: &'a u32, s: &'static u32) -> &'static u32 {
+   |                        -- lifetime `'a` defined here
+LL |     let ((y, _z),) = ((s, _x),): (PairCoupledRegions<_>,);
+LL |     y //~ ERROR lifetime may not live long enough
+   |     ^ returning this value requires that `'a` must outlive `'static`
+
+error: lifetime may not live long enough
+  --> $DIR/issue-57731-ascibed-coupled-types.rs:32:5
+   |
+LL | fn cast_coupled_wilds_rhs<'a>(_x: &'a u32, s: &'static u32) -> &'static u32 {
+   |                           -- lifetime `'a` defined here
+LL |     let ((y, _z),) = ((s, _x),) as (PairCoupledTypes<_>,);
+LL |     y //~ ERROR lifetime may not live long enough
+   |     ^ returning this value requires that `'a` must outlive `'static`
+
+error: lifetime may not live long enough
+  --> $DIR/issue-57731-ascibed-coupled-types.rs:37:5
+   |
+LL | fn cast_coupled_regions_rhs<'a>(_x: &'a u32, s: &'static u32) -> &'static u32 {
+   |                             -- lifetime `'a` defined here
+LL |     let ((y, _z),) = ((s, _x),) as (PairCoupledRegions<_>,);
+LL |     y //~ ERROR lifetime may not live long enough
+   |     ^ returning this value requires that `'a` must outlive `'static`
+
+error: aborting due to 4 previous errors
+
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() {
diff --git a/src/tools/clippy b/src/tools/clippy
-Subproject 280069ddc750d8a20d075c76322c45d5db4a48f
+Subproject f1753522d8f3bb2d218266b4760f7a99f027f5c