diff --git a/src/librustc/ich/impls_mir.rs b/src/librustc/ich/impls_mir.rs
index 337cc0fc627..b660187945c 100644
--- a/src/librustc/ich/impls_mir.rs
+++ b/src/librustc/ich/impls_mir.rs
@@ -587,3 +587,24 @@ 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::FnDef(ref def_id, ref substs) => {
+                def_id.hash_stable(hcx, hasher);
+                substs.hash_stable(hcx, hasher);
+            }
+            mir::UserTypeAnnotation::AdtDef(ref def_id, ref substs) => {
+                def_id.hash_stable(hcx, hasher);
+                substs.hash_stable(hcx, hasher);
+            }
+        }
+    }
+}
diff --git a/src/librustc/ich/impls_ty.rs b/src/librustc/ich/impls_ty.rs
index dd2c41dda64..e54968c5274 100644
--- a/src/librustc/ich/impls_ty.rs
+++ b/src/librustc/ich/impls_ty.rs
@@ -1417,3 +1417,8 @@ impl_stable_hash_for!(enum traits::QuantifierKind {
     Universal,
     Existential
 });
+
+impl_stable_hash_for!(struct ty::subst::UserSubsts<'tcx> { substs, user_self_ty });
+
+impl_stable_hash_for!(struct ty::subst::UserSelfTy<'tcx> { impl_def_id, self_ty });
+
diff --git a/src/librustc/infer/canonical/mod.rs b/src/librustc/infer/canonical/mod.rs
index a78b5b7d072..1863f08930f 100644
--- a/src/librustc/infer/canonical/mod.rs
+++ b/src/librustc/infer/canonical/mod.rs
@@ -241,7 +241,7 @@ impl<'cx, 'gcx, 'tcx> InferCtxt<'cx, 'gcx, 'tcx> {
     /// canonicalized) then represents the values that you computed
     /// for each of the canonical inputs to your query.
 
-    pub(in infer) fn instantiate_canonical_with_fresh_inference_vars<T>(
+    pub fn instantiate_canonical_with_fresh_inference_vars<T>(
         &self,
         span: Span,
         canonical: &Canonical<'tcx, T>,
@@ -249,9 +249,6 @@ impl<'cx, 'gcx, 'tcx> InferCtxt<'cx, 'gcx, 'tcx> {
     where
         T: TypeFoldable<'tcx>,
     {
-        assert_eq!(self.universe(), ty::UniverseIndex::ROOT, "infcx not newly created");
-        assert_eq!(self.type_variables.borrow().num_vars(), 0, "infcx not newly created");
-
         let canonical_inference_vars =
             self.fresh_inference_vars_for_canonical_vars(span, canonical.variables);
         let result = canonical.substitute(self.tcx, &canonical_inference_vars);
diff --git a/src/librustc/infer/mod.rs b/src/librustc/infer/mod.rs
index ef9886e06d4..fbd38ebd78c 100644
--- a/src/librustc/infer/mod.rs
+++ b/src/librustc/infer/mod.rs
@@ -62,6 +62,7 @@ mod higher_ranked;
 pub mod lattice;
 mod lexical_region_resolve;
 mod lub;
+pub mod nll_relate;
 pub mod opaque_types;
 pub mod outlives;
 pub mod region_constraints;
diff --git a/src/librustc/infer/nll_relate/mod.rs b/src/librustc/infer/nll_relate/mod.rs
new file mode 100644
index 00000000000..e003c1989e0
--- /dev/null
+++ b/src/librustc/infer/nll_relate/mod.rs
@@ -0,0 +1,736 @@
+// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+//! This code is kind of an alternate way of doing subtyping,
+//! supertyping, and type equating, distinct from the `combine.rs`
+//! code but very similar in its effect and design. Eventually the two
+//! ought to be merged. This code is intended for use in NLL.
+//!
+//! Here are the key differences:
+//!
+//! - This code generally assumes that there are no unbound type
+//!   inferences variables, because at NLL
+//!   time types are fully inferred up-to regions.
+//!   - Actually, to support user-given type annotations like
+//!     `Vec<_>`, we do have some measure of support for type
+//!     inference variables, but we impose some simplifying
+//!     assumptions on them that would not be suitable for the infer
+//!     code more generally. This could be fixed.
+//! - This code uses "universes" to handle higher-ranked regions and
+//!   not the leak-check. This is "more correct" than what rustc does
+//!   and we are generally migrating in this direction, but NLL had to
+//!   get there first.
+
+use crate::infer::InferCtxt;
+use crate::ty::fold::{TypeFoldable, TypeVisitor};
+use crate::ty::relate::{self, Relate, RelateResult, TypeRelation};
+use crate::ty::subst::Kind;
+use crate::ty::{self, Ty, TyCtxt};
+use rustc_data_structures::fx::FxHashMap;
+
+pub struct TypeRelating<'me, 'gcx: 'tcx, 'tcx: 'me, D>
+where
+    D: TypeRelatingDelegate<'tcx>,
+{
+    infcx: &'me InferCtxt<'me, 'gcx, 'tcx>,
+
+    /// Callback to use when we deduce an outlives relationship
+    delegate: D,
+
+    /// How are we relating `a` and `b`?
+    ///
+    /// - covariant means `a <: b`
+    /// - contravariant means `b <: a`
+    /// - invariant means `a == b
+    /// - bivariant means that it doesn't matter
+    ambient_variance: ty::Variance,
+
+    /// When we pass through a set of binders (e.g., when looking into
+    /// a `fn` type), we push a new bound region scope onto here.  This
+    /// will contain the instantiated region for each region in those
+    /// binders. When we then encounter a `ReLateBound(d, br)`, we can
+    /// use the debruijn index `d` to find the right scope, and then
+    /// bound region name `br` to find the specific instantiation from
+    /// within that scope. See `replace_bound_region`.
+    ///
+    /// This field stores the instantiations for late-bound regions in
+    /// the `a` type.
+    a_scopes: Vec<BoundRegionScope<'tcx>>,
+
+    /// Same as `a_scopes`, but for the `b` type.
+    b_scopes: Vec<BoundRegionScope<'tcx>>,
+}
+
+pub trait TypeRelatingDelegate<'tcx> {
+    /// Push a constraint `sup: sub` -- this constraint must be
+    /// satisfied for the two types to be related. `sub` and `sup` may
+    /// be regions from the type or new variables created through the
+    /// delegate.
+    fn push_outlives(&mut self, sup: ty::Region<'tcx>, sub: ty::Region<'tcx>);
+
+    /// Creates a new universe index. Used when instantiating placeholders.
+    fn create_next_universe(&mut self) -> ty::UniverseIndex;
+
+    /// Creates a new region variable representing a higher-ranked
+    /// region that is instantiated existentially. This creates an
+    /// inference variable, typically.
+    ///
+    /// So e.g. if you have `for<'a> fn(..) <: for<'b> fn(..)`, then
+    /// we will invoke this method to instantiate `'a` with an
+    /// inference variable (though `'b` would be instantiated first,
+    /// as a placeholder).
+    fn next_existential_region_var(&mut self) -> ty::Region<'tcx>;
+
+    /// Creates a new region variable representing a
+    /// higher-ranked region that is instantiated universally.
+    /// This creates a new region placeholder, typically.
+    ///
+    /// So e.g. if you have `for<'a> fn(..) <: for<'b> fn(..)`, then
+    /// we will invoke this method to instantiate `'b` with a
+    /// placeholder region.
+    fn next_placeholder_region(&mut self, placeholder: ty::Placeholder) -> ty::Region<'tcx>;
+
+    /// Creates a new existential region in the given universe. This
+    /// is used when handling subtyping and type variables -- if we
+    /// have that `?X <: Foo<'a>`, for example, we would instantiate
+    /// `?X` with a type like `Foo<'?0>` where `'?0` is a fresh
+    /// existential variable created by this function. We would then
+    /// relate `Foo<'?0>` with `Foo<'a>` (and probably add an outlives
+    /// relation stating that `'?0: 'a`).
+    fn generalize_existential(&mut self, universe: ty::UniverseIndex) -> ty::Region<'tcx>;
+}
+
+#[derive(Clone, Debug)]
+struct ScopesAndKind<'tcx> {
+    scopes: Vec<BoundRegionScope<'tcx>>,
+    kind: Kind<'tcx>,
+}
+
+#[derive(Clone, Debug, Default)]
+struct BoundRegionScope<'tcx> {
+    map: FxHashMap<ty::BoundRegion, ty::Region<'tcx>>,
+}
+
+#[derive(Copy, Clone)]
+struct UniversallyQuantified(bool);
+
+impl<'me, 'gcx, 'tcx, D> TypeRelating<'me, 'gcx, 'tcx, D>
+where
+    D: TypeRelatingDelegate<'tcx>,
+{
+    pub fn new(
+        infcx: &'me InferCtxt<'me, 'gcx, 'tcx>,
+        delegate: D,
+        ambient_variance: ty::Variance,
+    ) -> Self {
+        Self {
+            infcx,
+            delegate,
+            ambient_variance,
+            a_scopes: vec![],
+            b_scopes: vec![],
+        }
+    }
+
+    fn ambient_covariance(&self) -> bool {
+        match self.ambient_variance {
+            ty::Variance::Covariant | ty::Variance::Invariant => true,
+            ty::Variance::Contravariant | ty::Variance::Bivariant => false,
+        }
+    }
+
+    fn ambient_contravariance(&self) -> bool {
+        match self.ambient_variance {
+            ty::Variance::Contravariant | ty::Variance::Invariant => true,
+            ty::Variance::Covariant | ty::Variance::Bivariant => false,
+        }
+    }
+
+    fn create_scope(
+        &mut self,
+        value: &ty::Binder<impl TypeFoldable<'tcx>>,
+        universally_quantified: UniversallyQuantified,
+    ) -> BoundRegionScope<'tcx> {
+        let mut scope = BoundRegionScope::default();
+
+        // Create a callback that creates (via the delegate) either an
+        // existential or placeholder region as needed.
+        let mut next_region = {
+            let delegate = &mut self.delegate;
+            let mut lazy_universe = None;
+            move |br: ty::BoundRegion| {
+                if universally_quantified.0 {
+                    // The first time this closure is called, create a
+                    // new universe for the placeholders we will make
+                    // from here out.
+                    let universe = lazy_universe.unwrap_or_else(|| {
+                        let universe = delegate.create_next_universe();
+                        lazy_universe = Some(universe);
+                        universe
+                    });
+
+                    let placeholder = ty::Placeholder { universe, name: br };
+                    delegate.next_placeholder_region(placeholder)
+                } else {
+                    delegate.next_existential_region_var()
+                }
+            }
+        };
+
+        value.skip_binder().visit_with(&mut ScopeInstantiator {
+            next_region: &mut next_region,
+            target_index: ty::INNERMOST,
+            bound_region_scope: &mut scope,
+        });
+
+        scope
+    }
+
+    /// When we encounter binders during the type traversal, we record
+    /// the value to substitute for each of the things contained in
+    /// that binder. (This will be either a universal placeholder or
+    /// an existential inference variable.) Given the debruijn index
+    /// `debruijn` (and name `br`) of some binder we have now
+    /// encountered, this routine finds the value that we instantiated
+    /// the region with; to do so, it indexes backwards into the list
+    /// of ambient scopes `scopes`.
+    fn lookup_bound_region(
+        debruijn: ty::DebruijnIndex,
+        br: &ty::BoundRegion,
+        first_free_index: ty::DebruijnIndex,
+        scopes: &[BoundRegionScope<'tcx>],
+    ) -> ty::Region<'tcx> {
+        // The debruijn index is a "reverse index" into the
+        // scopes listing. So when we have INNERMOST (0), we
+        // want the *last* scope pushed, and so forth.
+        let debruijn_index = debruijn.index() - first_free_index.index();
+        let scope = &scopes[scopes.len() - debruijn_index - 1];
+
+        // Find this bound region in that scope to map to a
+        // particular region.
+        scope.map[br]
+    }
+
+    /// If `r` is a bound region, find the scope in which it is bound
+    /// (from `scopes`) and return the value that we instantiated it
+    /// with. Otherwise just return `r`.
+    fn replace_bound_region(
+        &self,
+        r: ty::Region<'tcx>,
+        first_free_index: ty::DebruijnIndex,
+        scopes: &[BoundRegionScope<'tcx>],
+    ) -> ty::Region<'tcx> {
+        if let ty::ReLateBound(debruijn, br) = r {
+            Self::lookup_bound_region(*debruijn, br, first_free_index, scopes)
+        } else {
+            r
+        }
+    }
+
+    /// Push a new outlives requirement into our output set of
+    /// constraints.
+    fn push_outlives(&mut self, sup: ty::Region<'tcx>, sub: ty::Region<'tcx>) {
+        debug!("push_outlives({:?}: {:?})", sup, sub);
+
+        self.delegate.push_outlives(sup, sub);
+    }
+
+    /// When we encounter a canonical variable `var` in the output,
+    /// equate it with `kind`. If the variable has been previously
+    /// equated, then equate it again.
+    fn relate_var(&mut self, var_ty: Ty<'tcx>, value_ty: Ty<'tcx>) -> RelateResult<'tcx, Ty<'tcx>> {
+        debug!("equate_var(var_ty={:?}, value_ty={:?})", var_ty, value_ty);
+
+        let generalized_ty = self.generalize_value(value_ty);
+        self.infcx
+            .force_instantiate_unchecked(var_ty, generalized_ty);
+
+        // The generalized values we extract from `canonical_var_values` have
+        // been fully instantiated and hence the set of scopes we have
+        // doesn't matter -- just to be sure, put an empty vector
+        // in there.
+        let old_a_scopes = ::std::mem::replace(&mut self.a_scopes, vec![]);
+
+        // Relate the generalized kind to the original one.
+        let result = self.relate(&generalized_ty, &value_ty);
+
+        // Restore the old scopes now.
+        self.a_scopes = old_a_scopes;
+
+        debug!("equate_var: complete, result = {:?}", result);
+        result
+    }
+
+    fn generalize_value<T: Relate<'tcx>>(&mut self, value: T) -> T {
+        TypeGeneralizer {
+            tcx: self.infcx.tcx,
+            delegate: &mut self.delegate,
+            first_free_index: ty::INNERMOST,
+            ambient_variance: self.ambient_variance,
+
+            // These always correspond to an `_` or `'_` written by
+            // user, and those are always in the root universe.
+            universe: ty::UniverseIndex::ROOT,
+        }.relate(&value, &value)
+            .unwrap()
+    }
+}
+
+impl<D> TypeRelation<'me, 'gcx, 'tcx> for TypeRelating<'me, 'gcx, 'tcx, D>
+where
+    D: TypeRelatingDelegate<'tcx>,
+{
+    fn tcx(&self) -> TyCtxt<'me, 'gcx, 'tcx> {
+        self.infcx.tcx
+    }
+
+    fn tag(&self) -> &'static str {
+        "nll::subtype"
+    }
+
+    fn a_is_expected(&self) -> bool {
+        true
+    }
+
+    fn relate_with_variance<T: Relate<'tcx>>(
+        &mut self,
+        variance: ty::Variance,
+        a: &T,
+        b: &T,
+    ) -> RelateResult<'tcx, T> {
+        debug!(
+            "relate_with_variance(variance={:?}, a={:?}, b={:?})",
+            variance, a, b
+        );
+
+        let old_ambient_variance = self.ambient_variance;
+        self.ambient_variance = self.ambient_variance.xform(variance);
+
+        debug!(
+            "relate_with_variance: ambient_variance = {:?}",
+            self.ambient_variance
+        );
+
+        let r = self.relate(a, b)?;
+
+        self.ambient_variance = old_ambient_variance;
+
+        debug!("relate_with_variance: r={:?}", r);
+
+        Ok(r)
+    }
+
+    fn tys(&mut self, a: Ty<'tcx>, b: Ty<'tcx>) -> RelateResult<'tcx, Ty<'tcx>> {
+        let a = self.infcx.shallow_resolve(a);
+        match a.sty {
+            ty::Infer(ty::TyVar(_)) | ty::Infer(ty::IntVar(_)) | ty::Infer(ty::FloatVar(_)) => {
+                self.relate_var(a.into(), b.into())
+            }
+
+            _ => {
+                debug!(
+                    "tys(a={:?}, b={:?}, variance={:?})",
+                    a, b, self.ambient_variance
+                );
+
+                relate::super_relate_tys(self, a, b)
+            }
+        }
+    }
+
+    fn regions(
+        &mut self,
+        a: ty::Region<'tcx>,
+        b: ty::Region<'tcx>,
+    ) -> RelateResult<'tcx, ty::Region<'tcx>> {
+        debug!(
+            "regions(a={:?}, b={:?}, variance={:?})",
+            a, b, self.ambient_variance
+        );
+
+        let v_a = self.replace_bound_region(a, ty::INNERMOST, &self.a_scopes);
+        let v_b = self.replace_bound_region(b, ty::INNERMOST, &self.b_scopes);
+
+        debug!("regions: v_a = {:?}", v_a);
+        debug!("regions: v_b = {:?}", v_b);
+
+        if self.ambient_covariance() {
+            // Covariance: a <= b. Hence, `b: a`.
+            self.push_outlives(v_b, v_a);
+        }
+
+        if self.ambient_contravariance() {
+            // Contravariant: b <= a. Hence, `a: b`.
+            self.push_outlives(v_a, v_b);
+        }
+
+        Ok(a)
+    }
+
+    fn binders<T>(
+        &mut self,
+        a: &ty::Binder<T>,
+        b: &ty::Binder<T>,
+    ) -> RelateResult<'tcx, ty::Binder<T>>
+    where
+        T: Relate<'tcx>,
+    {
+        // We want that
+        //
+        // ```
+        // for<'a> fn(&'a u32) -> &'a u32 <:
+        //   fn(&'b u32) -> &'b u32
+        // ```
+        //
+        // but not
+        //
+        // ```
+        // fn(&'a u32) -> &'a u32 <:
+        //   for<'b> fn(&'b u32) -> &'b u32
+        // ```
+        //
+        // We therefore proceed as follows:
+        //
+        // - Instantiate binders on `b` universally, yielding a universe U1.
+        // - Instantiate binders on `a` existentially in U1.
+
+        debug!(
+            "binders({:?}: {:?}, ambient_variance={:?})",
+            a, b, self.ambient_variance
+        );
+
+        if self.ambient_covariance() {
+            // Covariance, so we want `for<..> A <: for<..> B` --
+            // therefore we compare any instantiation of A (i.e., A
+            // instantiated with existentials) against every
+            // instantiation of B (i.e., B instantiated with
+            // universals).
+
+            let b_scope = self.create_scope(b, UniversallyQuantified(true));
+            let a_scope = self.create_scope(a, UniversallyQuantified(false));
+
+            debug!("binders: a_scope = {:?} (existential)", a_scope);
+            debug!("binders: b_scope = {:?} (universal)", b_scope);
+
+            self.b_scopes.push(b_scope);
+            self.a_scopes.push(a_scope);
+
+            // Reset the ambient variance to covariant. This is needed
+            // to correctly handle cases like
+            //
+            //     for<'a> fn(&'a u32, &'a u3) == for<'b, 'c> fn(&'b u32, &'c u32)
+            //
+            // Somewhat surprisingly, these two types are actually
+            // **equal**, even though the one on the right looks more
+            // polymorphic. The reason is due to subtyping. To see it,
+            // consider that each function can call the other:
+            //
+            // - The left function can call the right with `'b` and
+            //   `'c` both equal to `'a`
+            //
+            // - The right function can call the left with `'a` set to
+            //   `{P}`, where P is the point in the CFG where the call
+            //   itself occurs. Note that `'b` and `'c` must both
+            //   include P. At the point, the call works because of
+            //   subtyping (i.e., `&'b u32 <: &{P} u32`).
+            let variance = ::std::mem::replace(&mut self.ambient_variance, ty::Variance::Covariant);
+
+            self.relate(a.skip_binder(), b.skip_binder())?;
+
+            self.ambient_variance = variance;
+
+            self.b_scopes.pop().unwrap();
+            self.a_scopes.pop().unwrap();
+        }
+
+        if self.ambient_contravariance() {
+            // Contravariance, so we want `for<..> A :> for<..> B`
+            // -- therefore we compare every instantiation of A (i.e.,
+            // A instantiated with universals) against any
+            // instantiation of B (i.e., B instantiated with
+            // existentials). Opposite of above.
+
+            let a_scope = self.create_scope(a, UniversallyQuantified(true));
+            let b_scope = self.create_scope(b, UniversallyQuantified(false));
+
+            debug!("binders: a_scope = {:?} (universal)", a_scope);
+            debug!("binders: b_scope = {:?} (existential)", b_scope);
+
+            self.a_scopes.push(a_scope);
+            self.b_scopes.push(b_scope);
+
+            // Reset ambient variance to contravariance. See the
+            // covariant case above for an explanation.
+            let variance =
+                ::std::mem::replace(&mut self.ambient_variance, ty::Variance::Contravariant);
+
+            self.relate(a.skip_binder(), b.skip_binder())?;
+
+            self.ambient_variance = variance;
+
+            self.b_scopes.pop().unwrap();
+            self.a_scopes.pop().unwrap();
+        }
+
+        Ok(a.clone())
+    }
+}
+
+/// When we encounter a binder like `for<..> fn(..)`, we actually have
+/// to walk the `fn` value to find all the values bound by the `for`
+/// (these are not explicitly present in the ty representation right
+/// now). This visitor handles that: it descends the type, tracking
+/// binder depth, and finds late-bound regions targeting the
+/// `for<..`>.  For each of those, it creates an entry in
+/// `bound_region_scope`.
+struct ScopeInstantiator<'me, 'tcx: 'me> {
+    next_region: &'me mut dyn FnMut(ty::BoundRegion) -> ty::Region<'tcx>,
+    // The debruijn index of the scope we are instantiating.
+    target_index: ty::DebruijnIndex,
+    bound_region_scope: &'me mut BoundRegionScope<'tcx>,
+}
+
+impl<'me, 'tcx> TypeVisitor<'tcx> for ScopeInstantiator<'me, 'tcx> {
+    fn visit_binder<T: TypeFoldable<'tcx>>(&mut self, t: &ty::Binder<T>) -> bool {
+        self.target_index.shift_in(1);
+        t.super_visit_with(self);
+        self.target_index.shift_out(1);
+
+        false
+    }
+
+    fn visit_region(&mut self, r: ty::Region<'tcx>) -> bool {
+        let ScopeInstantiator {
+            bound_region_scope,
+            next_region,
+            ..
+        } = self;
+
+        match r {
+            ty::ReLateBound(debruijn, br) if *debruijn == self.target_index => {
+                bound_region_scope
+                    .map
+                    .entry(*br)
+                    .or_insert_with(|| next_region(*br));
+            }
+
+            _ => {}
+        }
+
+        false
+    }
+}
+
+/// The "type generalize" is used when handling inference variables.
+///
+/// The basic strategy for handling a constraint like `?A <: B` is to
+/// apply a "generalization strategy" to the type `B` -- this replaces
+/// all the lifetimes in the type `B` with fresh inference
+/// variables. (You can read more about the strategy in this [blog
+/// post].)
+///
+/// As an example, if we had `?A <: &'x u32`, we would generalize `&'x
+/// u32` to `&'0 u32` where `'0` is a fresh variable. This becomes the
+/// value of `A`. Finally, we relate `&'0 u32 <: &'x u32`, which
+/// establishes `'0: 'x` as a constraint.
+///
+/// As a side-effect of this generalization procedure, we also replace
+/// all the bound regions that we have traversed with concrete values,
+/// so that the resulting generalized type is independent from the
+/// scopes.
+///
+/// [blog post]: https://is.gd/0hKvIr
+struct TypeGeneralizer<'me, 'gcx: 'tcx, 'tcx: 'me, D>
+where
+    D: TypeRelatingDelegate<'tcx> + 'me,
+{
+    tcx: TyCtxt<'me, 'gcx, 'tcx>,
+
+    delegate: &'me mut D,
+
+    /// After we generalize this type, we are going to relative it to
+    /// some other type. What will be the variance at this point?
+    ambient_variance: ty::Variance,
+
+    first_free_index: ty::DebruijnIndex,
+
+    universe: ty::UniverseIndex,
+}
+
+impl<D> TypeRelation<'me, 'gcx, 'tcx> for TypeGeneralizer<'me, 'gcx, 'tcx, D>
+where
+    D: TypeRelatingDelegate<'tcx>,
+{
+    fn tcx(&self) -> TyCtxt<'me, 'gcx, 'tcx> {
+        self.tcx
+    }
+
+    fn tag(&self) -> &'static str {
+        "nll::generalizer"
+    }
+
+    fn a_is_expected(&self) -> bool {
+        true
+    }
+
+    fn relate_with_variance<T: Relate<'tcx>>(
+        &mut self,
+        variance: ty::Variance,
+        a: &T,
+        b: &T,
+    ) -> RelateResult<'tcx, T> {
+        debug!(
+            "TypeGeneralizer::relate_with_variance(variance={:?}, a={:?}, b={:?})",
+            variance, a, b
+        );
+
+        let old_ambient_variance = self.ambient_variance;
+        self.ambient_variance = self.ambient_variance.xform(variance);
+
+        debug!(
+            "TypeGeneralizer::relate_with_variance: ambient_variance = {:?}",
+            self.ambient_variance
+        );
+
+        let r = self.relate(a, b)?;
+
+        self.ambient_variance = old_ambient_variance;
+
+        debug!("TypeGeneralizer::relate_with_variance: r={:?}", r);
+
+        Ok(r)
+    }
+
+    fn tys(&mut self, a: Ty<'tcx>, _: Ty<'tcx>) -> RelateResult<'tcx, Ty<'tcx>> {
+        debug!("TypeGeneralizer::tys(a={:?})", a,);
+
+        match a.sty {
+            ty::Infer(ty::TyVar(_)) | ty::Infer(ty::IntVar(_)) | ty::Infer(ty::FloatVar(_)) => {
+                bug!(
+                    "unexpected inference variable encountered in NLL generalization: {:?}",
+                    a
+                );
+            }
+
+            _ => relate::super_relate_tys(self, a, a),
+        }
+    }
+
+    fn regions(
+        &mut self,
+        a: ty::Region<'tcx>,
+        _: ty::Region<'tcx>,
+    ) -> RelateResult<'tcx, ty::Region<'tcx>> {
+        debug!("TypeGeneralizer::regions(a={:?})", a,);
+
+        if let ty::ReLateBound(debruijn, _) = a {
+            if *debruijn < self.first_free_index {
+                return Ok(a);
+            }
+        }
+
+        // For now, we just always create a fresh region variable to
+        // replace all the regions in the source type. In the main
+        // type checker, we special case the case where the ambient
+        // variance is `Invariant` and try to avoid creating a fresh
+        // region variable, but since this comes up so much less in
+        // NLL (only when users use `_` etc) it is much less
+        // important.
+        //
+        // As an aside, since these new variables are created in
+        // `self.universe` universe, this also serves to enforce the
+        // universe scoping rules.
+        //
+        // FIXME(#54105) -- if the ambient variance is bivariant,
+        // though, we may however need to check well-formedness or
+        // risk a problem like #41677 again.
+
+        let replacement_region_vid = self.delegate.generalize_existential(self.universe);
+
+        Ok(replacement_region_vid)
+    }
+
+    fn binders<T>(
+        &mut self,
+        a: &ty::Binder<T>,
+        _: &ty::Binder<T>,
+    ) -> RelateResult<'tcx, ty::Binder<T>>
+    where
+        T: Relate<'tcx>,
+    {
+        debug!("TypeGeneralizer::binders(a={:?})", a,);
+
+        self.first_free_index.shift_in(1);
+        let result = self.relate(a.skip_binder(), a.skip_binder())?;
+        self.first_free_index.shift_out(1);
+        Ok(ty::Binder::bind(result))
+    }
+}
+
+impl InferCtxt<'_, '_, 'tcx> {
+    /// A hacky sort of method used by the NLL type-relating code:
+    ///
+    /// - `var` must be some unbound type variable.
+    /// - `value` must be a suitable type to use as its value.
+    ///
+    /// `var` will then be equated with `value`. Note that this
+    /// sidesteps a number of important checks, such as the "occurs
+    /// check" that prevents cyclic types, so it is important not to
+    /// use this method during regular type-check.
+    fn force_instantiate_unchecked(&self, var: Ty<'tcx>, value: Ty<'tcx>) {
+        match (&var.sty, &value.sty) {
+            (&ty::Infer(ty::TyVar(vid)), _) => {
+                let mut type_variables = self.type_variables.borrow_mut();
+
+                // In NLL, we don't have type inference variables
+                // floating around, so we can do this rather imprecise
+                // variant of the occurs-check.
+                assert!(!value.has_infer_types());
+
+                type_variables.instantiate(vid, value);
+            }
+
+            (&ty::Infer(ty::IntVar(vid)), &ty::Int(value)) => {
+                let mut int_unification_table = self.int_unification_table.borrow_mut();
+                int_unification_table
+                    .unify_var_value(vid, Some(ty::IntVarValue::IntType(value)))
+                    .unwrap_or_else(|_| {
+                        bug!("failed to unify int var `{:?}` with `{:?}`", vid, value);
+                    });
+            }
+
+            (&ty::Infer(ty::IntVar(vid)), &ty::Uint(value)) => {
+                let mut int_unification_table = self.int_unification_table.borrow_mut();
+                int_unification_table
+                    .unify_var_value(vid, Some(ty::IntVarValue::UintType(value)))
+                    .unwrap_or_else(|_| {
+                        bug!("failed to unify int var `{:?}` with `{:?}`", vid, value);
+                    });
+            }
+
+            (&ty::Infer(ty::FloatVar(vid)), &ty::Float(value)) => {
+                let mut float_unification_table = self.float_unification_table.borrow_mut();
+                float_unification_table
+                    .unify_var_value(vid, Some(ty::FloatVarValue(value)))
+                    .unwrap_or_else(|_| {
+                        bug!("failed to unify float var `{:?}` with `{:?}`", vid, value)
+                    });
+            }
+
+            _ => {
+                bug!(
+                    "force_instantiate_unchecked invoked with bad combination: var={:?} value={:?}",
+                    var,
+                    value,
+                );
+            }
+        }
+    }
+}
diff --git a/src/librustc/mir/mod.rs b/src/librustc/mir/mod.rs
index 2587e19b1cb..48b2ccbcf87 100644
--- a/src/librustc/mir/mod.rs
+++ b/src/librustc/mir/mod.rs
@@ -37,7 +37,7 @@ use syntax::ast::{self, Name};
 use syntax::symbol::InternedString;
 use syntax_pos::{Span, DUMMY_SP};
 use ty::fold::{TypeFoldable, TypeFolder, TypeVisitor};
-use ty::subst::{Subst, Substs};
+use ty::subst::{CanonicalUserSubsts, Subst, Substs};
 use ty::{self, AdtDef, CanonicalTy, ClosureSubsts, GeneratorSubsts, Region, Ty, TyCtxt};
 use util::ppaux;
 
@@ -710,7 +710,7 @@ pub struct LocalDecl<'tcx> {
     /// e.g. via `let x: T`, then we carry that type here. The MIR
     /// borrow checker needs this information since it can affect
     /// region inference.
-    pub user_ty: Option<(CanonicalTy<'tcx>, Span)>,
+    pub user_ty: Option<(UserTypeAnnotation<'tcx>, Span)>,
 
     /// Name of the local, used in debuginfo and pretty-printing.
     ///
@@ -1737,7 +1737,7 @@ pub enum StatementKind<'tcx> {
     /// - `Contravariant` -- requires that `T_y :> T`
     /// - `Invariant` -- requires that `T_y == T`
     /// - `Bivariant` -- no effect
-    AscribeUserType(Place<'tcx>, ty::Variance, CanonicalTy<'tcx>),
+    AscribeUserType(Place<'tcx>, ty::Variance, UserTypeAnnotation<'tcx>),
 
     /// No-op. Useful for deleting instructions without affecting statement indices.
     Nop,
@@ -2188,7 +2188,7 @@ pub enum AggregateKind<'tcx> {
         &'tcx AdtDef,
         usize,
         &'tcx Substs<'tcx>,
-        Option<CanonicalTy<'tcx>>,
+        Option<UserTypeAnnotation<'tcx>>,
         Option<usize>,
     ),
 
@@ -2392,7 +2392,7 @@ impl<'tcx> Debug for Rvalue<'tcx> {
 /// this does not necessarily mean that they are "==" in Rust -- in
 /// particular one must be wary of `NaN`!
 
-#[derive(Clone, PartialEq, Eq, Hash, RustcEncodable, RustcDecodable)]
+#[derive(Copy, Clone, PartialEq, Eq, Hash, RustcEncodable, RustcDecodable)]
 pub struct Constant<'tcx> {
     pub span: Span,
     pub ty: Ty<'tcx>,
@@ -2402,11 +2402,29 @@ pub struct Constant<'tcx> {
     /// indicate that `Vec<_>` was explicitly specified.
     ///
     /// Needed for NLL to impose user-given type constraints.
-    pub user_ty: Option<CanonicalTy<'tcx>>,
+    pub user_ty: Option<UserTypeAnnotation<'tcx>>,
 
     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>),
+    FnDef(DefId, CanonicalUserSubsts<'tcx>),
+    AdtDef(&'tcx AdtDef, CanonicalUserSubsts<'tcx>),
+}
+
+EnumTypeFoldableImpl! {
+    impl<'tcx> TypeFoldable<'tcx> for UserTypeAnnotation<'tcx> {
+        (UserTypeAnnotation::Ty)(ty),
+        (UserTypeAnnotation::FnDef)(def, substs),
+        (UserTypeAnnotation::AdtDef)(def, substs),
+    }
+}
+
 newtype_index! {
     pub struct Promoted {
         DEBUG_FORMAT = "promoted[{}]"
diff --git a/src/librustc/mir/visit.rs b/src/librustc/mir/visit.rs
index 920dc88d6a8..76c76404d2f 100644
--- a/src/librustc/mir/visit.rs
+++ b/src/librustc/mir/visit.rs
@@ -10,7 +10,7 @@
 
 use hir::def_id::DefId;
 use ty::subst::Substs;
-use ty::{CanonicalTy, ClosureSubsts, GeneratorSubsts, Region, Ty};
+use ty::{ClosureSubsts, GeneratorSubsts, Region, Ty};
 use mir::*;
 use syntax_pos::Span;
 
@@ -147,9 +147,9 @@ macro_rules! make_mir_visitor {
             fn visit_ascribe_user_ty(&mut self,
                                      place: & $($mutability)* Place<'tcx>,
                                      variance: & $($mutability)* ty::Variance,
-                                     c_ty: & $($mutability)* CanonicalTy<'tcx>,
+                                     user_ty: & $($mutability)* UserTypeAnnotation<'tcx>,
                                      location: Location) {
-                self.super_ascribe_user_ty(place, variance, c_ty, location);
+                self.super_ascribe_user_ty(place, variance, user_ty, location);
             }
 
             fn visit_place(&mut self,
@@ -214,8 +214,11 @@ macro_rules! make_mir_visitor {
                 self.super_ty(ty);
             }
 
-            fn visit_user_ty(&mut self, ty: & $($mutability)* CanonicalTy<'tcx>) {
-                self.super_canonical_ty(ty);
+            fn visit_user_type_annotation(
+                &mut self,
+                ty: & $($mutability)* UserTypeAnnotation<'tcx>,
+            ) {
+                self.super_user_type_annotation(ty);
             }
 
             fn visit_region(&mut self,
@@ -390,9 +393,9 @@ macro_rules! make_mir_visitor {
                     StatementKind::AscribeUserType(
                         ref $($mutability)* place,
                         ref $($mutability)* variance,
-                        ref $($mutability)* c_ty,
+                        ref $($mutability)* user_ty,
                     ) => {
-                        self.visit_ascribe_user_ty(place, variance, c_ty, location);
+                        self.visit_ascribe_user_ty(place, variance, user_ty, location);
                     }
                     StatementKind::Nop => {}
                 }
@@ -637,10 +640,10 @@ macro_rules! make_mir_visitor {
             fn super_ascribe_user_ty(&mut self,
                                      place: & $($mutability)* Place<'tcx>,
                                      _variance: & $($mutability)* ty::Variance,
-                                     c_ty: & $($mutability)* CanonicalTy<'tcx>,
+                                     user_ty: & $($mutability)* UserTypeAnnotation<'tcx>,
                                      location: Location) {
                 self.visit_place(place, PlaceContext::Validate, location);
-                self.visit_user_ty(c_ty);
+                self.visit_user_type_annotation(user_ty);
             }
 
             fn super_place(&mut self,
@@ -736,7 +739,7 @@ macro_rules! make_mir_visitor {
                     source_info: *source_info,
                 });
                 if let Some((user_ty, _)) = user_ty {
-                    self.visit_user_ty(user_ty);
+                    self.visit_user_type_annotation(user_ty);
                 }
                 self.visit_source_info(source_info);
                 self.visit_source_scope(visibility_scope);
@@ -783,7 +786,10 @@ macro_rules! make_mir_visitor {
                 self.visit_source_scope(scope);
             }
 
-            fn super_canonical_ty(&mut self, _ty: & $($mutability)* CanonicalTy<'tcx>) {
+            fn super_user_type_annotation(
+                &mut self,
+                _ty: & $($mutability)* UserTypeAnnotation<'tcx>,
+            ) {
             }
 
             fn super_ty(&mut self, _ty: & $($mutability)* Ty<'tcx>) {
diff --git a/src/librustc/ty/context.rs b/src/librustc/ty/context.rs
index ab1df2d4c3b..6f0f258a217 100644
--- a/src/librustc/ty/context.rs
+++ b/src/librustc/ty/context.rs
@@ -33,7 +33,7 @@ use middle::resolve_lifetime::{self, ObjectLifetimeDefault};
 use middle::stability;
 use mir::{self, Mir, interpret};
 use mir::interpret::Allocation;
-use ty::subst::{CanonicalSubsts, Kind, Substs, Subst};
+use ty::subst::{CanonicalUserSubsts, Kind, Substs, Subst};
 use ty::ReprOptions;
 use traits;
 use traits::{Clause, Clauses, GoalKind, Goal, Goals};
@@ -383,7 +383,7 @@ pub struct TypeckTables<'tcx> {
     /// If the user wrote `foo.collect::<Vec<_>>()`, then the
     /// canonical substitutions would include only `for<X> { Vec<X>
     /// }`.
-    user_substs: ItemLocalMap<CanonicalSubsts<'tcx>>,
+    user_substs: ItemLocalMap<CanonicalUserSubsts<'tcx>>,
 
     adjustments: ItemLocalMap<Vec<ty::adjustment::Adjustment<'tcx>>>,
 
@@ -573,14 +573,14 @@ impl<'tcx> TypeckTables<'tcx> {
         self.node_substs.get(&id.local_id).cloned()
     }
 
-    pub fn user_substs_mut(&mut self) -> LocalTableInContextMut<'_, CanonicalSubsts<'tcx>> {
+    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<CanonicalSubsts<'tcx>> {
+    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()
     }
diff --git a/src/librustc/ty/subst.rs b/src/librustc/ty/subst.rs
index c0a42fd5854..64cfba7df6e 100644
--- a/src/librustc/ty/subst.rs
+++ b/src/librustc/ty/subst.rs
@@ -323,33 +323,6 @@ impl<'tcx> TypeFoldable<'tcx> for &'tcx Substs<'tcx> {
     }
 }
 
-pub type CanonicalSubsts<'gcx> = Canonical<'gcx, &'gcx Substs<'gcx>>;
-
-impl<'gcx> CanonicalSubsts<'gcx> {
-    /// 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 {
-        self.value.iter().zip(CanonicalVar::new(0)..).all(|(kind, cvar)| {
-            match kind.unpack() {
-                UnpackedKind::Type(ty) => match ty.sty {
-                    ty::Infer(ty::CanonicalTy(cvar1)) => cvar == cvar1,
-                    _ => false,
-                },
-
-                UnpackedKind::Lifetime(r) => match r {
-                    ty::ReCanonical(cvar1) => cvar == *cvar1,
-                    _ => false,
-                },
-            }
-        })
-    }
-}
-
 impl<'tcx> serialize::UseSpecializedDecodable for &'tcx Substs<'tcx> {}
 
 ///////////////////////////////////////////////////////////////////////////
@@ -564,3 +537,98 @@ impl<'a, 'gcx, 'tcx> SubstFolder<'a, 'gcx, 'tcx> {
         self.tcx().mk_region(ty::fold::shift_region(*region, self.region_binders_passed))
     }
 }
+
+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(CanonicalVar::new(0)..).all(|(kind, cvar)| {
+            match kind.unpack() {
+                UnpackedKind::Type(ty) => match ty.sty {
+                    ty::Infer(ty::CanonicalTy(cvar1)) => cvar == cvar1,
+                    _ => false,
+                },
+
+                UnpackedKind::Lifetime(r) => match r {
+                    ty::ReCanonical(cvar1) => cvar == *cvar1,
+                    _ => 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)]
+pub struct UserSubsts<'tcx> {
+    /// The substitutions for the item as given by the user.
+    pub substs: &'tcx Substs<'tcx>,
+
+    /// The self-type, in the case of a `<T>::Item` path (when applied
+    /// to an inherent impl). See `UserSelfTy` below.
+    pub user_self_ty: Option<UserSelfTy<'tcx>>,
+}
+
+BraceStructTypeFoldableImpl! {
+    impl<'tcx> TypeFoldable<'tcx> for UserSubsts<'tcx> {
+        substs,
+        user_self_ty,
+    }
+}
+
+BraceStructLiftImpl! {
+    impl<'a, 'tcx> Lift<'tcx> for UserSubsts<'a> {
+        type Lifted = UserSubsts<'tcx>;
+        substs,
+        user_self_ty,
+    }
+}
+
+/// Specifies the user-given self-type. In the case of a path that
+/// refers to a member in an inherent impl, this self-type is
+/// sometimes needed to constrain the type parameters on the impl. For
+/// example, in this code:
+///
+/// ```
+/// struct Foo<T> { }
+/// impl<A> Foo<A> { fn method() { } }
+/// ```
+///
+/// when you then have a path like `<Foo<&'static u32>>::method`,
+/// this struct would carry the def-id of the impl along with the
+/// self-type `Foo<u32>`. Then we can instantiate the parameters of
+/// the impl (with the substs from `UserSubsts`) and apply those to
+/// the self-type, giving `Foo<?A>`. Finally, we unify that with
+/// the self-type here, which contains `?A` to be `&'static u32`
+#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, RustcEncodable, RustcDecodable)]
+pub struct UserSelfTy<'tcx> {
+    pub impl_def_id: DefId,
+    pub self_ty: Ty<'tcx>,
+}
+
+BraceStructTypeFoldableImpl! {
+    impl<'tcx> TypeFoldable<'tcx> for UserSelfTy<'tcx> {
+        impl_def_id,
+        self_ty,
+    }
+}
+
+BraceStructLiftImpl! {
+    impl<'a, 'tcx> Lift<'tcx> for UserSelfTy<'a> {
+        type Lifted = UserSelfTy<'tcx>;
+        impl_def_id,
+        self_ty,
+    }
+}
diff --git a/src/librustc_mir/borrow_check/nll/constraint_generation.rs b/src/librustc_mir/borrow_check/nll/constraint_generation.rs
index 7e8e1b32d4d..30b263a923a 100644
--- a/src/librustc_mir/borrow_check/nll/constraint_generation.rs
+++ b/src/librustc_mir/borrow_check/nll/constraint_generation.rs
@@ -18,9 +18,10 @@ use rustc::mir::visit::TyContext;
 use rustc::mir::visit::Visitor;
 use rustc::mir::{BasicBlock, BasicBlockData, Location, Mir, Place, Rvalue};
 use rustc::mir::{Statement, Terminator};
+use rustc::mir::UserTypeAnnotation;
 use rustc::ty::fold::TypeFoldable;
 use rustc::ty::subst::Substs;
-use rustc::ty::{self, CanonicalTy, ClosureSubsts, GeneratorSubsts, RegionVid};
+use rustc::ty::{self, ClosureSubsts, GeneratorSubsts, RegionVid};
 
 pub(super) fn generate_constraints<'cx, 'gcx, 'tcx>(
     infcx: &InferCtxt<'cx, 'gcx, 'tcx>,
@@ -179,7 +180,7 @@ impl<'cg, 'cx, 'gcx, 'tcx> Visitor<'tcx> for ConstraintGeneration<'cg, 'cx, 'gcx
         &mut self,
         _place: &Place<'tcx>,
         _variance: &ty::Variance,
-        _c_ty: &CanonicalTy<'tcx>,
+        _user_ty: &UserTypeAnnotation<'tcx>,
         _location: Location,
     ) {
     }
diff --git a/src/librustc_mir/borrow_check/nll/renumber.rs b/src/librustc_mir/borrow_check/nll/renumber.rs
index 15a60badc93..363afb87ed9 100644
--- a/src/librustc_mir/borrow_check/nll/renumber.rs
+++ b/src/librustc_mir/borrow_check/nll/renumber.rs
@@ -9,8 +9,8 @@
 // except according to those terms.
 
 use rustc::ty::subst::Substs;
-use rustc::ty::{self, CanonicalTy, ClosureSubsts, GeneratorSubsts, Ty, TypeFoldable};
-use rustc::mir::{BasicBlock, Location, Mir, Statement, StatementKind};
+use rustc::ty::{self, ClosureSubsts, GeneratorSubsts, Ty, TypeFoldable};
+use rustc::mir::{BasicBlock, Location, Mir, Statement, StatementKind, UserTypeAnnotation};
 use rustc::mir::visit::{MutVisitor, TyContext};
 use rustc::infer::{InferCtxt, NLLRegionVariableOrigin};
 
@@ -65,12 +65,12 @@ impl<'a, 'gcx, 'tcx> MutVisitor<'tcx> for NLLVisitor<'a, 'gcx, 'tcx> {
         debug!("visit_ty: ty={:?}", ty);
     }
 
-    fn visit_user_ty(&mut self, _ty: &mut CanonicalTy<'tcx>) {
-        // `user_ty` annotations represent the types that the user
+    fn visit_user_type_annotation(&mut self, _ty: &mut UserTypeAnnotation<'tcx>) {
+        // User type annotations represent the types that the user
         // wrote in the progarm. We don't want to erase the regions
         // from these types: rather, we want to add them as
         // constraints at type-check time.
-        debug!("visit_user_ty: skipping renumber");
+        debug!("visit_user_type_annotation: skipping renumber");
     }
 
     fn visit_substs(&mut self, substs: &mut &'tcx Substs<'tcx>, location: Location) {
diff --git a/src/librustc_mir/borrow_check/nll/type_check/mod.rs b/src/librustc_mir/borrow_check/nll/type_check/mod.rs
index e11f452e16b..1e79bc272e4 100644
--- a/src/librustc_mir/borrow_check/nll/type_check/mod.rs
+++ b/src/librustc_mir/borrow_check/nll/type_check/mod.rs
@@ -43,7 +43,7 @@ use rustc::traits::query::{Fallible, NoSolution};
 use rustc::traits::{ObligationCause, PredicateObligations};
 use rustc::ty::fold::TypeFoldable;
 use rustc::ty::subst::{Subst, UnpackedKind};
-use rustc::ty::{self, CanonicalTy, RegionVid, ToPolyTraitRef, Ty, TyCtxt, TyKind};
+use rustc::ty::{self, RegionVid, ToPolyTraitRef, Ty, TyCtxt, TyKind};
 use std::rc::Rc;
 use std::{fmt, iter};
 use syntax_pos::{Span, DUMMY_SP};
@@ -966,7 +966,7 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> {
         &mut self,
         a: Ty<'tcx>,
         v: ty::Variance,
-        b: CanonicalTy<'tcx>,
+        b: UserTypeAnnotation<'tcx>,
         locations: Locations,
         category: ConstraintCategory,
     ) -> Fallible<()> {
@@ -1837,7 +1837,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<CanonicalTy<'tcx>> {
+    fn rvalue_user_ty(&self, rvalue: &Rvalue<'tcx>) -> Option<UserTypeAnnotation<'tcx>> {
         match rvalue {
             Rvalue::Use(_)
             | Rvalue::Repeat(..)
diff --git a/src/librustc_mir/borrow_check/nll/type_check/relate_tys.rs b/src/librustc_mir/borrow_check/nll/type_check/relate_tys.rs
index 96cc1c0afec..72120eb1841 100644
--- a/src/librustc_mir/borrow_check/nll/type_check/relate_tys.rs
+++ b/src/librustc_mir/borrow_check/nll/type_check/relate_tys.rs
@@ -10,16 +10,14 @@
 
 use borrow_check::nll::constraints::OutlivesConstraint;
 use borrow_check::nll::type_check::{BorrowCheckContext, Locations};
-use rustc::infer::canonical::{Canonical, CanonicalVarInfos, CanonicalVarValues};
+use rustc::infer::nll_relate::{TypeRelating, TypeRelatingDelegate};
 use rustc::infer::{InferCtxt, NLLRegionVariableOrigin};
-use rustc::mir::ConstraintCategory;
+use rustc::mir::{ConstraintCategory, UserTypeAnnotation};
 use rustc::traits::query::Fallible;
-use rustc::ty::fold::{TypeFoldable, TypeVisitor};
-use rustc::ty::relate::{self, Relate, RelateResult, TypeRelation};
-use rustc::ty::subst::Kind;
-use rustc::ty::{self, CanonicalTy, CanonicalVar, Ty, TyCtxt};
-use rustc_data_structures::fx::FxHashMap;
-use rustc_data_structures::indexed_vec::IndexVec;
+use rustc::ty::relate::TypeRelation;
+use rustc::ty::subst::{Subst, UserSelfTy, UserSubsts};
+use rustc::ty::{self, Ty, TypeFoldable};
+use syntax_pos::DUMMY_SP;
 
 /// Adds sufficient constraints to ensure that `a <: b`.
 pub(super) fn sub_types<'tcx>(
@@ -32,10 +30,9 @@ pub(super) fn sub_types<'tcx>(
 ) -> Fallible<()> {
     debug!("sub_types(a={:?}, b={:?}, locations={:?})", a, b, locations);
     TypeRelating::new(
-        infcx.tcx,
+        infcx,
         NllTypeRelatingDelegate::new(infcx, borrowck_context, locations, category),
         ty::Variance::Covariant,
-        ty::List::empty(),
     ).relate(&a, &b)?;
     Ok(())
 }
@@ -51,10 +48,9 @@ pub(super) fn eq_types<'tcx>(
 ) -> Fallible<()> {
     debug!("eq_types(a={:?}, b={:?}, locations={:?})", a, b, locations);
     TypeRelating::new(
-        infcx.tcx,
+        infcx,
         NllTypeRelatingDelegate::new(infcx, borrowck_context, locations, category),
         ty::Variance::Invariant,
-        ty::List::empty(),
     ).relate(&a, &b)?;
     Ok(())
 }
@@ -66,19 +62,15 @@ pub(super) fn relate_type_and_user_type<'tcx>(
     infcx: &InferCtxt<'_, '_, 'tcx>,
     a: Ty<'tcx>,
     v: ty::Variance,
-    b: CanonicalTy<'tcx>,
+    user_ty: UserTypeAnnotation<'tcx>,
     locations: Locations,
     category: ConstraintCategory,
     borrowck_context: Option<&mut BorrowCheckContext<'_, 'tcx>>,
 ) -> Fallible<Ty<'tcx>> {
     debug!(
-        "sub_type_and_user_type(a={:?}, b={:?}, locations={:?})",
-        a, b, locations
+        "relate_type_and_user_type(a={:?}, v={:?}, b={:?}, locations={:?})",
+        a, v, user_ty, locations
     );
-    let Canonical {
-        variables: b_variables,
-        value: b_value,
-    } = b;
 
     // The `TypeRelating` code assumes that the "canonical variables"
     // appear in the "a" side, so flip `Contravariant` ambient
@@ -86,108 +78,75 @@ pub(super) fn relate_type_and_user_type<'tcx>(
     let v1 = ty::Contravariant.xform(v);
 
     let mut type_relating = TypeRelating::new(
-        infcx.tcx,
+        infcx,
         NllTypeRelatingDelegate::new(infcx, borrowck_context, locations, category),
         v1,
-        b_variables,
     );
-    type_relating.relate(&b_value, &a)?;
 
-    Ok(b.substitute(
-        infcx.tcx,
-        &CanonicalVarValues {
-            var_values: type_relating
-                .canonical_var_values
-                .into_iter()
-                .map(|x| x.expect("unsubstituted canonical variable"))
-                .collect(),
-        },
-    ))
-}
+    match user_ty {
+        UserTypeAnnotation::Ty(canonical_ty) => {
+            let (ty, _) =
+                infcx.instantiate_canonical_with_fresh_inference_vars(DUMMY_SP, &canonical_ty);
+            type_relating.relate(&ty, &a)?;
+            Ok(ty)
+        }
+        UserTypeAnnotation::FnDef(def_id, canonical_substs) => {
+            let (
+                UserSubsts {
+                    substs,
+                    user_self_ty,
+                },
+                _,
+            ) = infcx.instantiate_canonical_with_fresh_inference_vars(DUMMY_SP, &canonical_substs);
+            let ty = infcx.tcx.mk_fn_def(def_id, substs);
 
-struct TypeRelating<'me, 'gcx: 'tcx, 'tcx: 'me, D>
-where
-    D: TypeRelatingDelegate<'tcx>,
-{
-    tcx: TyCtxt<'me, 'gcx, 'tcx>,
+            type_relating.relate(&ty, &a)?;
 
-    /// Callback to use when we deduce an outlives relationship
-    delegate: D,
+            if let Some(UserSelfTy {
+                impl_def_id,
+                self_ty,
+            }) = user_self_ty
+            {
+                let impl_self_ty = infcx.tcx.type_of(impl_def_id);
+                let impl_self_ty = impl_self_ty.subst(infcx.tcx, &substs);
 
-    /// How are we relating `a` and `b`?
-    ///
-    /// - covariant means `a <: b`
-    /// - contravariant means `b <: a`
-    /// - invariant means `a == b
-    /// - bivariant means that it doesn't matter
-    ambient_variance: ty::Variance,
+                // There may be type variables in `substs` and hence
+                // in `impl_self_ty`, but they should all have been
+                // resolved to some fixed value during the first call
+                // to `relate`, above. Therefore, if we use
+                // `resolve_type_vars_if_possible` we should get to
+                // something without type variables. This is important
+                // because the `b` type in `relate_with_variance`
+                // below is not permitted to have inference variables.
+                let impl_self_ty = infcx.resolve_type_vars_if_possible(&impl_self_ty);
+                assert!(!impl_self_ty.has_infer_types());
 
-    /// When we pass through a set of binders (e.g., when looking into
-    /// a `fn` type), we push a new bound region scope onto here.  This
-    /// will contain the instantiated region for each region in those
-    /// binders. When we then encounter a `ReLateBound(d, br)`, we can
-    /// use the debruijn index `d` to find the right scope, and then
-    /// bound region name `br` to find the specific instantiation from
-    /// within that scope. See `replace_bound_region`.
-    ///
-    /// This field stores the instantiations for late-bound regions in
-    /// the `a` type.
-    a_scopes: Vec<BoundRegionScope<'tcx>>,
+                type_relating.relate_with_variance(
+                    ty::Variance::Invariant,
+                    &self_ty,
+                    &impl_self_ty,
+                )?;
+            }
 
-    /// Same as `a_scopes`, but for the `b` type.
-    b_scopes: Vec<BoundRegionScope<'tcx>>,
+            Ok(ty)
+        }
+        UserTypeAnnotation::AdtDef(adt_def, canonical_substs) => {
+            let (
+                UserSubsts {
+                    substs,
+                    user_self_ty,
+                },
+                _,
+            ) = infcx.instantiate_canonical_with_fresh_inference_vars(DUMMY_SP, &canonical_substs);
 
-    /// As we execute, the type on the LHS *may* come from a canonical
-    /// source. In that case, we will sometimes find a constraint like
-    /// `?0 = B`, where `B` is a type from the RHS. The first time we
-    /// find that, we simply record `B` (and the list of scopes that
-    /// tells us how to *interpret* `B`). The next time we encounter
-    /// `?0`, then, we can read this value out and use it.
-    ///
-    /// One problem: these variables may be in some other universe,
-    /// how can we enforce that? I guess I could add some kind of
-    /// "minimum universe constraint" that we can feed to the NLL checker.
-    /// --> also, we know this doesn't happen
-    canonical_var_values: IndexVec<CanonicalVar, Option<Kind<'tcx>>>,
-}
+            // We don't extract adt-defs with a self-type.
+            assert!(user_self_ty.is_none());
 
-trait TypeRelatingDelegate<'tcx> {
-    /// Push a constraint `sup: sub` -- this constraint must be
-    /// satisfied for the two types to be related. `sub` and `sup` may
-    /// be regions from the type or new variables created through the
-    /// delegate.
-    fn push_outlives(&mut self, sup: ty::Region<'tcx>, sub: ty::Region<'tcx>);
-
-    /// Creates a new universe index. Used when instantiating placeholders.
-    fn create_next_universe(&mut self) -> ty::UniverseIndex;
-
-    /// Creates a new region variable representing a higher-ranked
-    /// region that is instantiated existentially. This creates an
-    /// inference variable, typically.
-    ///
-    /// So e.g. if you have `for<'a> fn(..) <: for<'b> fn(..)`, then
-    /// we will invoke this method to instantiate `'a` with an
-    /// inference variable (though `'b` would be instantiated first,
-    /// as a placeholder).
-    fn next_existential_region_var(&mut self) -> ty::Region<'tcx>;
-
-    /// Creates a new region variable representing a
-    /// higher-ranked region that is instantiated universally.
-    /// This creates a new region placeholder, typically.
-    ///
-    /// So e.g. if you have `for<'a> fn(..) <: for<'b> fn(..)`, then
-    /// we will invoke this method to instantiate `'b` with a
-    /// placeholder region.
-    fn next_placeholder_region(&mut self, placeholder: ty::Placeholder) -> ty::Region<'tcx>;
-
-    /// Creates a new existential region in the given universe. This
-    /// is used when handling subtyping and type variables -- if we
-    /// have that `?X <: Foo<'a>`, for example, we would instantiate
-    /// `?X` with a type like `Foo<'?0>` where `'?0` is a fresh
-    /// existential variable created by this function. We would then
-    /// relate `Foo<'?0>` with `Foo<'a>` (and probably add an outlives
-    /// relation stating that `'?0: 'a`).
-    fn generalize_existential(&mut self, universe: ty::UniverseIndex) -> ty::Region<'tcx>;
+            let ty = infcx.tcx.mk_adt(adt_def, substs);
+            type_relating.relate(&ty, &a)?;
+            Ok(ty)
+        }
+    }
 }
 
 struct NllTypeRelatingDelegate<'me, 'bccx: 'me, 'gcx: 'tcx, 'tcx: 'bccx> {
@@ -256,585 +215,3 @@ impl TypeRelatingDelegate<'tcx> for NllTypeRelatingDelegate<'_, '_, '_, 'tcx> {
         }
     }
 }
-
-#[derive(Clone, Debug)]
-struct ScopesAndKind<'tcx> {
-    scopes: Vec<BoundRegionScope<'tcx>>,
-    kind: Kind<'tcx>,
-}
-
-#[derive(Clone, Debug, Default)]
-struct BoundRegionScope<'tcx> {
-    map: FxHashMap<ty::BoundRegion, ty::Region<'tcx>>,
-}
-
-#[derive(Copy, Clone)]
-struct UniversallyQuantified(bool);
-
-impl<'me, 'gcx, 'tcx, D> TypeRelating<'me, 'gcx, 'tcx, D>
-where
-    D: TypeRelatingDelegate<'tcx>,
-{
-    fn new(
-        tcx: TyCtxt<'me, 'gcx, 'tcx>,
-        delegate: D,
-        ambient_variance: ty::Variance,
-        canonical_var_infos: CanonicalVarInfos<'tcx>,
-    ) -> Self {
-        let canonical_var_values = IndexVec::from_elem_n(None, canonical_var_infos.len());
-        Self {
-            tcx,
-            delegate,
-            ambient_variance,
-            canonical_var_values,
-            a_scopes: vec![],
-            b_scopes: vec![],
-        }
-    }
-
-    fn ambient_covariance(&self) -> bool {
-        match self.ambient_variance {
-            ty::Variance::Covariant | ty::Variance::Invariant => true,
-            ty::Variance::Contravariant | ty::Variance::Bivariant => false,
-        }
-    }
-
-    fn ambient_contravariance(&self) -> bool {
-        match self.ambient_variance {
-            ty::Variance::Contravariant | ty::Variance::Invariant => true,
-            ty::Variance::Covariant | ty::Variance::Bivariant => false,
-        }
-    }
-
-    fn create_scope(
-        &mut self,
-        value: &ty::Binder<impl TypeFoldable<'tcx>>,
-        universally_quantified: UniversallyQuantified,
-    ) -> BoundRegionScope<'tcx> {
-        let mut scope = BoundRegionScope::default();
-
-        // Create a callback that creates (via the delegate) either an
-        // existential or placeholder region as needed.
-        let mut next_region = {
-            let delegate = &mut self.delegate;
-            let mut lazy_universe = None;
-            move |br: ty::BoundRegion| {
-                if universally_quantified.0 {
-                    // The first time this closure is called, create a
-                    // new universe for the placeholders we will make
-                    // from here out.
-                    let universe = lazy_universe.unwrap_or_else(|| {
-                        let universe = delegate.create_next_universe();
-                        lazy_universe = Some(universe);
-                        universe
-                    });
-
-                    let placeholder = ty::Placeholder { universe, name: br };
-                    delegate.next_placeholder_region(placeholder)
-                } else {
-                    delegate.next_existential_region_var()
-                }
-            }
-        };
-
-        value.skip_binder().visit_with(&mut ScopeInstantiator {
-            next_region: &mut next_region,
-            target_index: ty::INNERMOST,
-            bound_region_scope: &mut scope,
-        });
-
-        scope
-    }
-
-    /// When we encounter binders during the type traversal, we record
-    /// the value to substitute for each of the things contained in
-    /// that binder. (This will be either a universal placeholder or
-    /// an existential inference variable.) Given the debruijn index
-    /// `debruijn` (and name `br`) of some binder we have now
-    /// encountered, this routine finds the value that we instantiated
-    /// the region with; to do so, it indexes backwards into the list
-    /// of ambient scopes `scopes`.
-    fn lookup_bound_region(
-        debruijn: ty::DebruijnIndex,
-        br: &ty::BoundRegion,
-        first_free_index: ty::DebruijnIndex,
-        scopes: &[BoundRegionScope<'tcx>],
-    ) -> ty::Region<'tcx> {
-        // The debruijn index is a "reverse index" into the
-        // scopes listing. So when we have INNERMOST (0), we
-        // want the *last* scope pushed, and so forth.
-        let debruijn_index = debruijn.index() - first_free_index.index();
-        let scope = &scopes[scopes.len() - debruijn_index - 1];
-
-        // Find this bound region in that scope to map to a
-        // particular region.
-        scope.map[br]
-    }
-
-    /// If `r` is a bound region, find the scope in which it is bound
-    /// (from `scopes`) and return the value that we instantiated it
-    /// with. Otherwise just return `r`.
-    fn replace_bound_region(
-        &self,
-        r: ty::Region<'tcx>,
-        first_free_index: ty::DebruijnIndex,
-        scopes: &[BoundRegionScope<'tcx>],
-    ) -> ty::Region<'tcx> {
-        if let ty::ReLateBound(debruijn, br) = r {
-            Self::lookup_bound_region(*debruijn, br, first_free_index, scopes)
-        } else {
-            r
-        }
-    }
-
-    /// Push a new outlives requirement into our output set of
-    /// constraints.
-    fn push_outlives(&mut self, sup: ty::Region<'tcx>, sub: ty::Region<'tcx>) {
-        debug!("push_outlives({:?}: {:?})", sup, sub);
-
-        self.delegate.push_outlives(sup, sub);
-    }
-
-    /// When we encounter a canonical variable `var` in the output,
-    /// equate it with `kind`. If the variable has been previously
-    /// equated, then equate it again.
-    fn relate_var(
-        &mut self,
-        var: CanonicalVar,
-        b_kind: Kind<'tcx>,
-    ) -> RelateResult<'tcx, Kind<'tcx>> {
-        debug!("equate_var(var={:?}, b_kind={:?})", var, b_kind);
-
-        let generalized_kind = match self.canonical_var_values[var] {
-            Some(v) => v,
-            None => {
-                let generalized_kind = self.generalize_value(b_kind);
-                self.canonical_var_values[var] = Some(generalized_kind);
-                generalized_kind
-            }
-        };
-
-        // The generalized values we extract from `canonical_var_values` have
-        // been fully instantiated and hence the set of scopes we have
-        // doesn't matter -- just to be sure, put an empty vector
-        // in there.
-        let old_a_scopes = ::std::mem::replace(&mut self.a_scopes, vec![]);
-
-        // Relate the generalized kind to the original one.
-        let result = self.relate(&generalized_kind, &b_kind);
-
-        // Restore the old scopes now.
-        self.a_scopes = old_a_scopes;
-
-        debug!("equate_var: complete, result = {:?}", result);
-        return result;
-    }
-
-    fn generalize_value(&mut self, kind: Kind<'tcx>) -> Kind<'tcx> {
-        TypeGeneralizer {
-            tcx: self.tcx,
-            delegate: &mut self.delegate,
-            first_free_index: ty::INNERMOST,
-            ambient_variance: self.ambient_variance,
-
-            // These always correspond to an `_` or `'_` written by
-            // user, and those are always in the root universe.
-            universe: ty::UniverseIndex::ROOT,
-        }.relate(&kind, &kind)
-            .unwrap()
-    }
-}
-
-impl<D> TypeRelation<'me, 'gcx, 'tcx> for TypeRelating<'me, 'gcx, 'tcx, D>
-where
-    D: TypeRelatingDelegate<'tcx>,
-{
-    fn tcx(&self) -> TyCtxt<'me, 'gcx, 'tcx> {
-        self.tcx
-    }
-
-    fn tag(&self) -> &'static str {
-        "nll::subtype"
-    }
-
-    fn a_is_expected(&self) -> bool {
-        true
-    }
-
-    fn relate_with_variance<T: Relate<'tcx>>(
-        &mut self,
-        variance: ty::Variance,
-        a: &T,
-        b: &T,
-    ) -> RelateResult<'tcx, T> {
-        debug!(
-            "relate_with_variance(variance={:?}, a={:?}, b={:?})",
-            variance, a, b
-        );
-
-        let old_ambient_variance = self.ambient_variance;
-        self.ambient_variance = self.ambient_variance.xform(variance);
-
-        debug!(
-            "relate_with_variance: ambient_variance = {:?}",
-            self.ambient_variance
-        );
-
-        let r = self.relate(a, b)?;
-
-        self.ambient_variance = old_ambient_variance;
-
-        debug!("relate_with_variance: r={:?}", r);
-
-        Ok(r)
-    }
-
-    fn tys(&mut self, a: Ty<'tcx>, b: Ty<'tcx>) -> RelateResult<'tcx, Ty<'tcx>> {
-        // Watch out for the case that we are matching a `?T` against the
-        // right-hand side.
-        if let ty::Infer(ty::CanonicalTy(var)) = a.sty {
-            self.relate_var(var, b.into())?;
-            Ok(a)
-        } else {
-            debug!(
-                "tys(a={:?}, b={:?}, variance={:?})",
-                a, b, self.ambient_variance
-            );
-
-            relate::super_relate_tys(self, a, b)
-        }
-    }
-
-    fn regions(
-        &mut self,
-        a: ty::Region<'tcx>,
-        b: ty::Region<'tcx>,
-    ) -> RelateResult<'tcx, ty::Region<'tcx>> {
-        if let ty::ReCanonical(var) = a {
-            self.relate_var(*var, b.into())?;
-            return Ok(a);
-        }
-
-        debug!(
-            "regions(a={:?}, b={:?}, variance={:?})",
-            a, b, self.ambient_variance
-        );
-
-        let v_a = self.replace_bound_region(a, ty::INNERMOST, &self.a_scopes);
-        let v_b = self.replace_bound_region(b, ty::INNERMOST, &self.b_scopes);
-
-        debug!("regions: v_a = {:?}", v_a);
-        debug!("regions: v_b = {:?}", v_b);
-
-        if self.ambient_covariance() {
-            // Covariance: a <= b. Hence, `b: a`.
-            self.push_outlives(v_b, v_a);
-        }
-
-        if self.ambient_contravariance() {
-            // Contravariant: b <= a. Hence, `a: b`.
-            self.push_outlives(v_a, v_b);
-        }
-
-        Ok(a)
-    }
-
-    fn binders<T>(
-        &mut self,
-        a: &ty::Binder<T>,
-        b: &ty::Binder<T>,
-    ) -> RelateResult<'tcx, ty::Binder<T>>
-    where
-        T: Relate<'tcx>,
-    {
-        // We want that
-        //
-        // ```
-        // for<'a> fn(&'a u32) -> &'a u32 <:
-        //   fn(&'b u32) -> &'b u32
-        // ```
-        //
-        // but not
-        //
-        // ```
-        // fn(&'a u32) -> &'a u32 <:
-        //   for<'b> fn(&'b u32) -> &'b u32
-        // ```
-        //
-        // We therefore proceed as follows:
-        //
-        // - Instantiate binders on `b` universally, yielding a universe U1.
-        // - Instantiate binders on `a` existentially in U1.
-
-        debug!(
-            "binders({:?}: {:?}, ambient_variance={:?})",
-            a, b, self.ambient_variance
-        );
-
-        if self.ambient_covariance() {
-            // Covariance, so we want `for<..> A <: for<..> B` --
-            // therefore we compare any instantiation of A (i.e., A
-            // instantiated with existentials) against every
-            // instantiation of B (i.e., B instantiated with
-            // universals).
-
-            let b_scope = self.create_scope(b, UniversallyQuantified(true));
-            let a_scope = self.create_scope(a, UniversallyQuantified(false));
-
-            debug!("binders: a_scope = {:?} (existential)", a_scope);
-            debug!("binders: b_scope = {:?} (universal)", b_scope);
-
-            self.b_scopes.push(b_scope);
-            self.a_scopes.push(a_scope);
-
-            // Reset the ambient variance to covariant. This is needed
-            // to correctly handle cases like
-            //
-            //     for<'a> fn(&'a u32, &'a u3) == for<'b, 'c> fn(&'b u32, &'c u32)
-            //
-            // Somewhat surprisingly, these two types are actually
-            // **equal**, even though the one on the right looks more
-            // polymorphic. The reason is due to subtyping. To see it,
-            // consider that each function can call the other:
-            //
-            // - The left function can call the right with `'b` and
-            //   `'c` both equal to `'a`
-            //
-            // - The right function can call the left with `'a` set to
-            //   `{P}`, where P is the point in the CFG where the call
-            //   itself occurs. Note that `'b` and `'c` must both
-            //   include P. At the point, the call works because of
-            //   subtyping (i.e., `&'b u32 <: &{P} u32`).
-            let variance = ::std::mem::replace(&mut self.ambient_variance, ty::Variance::Covariant);
-
-            self.relate(a.skip_binder(), b.skip_binder())?;
-
-            self.ambient_variance = variance;
-
-            self.b_scopes.pop().unwrap();
-            self.a_scopes.pop().unwrap();
-        }
-
-        if self.ambient_contravariance() {
-            // Contravariance, so we want `for<..> A :> for<..> B`
-            // -- therefore we compare every instantiation of A (i.e.,
-            // A instantiated with universals) against any
-            // instantiation of B (i.e., B instantiated with
-            // existentials). Opposite of above.
-
-            let a_scope = self.create_scope(a, UniversallyQuantified(true));
-            let b_scope = self.create_scope(b, UniversallyQuantified(false));
-
-            debug!("binders: a_scope = {:?} (universal)", a_scope);
-            debug!("binders: b_scope = {:?} (existential)", b_scope);
-
-            self.a_scopes.push(a_scope);
-            self.b_scopes.push(b_scope);
-
-            // Reset ambient variance to contravariance. See the
-            // covariant case above for an explanation.
-            let variance =
-                ::std::mem::replace(&mut self.ambient_variance, ty::Variance::Contravariant);
-
-            self.relate(a.skip_binder(), b.skip_binder())?;
-
-            self.ambient_variance = variance;
-
-            self.b_scopes.pop().unwrap();
-            self.a_scopes.pop().unwrap();
-        }
-
-        Ok(a.clone())
-    }
-}
-
-/// When we encounter a binder like `for<..> fn(..)`, we actually have
-/// to walk the `fn` value to find all the values bound by the `for`
-/// (these are not explicitly present in the ty representation right
-/// now). This visitor handles that: it descends the type, tracking
-/// binder depth, and finds late-bound regions targeting the
-/// `for<..`>.  For each of those, it creates an entry in
-/// `bound_region_scope`.
-struct ScopeInstantiator<'me, 'tcx: 'me> {
-    next_region: &'me mut dyn FnMut(ty::BoundRegion) -> ty::Region<'tcx>,
-    // The debruijn index of the scope we are instantiating.
-    target_index: ty::DebruijnIndex,
-    bound_region_scope: &'me mut BoundRegionScope<'tcx>,
-}
-
-impl<'me, 'tcx> TypeVisitor<'tcx> for ScopeInstantiator<'me, 'tcx> {
-    fn visit_binder<T: TypeFoldable<'tcx>>(&mut self, t: &ty::Binder<T>) -> bool {
-        self.target_index.shift_in(1);
-        t.super_visit_with(self);
-        self.target_index.shift_out(1);
-
-        false
-    }
-
-    fn visit_region(&mut self, r: ty::Region<'tcx>) -> bool {
-        let ScopeInstantiator {
-            bound_region_scope,
-            next_region,
-            ..
-        } = self;
-
-        match r {
-            ty::ReLateBound(debruijn, br) if *debruijn == self.target_index => {
-                bound_region_scope
-                    .map
-                    .entry(*br)
-                    .or_insert_with(|| next_region(*br));
-            }
-
-            _ => {}
-        }
-
-        false
-    }
-}
-
-/// The "type generalize" is used when handling inference variables.
-///
-/// The basic strategy for handling a constraint like `?A <: B` is to
-/// apply a "generalization strategy" to the type `B` -- this replaces
-/// all the lifetimes in the type `B` with fresh inference
-/// variables. (You can read more about the strategy in this [blog
-/// post].)
-///
-/// As an example, if we had `?A <: &'x u32`, we would generalize `&'x
-/// u32` to `&'0 u32` where `'0` is a fresh variable. This becomes the
-/// value of `A`. Finally, we relate `&'0 u32 <: &'x u32`, which
-/// establishes `'0: 'x` as a constraint.
-///
-/// As a side-effect of this generalization procedure, we also replace
-/// all the bound regions that we have traversed with concrete values,
-/// so that the resulting generalized type is independent from the
-/// scopes.
-///
-/// [blog post]: https://is.gd/0hKvIr
-struct TypeGeneralizer<'me, 'gcx: 'tcx, 'tcx: 'me, D>
-where
-    D: TypeRelatingDelegate<'tcx> + 'me,
-{
-    tcx: TyCtxt<'me, 'gcx, 'tcx>,
-
-    delegate: &'me mut D,
-
-    /// After we generalize this type, we are going to relative it to
-    /// some other type. What will be the variance at this point?
-    ambient_variance: ty::Variance,
-
-    first_free_index: ty::DebruijnIndex,
-
-    universe: ty::UniverseIndex,
-}
-
-impl<D> TypeRelation<'me, 'gcx, 'tcx> for TypeGeneralizer<'me, 'gcx, 'tcx, D>
-where
-    D: TypeRelatingDelegate<'tcx>,
-{
-    fn tcx(&self) -> TyCtxt<'me, 'gcx, 'tcx> {
-        self.tcx
-    }
-
-    fn tag(&self) -> &'static str {
-        "nll::generalizer"
-    }
-
-    fn a_is_expected(&self) -> bool {
-        true
-    }
-
-    fn relate_with_variance<T: Relate<'tcx>>(
-        &mut self,
-        variance: ty::Variance,
-        a: &T,
-        b: &T,
-    ) -> RelateResult<'tcx, T> {
-        debug!(
-            "TypeGeneralizer::relate_with_variance(variance={:?}, a={:?}, b={:?})",
-            variance, a, b
-        );
-
-        let old_ambient_variance = self.ambient_variance;
-        self.ambient_variance = self.ambient_variance.xform(variance);
-
-        debug!(
-            "TypeGeneralizer::relate_with_variance: ambient_variance = {:?}",
-            self.ambient_variance
-        );
-
-        let r = self.relate(a, b)?;
-
-        self.ambient_variance = old_ambient_variance;
-
-        debug!("TypeGeneralizer::relate_with_variance: r={:?}", r);
-
-        Ok(r)
-    }
-
-    fn tys(&mut self, a: Ty<'tcx>, _: Ty<'tcx>) -> RelateResult<'tcx, Ty<'tcx>> {
-        debug!("TypeGeneralizer::tys(a={:?})", a,);
-
-        match a.sty {
-            ty::Infer(ty::TyVar(_)) | ty::Infer(ty::IntVar(_)) | ty::Infer(ty::FloatVar(_)) => {
-                bug!(
-                    "unexpected inference variable encountered in NLL generalization: {:?}",
-                    a
-                );
-            }
-
-            _ => relate::super_relate_tys(self, a, a),
-        }
-    }
-
-    fn regions(
-        &mut self,
-        a: ty::Region<'tcx>,
-        _: ty::Region<'tcx>,
-    ) -> RelateResult<'tcx, ty::Region<'tcx>> {
-        debug!("TypeGeneralizer::regions(a={:?})", a,);
-
-        if let ty::ReLateBound(debruijn, _) = a {
-            if *debruijn < self.first_free_index {
-                return Ok(a);
-            }
-        }
-
-        // For now, we just always create a fresh region variable to
-        // replace all the regions in the source type. In the main
-        // type checker, we special case the case where the ambient
-        // variance is `Invariant` and try to avoid creating a fresh
-        // region variable, but since this comes up so much less in
-        // NLL (only when users use `_` etc) it is much less
-        // important.
-        //
-        // As an aside, since these new variables are created in
-        // `self.universe` universe, this also serves to enforce the
-        // universe scoping rules.
-        //
-        // FIXME(#54105) -- if the ambient variance is bivariant,
-        // though, we may however need to check well-formedness or
-        // risk a problem like #41677 again.
-
-        let replacement_region_vid = self.delegate.generalize_existential(self.universe);
-
-        Ok(replacement_region_vid)
-    }
-
-    fn binders<T>(
-        &mut self,
-        a: &ty::Binder<T>,
-        _: &ty::Binder<T>,
-    ) -> RelateResult<'tcx, ty::Binder<T>>
-    where
-        T: Relate<'tcx>,
-    {
-        debug!("TypeGeneralizer::binders(a={:?})", a,);
-
-        self.first_free_index.shift_in(1);
-        let result = self.relate(a.skip_binder(), a.skip_binder())?;
-        self.first_free_index.shift_out(1);
-        Ok(ty::Binder::bind(result))
-    }
-}
diff --git a/src/librustc_mir/build/matches/mod.rs b/src/librustc_mir/build/matches/mod.rs
index 394fa4e077c..99c0a52a8ee 100644
--- a/src/librustc_mir/build/matches/mod.rs
+++ b/src/librustc_mir/build/matches/mod.rs
@@ -20,7 +20,7 @@ use build::{GuardFrame, GuardFrameLocal, LocalsForNode};
 use hair::*;
 use rustc::hir;
 use rustc::mir::*;
-use rustc::ty::{self, CanonicalTy, Ty};
+use rustc::ty::{self, Ty};
 use rustc_data_structures::bit_set::BitSet;
 use rustc_data_structures::fx::FxHashMap;
 use syntax::ast::{Name, NodeId};
@@ -491,7 +491,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
     pub fn visit_bindings(
         &mut self,
         pattern: &Pattern<'tcx>,
-        mut pattern_user_ty: Option<(CanonicalTy<'tcx>, Span)>,
+        mut pattern_user_ty: Option<(UserTypeAnnotation<'tcx>, Span)>,
         f: &mut impl FnMut(
             &mut Self,
             Mutability,
@@ -500,7 +500,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
             NodeId,
             Span,
             Ty<'tcx>,
-            Option<(CanonicalTy<'tcx>, Span)>,
+            Option<(UserTypeAnnotation<'tcx>, Span)>,
         ),
     ) {
         match *pattern.kind {
@@ -626,7 +626,7 @@ struct Binding<'tcx> {
 struct Ascription<'tcx> {
     span: Span,
     source: Place<'tcx>,
-    user_ty: CanonicalTy<'tcx>,
+    user_ty: UserTypeAnnotation<'tcx>,
 }
 
 #[derive(Clone, Debug)]
@@ -1470,7 +1470,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
         num_patterns: usize,
         var_id: NodeId,
         var_ty: Ty<'tcx>,
-        user_var_ty: Option<(CanonicalTy<'tcx>, Span)>,
+        user_var_ty: Option<(UserTypeAnnotation<'tcx>, Span)>,
         has_guard: ArmHasGuard,
         opt_match_place: Option<(Option<Place<'tcx>>, Span)>,
         pat_span: Span,
diff --git a/src/librustc_mir/hair/cx/block.rs b/src/librustc_mir/hair/cx/block.rs
index 022c606a0f8..9865867a196 100644
--- a/src/librustc_mir/hair/cx/block.rs
+++ b/src/librustc_mir/hair/cx/block.rs
@@ -86,12 +86,12 @@ 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_tys().get(ty.hir_id) {
                                 pattern = Pattern {
                                     ty: pattern.ty,
                                     span: pattern.span,
                                     kind: Box::new(PatternKind::AscribeUserType {
-                                        user_ty: *user_ty,
+                                        user_ty: UserTypeAnnotation::Ty(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 c969a3ef348..56a29f29d68 100644
--- a/src/librustc_mir/hair/cx/expr.rs
+++ b/src/librustc_mir/hair/cx/expr.rs
@@ -295,13 +295,7 @@ fn make_mirror_unadjusted<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>,
                     let substs = cx.tables().node_substs(fun.hir_id);
 
                     let user_ty = cx.tables().user_substs(fun.hir_id)
-                        .map(|user_substs| {
-                            user_substs.unchecked_map(|user_substs| {
-                                // Here, we just pair an `AdtDef` with the
-                                // `user_substs`, so no new types etc are introduced.
-                                cx.tcx().mk_adt(adt_def, user_substs)
-                            })
-                        });
+                        .map(|user_substs| UserTypeAnnotation::AdtDef(adt_def, user_substs));
 
                     let field_refs = args.iter()
                         .enumerate()
@@ -725,9 +719,15 @@ fn make_mirror_unadjusted<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>,
         }
         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)
-                .expect(&format!("{:?} not found in user_provided_tys, source: {:?}", ty, source));
+            let user_ty = UserTypeAnnotation::Ty(
+                *user_provided_tys
+                    .get(ty.hir_id)
+                    .expect(&format!(
+                        "{:?} not found in user_provided_tys, source: {:?}",
+                        ty,
+                        source,
+                    ))
+            );
             if source.is_place_expr() {
                 ExprKind::PlaceTypeAscription {
                     source: source.to_ref(),
@@ -759,11 +759,11 @@ fn make_mirror_unadjusted<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>,
     }
 }
 
-fn user_annotated_ty_for_def(
+fn user_substs_applied_to_def(
     cx: &mut Cx<'a, 'gcx, 'tcx>,
     hir_id: hir::HirId,
     def: &Def,
-) -> Option<CanonicalTy<'tcx>> {
+) -> Option<UserTypeAnnotation<'tcx>> {
     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
@@ -772,11 +772,7 @@ fn user_annotated_ty_for_def(
         Def::Method(_) |
         Def::StructCtor(_, CtorKind::Fn) |
         Def::VariantCtor(_, CtorKind::Fn) =>
-            Some(cx.tables().user_substs(hir_id)?.unchecked_map(|user_substs| {
-                // Here, we just pair a `DefId` with the
-                // `user_substs`, so no new types etc are introduced.
-                cx.tcx().mk_fn_def(def.def_id(), user_substs)
-            })),
+            Some(UserTypeAnnotation::FnDef(def.def_id(), cx.tables().user_substs(hir_id)?)),
 
         Def::Const(_def_id) |
         Def::AssociatedConst(_def_id) =>
@@ -795,7 +791,7 @@ fn user_annotated_ty_for_def(
             cx.user_substs_applied_to_ty_of_hir_id(hir_id),
 
         _ =>
-            bug!("user_annotated_ty_for_def: unexpected def {:?} at {:?}", def, hir_id)
+            bug!("user_substs_applied_to_def: unexpected def {:?} at {:?}", def, hir_id)
     }
 }
 
@@ -815,7 +811,7 @@ fn method_callee<'a, 'gcx, 'tcx>(
                 .unwrap_or_else(|| {
                     span_bug!(expr.span, "no type-dependent def for method callee")
                 });
-            let user_ty = user_annotated_ty_for_def(cx, expr.hir_id, def);
+            let user_ty = user_substs_applied_to_def(cx, expr.hir_id, def);
             (def.def_id(), cx.tables().node_substs(expr.hir_id), user_ty)
         }
     };
@@ -882,7 +878,7 @@ fn convert_path_expr<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>,
         Def::StructCtor(_, CtorKind::Fn) |
         Def::VariantCtor(_, CtorKind::Fn) |
         Def::SelfCtor(..) => {
-            let user_ty = user_annotated_ty_for_def(cx, expr.hir_id, &def);
+            let user_ty = user_substs_applied_to_def(cx, expr.hir_id, &def);
             ExprKind::Literal {
                 literal: ty::Const::zero_sized(
                     cx.tcx,
diff --git a/src/librustc_mir/hair/mod.rs b/src/librustc_mir/hair/mod.rs
index e4f88e4fcc3..781b6c92aa1 100644
--- a/src/librustc_mir/hair/mod.rs
+++ b/src/librustc_mir/hair/mod.rs
@@ -14,11 +14,11 @@
 //! unit-tested and separated from the Rust source and compiler data
 //! structures.
 
-use rustc::mir::{BinOp, BorrowKind, Field, UnOp};
+use rustc::mir::{BinOp, BorrowKind, UserTypeAnnotation, Field, UnOp};
 use rustc::hir::def_id::DefId;
 use rustc::middle::region;
 use rustc::ty::subst::Substs;
-use rustc::ty::{AdtDef, CanonicalTy, UpvarSubsts, Region, Ty, Const};
+use rustc::ty::{AdtDef, UpvarSubsts, Region, Ty, Const};
 use rustc::hir;
 use syntax::ast;
 use syntax_pos::Span;
@@ -268,7 +268,7 @@ pub enum ExprKind<'tcx> {
 
         /// Optional user-given substs: for something like `let x =
         /// Bar::<T> { ... }`.
-        user_ty: Option<CanonicalTy<'tcx>>,
+        user_ty: Option<UserTypeAnnotation<'tcx>>,
 
         fields: Vec<FieldExprRef<'tcx>>,
         base: Option<FruInfo<'tcx>>
@@ -276,12 +276,12 @@ pub enum ExprKind<'tcx> {
     PlaceTypeAscription {
         source: ExprRef<'tcx>,
         /// Type that the user gave to this expression
-        user_ty: CanonicalTy<'tcx>,
+        user_ty: UserTypeAnnotation<'tcx>,
     },
     ValueTypeAscription {
         source: ExprRef<'tcx>,
         /// Type that the user gave to this expression
-        user_ty: CanonicalTy<'tcx>,
+        user_ty: UserTypeAnnotation<'tcx>,
     },
     Closure {
         closure_id: DefId,
@@ -291,13 +291,7 @@ pub enum ExprKind<'tcx> {
     },
     Literal {
         literal: &'tcx Const<'tcx>,
-
-        /// Optional user-given type: for something like
-        /// `collect::<Vec<_>>`, this would be present and would
-        /// indicate that `Vec<_>` was explicitly specified.
-        ///
-        /// Needed for NLL to impose user-given type constraints.
-        user_ty: Option<CanonicalTy<'tcx>>,
+        user_ty: Option<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 0238a23895e..cb974366a30 100644
--- a/src/librustc_mir/hair/pattern/mod.rs
+++ b/src/librustc_mir/hair/pattern/mod.rs
@@ -20,9 +20,9 @@ use const_eval::{const_field, const_variant_index};
 
 use hair::util::UserAnnotatedTyHelpers;
 
-use rustc::mir::{fmt_const_val, Field, BorrowKind, Mutability};
+use rustc::mir::{fmt_const_val, Field, BorrowKind, Mutability, UserTypeAnnotation};
 use rustc::mir::interpret::{Scalar, GlobalId, ConstValue, sign_extend};
-use rustc::ty::{self, CanonicalTy, TyCtxt, AdtDef, Ty, Region};
+use rustc::ty::{self, Region, TyCtxt, AdtDef, Ty};
 use rustc::ty::subst::{Substs, Kind};
 use rustc::hir::{self, PatKind, RangeEnd};
 use rustc::hir::def::{Def, CtorKind};
@@ -69,7 +69,7 @@ pub enum PatternKind<'tcx> {
     Wild,
 
     AscribeUserType {
-        user_ty: CanonicalTy<'tcx>,
+        user_ty: UserTypeAnnotation<'tcx>,
         subpattern: Pattern<'tcx>,
         user_ty_span: Span,
     },
@@ -980,7 +980,7 @@ macro_rules! CloneImpls {
 CloneImpls!{ <'tcx>
     Span, Field, Mutability, ast::Name, ast::NodeId, usize, &'tcx ty::Const<'tcx>,
     Region<'tcx>, Ty<'tcx>, BindingMode<'tcx>, &'tcx AdtDef,
-    &'tcx Substs<'tcx>, &'tcx Kind<'tcx>, CanonicalTy<'tcx>
+    &'tcx Substs<'tcx>, &'tcx Kind<'tcx>, UserTypeAnnotation<'tcx>
 }
 
 impl<'tcx> PatternFoldable<'tcx> for FieldPattern<'tcx> {
diff --git a/src/librustc_mir/hair/util.rs b/src/librustc_mir/hair/util.rs
index 48a2e67a3dc..71cbac6b7c8 100644
--- a/src/librustc_mir/hair/util.rs
+++ b/src/librustc_mir/hair/util.rs
@@ -9,7 +9,8 @@
 // except according to those terms.
 
 use rustc::hir;
-use rustc::ty::{self, AdtDef, CanonicalTy, TyCtxt};
+use rustc::mir::UserTypeAnnotation;
+use rustc::ty::{self, AdtDef, TyCtxt};
 
 crate trait UserAnnotatedTyHelpers<'gcx: 'tcx, 'tcx> {
     fn tcx(&self) -> TyCtxt<'_, 'gcx, 'tcx>;
@@ -20,32 +21,22 @@ crate trait UserAnnotatedTyHelpers<'gcx: 'tcx, 'tcx> {
         &self,
         hir_id: hir::HirId,
         adt_def: &'tcx AdtDef,
-    ) -> Option<CanonicalTy<'tcx>> {
+    ) -> Option<UserTypeAnnotation<'tcx>> {
         let user_substs = self.tables().user_substs(hir_id)?;
-        Some(user_substs.unchecked_map(|user_substs| {
-            // Here, we just pair an `AdtDef` with the
-            // `user_substs`, so no new types etc are introduced.
-            self.tcx().mk_adt(adt_def, user_substs)
-        }))
+        Some(UserTypeAnnotation::AdtDef(adt_def, 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<CanonicalTy<'tcx>> {
+    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)?;
         match &self.tables().node_id_to_type(hir_id).sty {
-            ty::Adt(adt_def, _) => Some(user_substs.unchecked_map(|user_substs| {
-                // Ok to call `unchecked_map` because we just pair an
-                // `AdtDef` with the `user_substs`, so no new types
-                // etc are introduced.
-                self.tcx().mk_adt(adt_def, user_substs)
-            })),
-            ty::FnDef(def_id, _) => Some(user_substs.unchecked_map(|user_substs| {
-                // Here, we just pair a `DefId` with the
-                // `user_substs`, so no new types etc are introduced.
-                self.tcx().mk_fn_def(*def_id, user_substs)
-            })),
+            ty::Adt(adt_def, _) => Some(UserTypeAnnotation::AdtDef(adt_def, user_substs)),
+            ty::FnDef(def_id, _) => Some(UserTypeAnnotation::FnDef(*def_id, user_substs)),
             sty => bug!(
                 "sty: {:?} should not have user-substs {:?} recorded ",
                 sty,
diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs
index d840c587464..14ce1bb4ccd 100644
--- a/src/librustc_typeck/check/mod.rs
+++ b/src/librustc_typeck/check/mod.rs
@@ -95,7 +95,8 @@ use rustc::infer::opaque_types::OpaqueTypeDecl;
 use rustc::infer::type_variable::{TypeVariableOrigin};
 use rustc::middle::region;
 use rustc::mir::interpret::{ConstValue, GlobalId};
-use rustc::ty::subst::{CanonicalSubsts, UnpackedKind, Subst, Substs};
+use rustc::ty::subst::{CanonicalUserSubsts, UnpackedKind, Subst, Substs,
+                       UserSelfTy, UserSubsts};
 use rustc::traits::{self, ObligationCause, ObligationCauseCode, TraitEngine};
 use rustc::ty::{self, Ty, TyCtxt, GenericParamDefKind, Visibility, ToPredicate, RegionKind};
 use rustc::ty::adjustment::{Adjust, Adjustment, AllowTwoPhase, AutoBorrow, AutoBorrowMutability};
@@ -2136,7 +2137,10 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                             method.substs[i]
                         }
                     });
-                    self.infcx.canonicalize_response(&just_method_substs)
+                    self.infcx.canonicalize_response(&UserSubsts {
+                        substs: just_method_substs,
+                        user_self_ty: None, // not relevant here
+                    })
                 });
 
                 debug!("write_method_call: user_substs = {:?}", user_substs);
@@ -2163,7 +2167,12 @@ 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(&self, hir_id: hir::HirId, substs: &'tcx Substs<'tcx>) {
+    pub fn write_user_substs_from_substs(
+        &self,
+        hir_id: hir::HirId,
+        substs: &'tcx Substs<'tcx>,
+        user_self_ty: Option<UserSelfTy<'tcx>>,
+    ) {
         debug!(
             "write_user_substs_from_substs({:?}, {:?}) in fcx {}",
             hir_id,
@@ -2172,13 +2181,16 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
         );
 
         if !substs.is_noop() {
-            let user_substs = self.infcx.canonicalize_response(&substs);
+            let user_substs = self.infcx.canonicalize_response(&UserSubsts {
+                substs,
+                user_self_ty,
+            });
             debug!("instantiate_value_path: user_substs = {:?}", user_substs);
             self.write_user_substs(hir_id, user_substs);
         }
     }
 
-    pub fn write_user_substs(&self, hir_id: hir::HirId, substs: CanonicalSubsts<'tcx>) {
+    pub fn write_user_substs(&self, hir_id: hir::HirId, substs: CanonicalUserSubsts<'tcx>) {
         debug!(
             "write_user_substs({:?}, {:?}) in fcx {}",
             hir_id,
@@ -3617,7 +3629,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);
+            self.write_user_substs_from_substs(hir_id, substs, None);
 
             // Check bounds on type arguments used in the path.
             let bounds = self.instantiate_bounds(path_span, did, substs);
@@ -5005,7 +5017,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
 
         let path_segs = self.def_ids_for_path_segments(segments, def);
 
-        let mut ufcs_associated = None;
+        let mut user_self_ty = None;
         match def {
             Def::Method(def_id) |
             Def::AssociatedConst(def_id) => {
@@ -5014,12 +5026,20 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                     ty::TraitContainer(trait_did) => {
                         callee::check_legal_trait_for_method_call(self.tcx, span, trait_did)
                     }
-                    ty::ImplContainer(_) => {}
-                }
-                if segments.len() == 1 {
-                    // `<T>::assoc` will end up here, and so can `T::assoc`.
-                    let self_ty = self_ty.expect("UFCS sugared assoc missing Self");
-                    ufcs_associated = Some((container, self_ty));
+                    ty::ImplContainer(impl_def_id) => {
+                        if segments.len() == 1 {
+                            // `<T>::assoc` will end up here, and so
+                            // can `T::assoc`. It this came from an
+                            // inherent impl, we need to record the
+                            // `T` for posterity (see `UserSelfTy` for
+                            // details).
+                            let self_ty = self_ty.expect("UFCS sugared assoc missing Self");
+                            user_self_ty = Some(UserSelfTy {
+                                impl_def_id,
+                                self_ty,
+                            });
+                        }
+                    }
                 }
             }
             _ => {}
@@ -5173,6 +5193,10 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
         assert!(!substs.has_escaping_regions());
         assert!(!ty.has_escaping_regions());
 
+        // Write the "user substs" down first thing for later.
+        let hir_id = self.tcx.hir.node_to_hir_id(node_id);
+        self.write_user_substs_from_substs(hir_id, substs, user_self_ty);
+
         // Add all the obligations that are required, substituting and
         // normalized appropriately.
         let bounds = self.instantiate_bounds(span, def_id, &substs);
@@ -5184,7 +5208,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
         // the referenced item.
         let ty_substituted = self.instantiate_type_scheme(span, &substs, &ty);
 
-        if let Some((ty::ImplContainer(impl_def_id), self_ty)) = ufcs_associated {
+        if let Some(UserSelfTy { impl_def_id, self_ty }) = user_self_ty {
             // In the case of `Foo<T>::method` and `<Foo<T>>::method`, if `method`
             // is inherent, there is no `Self` parameter, instead, the impl needs
             // type parameters, which we can infer by unifying the provided `Self`
@@ -5208,16 +5232,8 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
         debug!("instantiate_value_path: type of {:?} is {:?}",
                node_id,
                ty_substituted);
-        let hir_id = self.tcx.hir.node_to_hir_id(node_id);
         self.write_substs(hir_id, substs);
 
-        debug!(
-            "instantiate_value_path: id={:?} substs={:?}",
-            node_id,
-            substs,
-        );
-        self.write_user_substs_from_substs(hir_id, substs);
-
         (ty_substituted, new_def)
     }
 
diff --git a/src/test/mir-opt/basic_assignment.rs b/src/test/mir-opt/basic_assignment.rs
index 1abe63afa80..64e574fa8ae 100644
--- a/src/test/mir-opt/basic_assignment.rs
+++ b/src/test/mir-opt/basic_assignment.rs
@@ -56,7 +56,7 @@ fn main() {
 //        StorageLive(_4);
 //        _4 = std::option::Option<std::boxed::Box<u32>>::None;
 //        FakeRead(ForLet, _4);
-//        AscribeUserType(_4, o, Canonical { variables: [], value: std::option::Option<std::boxed::Box<u32>> });
+//        AscribeUserType(_4, o, Ty(Canonical { variables: [], value: std::option::Option<std::boxed::Box<u32>> }));
 //        StorageLive(_5);
 //        StorageLive(_6);
 //        _6 = move _4;
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 2b0e5039d8d..901ace59d33 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 { variables: [], value: [u32] }
+error: user substs: Canonical { variables: [], value: UserSubsts { substs: [u32], user_self_ty: None } }
   --> $DIR/dump-adt-brace-struct.rs:28: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 6531f87dd98..a26be359fc4 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 { variables: [], value: [u32] }
+error: user substs: Canonical { variables: [], value: UserSubsts { substs: [u32], user_self_ty: None } }
   --> $DIR/dump-fn-method.rs:36:13
    |
 LL |     let x = foo::<u32>; //~ ERROR [u32]
    |             ^^^^^^^^^^
 
-error: user substs: Canonical { variables: [CanonicalVarInfo { kind: Ty(General) }, CanonicalVarInfo { kind: Ty(General) }], value: [?0, u32, ?1] }
+error: user substs: Canonical { variables: [CanonicalVarInfo { kind: Ty(General) }, CanonicalVarInfo { kind: Ty(General) }], value: UserSubsts { substs: [?0, u32, ?1], user_self_ty: None } }
   --> $DIR/dump-fn-method.rs:42:13
    |
 LL |     let x = <_ as Bazoom<u32>>::method::<_>; //~ ERROR [?0, u32, ?1]
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
-error: user substs: Canonical { variables: [], value: [u8, u16, u32] }
+error: user substs: Canonical { variables: [], value: UserSubsts { substs: [u8, u16, u32], user_self_ty: None } }
   --> $DIR/dump-fn-method.rs:46:13
    |
 LL |     let x = <u8 as Bazoom<u16>>::method::<u32>; //~ ERROR [u8, u16, u32]
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
-error: user substs: Canonical { variables: [CanonicalVarInfo { kind: Ty(General) }, CanonicalVarInfo { kind: Ty(General) }], value: [?0, ?1, u32] }
+error: user substs: Canonical { variables: [CanonicalVarInfo { kind: Ty(General) }, CanonicalVarInfo { kind: Ty(General) }], value: UserSubsts { substs: [?0, ?1, u32], user_self_ty: None } }
   --> $DIR/dump-fn-method.rs:54:5
    |
 LL |     y.method::<u32>(44, 66); //~ ERROR [?0, ?1, u32]
diff --git a/src/test/ui/nll/user-annotations/method-ufcs-inherent-1.rs b/src/test/ui/nll/user-annotations/method-ufcs-inherent-1.rs
new file mode 100644
index 00000000000..b7292c0acbe
--- /dev/null
+++ b/src/test/ui/nll/user-annotations/method-ufcs-inherent-1.rs
@@ -0,0 +1,20 @@
+#![feature(nll)]
+
+// Check that substitutions given on the self type (here, `A`) carry
+// through to NLL.
+
+struct A<'a> { x: &'a u32 }
+
+impl<'a> A<'a> {
+    fn new<'b, T>(x: &'a u32, y: T) -> Self {
+        Self { x }
+    }
+}
+
+fn foo<'a>() {
+    let v = 22;
+    let x = A::<'a>::new(&v, 22);
+    //~^ ERROR
+}
+
+fn main() {}
diff --git a/src/test/ui/nll/user-annotations/method-ufcs-inherent-1.stderr b/src/test/ui/nll/user-annotations/method-ufcs-inherent-1.stderr
new file mode 100644
index 00000000000..aa133ce286d
--- /dev/null
+++ b/src/test/ui/nll/user-annotations/method-ufcs-inherent-1.stderr
@@ -0,0 +1,18 @@
+error[E0597]: `v` does not live long enough
+  --> $DIR/method-ufcs-inherent-1.rs:16:26
+   |
+LL |     let x = A::<'a>::new(&v, 22);
+   |                          ^^ borrowed value does not live long enough
+LL |     //~^ ERROR
+LL | }
+   | - `v` dropped here while still borrowed
+   |
+note: borrowed value must be valid for the lifetime 'a as defined on the function body at 14:8...
+  --> $DIR/method-ufcs-inherent-1.rs:14:8
+   |
+LL | fn foo<'a>() {
+   |        ^^
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0597`.
diff --git a/src/test/ui/nll/user-annotations/method-ufcs-inherent-2.rs b/src/test/ui/nll/user-annotations/method-ufcs-inherent-2.rs
new file mode 100644
index 00000000000..a77d6af5323
--- /dev/null
+++ b/src/test/ui/nll/user-annotations/method-ufcs-inherent-2.rs
@@ -0,0 +1,21 @@
+#![feature(nll)]
+
+// Check that substitutions given on the self type (here, `A`) can be
+// used in combination with annotations given for method arguments.
+
+struct A<'a> { x: &'a u32 }
+
+impl<'a> A<'a> {
+    fn new<'b, T>(x: &'a u32, y: T) -> Self {
+        Self { x }
+    }
+}
+
+fn foo<'a>() {
+    let v = 22;
+    let x = A::<'a>::new::<&'a u32>(&v, &v);
+    //~^ ERROR
+    //~| ERROR
+}
+
+fn main() {}
diff --git a/src/test/ui/nll/user-annotations/method-ufcs-inherent-2.stderr b/src/test/ui/nll/user-annotations/method-ufcs-inherent-2.stderr
new file mode 100644
index 00000000000..f1f4787d058
--- /dev/null
+++ b/src/test/ui/nll/user-annotations/method-ufcs-inherent-2.stderr
@@ -0,0 +1,33 @@
+error[E0597]: `v` does not live long enough
+  --> $DIR/method-ufcs-inherent-2.rs:16:37
+   |
+LL |     let x = A::<'a>::new::<&'a u32>(&v, &v);
+   |                                     ^^ borrowed value does not live long enough
+...
+LL | }
+   | - `v` dropped here while still borrowed
+   |
+note: borrowed value must be valid for the lifetime 'a as defined on the function body at 14:8...
+  --> $DIR/method-ufcs-inherent-2.rs:14:8
+   |
+LL | fn foo<'a>() {
+   |        ^^
+
+error[E0597]: `v` does not live long enough
+  --> $DIR/method-ufcs-inherent-2.rs:16:41
+   |
+LL |     let x = A::<'a>::new::<&'a u32>(&v, &v);
+   |                                         ^^ borrowed value does not live long enough
+...
+LL | }
+   | - `v` dropped here while still borrowed
+   |
+note: borrowed value must be valid for the lifetime 'a as defined on the function body at 14:8...
+  --> $DIR/method-ufcs-inherent-2.rs:14:8
+   |
+LL | fn foo<'a>() {
+   |        ^^
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0597`.
diff --git a/src/test/ui/nll/user-annotations/method-ufcs-inherent-3.rs b/src/test/ui/nll/user-annotations/method-ufcs-inherent-3.rs
new file mode 100644
index 00000000000..24d83c468f4
--- /dev/null
+++ b/src/test/ui/nll/user-annotations/method-ufcs-inherent-3.rs
@@ -0,0 +1,20 @@
+#![feature(nll)]
+
+// Check that inherent methods invoked with `<T>::new` style
+// carry their annotations through to NLL.
+
+struct A<'a> { x: &'a u32 }
+
+impl<'a> A<'a> {
+    fn new<'b, T>(x: &'a u32, y: T) -> Self {
+        Self { x }
+    }
+}
+
+fn foo<'a>() {
+    let v = 22;
+    let x = <A<'a>>::new(&v, 22);
+    //~^ ERROR
+}
+
+fn main() {}
diff --git a/src/test/ui/nll/user-annotations/method-ufcs-inherent-3.stderr b/src/test/ui/nll/user-annotations/method-ufcs-inherent-3.stderr
new file mode 100644
index 00000000000..f3766a8c8e5
--- /dev/null
+++ b/src/test/ui/nll/user-annotations/method-ufcs-inherent-3.stderr
@@ -0,0 +1,18 @@
+error[E0597]: `v` does not live long enough
+  --> $DIR/method-ufcs-inherent-3.rs:16:26
+   |
+LL |     let x = <A<'a>>::new(&v, 22);
+   |                          ^^ borrowed value does not live long enough
+LL |     //~^ ERROR
+LL | }
+   | - `v` dropped here while still borrowed
+   |
+note: borrowed value must be valid for the lifetime 'a as defined on the function body at 14:8...
+  --> $DIR/method-ufcs-inherent-3.rs:14:8
+   |
+LL | fn foo<'a>() {
+   |        ^^
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0597`.
diff --git a/src/test/ui/nll/user-annotations/method-ufcs-inherent-4.rs b/src/test/ui/nll/user-annotations/method-ufcs-inherent-4.rs
new file mode 100644
index 00000000000..3f88c3df48e
--- /dev/null
+++ b/src/test/ui/nll/user-annotations/method-ufcs-inherent-4.rs
@@ -0,0 +1,22 @@
+#![feature(nll)]
+
+// Check that inherent methods invoked with `<T>::new` style
+// carry their annotations through to NLL in connection with
+// method type parameters.
+
+struct A<'a> { x: &'a u32 }
+
+impl<'a> A<'a> {
+    fn new<'b, T>(x: &'a u32, y: T) -> Self {
+        Self { x }
+    }
+}
+
+fn foo<'a>() {
+    let v = 22;
+    let x = <A<'a>>::new::<&'a u32>(&v, &v);
+    //~^ ERROR
+    //~| ERROR
+}
+
+fn main() {}
diff --git a/src/test/ui/nll/user-annotations/method-ufcs-inherent-4.stderr b/src/test/ui/nll/user-annotations/method-ufcs-inherent-4.stderr
new file mode 100644
index 00000000000..c9bce5077d6
--- /dev/null
+++ b/src/test/ui/nll/user-annotations/method-ufcs-inherent-4.stderr
@@ -0,0 +1,33 @@
+error[E0597]: `v` does not live long enough
+  --> $DIR/method-ufcs-inherent-4.rs:17:37
+   |
+LL |     let x = <A<'a>>::new::<&'a u32>(&v, &v);
+   |                                     ^^ borrowed value does not live long enough
+...
+LL | }
+   | - `v` dropped here while still borrowed
+   |
+note: borrowed value must be valid for the lifetime 'a as defined on the function body at 15:8...
+  --> $DIR/method-ufcs-inherent-4.rs:15:8
+   |
+LL | fn foo<'a>() {
+   |        ^^
+
+error[E0597]: `v` does not live long enough
+  --> $DIR/method-ufcs-inherent-4.rs:17:41
+   |
+LL |     let x = <A<'a>>::new::<&'a u32>(&v, &v);
+   |                                         ^^ borrowed value does not live long enough
+...
+LL | }
+   | - `v` dropped here while still borrowed
+   |
+note: borrowed value must be valid for the lifetime 'a as defined on the function body at 15:8...
+  --> $DIR/method-ufcs-inherent-4.rs:15:8
+   |
+LL | fn foo<'a>() {
+   |        ^^
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0597`.