about summary refs log tree commit diff
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2019-01-01 15:26:12 +0000
committerbors <bors@rust-lang.org>2019-01-01 15:26:12 +0000
commitcae164753f557f668cb75610abda4f790981e5e6 (patch)
tree515bcca8a0e1239da5a7358488826f136d4d4d31
parent36500deb1a276e47e9780876c136e8ceea46a860 (diff)
parentc20ba65a0b3142bbd88031fbf6eb7ef46bc1f7b3 (diff)
Auto merge of #55937 - davidtwco:issue-54943, r=pnkfelix
NLL: User type annotations refactor, associated constant patterns and ref bindings.

Fixes #55511 and Fixes #55401. Contributes to #54943.

This PR performs a large refactoring on user type annotations, checks user type annotations for associated constants in patterns and that user type annotations for `ref` bindings are respected.

r? @nikomatsakis
-rw-r--r--src/librustc/ich/impls_mir.rs17
-rw-r--r--src/librustc/ich/impls_ty.rs26
-rw-r--r--src/librustc/mir/mod.rs125
-rw-r--r--src/librustc/mir/visit.rs24
-rw-r--r--src/librustc/traits/query/type_op/ascribe_user_type.rs2
-rw-r--r--src/librustc/ty/context.rs146
-rw-r--r--src/librustc/ty/mod.rs4
-rw-r--r--src/librustc/ty/query/mod.rs4
-rw-r--r--src/librustc/ty/subst.rs40
-rw-r--r--src/librustc/ty/wf.rs7
-rw-r--r--src/librustc_mir/borrow_check/nll/mod.rs3
-rw-r--r--src/librustc_mir/borrow_check/nll/renumber.rs14
-rw-r--r--src/librustc_mir/borrow_check/nll/type_check/mod.rs103
-rw-r--r--src/librustc_mir/build/block.rs3
-rw-r--r--src/librustc_mir/build/expr/as_constant.rs15
-rw-r--r--src/librustc_mir/build/expr/as_place.rs10
-rw-r--r--src/librustc_mir/build/expr/as_rvalue.rs3
-rw-r--r--src/librustc_mir/build/matches/mod.rs64
-rw-r--r--src/librustc_mir/build/mod.rs3
-rw-r--r--src/librustc_mir/hair/cx/block.rs5
-rw-r--r--src/librustc_mir/hair/cx/expr.rs63
-rw-r--r--src/librustc_mir/hair/mod.rs15
-rw-r--r--src/librustc_mir/hair/pattern/mod.rs165
-rw-r--r--src/librustc_mir/hair/util.rs34
-rw-r--r--src/librustc_mir/shim.rs4
-rw-r--r--src/librustc_mir/transform/promote_consts.rs1
-rw-r--r--src/librustc_mir/util/pretty.rs14
-rw-r--r--src/librustc_traits/type_op.rs55
-rw-r--r--src/librustc_typeck/check/method/mod.rs22
-rw-r--r--src/librustc_typeck/check/mod.rs105
-rw-r--r--src/librustc_typeck/check/writeback.rs44
-rw-r--r--src/test/incremental/hashes/let_expressions.rs2
-rw-r--r--src/test/mir-opt/basic_assignment.rs2
-rw-r--r--src/test/run-pass/associated-consts/associated-const-range-match-patterns.rs2
-rw-r--r--src/test/ui/issue-54943-1.rs15
-rw-r--r--src/test/ui/issue-54943-2.rs18
-rw-r--r--src/test/ui/issue-54943-3.rs21
-rw-r--r--src/test/ui/issue-54943.rs17
-rw-r--r--src/test/ui/issue-55511.nll.stderr15
-rw-r--r--src/test/ui/issue-55511.rs19
-rw-r--r--src/test/ui/issue-55511.stderr14
-rw-r--r--src/test/ui/nll/issue-55401.rs8
-rw-r--r--src/test/ui/nll/issue-55401.stderr11
-rw-r--r--src/test/ui/nll/user-annotations/dump-adt-brace-struct.stderr2
-rw-r--r--src/test/ui/nll/user-annotations/dump-fn-method.stderr8
-rw-r--r--src/test/ui/regions/regions-outlives-projection-container-wc.rs4
-rw-r--r--src/test/ui/regions/regions-outlives-projection-container-wc.stderr6
47 files changed, 804 insertions, 500 deletions
diff --git a/src/librustc/ich/impls_mir.rs b/src/librustc/ich/impls_mir.rs
index dbabff9ee88..002ac7cc7a9 100644
--- a/src/librustc/ich/impls_mir.rs
+++ b/src/librustc/ich/impls_mir.rs
@@ -494,22 +494,5 @@ impl<'a, 'gcx> HashStable<StableHashingContext<'a>> for mir::ClosureOutlivesSubj
 
 impl_stable_hash_for!(struct mir::interpret::GlobalId<'tcx> { instance, promoted });
 
-impl<'a, 'gcx> HashStable<StableHashingContext<'a>> for mir::UserTypeAnnotation<'gcx> {
-    fn hash_stable<W: StableHasherResult>(&self,
-                                          hcx: &mut StableHashingContext<'a>,
-                                          hasher: &mut StableHasher<W>) {
-        mem::discriminant(self).hash_stable(hcx, hasher);
-        match *self {
-            mir::UserTypeAnnotation::Ty(ref ty) => {
-                ty.hash_stable(hcx, hasher);
-            }
-            mir::UserTypeAnnotation::TypeOf(ref def_id, ref substs) => {
-                def_id.hash_stable(hcx, hasher);
-                substs.hash_stable(hcx, hasher);
-            }
-        }
-    }
-}
-
 impl_stable_hash_for!(struct mir::UserTypeProjection<'tcx> { base, projs });
 impl_stable_hash_for!(struct mir::UserTypeProjections<'tcx> { contents });
diff --git a/src/librustc/ich/impls_ty.rs b/src/librustc/ich/impls_ty.rs
index 65b8f04e30a..b2fe4b7561c 100644
--- a/src/librustc/ich/impls_ty.rs
+++ b/src/librustc/ich/impls_ty.rs
@@ -1251,3 +1251,29 @@ impl_stable_hash_for!(
         goal,
     }
 );
+
+impl<'a, 'gcx> HashStable<StableHashingContext<'a>> for ty::UserTypeAnnotation<'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.hash_stable(hcx, hasher);
+            }
+            ty::UserTypeAnnotation::TypeOf(ref def_id, ref substs) => {
+                def_id.hash_stable(hcx, hasher);
+                substs.hash_stable(hcx, hasher);
+            }
+        }
+    }
+}
+
+impl<'a> HashStable<StableHashingContext<'a>> for ty::UserTypeAnnotationIndex {
+    #[inline]
+    fn hash_stable<W: StableHasherResult>(&self,
+                                          hcx: &mut StableHashingContext<'a>,
+                                          hasher: &mut StableHasher<W>) {
+        self.index().hash_stable(hcx, hasher);
+    }
+}
diff --git a/src/librustc/mir/mod.rs b/src/librustc/mir/mod.rs
index 36d51c59712..2936405ebd0 100644
--- a/src/librustc/mir/mod.rs
+++ b/src/librustc/mir/mod.rs
@@ -27,9 +27,12 @@ use syntax::ast::{self, Name};
 use syntax::symbol::InternedString;
 use syntax_pos::{Span, DUMMY_SP};
 use ty::fold::{TypeFoldable, TypeFolder, TypeVisitor};
-use ty::subst::{CanonicalUserSubsts, Subst, Substs};
-use ty::{self, AdtDef, CanonicalTy, ClosureSubsts, GeneratorSubsts, Region, Ty, TyCtxt};
+use ty::subst::{Subst, Substs};
 use ty::layout::VariantIdx;
+use ty::{
+    self, AdtDef, CanonicalUserTypeAnnotations, ClosureSubsts, GeneratorSubsts, Region, Ty, TyCtxt,
+    UserTypeAnnotationIndex, UserTypeAnnotation,
+};
 use util::ppaux;
 
 pub use mir::interpret::AssertMessage;
@@ -121,6 +124,9 @@ pub struct Mir<'tcx> {
     /// variables and temporaries.
     pub local_decls: LocalDecls<'tcx>,
 
+    /// User type annotations
+    pub user_type_annotations: CanonicalUserTypeAnnotations<'tcx>,
+
     /// Number of arguments this function takes.
     ///
     /// Starting at local 1, `arg_count` locals will be provided by the caller
@@ -161,7 +167,8 @@ impl<'tcx> Mir<'tcx> {
         source_scope_local_data: ClearCrossCrate<IndexVec<SourceScope, SourceScopeLocalData>>,
         promoted: IndexVec<Promoted, Mir<'tcx>>,
         yield_ty: Option<Ty<'tcx>>,
-        local_decls: IndexVec<Local, LocalDecl<'tcx>>,
+        local_decls: LocalDecls<'tcx>,
+        user_type_annotations: CanonicalUserTypeAnnotations<'tcx>,
         arg_count: usize,
         upvar_decls: Vec<UpvarDecl>,
         span: Span,
@@ -185,6 +192,7 @@ impl<'tcx> Mir<'tcx> {
             generator_drop: None,
             generator_layout: None,
             local_decls,
+            user_type_annotations,
             arg_count,
             upvar_decls,
             spread_arg: None,
@@ -418,6 +426,7 @@ impl_stable_hash_for!(struct Mir<'tcx> {
     generator_drop,
     generator_layout,
     local_decls,
+    user_type_annotations,
     arg_count,
     upvar_decls,
     spread_arg,
@@ -2232,7 +2241,7 @@ pub enum AggregateKind<'tcx> {
         &'tcx AdtDef,
         VariantIdx,
         &'tcx Substs<'tcx>,
-        Option<UserTypeAnnotation<'tcx>>,
+        Option<UserTypeAnnotationIndex>,
         Option<usize>,
     ),
 
@@ -2446,38 +2455,11 @@ pub struct Constant<'tcx> {
     /// indicate that `Vec<_>` was explicitly specified.
     ///
     /// Needed for NLL to impose user-given type constraints.
-    pub user_ty: Option<UserTypeAnnotation<'tcx>>,
+    pub user_ty: Option<UserTypeAnnotationIndex>,
 
     pub literal: &'tcx ty::Const<'tcx>,
 }
 
-/// A user-given type annotation attached to a constant.  These arise
-/// 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> {
-    Ty(CanonicalTy<'tcx>),
-
-    /// The canonical type is the result of `type_of(def_id)` with the
-    /// given substitutions applied.
-    TypeOf(DefId, CanonicalUserSubsts<'tcx>),
-}
-
-EnumTypeFoldableImpl! {
-    impl<'tcx> TypeFoldable<'tcx> for UserTypeAnnotation<'tcx> {
-        (UserTypeAnnotation::Ty)(ty),
-        (UserTypeAnnotation::TypeOf)(def, substs),
-    }
-}
-
-EnumLiftImpl! {
-    impl<'a, 'tcx> Lift<'tcx> for UserTypeAnnotation<'a> {
-        type Lifted = UserTypeAnnotation<'tcx>;
-        (UserTypeAnnotation::Ty)(ty),
-        (UserTypeAnnotation::TypeOf)(def, substs),
-    }
-}
-
 /// A collection of projections into user types.
 ///
 /// They are projections because a binding can occur a part of a
@@ -2537,6 +2519,48 @@ impl<'tcx> UserTypeProjections<'tcx> {
     pub fn projections(&self) -> impl Iterator<Item=&UserTypeProjection<'tcx>> {
         self.contents.iter().map(|&(ref user_type, _span)| user_type)
     }
+
+    pub fn push_projection(
+        mut self,
+        user_ty: &UserTypeProjection<'tcx>,
+        span: Span,
+    ) -> Self {
+        self.contents.push((user_ty.clone(), span));
+        self
+    }
+
+    fn map_projections(
+        mut self,
+        mut f: impl FnMut(UserTypeProjection<'tcx>) -> UserTypeProjection<'tcx>
+    ) -> Self {
+        self.contents = self.contents.drain(..).map(|(proj, span)| (f(proj), span)).collect();
+        self
+    }
+
+    pub fn index(self) -> Self {
+        self.map_projections(|pat_ty_proj| pat_ty_proj.index())
+    }
+
+    pub fn subslice(self, from: u32, to: u32) -> Self {
+        self.map_projections(|pat_ty_proj| pat_ty_proj.subslice(from, to))
+    }
+
+    pub fn deref(self) -> Self {
+        self.map_projections(|pat_ty_proj| pat_ty_proj.deref())
+    }
+
+    pub fn leaf(self, field: Field) -> Self {
+        self.map_projections(|pat_ty_proj| pat_ty_proj.leaf(field))
+    }
+
+    pub fn variant(
+        self,
+        adt_def: &'tcx AdtDef,
+        variant_index: VariantIdx,
+        field: Field,
+    ) -> Self {
+        self.map_projections(|pat_ty_proj| pat_ty_proj.variant(adt_def, variant_index, field))
+    }
 }
 
 /// Encodes the effect of a user-supplied type annotation on the
@@ -2556,12 +2580,45 @@ impl<'tcx> UserTypeProjections<'tcx> {
 ///   determined by finding the type of the `.0` field from `T`.
 #[derive(Clone, Debug, PartialEq, Eq, Hash, RustcEncodable, RustcDecodable)]
 pub struct UserTypeProjection<'tcx> {
-    pub base: UserTypeAnnotation<'tcx>,
+    pub base: UserTypeAnnotationIndex,
     pub projs: Vec<ProjectionElem<'tcx, (), ()>>,
 }
 
 impl<'tcx> Copy for ProjectionKind<'tcx> { }
 
+impl<'tcx> UserTypeProjection<'tcx> {
+    pub(crate) fn index(mut self) -> Self {
+        self.projs.push(ProjectionElem::Index(()));
+        self
+    }
+
+    pub(crate) fn subslice(mut self, from: u32, to: u32) -> Self {
+        self.projs.push(ProjectionElem::Subslice { from, to });
+        self
+    }
+
+    pub(crate) fn deref(mut self) -> Self {
+        self.projs.push(ProjectionElem::Deref);
+        self
+    }
+
+    pub(crate) fn leaf(mut self, field: Field) -> Self {
+        self.projs.push(ProjectionElem::Field(field, ()));
+        self
+    }
+
+    pub(crate) fn variant(
+        mut self,
+        adt_def: &'tcx AdtDef,
+        variant_index: VariantIdx,
+        field: Field,
+    ) -> Self {
+        self.projs.push(ProjectionElem::Downcast(adt_def, variant_index));
+        self.projs.push(ProjectionElem::Field(field, ()));
+        self
+    }
+}
+
 CloneTypeFoldableAndLiftImpls! { ProjectionKind<'tcx>, }
 
 impl<'tcx> TypeFoldable<'tcx> for UserTypeProjection<'tcx> {
@@ -2970,6 +3027,7 @@ CloneTypeFoldableAndLiftImpls! {
     SourceScope,
     SourceScopeData,
     SourceScopeLocalData,
+    UserTypeAnnotationIndex,
 }
 
 BraceStructTypeFoldableImpl! {
@@ -2983,6 +3041,7 @@ BraceStructTypeFoldableImpl! {
         generator_drop,
         generator_layout,
         local_decls,
+        user_type_annotations,
         arg_count,
         upvar_decls,
         spread_arg,
diff --git a/src/librustc/mir/visit.rs b/src/librustc/mir/visit.rs
index a20b8231f88..67f85fbc867 100644
--- a/src/librustc/mir/visit.rs
+++ b/src/librustc/mir/visit.rs
@@ -1,4 +1,5 @@
 use hir::def_id::DefId;
+use infer::canonical::Canonical;
 use ty::subst::Substs;
 use ty::{ClosureSubsts, GeneratorSubsts, Region, Ty};
 use mir::*;
@@ -219,9 +220,10 @@ macro_rules! make_mir_visitor {
 
             fn visit_user_type_annotation(
                 &mut self,
-                ty: & $($mutability)* UserTypeAnnotation<'tcx>,
+                index: UserTypeAnnotationIndex,
+                ty: & $($mutability)* Canonical<'tcx, UserTypeAnnotation<'tcx>>,
             ) {
-                self.super_user_type_annotation(ty);
+                self.super_user_type_annotation(index, ty);
             }
 
             fn visit_region(&mut self,
@@ -307,6 +309,14 @@ 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];
+                    self.visit_user_type_annotation(
+                        index, annotation
+                    );
+                    self.visit_span(span);
+                }
+
                 self.visit_span(&$($mutability)* mir.span);
             }
 
@@ -865,18 +875,14 @@ macro_rules! make_mir_visitor {
 
             fn super_user_type_projection(
                 &mut self,
-                ty: & $($mutability)* UserTypeProjection<'tcx>,
+                _ty: & $($mutability)* UserTypeProjection<'tcx>,
             ) {
-                let UserTypeProjection {
-                    ref $($mutability)* base,
-                    projs: _, // Note: Does not visit projection elems!
-                } = *ty;
-                self.visit_user_type_annotation(base);
             }
 
             fn super_user_type_annotation(
                 &mut self,
-                _ty: & $($mutability)* UserTypeAnnotation<'tcx>,
+                _index: UserTypeAnnotationIndex,
+                _ty: & $($mutability)* Canonical<'tcx, UserTypeAnnotation<'tcx>>,
             ) {
             }
 
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 365c1d67ef9..b2f30564de9 100644
--- a/src/librustc/traits/query/type_op/ascribe_user_type.rs
+++ b/src/librustc/traits/query/type_op/ascribe_user_type.rs
@@ -22,7 +22,7 @@ impl<'tcx> AscribeUserType<'tcx> {
         user_substs: UserSubsts<'tcx>,
         projs: &'tcx ty::List<ProjectionKind<'tcx>>,
     ) -> Self {
-        AscribeUserType { mir_ty, variance, def_id, user_substs, projs }
+        Self { mir_ty, variance, def_id, user_substs, projs }
     }
 }
 
diff --git a/src/librustc/ty/context.rs b/src/librustc/ty/context.rs
index ea69d466ba6..32348e2e504 100644
--- a/src/librustc/ty/context.rs
+++ b/src/librustc/ty/context.rs
@@ -14,7 +14,7 @@ use hir::map as hir_map;
 use hir::map::DefPathHash;
 use lint::{self, Lint};
 use ich::{StableHashingContext, NodeIdHashingMode};
-use infer::canonical::{CanonicalVarInfo, CanonicalVarInfos};
+use infer::canonical::{Canonical, CanonicalVarInfo, CanonicalVarInfos};
 use infer::outlives::free_region_map::FreeRegionMap;
 use middle::cstore::CrateStoreDyn;
 use middle::cstore::EncodedMetadata;
@@ -23,7 +23,7 @@ use middle::resolve_lifetime::{self, ObjectLifetimeDefault};
 use middle::stability;
 use mir::{self, Mir, interpret, ProjectionKind};
 use mir::interpret::Allocation;
-use ty::subst::{CanonicalUserSubsts, Kind, Substs, Subst};
+use ty::subst::{Kind, Substs, Subst};
 use ty::ReprOptions;
 use traits;
 use traits::{Clause, Clauses, GoalKind, Goal, Goals};
@@ -38,8 +38,8 @@ use ty::GenericParamDefKind;
 use ty::layout::{LayoutDetails, TargetDataLayout, VariantIdx};
 use ty::query;
 use ty::steal::Steal;
-use ty::BindingMode;
-use ty::CanonicalTy;
+use ty::subst::{UserSubsts, UnpackedKind};
+use ty::{BoundVar, BindingMode};
 use ty::CanonicalPolyFnSig;
 use util::nodemap::{DefIdMap, DefIdSet, ItemLocalMap};
 use util::nodemap::{FxHashMap, FxHashSet};
@@ -49,7 +49,7 @@ use rustc_data_structures::stable_hasher::{HashStable, hash_stable_hashmap,
                                            StableHasher, StableHasherResult,
                                            StableVec};
 use arena::{TypedArena, SyncDroplessArena};
-use rustc_data_structures::indexed_vec::IndexVec;
+use rustc_data_structures::indexed_vec::{Idx, IndexVec};
 use rustc_data_structures::sync::{self, Lrc, Lock, WorkerLocal};
 use std::any::Any;
 use std::borrow::Borrow;
@@ -342,26 +342,21 @@ pub struct TypeckTables<'tcx> {
     /// other items.
     node_substs: ItemLocalMap<&'tcx Substs<'tcx>>,
 
-    /// Stores the canonicalized types provided by the user. See also
-    /// `AscribeUserType` statement in MIR.
-    user_provided_tys: ItemLocalMap<CanonicalTy<'tcx>>,
+    /// This will either store the canonicalized types provided by the user
+    /// or the substitutions that the user explicitly gave (if any) attached
+    /// to `id`. These will not include any inferred values. The canonical form
+    /// is used to capture things like `_` or other unspecified values.
+    ///
+    /// For example, if the user wrote `foo.collect::<Vec<_>>()`, then the
+    /// canonical substitutions would include only `for<X> { Vec<X> }`.
+    ///
+    /// See also `AscribeUserType` statement in MIR.
+    user_provided_types: ItemLocalMap<CanonicalUserTypeAnnotation<'tcx>>,
 
     /// Stores the canonicalized types provided by the user. See also
     /// `AscribeUserType` statement in MIR.
     pub user_provided_sigs: DefIdMap<CanonicalPolyFnSig<'tcx>>,
 
-    /// Stores the substitutions that the user explicitly gave (if any)
-    /// attached to `id`. These will not include any inferred
-    /// values. The canonical form is used to capture things like `_`
-    /// or other unspecified values.
-    ///
-    /// Example:
-    ///
-    /// If the user wrote `foo.collect::<Vec<_>>()`, then the
-    /// canonical substitutions would include only `for<X> { Vec<X>
-    /// }`.
-    user_substs: ItemLocalMap<CanonicalUserSubsts<'tcx>>,
-
     adjustments: ItemLocalMap<Vec<ty::adjustment::Adjustment<'tcx>>>,
 
     /// Stores the actual binding mode for all instances of hir::BindingAnnotation.
@@ -432,11 +427,10 @@ impl<'tcx> TypeckTables<'tcx> {
             local_id_root,
             type_dependent_defs: Default::default(),
             field_indices: Default::default(),
-            user_provided_tys: Default::default(),
+            user_provided_types: Default::default(),
             user_provided_sigs: Default::default(),
             node_types: Default::default(),
             node_substs: Default::default(),
-            user_substs: Default::default(),
             adjustments: Default::default(),
             pat_binding_modes: Default::default(),
             pat_adjustments: Default::default(),
@@ -491,17 +485,21 @@ impl<'tcx> TypeckTables<'tcx> {
         }
     }
 
-    pub fn user_provided_tys(&self) -> LocalTableInContext<'_, CanonicalTy<'tcx>> {
+    pub fn user_provided_types(
+        &self
+    ) -> LocalTableInContext<'_, CanonicalUserTypeAnnotation<'tcx>> {
         LocalTableInContext {
             local_id_root: self.local_id_root,
-            data: &self.user_provided_tys
+            data: &self.user_provided_types
         }
     }
 
-    pub fn user_provided_tys_mut(&mut self) -> LocalTableInContextMut<'_, CanonicalTy<'tcx>> {
+    pub fn user_provided_types_mut(
+        &mut self
+    ) -> LocalTableInContextMut<'_, CanonicalUserTypeAnnotation<'tcx>> {
         LocalTableInContextMut {
             local_id_root: self.local_id_root,
-            data: &mut self.user_provided_tys
+            data: &mut self.user_provided_types
         }
     }
 
@@ -551,18 +549,6 @@ impl<'tcx> TypeckTables<'tcx> {
         self.node_substs.get(&id.local_id).cloned()
     }
 
-    pub fn user_substs_mut(&mut self) -> LocalTableInContextMut<'_, CanonicalUserSubsts<'tcx>> {
-        LocalTableInContextMut {
-            local_id_root: self.local_id_root,
-            data: &mut self.user_substs
-        }
-    }
-
-    pub fn user_substs(&self, id: hir::HirId) -> Option<CanonicalUserSubsts<'tcx>> {
-        validate_hir_id_for_typeck_tables(self.local_id_root, id, false);
-        self.user_substs.get(&id.local_id).cloned()
-    }
-
     // Returns the type of a pattern as a monotype. Like @expr_ty, this function
     // doesn't provide type parameter substitutions.
     pub fn pat_ty(&self, pat: &hir::Pat) -> Ty<'tcx> {
@@ -739,11 +725,10 @@ impl<'a, 'gcx> HashStable<StableHashingContext<'a>> for TypeckTables<'gcx> {
             local_id_root,
             ref type_dependent_defs,
             ref field_indices,
-            ref user_provided_tys,
+            ref user_provided_types,
             ref user_provided_sigs,
             ref node_types,
             ref node_substs,
-            ref user_substs,
             ref adjustments,
             ref pat_binding_modes,
             ref pat_adjustments,
@@ -763,11 +748,10 @@ impl<'a, 'gcx> HashStable<StableHashingContext<'a>> for TypeckTables<'gcx> {
         hcx.with_node_id_hashing_mode(NodeIdHashingMode::HashDefPath, |hcx| {
             type_dependent_defs.hash_stable(hcx, hasher);
             field_indices.hash_stable(hcx, hasher);
-            user_provided_tys.hash_stable(hcx, hasher);
+            user_provided_types.hash_stable(hcx, hasher);
             user_provided_sigs.hash_stable(hcx, hasher);
             node_types.hash_stable(hcx, hasher);
             node_substs.hash_stable(hcx, hasher);
-            user_substs.hash_stable(hcx, hasher);
             adjustments.hash_stable(hcx, hasher);
             pat_binding_modes.hash_stable(hcx, hasher);
             pat_adjustments.hash_stable(hcx, hasher);
@@ -805,6 +789,84 @@ impl<'a, 'gcx> HashStable<StableHashingContext<'a>> for TypeckTables<'gcx> {
     }
 }
 
+newtype_index! {
+    pub struct UserTypeAnnotationIndex {
+        DEBUG_FORMAT = "UserTypeAnnotation({})",
+        const START_INDEX = 0,
+    }
+}
+
+/// Mapping of type annotation indices to canonical user type annotations.
+pub type CanonicalUserTypeAnnotations<'tcx> =
+    IndexVec<UserTypeAnnotationIndex, (Span, CanonicalUserTypeAnnotation<'tcx>)>;
+
+/// Canonicalized user type annotation.
+pub type CanonicalUserTypeAnnotation<'gcx> = Canonical<'gcx, UserTypeAnnotation<'gcx>>;
+
+impl CanonicalUserTypeAnnotation<'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) => {
+                if user_substs.user_self_ty.is_some() {
+                    return false;
+                }
+
+                user_substs.substs.iter().zip(BoundVar::new(0)..).all(|(kind, cvar)| {
+                    match kind.unpack() {
+                        UnpackedKind::Type(ty) => match ty.sty {
+                            ty::Bound(debruijn, b) => {
+                                // We only allow a `ty::INNERMOST` index in substitutions.
+                                assert_eq!(debruijn, ty::INNERMOST);
+                                cvar == b.var
+                            }
+                            _ => false,
+                        },
+
+                        UnpackedKind::Lifetime(r) => match r {
+                            ty::ReLateBound(debruijn, br) => {
+                                // We only allow a `ty::INNERMOST` index in substitutions.
+                                assert_eq!(*debruijn, ty::INNERMOST);
+                                cvar == br.assert_bound_var()
+                            }
+                            _ => false,
+                        },
+                    }
+                })
+            },
+        }
+    }
+}
+
+/// A user-given type annotation attached to a constant.  These arise
+/// 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> {
+    Ty(Ty<'tcx>),
+
+    /// The canonical type is the result of `type_of(def_id)` with the
+    /// given substitutions applied.
+    TypeOf(DefId, UserSubsts<'tcx>),
+}
+
+EnumTypeFoldableImpl! {
+    impl<'tcx> TypeFoldable<'tcx> for UserTypeAnnotation<'tcx> {
+        (UserTypeAnnotation::Ty)(ty),
+        (UserTypeAnnotation::TypeOf)(def, substs),
+    }
+}
+
+EnumLiftImpl! {
+    impl<'a, 'tcx> Lift<'tcx> for UserTypeAnnotation<'a> {
+        type Lifted = UserTypeAnnotation<'tcx>;
+        (UserTypeAnnotation::Ty)(ty),
+        (UserTypeAnnotation::TypeOf)(def, substs),
+    }
+}
+
 impl<'tcx> CommonTypes<'tcx> {
     fn new(interners: &CtxtInterners<'tcx>) -> CommonTypes<'tcx> {
         let mk = |sty| CtxtInterners::intern_ty(interners, interners, sty);
diff --git a/src/librustc/ty/mod.rs b/src/librustc/ty/mod.rs
index 8348aa8a956..d40dd830e9f 100644
--- a/src/librustc/ty/mod.rs
+++ b/src/librustc/ty/mod.rs
@@ -73,6 +73,10 @@ 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,
+};
 
 pub use self::instance::{Instance, InstanceDef};
 
diff --git a/src/librustc/ty/query/mod.rs b/src/librustc/ty/query/mod.rs
index 22bd1cd90a7..842aea07614 100644
--- a/src/librustc/ty/query/mod.rs
+++ b/src/librustc/ty/query/mod.rs
@@ -26,8 +26,8 @@ use session::config::OutputFilenames;
 use traits::{self, Vtable};
 use traits::query::{
     CanonicalPredicateGoal, CanonicalProjectionGoal,
-    CanonicalTyGoal, CanonicalTypeOpAscribeUserTypeGoal, CanonicalTypeOpEqGoal,
-    CanonicalTypeOpSubtypeGoal, CanonicalTypeOpProvePredicateGoal,
+    CanonicalTyGoal, CanonicalTypeOpAscribeUserTypeGoal,
+    CanonicalTypeOpEqGoal, CanonicalTypeOpSubtypeGoal, CanonicalTypeOpProvePredicateGoal,
     CanonicalTypeOpNormalizeGoal, NoSolution,
 };
 use traits::query::method_autoderef::MethodAutoderefStepsResult;
diff --git a/src/librustc/ty/subst.rs b/src/librustc/ty/subst.rs
index 560e80abb9c..64e7af815b4 100644
--- a/src/librustc/ty/subst.rs
+++ b/src/librustc/ty/subst.rs
@@ -2,12 +2,11 @@
 
 use hir::def_id::DefId;
 use infer::canonical::Canonical;
-use ty::{self, BoundVar, Lift, List, Ty, TyCtxt};
+use ty::{self, Lift, List, Ty, TyCtxt};
 use ty::fold::{TypeFoldable, TypeFolder, TypeVisitor};
 
 use serialize::{self, Encodable, Encoder, Decodable, Decoder};
 use syntax_pos::{Span, DUMMY_SP};
-use rustc_data_structures::indexed_vec::Idx;
 use smallvec::SmallVec;
 
 use core::intrinsics;
@@ -559,43 +558,6 @@ impl<'a, 'gcx, 'tcx> SubstFolder<'a, 'gcx, 'tcx> {
 
 pub type CanonicalUserSubsts<'tcx> = Canonical<'tcx, UserSubsts<'tcx>>;
 
-impl CanonicalUserSubsts<'tcx> {
-    /// True if this represents a substitution like
-    ///
-    /// ```text
-    /// [?0, ?1, ?2]
-    /// ```
-    ///
-    /// i.e., each thing is mapped to a canonical variable with the same index.
-    pub fn is_identity(&self) -> bool {
-        if self.value.user_self_ty.is_some() {
-            return false;
-        }
-
-        self.value.substs.iter().zip(BoundVar::new(0)..).all(|(kind, cvar)| {
-            match kind.unpack() {
-                UnpackedKind::Type(ty) => match ty.sty {
-                    ty::Bound(debruijn, b) => {
-                        // We only allow a `ty::INNERMOST` index in substitutions.
-                        assert_eq!(debruijn, ty::INNERMOST);
-                        cvar == b.var
-                    }
-                    _ => false,
-                },
-
-                UnpackedKind::Lifetime(r) => match r {
-                    ty::ReLateBound(debruijn, br) => {
-                        // We only allow a `ty::INNERMOST` index in substitutions.
-                        assert_eq!(*debruijn, ty::INNERMOST);
-                        cvar == br.assert_bound_var()
-                    }
-                    _ => false,
-                },
-            }
-        })
-    }
-}
-
 /// Stores the user-given substs to reach some fully qualified path
 /// (e.g., `<T>::Item` or `<T as Trait>::Item`).
 #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, RustcEncodable, RustcDecodable)]
diff --git a/src/librustc/ty/wf.rs b/src/librustc/ty/wf.rs
index f4a998fb990..aacc63c47de 100644
--- a/src/librustc/ty/wf.rs
+++ b/src/librustc/ty/wf.rs
@@ -289,6 +289,11 @@ impl<'a, 'gcx, 'tcx> WfPredicates<'a, 'gcx, 'tcx> {
                     self.out.extend(obligations);
                 }
 
+                ty::FnDef(did, substs) => {
+                    let obligations = self.nominal_obligations(did, substs);
+                    self.out.extend(obligations);
+                }
+
                 ty::Ref(r, rty, _) => {
                     // WfReference
                     if !r.has_escaping_bound_vars() && !rty.has_escaping_bound_vars() {
@@ -349,7 +354,7 @@ impl<'a, 'gcx, 'tcx> WfPredicates<'a, 'gcx, 'tcx> {
                     }
                 }
 
-                ty::FnDef(..) | ty::FnPtr(_) => {
+                ty::FnPtr(_) => {
                     // let the loop iterate into the argument/return
                     // types appearing in the fn signature
                 }
diff --git a/src/librustc_mir/borrow_check/nll/mod.rs b/src/librustc_mir/borrow_check/nll/mod.rs
index c5eabbbefa9..a092c3b8ecd 100644
--- a/src/librustc_mir/borrow_check/nll/mod.rs
+++ b/src/librustc_mir/borrow_check/nll/mod.rs
@@ -230,13 +230,14 @@ fn dump_mir_results<'a, 'gcx, 'tcx>(
                 // Before the CFG, dump out the values for each region variable.
                 PassWhere::BeforeCFG => {
                     regioncx.dump_mir(out)?;
+                    writeln!(out, "|")?;
 
                     if let Some(closure_region_requirements) = closure_region_requirements {
-                        writeln!(out, "|")?;
                         writeln!(out, "| Free Region Constraints")?;
                         for_each_region_constraint(closure_region_requirements, &mut |msg| {
                             writeln!(out, "| {}", msg)
                         })?;
+                        writeln!(out, "|")?;
                     }
                 }
 
diff --git a/src/librustc_mir/borrow_check/nll/renumber.rs b/src/librustc_mir/borrow_check/nll/renumber.rs
index 673ee4ec017..55af7399aab 100644
--- a/src/librustc_mir/borrow_check/nll/renumber.rs
+++ b/src/librustc_mir/borrow_check/nll/renumber.rs
@@ -1,6 +1,10 @@
+use rustc::infer::canonical::Canonical;
 use rustc::ty::subst::Substs;
-use rustc::ty::{self, ClosureSubsts, GeneratorSubsts, Ty, TypeFoldable};
-use rustc::mir::{Location, Mir, UserTypeAnnotation};
+use rustc::ty::{
+    self, ClosureSubsts, GeneratorSubsts, Ty, TypeFoldable, UserTypeAnnotation,
+    UserTypeAnnotationIndex,
+};
+use rustc::mir::{Location, Mir};
 use rustc::mir::visit::{MutVisitor, TyContext};
 use rustc::infer::{InferCtxt, NLLRegionVariableOrigin};
 
@@ -55,7 +59,11 @@ impl<'a, 'gcx, 'tcx> MutVisitor<'tcx> for NLLVisitor<'a, 'gcx, 'tcx> {
         debug!("visit_ty: ty={:?}", ty);
     }
 
-    fn visit_user_type_annotation(&mut self, _ty: &mut UserTypeAnnotation<'tcx>) {
+    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
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 6d2fb54587e..796a2f79f75 100644
--- a/src/librustc_mir/borrow_check/nll/type_check/mod.rs
+++ b/src/librustc_mir/borrow_check/nll/type_check/mod.rs
@@ -36,7 +36,10 @@ 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::{self, RegionVid, ToPolyTraitRef, Ty, TyCtxt, TyKind};
+use rustc::ty::{
+    self, RegionVid, ToPolyTraitRef, Ty, TyCtxt, TyKind, UserTypeAnnotation,
+    UserTypeAnnotationIndex,
+};
 use rustc_data_structures::fx::{FxHashMap, FxHashSet};
 use rustc_data_structures::indexed_vec::{IndexVec, Idx};
 use rustc::ty::layout::VariantIdx;
@@ -272,19 +275,20 @@ impl<'a, 'b, 'gcx, 'tcx> Visitor<'tcx> for TypeVerifier<'a, 'b, 'gcx, 'tcx> {
         self.sanitize_constant(constant, location);
         self.sanitize_type(constant, constant.ty);
 
-        if let Some(user_ty) = constant.user_ty {
+        if let Some(annotation_index) = constant.user_ty {
             if let Err(terr) = self.cx.relate_type_and_user_type(
                 constant.ty,
                 ty::Variance::Invariant,
-                &UserTypeProjection { base: user_ty, projs: vec![], },
+                &UserTypeProjection { base: annotation_index, projs: vec![], },
                 location.to_locations(),
                 ConstraintCategory::Boring,
             ) {
+                let annotation = self.cx.instantiated_type_annotations[&annotation_index];
                 span_mirbug!(
                     self,
                     constant,
                     "bad constant user type {:?} vs {:?}: {:?}",
-                    user_ty,
+                    annotation,
                     constant.ty,
                     terr,
                 );
@@ -303,8 +307,20 @@ impl<'a, 'b, 'gcx, 'tcx> Visitor<'tcx> for TypeVerifier<'a, 'b, 'gcx, 'tcx> {
         self.sanitize_type(local_decl, local_decl.ty);
 
         for (user_ty, span) in local_decl.user_ty.projections_and_spans() {
+            let ty = if !local_decl.is_nonref_binding() {
+                // If we have a binding of the form `let ref x: T = ..` then remove the outermost
+                // reference so we can check the type annotation for the remaining type.
+                if let ty::Ref(_, rty, _) = local_decl.ty.sty {
+                    rty
+                } else {
+                    bug!("{:?} with ref binding has wrong type {}", local, local_decl.ty);
+                }
+            } else {
+                local_decl.ty
+            };
+
             if let Err(terr) = self.cx.relate_type_and_user_type(
-                local_decl.ty,
+                ty,
                 ty::Variance::Invariant,
                 user_ty,
                 Locations::All(*span),
@@ -715,6 +731,15 @@ 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> {
@@ -860,7 +885,7 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> {
         borrowck_context: Option<&'a mut BorrowCheckContext<'a, 'tcx>>,
         universal_region_relations: Option<&'a UniversalRegionRelations<'tcx>>,
     ) -> Self {
-        TypeChecker {
+        let mut checker = Self {
             infcx,
             last_span: DUMMY_SP,
             mir,
@@ -871,7 +896,36 @@ 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
+    }
+
+    /// 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) {
+        debug!(
+            "instantiate_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
+            );
+            match annotation {
+                UserTypeAnnotation::Ty(ref mut ty) =>
+                    *ty = self.normalize(ty, Locations::All(*span)),
+                _ => {},
+            }
+            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
@@ -1003,18 +1057,14 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> {
             a, v, user_ty, locations,
         );
 
-        match user_ty.base {
-            UserTypeAnnotation::Ty(canonical_ty) => {
-                let (ty, _) = self.infcx
-                    .instantiate_canonical_with_fresh_inference_vars(DUMMY_SP, &canonical_ty);
-
+        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 ty = self.normalize(ty, locations);
 
                 // We need to follow any provided projetions into the type.
                 //
@@ -1048,13 +1098,7 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> {
                     self.relate_types(ty, v1, a, locations, category)?;
                 }
             }
-            UserTypeAnnotation::TypeOf(def_id, canonical_substs) => {
-                let (
-                    user_substs,
-                    _,
-                ) = self.infcx
-                    .instantiate_canonical_with_fresh_inference_vars(DUMMY_SP, &canonical_substs);
-
+            UserTypeAnnotation::TypeOf(def_id, user_substs) => {
                 let projs = self.infcx.tcx.intern_projs(&user_ty.projs);
                 self.fully_perform_op(
                     locations,
@@ -1225,19 +1269,20 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> {
                     );
                 }
 
-                if let Some(user_ty) = self.rvalue_user_ty(rv) {
+                if let Some(annotation_index) = self.rvalue_user_ty(rv) {
                     if let Err(terr) = self.relate_type_and_user_type(
                         rv_ty,
                         ty::Variance::Invariant,
-                        &UserTypeProjection { base: user_ty, projs: vec![], },
+                        &UserTypeProjection { base: annotation_index, projs: vec![], },
                         location.to_locations(),
                         ConstraintCategory::Boring,
                     ) {
+                        let annotation = self.instantiated_type_annotations[&annotation_index];
                         span_mirbug!(
                             self,
                             stmt,
                             "bad user type on rvalue ({:?} = {:?}): {:?}",
-                            user_ty,
+                            annotation,
                             rv_ty,
                             terr
                         );
@@ -1282,21 +1327,23 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> {
                     );
                 };
             }
-            StatementKind::AscribeUserType(ref place, variance, box ref c_ty) => {
+            StatementKind::AscribeUserType(ref place, variance, box ref projection) => {
                 let place_ty = place.ty(mir, tcx).to_ty(tcx);
                 if let Err(terr) = self.relate_type_and_user_type(
                     place_ty,
                     variance,
-                    c_ty,
+                    projection,
                     Locations::All(stmt.source_info.span),
                     ConstraintCategory::TypeAnnotation,
                 ) {
+                    let annotation = self.instantiated_type_annotations[&projection.base];
                     span_mirbug!(
                         self,
                         stmt,
-                        "bad type assert ({:?} <: {:?}): {:?}",
+                        "bad type assert ({:?} <: {:?} with projections {:?}): {:?}",
                         place_ty,
-                        c_ty,
+                        annotation,
+                        projection.projs,
                         terr
                     );
                 }
@@ -1955,7 +2002,7 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> {
     /// If this rvalue supports a user-given type annotation, then
     /// extract and return it. This represents the final type of the
     /// rvalue and will be unified with the inferred type.
-    fn rvalue_user_ty(&self, rvalue: &Rvalue<'tcx>) -> Option<UserTypeAnnotation<'tcx>> {
+    fn rvalue_user_ty(&self, rvalue: &Rvalue<'tcx>) -> Option<UserTypeAnnotationIndex> {
         match rvalue {
             Rvalue::Use(_)
             | Rvalue::Repeat(..)
diff --git a/src/librustc_mir/build/block.rs b/src/librustc_mir/build/block.rs
index ad4e5a50dcd..f3d89a7a025 100644
--- a/src/librustc_mir/build/block.rs
+++ b/src/librustc_mir/build/block.rs
@@ -141,9 +141,10 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
                             None, remainder_span, lint_level, slice::from_ref(&pattern),
                             ArmHasGuard(false), None);
 
+                        debug!("ast_block_stmts: pattern={:?}", pattern);
                         this.visit_bindings(
                             &pattern,
-                            &PatternTypeProjections::none(),
+                            UserTypeProjections::none(),
                             &mut |this, _, _, _, node, span, _, _| {
                                 this.storage_live_binding(block, node, span, OutsideGuard);
                                 this.schedule_drop_for_binding(node, span, OutsideGuard);
diff --git a/src/librustc_mir/build/expr/as_constant.rs b/src/librustc_mir/build/expr/as_constant.rs
index a5fbe566a4a..a431bfc61b3 100644
--- a/src/librustc_mir/build/expr/as_constant.rs
+++ b/src/librustc_mir/build/expr/as_constant.rs
@@ -29,11 +29,16 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
                 lint_level: _,
                 value,
             } => this.as_constant(value),
-            ExprKind::Literal { literal, user_ty } => Constant {
-                span,
-                ty,
-                user_ty,
-                literal,
+            ExprKind::Literal { literal, user_ty } => {
+                let user_ty = user_ty.map(|ty| {
+                    this.canonical_user_type_annotations.push((span, ty))
+                });
+                Constant {
+                    span,
+                    ty,
+                    user_ty,
+                    literal,
+                }
             },
             _ => span_bug!(span, "expression is not a valid constant {:?}", kind),
         }
diff --git a/src/librustc_mir/build/expr/as_place.rs b/src/librustc_mir/build/expr/as_place.rs
index d651b6bdca0..3ed00d57979 100644
--- a/src/librustc_mir/build/expr/as_place.rs
+++ b/src/librustc_mir/build/expr/as_place.rs
@@ -133,6 +133,9 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
             ExprKind::PlaceTypeAscription { source, user_ty } => {
                 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)
+                    );
                     this.cfg.push(
                         block,
                         Statement {
@@ -140,7 +143,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
                             kind: StatementKind::AscribeUserType(
                                 place.clone(),
                                 Variance::Invariant,
-                                box UserTypeProjection { base: user_ty, projs: vec![], },
+                                box UserTypeProjection { base: annotation_index, projs: vec![], },
                             ),
                         },
                     );
@@ -153,6 +156,9 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
                     block = this.as_temp(block, source.temp_lifetime, source, mutability)
                 );
                 if let Some(user_ty) = user_ty {
+                    let annotation_index = this.canonical_user_type_annotations.push(
+                        (source_info.span, user_ty)
+                    );
                     this.cfg.push(
                         block,
                         Statement {
@@ -160,7 +166,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
                             kind: StatementKind::AscribeUserType(
                                 Place::Local(temp.clone()),
                                 Variance::Invariant,
-                                box UserTypeProjection { base: user_ty, projs: vec![], },
+                                box UserTypeProjection { base: annotation_index, projs: vec![], },
                             ),
                         },
                     );
diff --git a/src/librustc_mir/build/expr/as_rvalue.rs b/src/librustc_mir/build/expr/as_rvalue.rs
index 2f0e06cd4da..7dcac05e702 100644
--- a/src/librustc_mir/build/expr/as_rvalue.rs
+++ b/src/librustc_mir/build/expr/as_rvalue.rs
@@ -331,6 +331,9 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
                         .collect()
                 };
 
+                let user_ty = user_ty.map(|ty| {
+                    this.canonical_user_type_annotations.push((expr_span, ty))
+                });
                 let adt = box AggregateKind::Adt(
                     adt_def,
                     variant_index,
diff --git a/src/librustc_mir/build/matches/mod.rs b/src/librustc_mir/build/matches/mod.rs
index 86dbf142273..fe5bc6e19db 100644
--- a/src/librustc_mir/build/matches/mod.rs
+++ b/src/librustc_mir/build/matches/mod.rs
@@ -8,7 +8,6 @@ use build::ForGuard::{self, OutsideGuard, RefWithinGuard, ValWithinGuard};
 use build::{BlockAnd, BlockAndExtension, Builder};
 use build::{GuardFrame, GuardFrameLocal, LocalsForNode};
 use hair::*;
-use hair::pattern::PatternTypeProjections;
 use rustc::mir::*;
 use rustc::ty::{self, Ty};
 use rustc::ty::layout::VariantIdx;
@@ -302,6 +301,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
+                );
                 self.cfg.push(
                     block,
                     Statement {
@@ -309,7 +311,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
                         kind: StatementKind::AscribeUserType(
                             place,
                             ty::Variance::Invariant,
-                            box pat_ascription_ty.user_ty(),
+                            user_ty,
                         ),
                     },
                 );
@@ -406,9 +408,10 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
         );
         let mut scope = self.source_scope;
         let num_patterns = patterns.len();
+        debug!("declare_bindings: patterns={:?}", patterns);
         self.visit_bindings(
             &patterns[0],
-            &PatternTypeProjections::none(),
+            UserTypeProjections::none(),
             &mut |this, mutability, name, mode, var, span, ty, user_ty| {
                 if visibility_scope.is_none() {
                     visibility_scope =
@@ -484,7 +487,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
     pub(super) fn visit_bindings(
         &mut self,
         pattern: &Pattern<'tcx>,
-        pattern_user_ty: &PatternTypeProjections<'tcx>,
+        pattern_user_ty: UserTypeProjections<'tcx>,
         f: &mut impl FnMut(
             &mut Self,
             Mutability,
@@ -493,9 +496,10 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
             NodeId,
             Span,
             Ty<'tcx>,
-            &PatternTypeProjections<'tcx>,
+            UserTypeProjections<'tcx>,
         ),
     ) {
+        debug!("visit_bindings: pattern={:?} pattern_user_ty={:?}", pattern, pattern_user_ty);
         match *pattern.kind {
             PatternKind::Binding {
                 mutability,
@@ -506,19 +510,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
                 ref subpattern,
                 ..
             } => {
-                let pattern_ref_binding; // sidestep temp lifetime limitations.
-                let binding_user_ty = match mode {
-                    BindingMode::ByValue => { pattern_user_ty }
-                    BindingMode::ByRef(..) => {
-                        // If this is a `ref` binding (e.g., `let ref
-                        // x: T = ..`), then the type of `x` is not
-                        // `T` but rather `&T`.
-                        pattern_ref_binding = pattern_user_ty.ref_binding();
-                        &pattern_ref_binding
-                    }
-                };
-
-                f(self, mutability, name, mode, var, pattern.span, ty, binding_user_ty);
+                f(self, mutability, name, mode, var, pattern.span, ty, pattern_user_ty.clone());
                 if let Some(subpattern) = subpattern.as_ref() {
                     self.visit_bindings(subpattern, pattern_user_ty, f);
                 }
@@ -536,18 +528,18 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
                 let from = u32::try_from(prefix.len()).unwrap();
                 let to = u32::try_from(suffix.len()).unwrap();
                 for subpattern in prefix {
-                    self.visit_bindings(subpattern, &pattern_user_ty.index(), f);
+                    self.visit_bindings(subpattern, pattern_user_ty.clone().index(), f);
                 }
                 for subpattern in slice {
-                    self.visit_bindings(subpattern, &pattern_user_ty.subslice(from, to), f);
+                    self.visit_bindings(subpattern, pattern_user_ty.clone().subslice(from, to), f);
                 }
                 for subpattern in suffix {
-                    self.visit_bindings(subpattern, &pattern_user_ty.index(), f);
+                    self.visit_bindings(subpattern, pattern_user_ty.clone().index(), f);
                 }
             }
             PatternKind::Constant { .. } | PatternKind::Range { .. } | PatternKind::Wild => {}
             PatternKind::Deref { ref subpattern } => {
-                self.visit_bindings(subpattern, &pattern_user_ty.deref(), f);
+                self.visit_bindings(subpattern, pattern_user_ty.deref(), f);
             }
             PatternKind::AscribeUserType { ref subpattern, ref user_ty, user_ty_span } => {
                 // This corresponds to something like
@@ -555,22 +547,28 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
                 // ```
                 // let A::<'a>(_): A<'static> = ...;
                 // ```
-                let subpattern_user_ty = pattern_user_ty.add_user_type(user_ty, user_ty_span);
-                self.visit_bindings(subpattern, &subpattern_user_ty, f)
+                let annotation = (user_ty_span, user_ty.base);
+                let projection = UserTypeProjection {
+                    base: self.canonical_user_type_annotations.push(annotation),
+                    projs: user_ty.projs.clone(),
+                };
+                let subpattern_user_ty = pattern_user_ty.push_projection(&projection, user_ty_span);
+                self.visit_bindings(subpattern, subpattern_user_ty, f)
             }
 
             PatternKind::Leaf { ref subpatterns } => {
                 for subpattern in subpatterns {
-                    let subpattern_user_ty = pattern_user_ty.leaf(subpattern.field);
-                    self.visit_bindings(&subpattern.pattern, &subpattern_user_ty, f);
+                    let subpattern_user_ty = pattern_user_ty.clone().leaf(subpattern.field);
+                    debug!("visit_bindings: subpattern_user_ty={:?}", subpattern_user_ty);
+                    self.visit_bindings(&subpattern.pattern, subpattern_user_ty, f);
                 }
             }
 
             PatternKind::Variant { adt_def, substs: _, variant_index, ref subpatterns } => {
                 for subpattern in subpatterns {
-                    let subpattern_user_ty = pattern_user_ty.variant(
+                    let subpattern_user_ty = pattern_user_ty.clone().variant(
                         adt_def, variant_index, subpattern.field);
-                    self.visit_bindings(&subpattern.pattern, &subpattern_user_ty, f);
+                    self.visit_bindings(&subpattern.pattern, subpattern_user_ty, f);
                 }
             }
         }
@@ -1314,6 +1312,9 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
                 ascription.user_ty,
             );
 
+            let user_ty = box ascription.user_ty.clone().user_ty(
+                &mut self.canonical_user_type_annotations, source_info.span
+            );
             self.cfg.push(
                 block,
                 Statement {
@@ -1321,7 +1322,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
                     kind: StatementKind::AscribeUserType(
                         ascription.source.clone(),
                         ty::Variance::Covariant,
-                        box ascription.user_ty.clone().user_ty(),
+                        user_ty,
                     ),
                 },
             );
@@ -1468,7 +1469,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
         num_patterns: usize,
         var_id: NodeId,
         var_ty: Ty<'tcx>,
-        user_var_ty: &PatternTypeProjections<'tcx>,
+        user_ty: UserTypeProjections<'tcx>,
         has_guard: ArmHasGuard,
         opt_match_place: Option<(Option<Place<'tcx>>, Span)>,
         pat_span: Span,
@@ -1484,10 +1485,11 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
             BindingMode::ByValue => ty::BindingMode::BindByValue(mutability.into()),
             BindingMode::ByRef { .. } => ty::BindingMode::BindByReference(mutability.into()),
         };
+        debug!("declare_binding: user_ty={:?}", user_ty);
         let local = LocalDecl::<'tcx> {
             mutability,
             ty: var_ty,
-            user_ty: user_var_ty.clone().user_ty(),
+            user_ty,
             name: Some(name),
             source_info,
             visibility_scope,
diff --git a/src/librustc_mir/build/mod.rs b/src/librustc_mir/build/mod.rs
index a700963749f..8acdecf6fa2 100644
--- a/src/librustc_mir/build/mod.rs
+++ b/src/librustc_mir/build/mod.rs
@@ -379,6 +379,7 @@ struct Builder<'a, 'gcx: 'a+'tcx, 'tcx: 'a> {
     /// (A match binding can have two locals; the 2nd is for the arm's guard.)
     var_indices: NodeMap<LocalsForNode>,
     local_decls: IndexVec<Local, LocalDecl<'tcx>>,
+    canonical_user_type_annotations: ty::CanonicalUserTypeAnnotations<'tcx>,
     upvar_decls: Vec<UpvarDecl>,
     unit_temp: Option<Place<'tcx>>,
 
@@ -812,6 +813,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
                 LocalDecl::new_return_place(return_ty, return_span),
                 1,
             ),
+            canonical_user_type_annotations: IndexVec::new(),
             upvar_decls,
             var_indices: Default::default(),
             unit_temp: None,
@@ -845,6 +847,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
             IndexVec::new(),
             yield_ty,
             self.local_decls,
+            self.canonical_user_type_annotations,
             self.arg_count,
             self.upvar_decls,
             self.fn_span,
diff --git a/src/librustc_mir/hair/cx/block.rs b/src/librustc_mir/hair/cx/block.rs
index 91568f7ff6b..e73cc40c8c6 100644
--- a/src/librustc_mir/hair/cx/block.rs
+++ b/src/librustc_mir/hair/cx/block.rs
@@ -78,12 +78,13 @@ fn mirror_stmts<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>,
                         let mut pattern = cx.pattern_from_hir(&local.pat);
 
                         if let Some(ty) = &local.ty {
-                            if let Some(&user_ty) = cx.tables.user_provided_tys().get(ty.hir_id) {
+                            if let Some(&user_ty) = cx.tables.user_provided_types().get(ty.hir_id) {
+                                debug!("mirror_stmts: user_ty={:?}", user_ty);
                                 pattern = Pattern {
                                     ty: pattern.ty,
                                     span: pattern.span,
                                     kind: Box::new(PatternKind::AscribeUserType {
-                                        user_ty: PatternTypeProjection::from_canonical_ty(user_ty),
+                                        user_ty: PatternTypeProjection::from_user_type(user_ty),
                                         user_ty_span: ty.span,
                                         subpattern: pattern
                                     })
diff --git a/src/librustc_mir/hair/cx/expr.rs b/src/librustc_mir/hair/cx/expr.rs
index 7b1ed2b0b26..293058a0f26 100644
--- a/src/librustc_mir/hair/cx/expr.rs
+++ b/src/librustc_mir/hair/cx/expr.rs
@@ -11,7 +11,7 @@ use rustc::ty::adjustment::{Adjustment, Adjust, AutoBorrow, AutoBorrowMutability
 use rustc::ty::cast::CastKind as TyCastKind;
 use rustc::hir;
 use rustc::hir::def_id::LocalDefId;
-use rustc::mir::{BorrowKind};
+use rustc::mir::BorrowKind;
 use syntax_pos::Span;
 
 impl<'tcx> Mirror<'tcx> for &'tcx hir::Expr {
@@ -283,9 +283,16 @@ fn make_mirror_unadjusted<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>,
                 };
                 if let Some((adt_def, index)) = adt_data {
                     let substs = cx.tables().node_substs(fun.hir_id);
-
-                    let user_ty = cx.tables().user_substs(fun.hir_id)
-                        .map(|user_substs| UserTypeAnnotation::TypeOf(adt_def.did, user_substs));
+                    let user_provided_types = cx.tables().user_provided_types();
+                    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 {
+                                *did = adt_def.did;
+                            }
+                            u_ty
+                        });
+                    debug!("make_mirror_unadjusted: (call) user_ty={:?}", user_ty);
 
                     let field_refs = args.iter()
                         .enumerate()
@@ -464,11 +471,14 @@ fn make_mirror_unadjusted<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>,
                 ty::Adt(adt, substs) => {
                     match adt.adt_kind() {
                         AdtKind::Struct | AdtKind::Union => {
+                            let user_provided_types = cx.tables().user_provided_types();
+                            let user_ty = user_provided_types.get(expr.hir_id).map(|u_ty| *u_ty);
+                            debug!("make_mirror_unadjusted: (struct/union) user_ty={:?}", user_ty);
                             ExprKind::Adt {
                                 adt_def: adt,
                                 variant_index: VariantIdx::new(0),
                                 substs,
-                                user_ty: cx.user_substs_applied_to_adt(expr.hir_id, adt),
+                                user_ty,
                                 fields: field_refs(cx, fields),
                                 base: base.as_ref().map(|base| {
                                     FruInfo {
@@ -487,11 +497,18 @@ fn make_mirror_unadjusted<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>,
                                     assert!(base.is_none());
 
                                     let index = adt.variant_index_with_id(variant_id);
+                                    let user_provided_types = cx.tables().user_provided_types();
+                                    let user_ty = user_provided_types.get(expr.hir_id)
+                                        .map(|u_ty| *u_ty);
+                                    debug!(
+                                        "make_mirror_unadjusted: (variant) user_ty={:?}",
+                                        user_ty
+                                    );
                                     ExprKind::Adt {
                                         adt_def: adt,
                                         variant_index: index,
                                         substs,
-                                        user_ty: cx.user_substs_applied_to_adt(expr.hir_id, adt),
+                                        user_ty,
                                         fields: field_refs(cx, fields),
                                         base: None,
                                     }
@@ -635,8 +652,8 @@ fn make_mirror_unadjusted<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>,
         }
         hir::ExprKind::Cast(ref source, ref cast_ty) => {
             // Check for a user-given type annotation on this `cast`
-            let user_ty = cx.tables.user_provided_tys().get(cast_ty.hir_id)
-                .map(|&t| UserTypeAnnotation::Ty(t));
+            let user_provided_types = cx.tables.user_provided_types();
+            let user_ty = user_provided_types.get(cast_ty.hir_id);
 
             debug!(
                 "cast({:?}) has ty w/ hir_id {:?} and user provided ty {:?}",
@@ -742,20 +759,20 @@ fn make_mirror_unadjusted<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>,
                     span: expr.span,
                     kind: cast,
                 };
+                debug!("make_mirror_unadjusted: (cast) user_ty={:?}", user_ty);
 
                 ExprKind::ValueTypeAscription {
                     source: cast_expr.to_ref(),
-                    user_ty: Some(user_ty),
+                    user_ty: Some(*user_ty),
                 }
             } else {
                 cast
             }
         }
         hir::ExprKind::Type(ref source, ref ty) => {
-            let user_provided_tys = cx.tables.user_provided_tys();
-            let user_ty = user_provided_tys
-                .get(ty.hir_id)
-                .map(|&c_ty| UserTypeAnnotation::Ty(c_ty));
+            let user_provided_types = cx.tables.user_provided_types();
+            let user_ty = user_provided_types.get(ty.hir_id).map(|u_ty| *u_ty);
+            debug!("make_mirror_unadjusted: (type) user_ty={:?}", user_ty);
             if source.is_place_expr() {
                 ExprKind::PlaceTypeAscription {
                     source: source.to_ref(),
@@ -792,8 +809,9 @@ fn user_substs_applied_to_def(
     cx: &mut Cx<'a, 'gcx, 'tcx>,
     hir_id: hir::HirId,
     def: &Def,
-) -> Option<UserTypeAnnotation<'tcx>> {
-    match def {
+) -> Option<ty::CanonicalUserTypeAnnotation<'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
         // a tuple-struct or tuple-variant. This has the type of a
         // `Fn` but with the user-given substitutions.
@@ -802,8 +820,7 @@ fn user_substs_applied_to_def(
         Def::StructCtor(_, CtorKind::Fn) |
         Def::VariantCtor(_, CtorKind::Fn) |
         Def::Const(_) |
-        Def::AssociatedConst(_) =>
-            Some(UserTypeAnnotation::TypeOf(def.def_id(), cx.tables().user_substs(hir_id)?)),
+        Def::AssociatedConst(_) => cx.tables().user_provided_types().get(hir_id).map(|u_ty| *u_ty),
 
         // A unit struct/variant which is used as a value (e.g.,
         // `None`). This has the type of the enum/struct that defines
@@ -819,7 +836,9 @@ fn user_substs_applied_to_def(
 
         _ =>
             bug!("user_substs_applied_to_def: unexpected def {:?} at {:?}", def, hir_id)
-    }
+    };
+    debug!("user_substs_applied_to_def: user_provided_type={:?}", user_provided_type);
+    user_provided_type
 }
 
 fn method_callee<'a, 'gcx, 'tcx>(
@@ -839,6 +858,7 @@ fn method_callee<'a, 'gcx, 'tcx>(
                     span_bug!(expr.span, "no type-dependent def for method callee")
                 });
             let user_ty = user_substs_applied_to_def(cx, expr.hir_id, def);
+            debug!("method_callee: user_ty={:?}", user_ty);
             (def.def_id(), cx.tables().node_substs(expr.hir_id), user_ty)
         }
     };
@@ -906,6 +926,7 @@ fn convert_path_expr<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>,
         Def::VariantCtor(_, CtorKind::Fn) |
         Def::SelfCtor(..) => {
             let user_ty = user_substs_applied_to_def(cx, expr.hir_id, &def);
+            debug!("convert_path_expr: user_ty={:?}", user_ty);
             ExprKind::Literal {
                 literal: ty::Const::zero_sized(
                     cx.tcx,
@@ -918,6 +939,7 @@ fn convert_path_expr<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>,
         Def::Const(def_id) |
         Def::AssociatedConst(def_id) => {
             let user_ty = user_substs_applied_to_def(cx, expr.hir_id, &def);
+            debug!("convert_path_expr: (const) user_ty={:?}", user_ty);
             ExprKind::Literal {
                 literal: ty::Const::unevaluated(
                     cx.tcx,
@@ -931,6 +953,9 @@ fn convert_path_expr<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>,
 
         Def::StructCtor(def_id, CtorKind::Const) |
         Def::VariantCtor(def_id, CtorKind::Const) => {
+            let user_provided_types = cx.tables.user_provided_types();
+            let user_provided_type = user_provided_types.get(expr.hir_id).map(|u_ty| *u_ty);
+            debug!("convert_path_expr: user_provided_type={:?}", user_provided_type);
             match cx.tables().node_id_to_type(expr.hir_id).sty {
                 // A unit struct/variant which is used as a value.
                 // We return a completely different ExprKind here to account for this special case.
@@ -939,7 +964,7 @@ fn convert_path_expr<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>,
                         adt_def,
                         variant_index: adt_def.variant_index_with_id(def_id),
                         substs,
-                        user_ty: cx.user_substs_applied_to_adt(expr.hir_id, adt_def),
+                        user_ty: user_provided_type,
                         fields: vec![],
                         base: None,
                     }
diff --git a/src/librustc_mir/hair/mod.rs b/src/librustc_mir/hair/mod.rs
index bcca501e600..b56e3d4e773 100644
--- a/src/librustc_mir/hair/mod.rs
+++ b/src/librustc_mir/hair/mod.rs
@@ -4,11 +4,12 @@
 //! unit-tested and separated from the Rust source and compiler data
 //! structures.
 
-use rustc::mir::{BinOp, BorrowKind, UserTypeAnnotation, Field, UnOp};
+use rustc::mir::{BinOp, BorrowKind, Field, UnOp};
 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, Region, Ty, Const};
+use rustc::ty::{AdtDef, UpvarSubsts, Region, Ty, Const, UserTypeAnnotation};
 use rustc::ty::layout::VariantIdx;
 use rustc::hir;
 use syntax::ast;
@@ -20,7 +21,7 @@ mod constant;
 
 pub mod pattern;
 pub use self::pattern::{BindingMode, Pattern, PatternKind, PatternRange, FieldPattern};
-pub(crate) use self::pattern::{PatternTypeProjection, PatternTypeProjections};
+pub(crate) use self::pattern::PatternTypeProjection;
 
 mod util;
 
@@ -265,7 +266,7 @@ pub enum ExprKind<'tcx> {
 
         /// Optional user-given substs: for something like `let x =
         /// Bar::<T> { ... }`.
-        user_ty: Option<UserTypeAnnotation<'tcx>>,
+        user_ty: Option<Canonical<'tcx, UserTypeAnnotation<'tcx>>>,
 
         fields: Vec<FieldExprRef<'tcx>>,
         base: Option<FruInfo<'tcx>>
@@ -273,12 +274,12 @@ pub enum ExprKind<'tcx> {
     PlaceTypeAscription {
         source: ExprRef<'tcx>,
         /// Type that the user gave to this expression
-        user_ty: Option<UserTypeAnnotation<'tcx>>,
+        user_ty: Option<Canonical<'tcx, UserTypeAnnotation<'tcx>>>,
     },
     ValueTypeAscription {
         source: ExprRef<'tcx>,
         /// Type that the user gave to this expression
-        user_ty: Option<UserTypeAnnotation<'tcx>>,
+        user_ty: Option<Canonical<'tcx, UserTypeAnnotation<'tcx>>>,
     },
     Closure {
         closure_id: DefId,
@@ -288,7 +289,7 @@ pub enum ExprKind<'tcx> {
     },
     Literal {
         literal: &'tcx Const<'tcx>,
-        user_ty: Option<UserTypeAnnotation<'tcx>>,
+        user_ty: Option<Canonical<'tcx, UserTypeAnnotation<'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 62ec52aac13..10d2d7bc1b1 100644
--- a/src/librustc_mir/hair/pattern/mod.rs
+++ b/src/librustc_mir/hair/pattern/mod.rs
@@ -12,9 +12,10 @@ use hair::util::UserAnnotatedTyHelpers;
 use hair::constant::*;
 
 use rustc::mir::{fmt_const_val, Field, BorrowKind, Mutability};
-use rustc::mir::{ProjectionElem, UserTypeAnnotation, UserTypeProjection, UserTypeProjections};
+use rustc::mir::{ProjectionElem, 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::subst::{Substs, Kind};
 use rustc::ty::layout::VariantIdx;
 use rustc::hir::{self, PatKind, RangeEnd};
@@ -58,113 +59,29 @@ pub struct Pattern<'tcx> {
 
 
 #[derive(Clone, Debug)]
-pub(crate) struct PatternTypeProjections<'tcx> {
-    contents: Vec<(PatternTypeProjection<'tcx>, Span)>,
+pub struct PatternTypeProjection<'tcx> {
+    pub base: CanonicalUserTypeAnnotation<'tcx>,
+    pub projs: Vec<ProjectionElem<'tcx, (), ()>>,
 }
 
-impl<'tcx> PatternTypeProjections<'tcx> {
-    pub(crate) fn user_ty(self) -> UserTypeProjections<'tcx> {
-        UserTypeProjections::from_projections(
-            self.contents.into_iter().map(|(pat_ty_proj, span)| (pat_ty_proj.user_ty(), span)))
-    }
-
-    pub(crate) fn none() -> Self {
-        PatternTypeProjections { contents: vec![] }
-    }
-
-    pub(crate) fn ref_binding(&self) -> Self {
-        // FIXME(#55401): ignore for now
-        PatternTypeProjections { contents: vec![] }
-    }
-
-    fn map_projs(&self,
-                 mut f: impl FnMut(&PatternTypeProjection<'tcx>) -> PatternTypeProjection<'tcx>)
-                 -> Self
-    {
-        PatternTypeProjections {
-            contents: self.contents
-                .iter()
-                .map(|(proj, span)| (f(proj), *span))
-                .collect(), }
-    }
-
-    pub(crate) fn index(&self) -> Self { self.map_projs(|pat_ty_proj| pat_ty_proj.index()) }
-
-    pub(crate) fn subslice(&self, from: u32, to: u32) -> Self {
-        self.map_projs(|pat_ty_proj| pat_ty_proj.subslice(from, to))
-    }
-
-    pub(crate) fn deref(&self) -> Self { self.map_projs(|pat_ty_proj| pat_ty_proj.deref()) }
-
-    pub(crate) fn leaf(&self, field: Field) -> Self {
-        self.map_projs(|pat_ty_proj| pat_ty_proj.leaf(field))
-    }
-
-    pub(crate) fn variant(&self,
-                          adt_def: &'tcx AdtDef,
-                          variant_index: VariantIdx,
-                          field: Field) -> Self {
-        self.map_projs(|pat_ty_proj| pat_ty_proj.variant(adt_def, variant_index, field))
-    }
-
-    pub(crate) fn add_user_type(&self, user_ty: &PatternTypeProjection<'tcx>, sp: Span) -> Self {
-        let mut new = self.clone();
-        new.contents.push((user_ty.clone(), sp));
-        new
-    }
-}
-
-#[derive(Clone, Debug)]
-pub struct PatternTypeProjection<'tcx>(UserTypeProjection<'tcx>);
-
 impl<'tcx> PatternTypeProjection<'tcx> {
-    pub(crate) fn index(&self) -> Self {
-        let mut new = self.clone();
-        new.0.projs.push(ProjectionElem::Index(()));
-        new
-    }
-
-    pub(crate) fn subslice(&self, from: u32, to: u32) -> Self {
-        let mut new = self.clone();
-        new.0.projs.push(ProjectionElem::Subslice { from, to });
-        new
-    }
-
-    pub(crate) fn deref(&self) -> Self {
-        let mut new = self.clone();
-        new.0.projs.push(ProjectionElem::Deref);
-        new
-    }
-
-    pub(crate) fn leaf(&self, field: Field) -> Self {
-        let mut new = self.clone();
-        new.0.projs.push(ProjectionElem::Field(field, ()));
-        new
-    }
-
-    pub(crate) fn variant(&self,
-                          adt_def: &'tcx AdtDef,
-                          variant_index: VariantIdx,
-                          field: Field) -> Self {
-        let mut new = self.clone();
-        new.0.projs.push(ProjectionElem::Downcast(adt_def, variant_index));
-        new.0.projs.push(ProjectionElem::Field(field, ()));
-        new
-    }
-
-    pub(crate) fn from_canonical_ty(c_ty: ty::CanonicalTy<'tcx>) -> Self {
-        Self::from_user_type(UserTypeAnnotation::Ty(c_ty))
-    }
-
-    pub(crate) fn from_user_type(u_ty: UserTypeAnnotation<'tcx>) -> Self {
-        Self::from_user_type_proj(UserTypeProjection { base: u_ty, projs: vec![], })
+    pub(crate) fn from_user_type(user_annotation: CanonicalUserTypeAnnotation<'tcx>) -> Self {
+        Self {
+            base: user_annotation,
+            projs: Vec::new(),
+        }
     }
 
-    pub(crate) fn from_user_type_proj(u_ty: UserTypeProjection<'tcx>) -> Self {
-        PatternTypeProjection(u_ty)
+    pub(crate) fn user_ty(
+        self,
+        annotations: &mut CanonicalUserTypeAnnotations<'tcx>,
+        span: Span,
+    ) -> UserTypeProjection<'tcx> {
+        UserTypeProjection {
+            base: annotations.push((span, self.base)),
+            projs: self.projs
+        }
     }
-
-    pub(crate) fn user_ty(self) -> UserTypeProjection<'tcx> { self.0 }
 }
 
 #[derive(Clone, Debug)]
@@ -788,18 +705,14 @@ impl<'a, 'tcx> PatternContext<'a, 'tcx> {
         };
 
         if let Some(user_ty) = self.user_substs_applied_to_ty_of_hir_id(hir_id) {
-            let subpattern = Pattern {
-                span,
-                ty,
-                kind: Box::new(kind),
-            };
-
-            debug!("pattern user_ty = {:?} for pattern at {:?}", user_ty, span);
-
-            let pat_ty = PatternTypeProjection::from_user_type(user_ty);
+            debug!("lower_variant_or_leaf: kind={:?} user_ty={:?} span={:?}", kind, user_ty, span);
             kind = PatternKind::AscribeUserType {
-                subpattern,
-                user_ty: pat_ty,
+                subpattern: Pattern {
+                    span,
+                    ty,
+                    kind: Box::new(kind),
+                },
+                user_ty: PatternTypeProjection::from_user_type(user_ty),
                 user_ty_span: span,
             };
         }
@@ -837,7 +750,28 @@ impl<'a, 'tcx> PatternContext<'a, 'tcx> {
                         };
                         match self.tcx.at(span).const_eval(self.param_env.and(cid)) {
                             Ok(value) => {
-                                return self.const_to_pat(instance, value, id, span)
+                                let pattern = self.const_to_pat(instance, value, id, span);
+                                if !is_associated_const {
+                                    return pattern;
+                                }
+
+                                let user_provided_types = self.tables().user_provided_types();
+                                return if let Some(u_ty) = user_provided_types.get(id) {
+                                    let user_ty = PatternTypeProjection::from_user_type(*u_ty);
+                                    Pattern {
+                                        span,
+                                        kind: Box::new(
+                                            PatternKind::AscribeUserType {
+                                                subpattern: pattern,
+                                                user_ty,
+                                                user_ty_span: span,
+                                            }
+                                        ),
+                                        ty: value.ty,
+                                    }
+                                } else {
+                                    pattern
+                                }
                             },
                             Err(_) => {
                                 self.tcx.sess.span_err(
@@ -927,7 +861,7 @@ impl<'a, 'tcx> PatternContext<'a, 'tcx> {
         id: hir::HirId,
         span: Span,
     ) -> Pattern<'tcx> {
-        debug!("const_to_pat: cv={:#?}", cv);
+        debug!("const_to_pat: cv={:#?} id={:?}", cv, id);
         let adt_subpattern = |i, variant_opt| {
             let field = Field::new(i);
             let val = const_field(
@@ -945,6 +879,7 @@ impl<'a, 'tcx> PatternContext<'a, 'tcx> {
                 }
             }).collect::<Vec<_>>()
         };
+        debug!("const_to_pat: cv.ty={:?} span={:?}", cv.ty, span);
         let kind = match cv.ty.sty {
             ty::Float(_) => {
                 let id = self.tcx.hir().hir_to_node_id(id);
diff --git a/src/librustc_mir/hair/util.rs b/src/librustc_mir/hair/util.rs
index 050fb8b846e..f0f8263b64d 100644
--- a/src/librustc_mir/hair/util.rs
+++ b/src/librustc_mir/hair/util.rs
@@ -1,37 +1,31 @@
 use rustc::hir;
-use rustc::mir::UserTypeAnnotation;
-use rustc::ty::{self, AdtDef, TyCtxt};
+use rustc::ty::{self, CanonicalUserTypeAnnotation, TyCtxt, UserTypeAnnotation};
 
 crate trait UserAnnotatedTyHelpers<'gcx: 'tcx, 'tcx> {
     fn tcx(&self) -> TyCtxt<'_, 'gcx, 'tcx>;
 
     fn tables(&self) -> &ty::TypeckTables<'tcx>;
 
-    fn user_substs_applied_to_adt(
-        &self,
-        hir_id: hir::HirId,
-        adt_def: &'tcx AdtDef,
-    ) -> Option<UserTypeAnnotation<'tcx>> {
-        let user_substs = self.tables().user_substs(hir_id)?;
-        Some(UserTypeAnnotation::TypeOf(adt_def.did, user_substs))
-    }
-
     /// Looks up the type associated with this hir-id and applies the
     /// user-given substitutions; the hir-id must map to a suitable
     /// type.
     fn user_substs_applied_to_ty_of_hir_id(
         &self,
         hir_id: hir::HirId,
-    ) -> Option<UserTypeAnnotation<'tcx>> {
-        let user_substs = self.tables().user_substs(hir_id)?;
+    ) -> Option<CanonicalUserTypeAnnotation<'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, _) => Some(UserTypeAnnotation::TypeOf(adt_def.did, user_substs)),
-            ty::FnDef(def_id, _) => Some(UserTypeAnnotation::TypeOf(*def_id, user_substs)),
-            sty => bug!(
-                "sty: {:?} should not have user-substs {:?} recorded ",
-                sty,
-                user_substs
-            ),
+            ty::Adt(adt_def, ..) => {
+                if let UserTypeAnnotation::TypeOf(ref mut did, _) = &mut user_ty.value {
+                    *did = adt_def.did;
+                }
+                Some(user_ty)
+            }
+            ty::FnDef(..) => Some(user_ty),
+            sty =>
+                bug!("sty: {:?} should not have user provided type {:?} recorded ", sty, user_ty),
         }
     }
 }
diff --git a/src/librustc_mir/shim.rs b/src/librustc_mir/shim.rs
index 1029611cecd..4c123d4a44b 100644
--- a/src/librustc_mir/shim.rs
+++ b/src/librustc_mir/shim.rs
@@ -207,6 +207,7 @@ fn build_drop_shim<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
         IndexVec::new(),
         None,
         local_decls_for_sig(&sig, span),
+        IndexVec::new(),
         sig.inputs().len(),
         vec![],
         span,
@@ -376,6 +377,7 @@ impl<'a, 'tcx> CloneShimBuilder<'a, 'tcx> {
             IndexVec::new(),
             None,
             self.local_decls,
+            IndexVec::new(),
             self.sig.inputs().len(),
             vec![],
             self.span,
@@ -825,6 +827,7 @@ fn build_call_shim<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
         IndexVec::new(),
         None,
         local_decls,
+        IndexVec::new(),
         sig.inputs().len(),
         vec![],
         span,
@@ -903,6 +906,7 @@ pub fn build_adt_ctor<'a, 'gcx, 'tcx>(infcx: &infer::InferCtxt<'a, 'gcx, 'tcx>,
         IndexVec::new(),
         None,
         local_decls,
+        IndexVec::new(),
         sig.inputs().len(),
         vec![],
         span,
diff --git a/src/librustc_mir/transform/promote_consts.rs b/src/librustc_mir/transform/promote_consts.rs
index 7e6554ae3d4..1602fc35a2c 100644
--- a/src/librustc_mir/transform/promote_consts.rs
+++ b/src/librustc_mir/transform/promote_consts.rs
@@ -400,6 +400,7 @@ pub fn promote_candidates<'a, 'tcx>(mir: &mut Mir<'tcx>,
                 IndexVec::new(),
                 None,
                 initial_locals,
+                IndexVec::new(),
                 0,
                 vec![],
                 mir.span,
diff --git a/src/librustc_mir/util/pretty.rs b/src/librustc_mir/util/pretty.rs
index 35b367855ad..6353eab6f65 100644
--- a/src/librustc_mir/util/pretty.rs
+++ b/src/librustc_mir/util/pretty.rs
@@ -142,6 +142,7 @@ fn dump_matched_mir_node<'a, 'gcx, 'tcx, F>(
         }
         writeln!(file, "")?;
         extra_data(PassWhere::BeforeCFG, &mut file)?;
+        write_user_type_annotations(mir, &mut file)?;
         write_mir_fn(tcx, source, mir, &mut extra_data, &mut file)?;
         extra_data(PassWhere::AfterCFG, &mut file)?;
     };
@@ -618,6 +619,19 @@ fn write_temp_decls(mir: &Mir, w: &mut dyn Write) -> io::Result<()> {
     Ok(())
 }
 
+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)?;
+    }
+    if !mir.user_type_annotations.is_empty() {
+        writeln!(w, "|")?;
+    }
+    Ok(())
+}
+
 pub fn dump_mir_def_ids(tcx: TyCtxt, single: Option<DefId>) -> Vec<DefId> {
     if let Some(i) = single {
         vec![i]
diff --git a/src/librustc_traits/type_op.rs b/src/librustc_traits/type_op.rs
index d38ce3478d9..52fcb5b80f4 100644
--- a/src/librustc_traits/type_op.rs
+++ b/src/librustc_traits/type_op.rs
@@ -14,7 +14,7 @@ use rustc::traits::{
     Normalized, Obligation, ObligationCause, TraitEngine, TraitEngineExt,
 };
 use rustc::ty::query::Providers;
-use rustc::ty::subst::{Kind, Subst, UserSelfTy, UserSubsts};
+use rustc::ty::subst::{Kind, Subst, UserSubsts, UserSelfTy};
 use rustc::ty::{
     FnSig, Lift, ParamEnv, ParamEnvAnd, PolyFnSig, Predicate, Ty, TyCtxt, TypeFoldable, Variance,
 };
@@ -44,28 +44,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, variance, def_id, user_substs, projs }
             ) = 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={:?} variance={:?} def_id={:?} \
+                 user_substs={:?} projs={:?}",
+                mir_ty, variance, def_id, user_substs, projs
             );
 
-            let mut cx = AscribeUserTypeCx {
-                infcx,
-                param_env,
-                fulfill_cx,
-            };
+            let mut cx = AscribeUserTypeCx { infcx, param_env, fulfill_cx };
             cx.relate_mir_and_user_ty(mir_ty, variance, def_id, user_substs, projs)?;
 
             Ok(())
@@ -130,10 +118,9 @@ impl AscribeUserTypeCx<'me, 'gcx, 'tcx> {
         projs: &[ProjectionKind<'tcx>],
     ) -> Result<(), NoSolution> {
         let UserSubsts {
-            substs,
             user_self_ty,
+            substs,
         } = user_substs;
-
         let tcx = self.tcx();
 
         let ty = tcx.type_of(def_id);
@@ -171,20 +158,6 @@ impl AscribeUserTypeCx<'me, 'gcx, 'tcx> {
             self.relate(mir_ty, variance, ty)?;
         }
 
-        if let Some(UserSelfTy {
-            impl_def_id,
-            self_ty,
-        }) = user_self_ty
-        {
-            let impl_self_ty = self.tcx().type_of(impl_def_id);
-            let impl_self_ty = self.subst(impl_self_ty, &substs);
-            let impl_self_ty = self.normalize(impl_self_ty);
-
-            self.relate(self_ty, Variance::Invariant, impl_self_ty)?;
-
-            self.prove_predicate(Predicate::WellFormed(impl_self_ty));
-        }
-
         // Prove the predicates coming along with `def_id`.
         //
         // Also, normalize the `instantiated_predicates`
@@ -198,6 +171,19 @@ impl AscribeUserTypeCx<'me, 'gcx, 'tcx> {
             self.prove_predicate(instantiated_predicate);
         }
 
+        if let Some(UserSelfTy {
+            impl_def_id,
+            self_ty,
+        }) = user_self_ty {
+            let impl_self_ty = self.tcx().type_of(impl_def_id);
+            let impl_self_ty = self.subst(impl_self_ty, &substs);
+            let impl_self_ty = self.normalize(impl_self_ty);
+
+            self.relate(self_ty, Variance::Invariant, impl_self_ty)?;
+
+            self.prove_predicate(Predicate::WellFormed(impl_self_ty));
+        }
+
         // In addition to proving the predicates, we have to
         // prove that `ty` is well-formed -- this is because
         // the WF of `ty` is predicated on the substs being
@@ -210,7 +196,6 @@ impl AscribeUserTypeCx<'me, 'gcx, 'tcx> {
         // type were ill-formed but did not appear in `ty`,
         // which...could happen with normalization...
         self.prove_predicate(Predicate::WellFormed(ty));
-
         Ok(())
     }
 }
diff --git a/src/librustc_typeck/check/method/mod.rs b/src/librustc_typeck/check/method/mod.rs
index fe5f43e3c01..1758f762524 100644
--- a/src/librustc_typeck/check/method/mod.rs
+++ b/src/librustc_typeck/check/method/mod.rs
@@ -357,16 +357,16 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
         })
     }
 
-    pub fn resolve_ufcs(&self,
-                        span: Span,
-                        method_name: ast::Ident,
-                        self_ty: Ty<'tcx>,
-                        expr_id: ast::NodeId)
-                        -> Result<Def, MethodError<'tcx>> {
-        debug!("resolve_ufcs: method_name={:?} self_ty={:?} expr_id={:?}",
-            method_name,
-            self_ty,
-            expr_id
+    pub fn resolve_ufcs(
+        &self,
+        span: Span,
+        method_name: ast::Ident,
+        self_ty: Ty<'tcx>,
+        expr_id: ast::NodeId
+    ) -> Result<Def, MethodError<'tcx>> {
+        debug!(
+            "resolve_ufcs: method_name={:?} self_ty={:?} expr_id={:?}",
+            method_name, self_ty, expr_id,
         );
 
         let tcx = self.tcx;
@@ -375,6 +375,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
         match self.probe_for_name(span, mode, method_name, IsSuggestion(false),
                                   self_ty, expr_id, ProbeScope::TraitsInScope) {
             Ok(pick) => {
+                debug!("resolve_ufcs: pick={:?}", pick);
                 if let Some(import_id) = pick.import_id {
                     let import_def_id = tcx.hir().local_def_id(import_id);
                     debug!("resolve_ufcs: used_trait_import: {:?}", import_def_id);
@@ -383,6 +384,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                 }
 
                 let def = pick.item.def();
+                debug!("resolve_ufcs: def={:?}", def);
                 tcx.check_stability(def.def_id(), Some(expr_id), span);
 
                 Ok(def)
diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs
index 974df84beef..d78d7273a36 100644
--- a/src/librustc_typeck/check/mod.rs
+++ b/src/librustc_typeck/check/mod.rs
@@ -102,13 +102,14 @@ use rustc::infer::type_variable::{TypeVariableOrigin};
 use rustc::middle::region;
 use rustc::mir::interpret::{ConstValue, GlobalId};
 use rustc::traits::{self, ObligationCause, ObligationCauseCode, TraitEngine};
-use rustc::ty::{self, AdtKind, Ty, TyCtxt, GenericParamDefKind, RegionKind, Visibility,
-                ToPolyTraitRef, ToPredicate};
+use rustc::ty::{
+    self, AdtKind, CanonicalUserTypeAnnotation, Ty, TyCtxt, GenericParamDefKind, Visibility,
+    ToPolyTraitRef, ToPredicate, RegionKind, UserTypeAnnotation
+};
 use rustc::ty::adjustment::{Adjust, Adjustment, AllowTwoPhase, AutoBorrow, AutoBorrowMutability};
 use rustc::ty::fold::TypeFoldable;
 use rustc::ty::query::Providers;
-use rustc::ty::subst::{CanonicalUserSubsts, UnpackedKind, Subst, Substs,
-                       UserSelfTy, UserSubsts};
+use rustc::ty::subst::{UnpackedKind, Subst, Substs, UserSelfTy, UserSubsts};
 use rustc::ty::util::{Representability, IntTypeExt, Discr};
 use rustc::ty::layout::VariantIdx;
 use syntax_pos::{self, BytePos, Span, MultiSpan};
@@ -974,10 +975,12 @@ impl<'a, 'gcx, 'tcx> Visitor<'gcx> for GatherLocalsVisitor<'a, 'gcx, 'tcx> {
                     o_ty
                 };
 
-                let c_ty = self.fcx.inh.infcx.canonicalize_user_type_annotation(&revealed_ty);
+                let c_ty = self.fcx.inh.infcx.canonicalize_user_type_annotation(
+                    &UserTypeAnnotation::Ty(revealed_ty)
+                );
                 debug!("visit_local: ty.hir_id={:?} o_ty={:?} revealed_ty={:?} c_ty={:?}",
                        ty.hir_id, o_ty, revealed_ty, c_ty);
-                self.fcx.tables.borrow_mut().user_provided_tys_mut().insert(ty.hir_id, c_ty);
+                self.fcx.tables.borrow_mut().user_provided_types_mut().insert(ty.hir_id, c_ty);
 
                 Some(LocalTy { decl_ty: o_ty, revealed_ty })
             },
@@ -2108,8 +2111,6 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
         self.tables.borrow_mut().field_indices_mut().insert(hir_id, index);
     }
 
-    // The NodeId and the ItemLocalId must identify the same item. We just pass
-    // both of them for consistency checking.
     pub fn write_method_call(&self,
                              hir_id: hir::HirId,
                              method: MethodCallee<'tcx>) {
@@ -2138,23 +2139,27 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
         if !method.substs.is_noop() {
             let method_generics = self.tcx.generics_of(method.def_id);
             if !method_generics.params.is_empty() {
-                let user_substs = self.infcx.probe(|_| {
-                    let just_method_substs = Substs::for_item(self.tcx, method.def_id, |param, _| {
-                        let i = param.index as usize;
-                        if i < method_generics.parent_count {
-                            self.infcx.var_for_def(DUMMY_SP, param)
-                        } else {
-                            method.substs[i]
-                        }
-                    });
-                    self.infcx.canonicalize_user_type_annotation(&UserSubsts {
-                        substs: just_method_substs,
+                let user_type_annotation = self.infcx.probe(|_| {
+                    let user_substs = UserSubsts {
+                        substs: Substs::for_item(self.tcx, method.def_id, |param, _| {
+                            let i = param.index as usize;
+                            if i < method_generics.parent_count {
+                                self.infcx.var_for_def(DUMMY_SP, param)
+                            } else {
+                                method.substs[i]
+                            }
+                        }),
                         user_self_ty: None, // not relevant here
-                    })
+                    };
+
+                    self.infcx.canonicalize_user_type_annotation(&UserTypeAnnotation::TypeOf(
+                        method.def_id,
+                        user_substs,
+                    ))
                 });
 
-                debug!("write_method_call: user_substs = {:?}", user_substs);
-                self.write_user_substs(hir_id, user_substs);
+                debug!("write_method_call: user_type_annotation={:?}", user_type_annotation);
+                self.write_user_type_annotation(hir_id, user_type_annotation);
             }
         }
     }
@@ -2177,41 +2182,47 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
     /// This should be invoked **before any unifications have
     /// occurred**, so that annotations like `Vec<_>` are preserved
     /// properly.
-    pub fn write_user_substs_from_substs(
+    pub fn write_user_type_annotation_from_substs(
         &self,
         hir_id: hir::HirId,
+        def_id: DefId,
         substs: &'tcx Substs<'tcx>,
         user_self_ty: Option<UserSelfTy<'tcx>>,
     ) {
         debug!(
-            "write_user_substs_from_substs({:?}, {:?}) in fcx {}",
-            hir_id,
-            substs,
-            self.tag(),
+            "write_user_type_annotation_from_substs: hir_id={:?} def_id={:?} substs={:?} \
+             user_self_ty={:?} in fcx {}",
+            hir_id, def_id, substs, user_self_ty, self.tag(),
         );
 
         if !substs.is_noop() {
-            let user_substs = self.infcx.canonicalize_user_type_annotation(&UserSubsts {
-                substs,
-                user_self_ty,
-            });
-            debug!("instantiate_value_path: user_substs = {:?}", user_substs);
-            self.write_user_substs(hir_id, user_substs);
+            let canonicalized = self.infcx.canonicalize_user_type_annotation(
+                &UserTypeAnnotation::TypeOf(def_id, UserSubsts {
+                    substs,
+                    user_self_ty,
+                })
+            );
+            debug!("write_user_type_annotation_from_substs: canonicalized={:?}", canonicalized);
+            self.write_user_type_annotation(hir_id, canonicalized);
         }
     }
 
-    pub fn write_user_substs(&self, hir_id: hir::HirId, substs: CanonicalUserSubsts<'tcx>) {
+    pub fn write_user_type_annotation(
+        &self,
+        hir_id: hir::HirId,
+        canonical_user_type_annotation: CanonicalUserTypeAnnotation<'tcx>,
+    ) {
         debug!(
-            "write_user_substs({:?}, {:?}) in fcx {}",
-            hir_id,
-            substs,
-            self.tag(),
+            "write_user_type_annotation: hir_id={:?} canonical_user_type_annotation={:?} tag={}",
+            hir_id, canonical_user_type_annotation, self.tag(),
         );
 
-        if !substs.is_identity() {
-            self.tables.borrow_mut().user_substs_mut().insert(hir_id, substs);
+        if !canonical_user_type_annotation.is_identity() {
+            self.tables.borrow_mut().user_provided_types_mut().insert(
+                hir_id, canonical_user_type_annotation
+            );
         } else {
-            debug!("write_user_substs: skipping identity substs");
+            debug!("write_user_type_annotation: skipping identity substs");
         }
     }
 
@@ -2377,6 +2388,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
 
     pub fn to_ty_saving_user_provided_ty(&self, ast_ty: &hir::Ty) -> Ty<'tcx> {
         let ty = self.to_ty(ast_ty);
+        debug!("to_ty_saving_user_provided_ty: ty={:?}", ty);
 
         // If the type given by the user has free regions, save it for
         // later, since NLL would like to enforce those. Also pass in
@@ -2386,8 +2398,9 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
         // 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(&ty);
-            self.tables.borrow_mut().user_provided_tys_mut().insert(ast_ty.hir_id, c_ty);
+            let c_ty = self.infcx.canonicalize_response(&UserTypeAnnotation::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);
         }
 
         ty
@@ -3742,7 +3755,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
         if let Some((variant, did, substs)) = variant {
             debug!("check_struct_path: did={:?} substs={:?}", did, substs);
             let hir_id = self.tcx.hir().node_to_hir_id(node_id);
-            self.write_user_substs_from_substs(hir_id, substs, None);
+            self.write_user_type_annotation_from_substs(hir_id, did, substs, None);
 
             // Check bounds on type arguments used in the path.
             let bounds = self.instantiate_bounds(path_span, did, substs);
@@ -4581,6 +4594,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                                        span: Span)
                                        -> (Def, Option<Ty<'tcx>>, &'b [hir::PathSegment])
     {
+        debug!("resolve_ty_and_def_ufcs: qpath={:?} node_id={:?} span={:?}", qpath, node_id, span);
         let (ty, qself, item_segment) = match *qpath {
             QPath::Resolved(ref opt_qself, ref path) => {
                 return (path.def,
@@ -5101,6 +5115,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
             Def::Method(def_id) |
             Def::AssociatedConst(def_id) => {
                 let container = tcx.associated_item(def_id).container;
+                debug!("instantiate_value_path: def={:?} container={:?}", def, container);
                 match container {
                     ty::TraitContainer(trait_did) => {
                         callee::check_legal_trait_for_method_call(tcx, span, trait_did)
@@ -5300,7 +5315,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
 
         // First, store the "user substs" for later.
         let hir_id = tcx.hir().node_to_hir_id(node_id);
-        self.write_user_substs_from_substs(hir_id, substs, user_self_ty);
+        self.write_user_type_annotation_from_substs(hir_id, def_id, substs, user_self_ty);
 
         // Add all the obligations that are required, substituting and
         // normalized appropriately.
diff --git a/src/librustc_typeck/check/writeback.rs b/src/librustc_typeck/check/writeback.rs
index 8bd9b097d2d..38de936a027 100644
--- a/src/librustc_typeck/check/writeback.rs
+++ b/src/librustc_typeck/check/writeback.rs
@@ -3,6 +3,7 @@
 // substitutions.
 
 use check::FnCtxt;
+use errors::DiagnosticBuilder;
 use rustc::hir;
 use rustc::hir::def_id::{DefId, DefIndex};
 use rustc::hir::intravisit::{self, NestedVisitorMap, Visitor};
@@ -357,7 +358,8 @@ impl<'cx, 'gcx, 'tcx> WritebackCx<'cx, 'gcx, 'tcx> {
         debug_assert_eq!(fcx_tables.local_id_root, self.tables.local_id_root);
         let common_local_id_root = fcx_tables.local_id_root.unwrap();
 
-        for (&local_id, c_ty) in fcx_tables.user_provided_tys().iter() {
+        let mut errors_buffer = Vec::new();
+        for (&local_id, c_ty) in fcx_tables.user_provided_types().iter() {
             let hir_id = hir::HirId {
                 owner: common_local_id_root.index,
                 local_id,
@@ -374,8 +376,30 @@ impl<'cx, 'gcx, 'tcx> WritebackCx<'cx, 'gcx, 'tcx> {
             };
 
             self.tables
-                .user_provided_tys_mut()
+                .user_provided_types_mut()
                 .insert(hir_id, c_ty.clone());
+
+            if let ty::UserTypeAnnotation::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);
+                    let span = self.tcx().hir().span(node_id);
+                    // We need to buffer the errors in order to guarantee a consistent
+                    // order when emitting them.
+                    let err = self.tcx().sess.struct_span_err(
+                        span,
+                        &format!("user substs: {:?}", user_substs)
+                    );
+                    err.buffer(&mut errors_buffer);
+                }
+            }
+        }
+
+        if !errors_buffer.is_empty() {
+            errors_buffer.sort_by_key(|diag| diag.span.primary_span());
+            for diag in errors_buffer.drain(..) {
+                DiagnosticBuilder::new_diagnostic(self.tcx().sess.diagnostic(), diag).emit();
+            }
         }
     }
 
@@ -573,22 +597,6 @@ impl<'cx, 'gcx, 'tcx> WritebackCx<'cx, 'gcx, 'tcx> {
             assert!(!substs.needs_infer() && !substs.has_placeholders());
             self.tables.node_substs_mut().insert(hir_id, substs);
         }
-
-        // Copy over any user-substs
-        if let Some(user_substs) = self.fcx.tables.borrow().user_substs(hir_id) {
-            let user_substs = self.tcx().lift_to_global(&user_substs).unwrap();
-            self.tables.user_substs_mut().insert(hir_id, user_substs);
-
-            // Unit-testing mechanism:
-            if self.rustc_dump_user_substs {
-                let node_id = self.tcx().hir().hir_to_node_id(hir_id);
-                let span = self.tcx().hir().span(node_id);
-                self.tcx().sess.span_err(
-                    span,
-                    &format!("user substs: {:?}", user_substs),
-                );
-            }
-        }
     }
 
     fn visit_adjustments(&mut self, span: Span, hir_id: hir::HirId) {
diff --git a/src/test/incremental/hashes/let_expressions.rs b/src/test/incremental/hashes/let_expressions.rs
index 3aa66527ca7..b6050f059c2 100644
--- a/src/test/incremental/hashes/let_expressions.rs
+++ b/src/test/incremental/hashes/let_expressions.rs
@@ -70,7 +70,7 @@ pub fn change_mutability_of_reference_type() {
 
 #[cfg(not(cfail1))]
 #[rustc_clean(cfg="cfail2",
-    except="HirBody,TypeckTables,MirValidated")]
+    except="HirBody,TypeckTables,MirValidated,MirOptimized")]
 #[rustc_clean(cfg="cfail3")]
 pub fn change_mutability_of_reference_type() {
     let _x: &mut u64;
diff --git a/src/test/mir-opt/basic_assignment.rs b/src/test/mir-opt/basic_assignment.rs
index bb304ea12ca..88fd53d4ba5 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: Ty(Canonical { max_universe: U0, variables: [], value: std::option::Option<std::boxed::Box<u32>> }), projs: [] });
+//        AscribeUserType(_4, o, UserTypeProjection { base: UserTypeAnnotation(1), projs: [] });
 //        StorageLive(_5);
 //        StorageLive(_6);
 //        _6 = move _4;
diff --git a/src/test/run-pass/associated-consts/associated-const-range-match-patterns.rs b/src/test/run-pass/associated-consts/associated-const-range-match-patterns.rs
index 647652d0273..4801369cfd1 100644
--- a/src/test/run-pass/associated-consts/associated-const-range-match-patterns.rs
+++ b/src/test/run-pass/associated-consts/associated-const-range-match-patterns.rs
@@ -1,5 +1,5 @@
 // run-pass
-#![allow(dead_code)]
+#![allow(dead_code, unreachable_patterns)]
 
 struct Foo;
 
diff --git a/src/test/ui/issue-54943-1.rs b/src/test/ui/issue-54943-1.rs
new file mode 100644
index 00000000000..7750e340361
--- /dev/null
+++ b/src/test/ui/issue-54943-1.rs
@@ -0,0 +1,15 @@
+#![feature(nll)]
+
+// This test is a minimal version of an ICE in the dropck-eyepatch tests
+// found in the fix for #54943.
+
+// compile-pass
+
+fn foo<T>(_t: T) {
+}
+
+fn main() {
+    struct A<'a, B: 'a>(&'a B);
+    let (a1, a2): (String, A<_>) = (String::from("auto"), A(&"this"));
+    foo((a1, a2));
+}
diff --git a/src/test/ui/issue-54943-2.rs b/src/test/ui/issue-54943-2.rs
new file mode 100644
index 00000000000..f829c38c35d
--- /dev/null
+++ b/src/test/ui/issue-54943-2.rs
@@ -0,0 +1,18 @@
+#![feature(nll)]
+
+// This test is a minimal version of an ICE in the dropck-eyepatch tests
+// found in the fix for #54943. In particular, this test is in unreachable
+// code as the initial fix for this ICE only worked if the code was reachable.
+
+// compile-pass
+
+fn foo<T>(_t: T) {
+}
+
+fn main() {
+    return;
+
+    struct A<'a, B: 'a>(&'a B);
+    let (a1, a2): (String, A<_>) = (String::from("auto"), A(&"this"));
+    foo((a1, a2));
+}
diff --git a/src/test/ui/issue-54943-3.rs b/src/test/ui/issue-54943-3.rs
new file mode 100644
index 00000000000..185077bd684
--- /dev/null
+++ b/src/test/ui/issue-54943-3.rs
@@ -0,0 +1,21 @@
+// compile-pass
+// FIXME(#54943) This test targets the scenario where proving the WF requirements requires
+// knowing the value of the `_` type present in the user type annotation - unfortunately, figuring
+// out the value of that `_` requires type-checking the surrounding code, but that code is dead,
+// so our NLL region checker doesn't have access to it. This test should actually fail to compile.
+
+#![feature(nll)]
+#![allow(warnings)]
+
+use std::fmt::Debug;
+
+fn foo<T: 'static + Debug>(_: T) { }
+
+fn bar<'a>() {
+    return;
+
+    let _x = foo::<Vec<_>>(Vec::<&'a u32>::new());
+    //~^ ERROR the type `&'a u32` does not fulfill the required lifetime [E0477]
+}
+
+fn main() {}
diff --git a/src/test/ui/issue-54943.rs b/src/test/ui/issue-54943.rs
new file mode 100644
index 00000000000..c720f627975
--- /dev/null
+++ b/src/test/ui/issue-54943.rs
@@ -0,0 +1,17 @@
+// 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)]
+
+fn foo<T: 'static>() { }
+
+fn boo<'a>() {
+    return;
+
+    let x = foo::<&'a u32>();
+    //~^ ERROR the type `&'a u32` does not fulfill the required lifetime [E0477]
+}
+
+fn main() {}
diff --git a/src/test/ui/issue-55511.nll.stderr b/src/test/ui/issue-55511.nll.stderr
new file mode 100644
index 00000000000..bf3e58e8cdb
--- /dev/null
+++ b/src/test/ui/issue-55511.nll.stderr
@@ -0,0 +1,15 @@
+error[E0597]: `a` does not live long enough
+  --> $DIR/issue-55511.rs:13:28
+   |
+LL |     let b = Some(Cell::new(&a));
+   |                            ^^ borrowed value does not live long enough
+...
+LL |         <() as Foo<'static>>::C => { }
+   |         ----------------------- type annotation requires that `a` is borrowed for `'static`
+...
+LL | }
+   | - `a` dropped here while still borrowed
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0597`.
diff --git a/src/test/ui/issue-55511.rs b/src/test/ui/issue-55511.rs
new file mode 100644
index 00000000000..4b9475ba627
--- /dev/null
+++ b/src/test/ui/issue-55511.rs
@@ -0,0 +1,19 @@
+use std::cell::Cell;
+
+trait Foo<'a> {
+    const C: Option<Cell<&'a u32>>;
+}
+
+impl<'a, T> Foo<'a> for T {
+    const C: Option<Cell<&'a u32>> = None;
+}
+
+fn main() {
+    let a = 22;
+    let b = Some(Cell::new(&a));
+    //~^ ERROR `a` does not live long enough [E0597]
+    match b {
+        <() as Foo<'static>>::C => { }
+        _ => { }
+    }
+}
diff --git a/src/test/ui/issue-55511.stderr b/src/test/ui/issue-55511.stderr
new file mode 100644
index 00000000000..24668f04551
--- /dev/null
+++ b/src/test/ui/issue-55511.stderr
@@ -0,0 +1,14 @@
+error[E0597]: `a` does not live long enough
+  --> $DIR/issue-55511.rs:13:29
+   |
+LL |     let b = Some(Cell::new(&a));
+   |                             ^ borrowed value does not live long enough
+...
+LL | }
+   | - borrowed value only lives until here
+   |
+   = note: borrowed value must be valid for the static lifetime...
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0597`.
diff --git a/src/test/ui/nll/issue-55401.rs b/src/test/ui/nll/issue-55401.rs
new file mode 100644
index 00000000000..2fa23449108
--- /dev/null
+++ b/src/test/ui/nll/issue-55401.rs
@@ -0,0 +1,8 @@
+#![feature(nll)]
+
+fn static_to_a_to_static_through_ref_in_tuple<'a>(x: &'a u32) -> &'static u32 {
+    let (ref y, _z): (&'a u32, u32) = (&22, 44);
+    *y //~ ERROR
+}
+
+fn main() {}
diff --git a/src/test/ui/nll/issue-55401.stderr b/src/test/ui/nll/issue-55401.stderr
new file mode 100644
index 00000000000..9e50db7b604
--- /dev/null
+++ b/src/test/ui/nll/issue-55401.stderr
@@ -0,0 +1,11 @@
+error: unsatisfied lifetime constraints
+  --> $DIR/issue-55401.rs:5:5
+   |
+LL | fn static_to_a_to_static_through_ref_in_tuple<'a>(x: &'a u32) -> &'static u32 {
+   |                                               -- lifetime `'a` defined here
+LL |     let (ref y, _z): (&'a u32, u32) = (&22, 44);
+LL |     *y //~ ERROR
+   |     ^^ returning this value requires that `'a` must outlive `'static`
+
+error: aborting due to previous error
+
diff --git a/src/test/ui/nll/user-annotations/dump-adt-brace-struct.stderr b/src/test/ui/nll/user-annotations/dump-adt-brace-struct.stderr
index 5a359cf9ed8..123c26195d0 100644
--- a/src/test/ui/nll/user-annotations/dump-adt-brace-struct.stderr
+++ b/src/test/ui/nll/user-annotations/dump-adt-brace-struct.stderr
@@ -1,4 +1,4 @@
-error: user substs: Canonical { max_universe: U0, variables: [], value: UserSubsts { substs: [u32], user_self_ty: None } }
+error: user substs: UserSubsts { substs: [u32], user_self_ty: None }
   --> $DIR/dump-adt-brace-struct.rs:18:5
    |
 LL |     SomeStruct::<u32> { t: 22 }; //~ ERROR [u32]
diff --git a/src/test/ui/nll/user-annotations/dump-fn-method.stderr b/src/test/ui/nll/user-annotations/dump-fn-method.stderr
index 3f159cc92b5..a1a4e43e8a3 100644
--- a/src/test/ui/nll/user-annotations/dump-fn-method.stderr
+++ b/src/test/ui/nll/user-annotations/dump-fn-method.stderr
@@ -1,22 +1,22 @@
-error: user substs: Canonical { max_universe: U0, variables: [], value: UserSubsts { substs: [u32], user_self_ty: None } }
+error: user substs: UserSubsts { substs: [u32], user_self_ty: None }
   --> $DIR/dump-fn-method.rs:26:13
    |
 LL |     let x = foo::<u32>; //~ ERROR [u32]
    |             ^^^^^^^^^^
 
-error: user substs: Canonical { max_universe: U0, variables: [CanonicalVarInfo { kind: Ty(General(U0)) }, CanonicalVarInfo { kind: Ty(General(U0)) }], value: UserSubsts { substs: [^0, u32, ^1], user_self_ty: None } }
+error: user substs: UserSubsts { substs: [^0, u32, ^1], user_self_ty: None }
   --> $DIR/dump-fn-method.rs:32:13
    |
 LL |     let x = <_ as Bazoom<u32>>::method::<_>; //~ ERROR [^0, u32, ^1]
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
-error: user substs: Canonical { max_universe: U0, variables: [], value: UserSubsts { substs: [u8, u16, u32], user_self_ty: None } }
+error: user substs: UserSubsts { substs: [u8, u16, u32], user_self_ty: None }
   --> $DIR/dump-fn-method.rs:36:13
    |
 LL |     let x = <u8 as Bazoom<u16>>::method::<u32>; //~ ERROR [u8, u16, u32]
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
-error: user substs: Canonical { max_universe: U0, variables: [CanonicalVarInfo { kind: Ty(General(U0)) }, CanonicalVarInfo { kind: Ty(General(U0)) }], value: UserSubsts { substs: [^0, ^1, u32], user_self_ty: None } }
+error: user substs: UserSubsts { substs: [^0, ^1, u32], user_self_ty: None }
   --> $DIR/dump-fn-method.rs:44:5
    |
 LL |     y.method::<u32>(44, 66); //~ ERROR [^0, ^1, u32]
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 d38706defe7..91a0d8590ff 100644
--- a/src/test/ui/regions/regions-outlives-projection-container-wc.rs
+++ b/src/test/ui/regions/regions-outlives-projection-container-wc.rs
@@ -31,9 +31,7 @@ fn with_assoc<'a,'b>() {
     // outlive 'a. In this case, that means TheType<'b>::TheAssocType,
     // which is &'b (), must outlive 'a.
 
-    // FIXME (#54943) NLL doesn't enforce WF condition in unreachable code if
-    // `_x` is changed to `_`
-    let _x: &'a WithAssoc<TheType<'b>> = loop { };
+    let _: &'a WithAssoc<TheType<'b>> = loop { };
     //~^ ERROR reference has a longer lifetime
 }
 
diff --git a/src/test/ui/regions/regions-outlives-projection-container-wc.stderr b/src/test/ui/regions/regions-outlives-projection-container-wc.stderr
index 2ed9fd4f9b4..0d73d3d6432 100644
--- a/src/test/ui/regions/regions-outlives-projection-container-wc.stderr
+++ b/src/test/ui/regions/regions-outlives-projection-container-wc.stderr
@@ -1,8 +1,8 @@
 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:36:13
+  --> $DIR/regions-outlives-projection-container-wc.rs:34:12
    |
-LL |     let _x: &'a WithAssoc<TheType<'b>> = loop { };
-   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL |     let _: &'a WithAssoc<TheType<'b>> = loop { };
+   |            ^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
 note: the pointer is valid for the lifetime 'a as defined on the function body at 28:15
   --> $DIR/regions-outlives-projection-container-wc.rs:28:15