about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--src/librustc/hir/def.rs2
-rw-r--r--src/librustc/ich/impls_mir.rs5
-rw-r--r--src/librustc/infer/canonical/mod.rs30
-rw-r--r--src/librustc/mir/mod.rs33
-rw-r--r--src/librustc/mir/tcx.rs2
-rw-r--r--src/librustc/mir/visit.rs13
-rw-r--r--src/librustc/ty/context.rs29
-rw-r--r--src/librustc/ty/subst.rs31
-rw-r--r--src/librustc_codegen_llvm/mir/rvalue.rs2
-rw-r--r--src/librustc_mir/borrow_check/nll/type_check/mod.rs73
-rw-r--r--src/librustc_mir/build/expr/as_constant.rs4
-rw-r--r--src/librustc_mir/build/expr/as_rvalue.rs12
-rw-r--r--src/librustc_mir/build/expr/into.rs2
-rw-r--r--src/librustc_mir/build/matches/test.rs11
-rw-r--r--src/librustc_mir/build/misc.rs4
-rw-r--r--src/librustc_mir/hair/cx/expr.rs128
-rw-r--r--src/librustc_mir/hair/mod.rs14
-rw-r--r--src/librustc_mir/interpret/step.rs2
-rw-r--r--src/librustc_mir/shim.rs5
-rw-r--r--src/librustc_mir/transform/deaggregator.rs2
-rw-r--r--src/librustc_mir/transform/elaborate_drops.rs1
-rw-r--r--src/librustc_mir/transform/generator.rs4
-rw-r--r--src/librustc_mir/transform/instcombine.rs2
-rw-r--r--src/librustc_mir/util/elaborate_drops.rs1
-rw-r--r--src/librustc_mir/util/pretty.rs10
-rw-r--r--src/librustc_typeck/astconv.rs2
-rw-r--r--src/librustc_typeck/check/mod.rs79
-rw-r--r--src/librustc_typeck/check/writeback.rs26
-rw-r--r--src/libsyntax/feature_gate.rs6
-rw-r--r--src/test/ui/hr-subtype/hr-subtype.free_inv_x_vs_free_inv_y.nll.stderr38
-rw-r--r--src/test/ui/hr-subtype/hr-subtype.free_x_vs_free_y.nll.stderr22
-rw-r--r--src/test/ui/nll/user-annotations/adt-brace-enums.rs62
-rw-r--r--src/test/ui/nll/user-annotations/adt-brace-enums.stderr41
-rw-r--r--src/test/ui/nll/user-annotations/adt-brace-structs.rs60
-rw-r--r--src/test/ui/nll/user-annotations/adt-brace-structs.stderr41
-rw-r--r--src/test/ui/nll/user-annotations/adt-nullary-enums.rs80
-rw-r--r--src/test/ui/nll/user-annotations/adt-nullary-enums.stderr44
-rw-r--r--src/test/ui/nll/user-annotations/adt-tuple-enums.rs64
-rw-r--r--src/test/ui/nll/user-annotations/adt-tuple-enums.stderr41
-rw-r--r--src/test/ui/nll/user-annotations/adt-tuple-struct.rs60
-rw-r--r--src/test/ui/nll/user-annotations/adt-tuple-struct.stderr41
-rw-r--r--src/test/ui/nll/user-annotations/dump-adt-brace-struct.rs29
-rw-r--r--src/test/ui/nll/user-annotations/dump-adt-brace-struct.stderr8
-rw-r--r--src/test/ui/nll/user-annotations/dump-fn-method.rs59
-rw-r--r--src/test/ui/nll/user-annotations/dump-fn-method.stderr26
-rw-r--r--src/test/ui/nll/user-annotations/fns.rs60
-rw-r--r--src/test/ui/nll/user-annotations/fns.stderr41
-rw-r--r--src/test/ui/nll/user-annotations/method-call.rs81
-rw-r--r--src/test/ui/nll/user-annotations/method-call.stderr41
-rw-r--r--src/test/ui/nll/user-annotations/method-ufcs-1.rs75
-rw-r--r--src/test/ui/nll/user-annotations/method-ufcs-1.stderr45
-rw-r--r--src/test/ui/nll/user-annotations/method-ufcs-2.rs75
-rw-r--r--src/test/ui/nll/user-annotations/method-ufcs-2.stderr45
-rw-r--r--src/test/ui/nll/user-annotations/method-ufcs-3.rs81
-rw-r--r--src/test/ui/nll/user-annotations/method-ufcs-3.stderr41
55 files changed, 1757 insertions, 79 deletions
diff --git a/src/librustc/hir/def.rs b/src/librustc/hir/def.rs
index 65146f2de84..b10f4785f16 100644
--- a/src/librustc/hir/def.rs
+++ b/src/librustc/hir/def.rs
@@ -68,7 +68,7 @@ pub enum Def {
     Const(DefId),
     Static(DefId, bool /* is_mutbl */),
     StructCtor(DefId, CtorKind), // DefId refers to NodeId of the struct's constructor
-    VariantCtor(DefId, CtorKind),
+    VariantCtor(DefId, CtorKind), // DefId refers to the enum variant
     Method(DefId),
     AssociatedConst(DefId),
 
diff --git a/src/librustc/ich/impls_mir.rs b/src/librustc/ich/impls_mir.rs
index 38ea536b4ee..1c9387d02d5 100644
--- a/src/librustc/ich/impls_mir.rs
+++ b/src/librustc/ich/impls_mir.rs
@@ -479,10 +479,11 @@ for mir::AggregateKind<'gcx> {
             mir::AggregateKind::Array(t) => {
                 t.hash_stable(hcx, hasher);
             }
-            mir::AggregateKind::Adt(adt_def, idx, substs, active_field) => {
+            mir::AggregateKind::Adt(adt_def, idx, substs, user_substs, active_field) => {
                 adt_def.hash_stable(hcx, hasher);
                 idx.hash_stable(hcx, hasher);
                 substs.hash_stable(hcx, hasher);
+                user_substs.hash_stable(hcx, hasher);
                 active_field.hash_stable(hcx, hasher);
             }
             mir::AggregateKind::Closure(def_id, ref substs) => {
@@ -528,7 +529,7 @@ impl_stable_hash_for!(enum mir::NullOp {
     SizeOf
 });
 
-impl_stable_hash_for!(struct mir::Constant<'tcx> { span, ty, literal });
+impl_stable_hash_for!(struct mir::Constant<'tcx> { span, ty, user_ty, literal });
 
 impl_stable_hash_for!(struct mir::Location { block, statement_index });
 
diff --git a/src/librustc/infer/canonical/mod.rs b/src/librustc/infer/canonical/mod.rs
index 2e57ef7b17d..85aa4f62f21 100644
--- a/src/librustc/infer/canonical/mod.rs
+++ b/src/librustc/infer/canonical/mod.rs
@@ -188,6 +188,36 @@ impl<'tcx, R> Canonical<'tcx, QueryResult<'tcx, R>> {
     }
 }
 
+impl<'gcx, V> Canonical<'gcx, V> {
+    /// Allows you to map the `value` of a canonical while keeping the
+    /// same set of bound variables.
+    ///
+    /// **WARNING:** This function is very easy to mis-use, hence the
+    /// name!  In particular, the new value `W` must use all **the
+    /// same type/region variables** in **precisely the same order**
+    /// as the original! (The ordering is defined by the
+    /// `TypeFoldable` implementation of the type in question.)
+    ///
+    /// An example of a **correct** use of this:
+    ///
+    /// ```rust,ignore (not real code)
+    /// let a: Canonical<'_, T> = ...;
+    /// let b: Canonical<'_, (T,)> = a.unchecked_map(|v| (v, ));
+    /// ```
+    ///
+    /// An example of an **incorrect** use of this:
+    ///
+    /// ```rust,ignore (not real code)
+    /// let a: Canonical<'tcx, T> = ...;
+    /// let ty: Ty<'tcx> = ...;
+    /// let b: Canonical<'tcx, (T, Ty<'tcx>)> = a.unchecked_map(|v| (v, ty));
+    /// ```
+    pub fn unchecked_map<W>(self, map_op: impl FnOnce(V) -> W) -> Canonical<'gcx, W> {
+        let Canonical { variables, value } = self;
+        Canonical { variables, value: map_op(value) }
+    }
+}
+
 pub type QueryRegionConstraint<'tcx> = ty::Binder<ty::OutlivesPredicate<Kind<'tcx>, Region<'tcx>>>;
 
 impl<'cx, 'gcx, 'tcx> InferCtxt<'cx, 'gcx, 'tcx> {
diff --git a/src/librustc/mir/mod.rs b/src/librustc/mir/mod.rs
index 6da6ef92c9f..86e521727c5 100644
--- a/src/librustc/mir/mod.rs
+++ b/src/librustc/mir/mod.rs
@@ -1888,12 +1888,15 @@ pub enum Operand<'tcx> {
     /// This implies that the type of the place must be `Copy`; this is true
     /// by construction during build, but also checked by the MIR type checker.
     Copy(Place<'tcx>),
+
     /// Move: The value (including old borrows of it) will not be used again.
     ///
     /// Safe for values of all types (modulo future developments towards `?Move`).
     /// Correct usage patterns are enforced by the borrow checker for safe code.
     /// `Copy` may be converted to `Move` to enable "last-use" optimizations.
     Move(Place<'tcx>),
+
+    /// Synthesizes a constant value.
     Constant(Box<Constant<'tcx>>),
 }
 
@@ -1909,6 +1912,9 @@ impl<'tcx> Debug for Operand<'tcx> {
 }
 
 impl<'tcx> Operand<'tcx> {
+    /// Convenience helper to make a constant that refers to the fn
+    /// with given def-id and substs. Since this is used to synthesize
+    /// MIR, assumes `user_ty` is None.
     pub fn function_handle<'a>(
         tcx: TyCtxt<'a, 'tcx, 'tcx>,
         def_id: DefId,
@@ -1919,6 +1925,7 @@ impl<'tcx> Operand<'tcx> {
         Operand::Constant(box Constant {
             span,
             ty,
+            user_ty: None,
             literal: ty::Const::zero_sized(tcx, ty),
         })
     }
@@ -2002,7 +2009,7 @@ pub enum AggregateKind<'tcx> {
     /// active field number and is present only for union expressions
     /// -- e.g. for a union expression `SomeUnion { c: .. }`, the
     /// active field index would identity the field `c`
-    Adt(&'tcx AdtDef, usize, &'tcx Substs<'tcx>, Option<usize>),
+    Adt(&'tcx AdtDef, usize, &'tcx Substs<'tcx>, Option<CanonicalTy<'tcx>>, Option<usize>),
 
     Closure(DefId, ClosureSubsts<'tcx>),
     Generator(DefId, GeneratorSubsts<'tcx>, hir::GeneratorMovability),
@@ -2128,7 +2135,7 @@ impl<'tcx> Debug for Rvalue<'tcx> {
                         _ => fmt_tuple(fmt, places),
                     },
 
-                    AggregateKind::Adt(adt_def, variant, substs, _) => {
+                    AggregateKind::Adt(adt_def, variant, substs, _user_ty, _) => {
                         let variant_def = &adt_def.variants[variant];
 
                         ppaux::parameterized(fmt, substs, variant_def.did, &[])?;
@@ -2207,6 +2214,14 @@ impl<'tcx> Debug for Rvalue<'tcx> {
 pub struct Constant<'tcx> {
     pub span: Span,
     pub ty: Ty<'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.
+    pub user_ty: Option<CanonicalTy<'tcx>>,
+
     pub literal: &'tcx ty::Const<'tcx>,
 }
 
@@ -2798,8 +2813,14 @@ impl<'tcx> TypeFoldable<'tcx> for Rvalue<'tcx> {
                 let kind = box match **kind {
                     AggregateKind::Array(ty) => AggregateKind::Array(ty.fold_with(folder)),
                     AggregateKind::Tuple => AggregateKind::Tuple,
-                    AggregateKind::Adt(def, v, substs, n) => {
-                        AggregateKind::Adt(def, v, substs.fold_with(folder), n)
+                    AggregateKind::Adt(def, v, substs, user_ty, n) => {
+                        AggregateKind::Adt(
+                            def,
+                            v,
+                            substs.fold_with(folder),
+                            user_ty.fold_with(folder),
+                            n,
+                        )
                     }
                     AggregateKind::Closure(id, substs) => {
                         AggregateKind::Closure(id, substs.fold_with(folder))
@@ -2831,7 +2852,8 @@ impl<'tcx> TypeFoldable<'tcx> for Rvalue<'tcx> {
                 (match **kind {
                     AggregateKind::Array(ty) => ty.visit_with(visitor),
                     AggregateKind::Tuple => false,
-                    AggregateKind::Adt(_, _, substs, _) => substs.visit_with(visitor),
+                    AggregateKind::Adt(_, _, substs, user_ty, _) =>
+                        substs.visit_with(visitor) || user_ty.visit_with(visitor),
                     AggregateKind::Closure(_, substs) => substs.visit_with(visitor),
                     AggregateKind::Generator(_, substs, _) => substs.visit_with(visitor),
                 }) || fields.visit_with(visitor)
@@ -2902,6 +2924,7 @@ impl<'tcx> TypeFoldable<'tcx> for Constant<'tcx> {
         Constant {
             span: self.span.clone(),
             ty: self.ty.fold_with(folder),
+            user_ty: self.user_ty.fold_with(folder),
             literal: self.literal.fold_with(folder),
         }
     }
diff --git a/src/librustc/mir/tcx.rs b/src/librustc/mir/tcx.rs
index ec395478ec6..c928be4f9df 100644
--- a/src/librustc/mir/tcx.rs
+++ b/src/librustc/mir/tcx.rs
@@ -216,7 +216,7 @@ impl<'tcx> Rvalue<'tcx> {
                     AggregateKind::Tuple => {
                         tcx.mk_tup(ops.iter().map(|op| op.ty(local_decls, tcx)))
                     }
-                    AggregateKind::Adt(def, _, substs, _) => {
+                    AggregateKind::Adt(def, _, substs, _, _) => {
                         tcx.type_of(def.did).subst(tcx, substs)
                     }
                     AggregateKind::Closure(did, substs) => {
diff --git a/src/librustc/mir/visit.rs b/src/librustc/mir/visit.rs
index cab6ed0c122..c7723fdf191 100644
--- a/src/librustc/mir/visit.rs
+++ b/src/librustc/mir/visit.rs
@@ -213,6 +213,10 @@ macro_rules! make_mir_visitor {
                 self.super_ty(ty);
             }
 
+            fn visit_canonical_ty(&mut self, ty: & $($mutability)* CanonicalTy<'tcx>) {
+                self.super_canonical_ty(ty);
+            }
+
             fn visit_region(&mut self,
                             region: & $($mutability)* ty::Region<'tcx>,
                             _: Location) {
@@ -585,6 +589,7 @@ macro_rules! make_mir_visitor {
                             AggregateKind::Adt(_adt_def,
                                                _variant_index,
                                                ref $($mutability)* substs,
+                                               _user_substs,
                                                _active_field_index) => {
                                 self.visit_substs(substs, location);
                             }
@@ -625,9 +630,10 @@ macro_rules! make_mir_visitor {
             }
 
             fn super_user_assert_ty(&mut self,
-                                    _c_ty: & $($mutability)* CanonicalTy<'tcx>,
+                                    c_ty: & $($mutability)* CanonicalTy<'tcx>,
                                     local: & $($mutability)* Local,
                                     location: Location) {
+                self.visit_canonical_ty(c_ty);
                 self.visit_local(local, PlaceContext::Validate, location);
             }
 
@@ -740,11 +746,13 @@ macro_rules! make_mir_visitor {
                 let Constant {
                     ref $($mutability)* span,
                     ref $($mutability)* ty,
+                    ref $($mutability)* user_ty,
                     ref $($mutability)* literal,
                 } = *constant;
 
                 self.visit_span(span);
                 self.visit_ty(ty, TyContext::Location(location));
+                drop(user_ty); // no visit method for this
                 self.visit_const(literal, location);
             }
 
@@ -764,6 +772,9 @@ macro_rules! make_mir_visitor {
                 self.visit_source_scope(scope);
             }
 
+            fn super_canonical_ty(&mut self, _ty: & $($mutability)* CanonicalTy<'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 0545a88f36b..424139e7527 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::{Kind, Substs, Subst};
+use ty::subst::{CanonicalSubsts, Kind, Substs, Subst};
 use ty::ReprOptions;
 use traits;
 use traits::{Clause, Clauses, Goal, Goals};
@@ -371,6 +371,18 @@ pub struct TypeckTables<'tcx> {
     /// other items.
     node_substs: ItemLocalMap<&'tcx Substs<'tcx>>,
 
+    /// Stores the substitutions that the user explicitly gave (if any)
+    /// attached to `id`. These will not include any inferred
+    /// values. The canonical form is used to capture things like `_`
+    /// or other unspecified values.
+    ///
+    /// Example:
+    ///
+    /// If the user wrote `foo.collect::<Vec<_>>()`, then the
+    /// canonical substitutions would include only `for<X> { Vec<X>
+    /// }`.
+    user_substs: ItemLocalMap<CanonicalSubsts<'tcx>>,
+
     adjustments: ItemLocalMap<Vec<ty::adjustment::Adjustment<'tcx>>>,
 
     /// Stores the actual binding mode for all instances of hir::BindingAnnotation.
@@ -444,6 +456,7 @@ impl<'tcx> TypeckTables<'tcx> {
             user_provided_tys: ItemLocalMap(),
             node_types: ItemLocalMap(),
             node_substs: ItemLocalMap(),
+            user_substs: ItemLocalMap(),
             adjustments: ItemLocalMap(),
             pat_binding_modes: ItemLocalMap(),
             pat_adjustments: ItemLocalMap(),
@@ -561,6 +574,18 @@ impl<'tcx> TypeckTables<'tcx> {
         self.node_substs.get(&id.local_id).cloned()
     }
 
+    pub fn user_substs_mut(&mut self) -> LocalTableInContextMut<CanonicalSubsts<'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>> {
+        validate_hir_id_for_typeck_tables(self.local_id_root, id, false);
+        self.user_substs.get(&id.local_id).cloned()
+    }
+
     // Returns the type of a pattern as a monotype. Like @expr_ty, this function
     // doesn't provide type parameter substitutions.
     pub fn pat_ty(&self, pat: &hir::Pat) -> Ty<'tcx> {
@@ -740,6 +765,7 @@ impl<'a, 'gcx> HashStable<StableHashingContext<'a>> for TypeckTables<'gcx> {
             ref user_provided_tys,
             ref node_types,
             ref node_substs,
+            ref user_substs,
             ref adjustments,
             ref pat_binding_modes,
             ref pat_adjustments,
@@ -762,6 +788,7 @@ impl<'a, 'gcx> HashStable<StableHashingContext<'a>> for TypeckTables<'gcx> {
             user_provided_tys.hash_stable(hcx, hasher);
             node_types.hash_stable(hcx, hasher);
             node_substs.hash_stable(hcx, hasher);
+            user_substs.hash_stable(hcx, hasher);
             adjustments.hash_stable(hcx, hasher);
             pat_binding_modes.hash_stable(hcx, hasher);
             pat_adjustments.hash_stable(hcx, hasher);
diff --git a/src/librustc/ty/subst.rs b/src/librustc/ty/subst.rs
index 0e85c68b8b1..6dadc507036 100644
--- a/src/librustc/ty/subst.rs
+++ b/src/librustc/ty/subst.rs
@@ -11,13 +11,15 @@
 // Type substitutions.
 
 use hir::def_id::DefId;
-use ty::{self, Lift, List, Ty, TyCtxt};
+use infer::canonical::Canonical;
+use ty::{self, CanonicalVar, Lift, List, Ty, TyCtxt};
 use ty::fold::{TypeFoldable, TypeFolder, TypeVisitor};
 
 use serialize::{self, Encodable, Encoder, Decodable, Decoder};
 use syntax_pos::{Span, DUMMY_SP};
 use rustc_data_structures::accumulate_vec::AccumulateVec;
 use rustc_data_structures::array_vec::ArrayVec;
+use rustc_data_structures::indexed_vec::Idx;
 
 use core::intrinsics;
 use std::cmp::Ordering;
@@ -339,6 +341,33 @@ 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> {}
 
 ///////////////////////////////////////////////////////////////////////////
diff --git a/src/librustc_codegen_llvm/mir/rvalue.rs b/src/librustc_codegen_llvm/mir/rvalue.rs
index 25f32360815..e301e5ae70b 100644
--- a/src/librustc_codegen_llvm/mir/rvalue.rs
+++ b/src/librustc_codegen_llvm/mir/rvalue.rs
@@ -148,7 +148,7 @@ impl FunctionCx<'a, 'll, 'tcx> {
 
             mir::Rvalue::Aggregate(ref kind, ref operands) => {
                 let (dest, active_field_index) = match **kind {
-                    mir::AggregateKind::Adt(adt_def, variant_index, _, active_field_index) => {
+                    mir::AggregateKind::Adt(adt_def, variant_index, _, _, active_field_index) => {
                         dest.codegen_set_discr(&bx, variant_index);
                         if adt_def.is_enum() {
                             (dest.project_downcast(&bx, variant_index), active_field_index)
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 2fb5861dff4..5c14e552cfd 100644
--- a/src/librustc_mir/borrow_check/nll/type_check/mod.rs
+++ b/src/librustc_mir/borrow_check/nll/type_check/mod.rs
@@ -15,7 +15,7 @@ use borrow_check::borrow_set::BorrowSet;
 use borrow_check::location::LocationTable;
 use borrow_check::nll::constraints::{ConstraintSet, OutlivesConstraint};
 use borrow_check::nll::facts::AllFacts;
-use borrow_check::nll::region_infer::values::{RegionValueElements, LivenessValues};
+use borrow_check::nll::region_infer::values::{LivenessValues, RegionValueElements};
 use borrow_check::nll::region_infer::{ClosureRegionRequirementsExt, TypeTest};
 use borrow_check::nll::type_check::free_region_relations::{CreateResult, UniversalRegionRelations};
 use borrow_check::nll::type_check::liveness::liveness_map::NllLivenessMap;
@@ -256,6 +256,22 @@ impl<'a, 'b, 'gcx, 'tcx> Visitor<'tcx> for TypeVerifier<'a, 'b, 'gcx, 'tcx> {
         self.super_constant(constant, location);
         self.sanitize_constant(constant, location);
         self.sanitize_type(constant, constant.ty);
+
+        if let Some(user_ty) = constant.user_ty {
+            if let Err(terr) =
+                self.cx
+                    .eq_canonical_type_and_type(user_ty, constant.ty, location.boring())
+            {
+                span_mirbug!(
+                    self,
+                    constant,
+                    "bad constant user type {:?} vs {:?}: {:?}",
+                    user_ty,
+                    constant.ty,
+                    terr,
+                );
+            }
+        }
     }
 
     fn visit_rvalue(&mut self, rvalue: &Rvalue<'tcx>, location: Location) {
@@ -343,8 +359,7 @@ impl<'a, 'b, 'gcx, 'tcx> TypeVerifier<'a, 'b, 'gcx, 'tcx> {
 
         debug!("sanitize_constant: expected_ty={:?}", constant.literal.ty);
 
-        if let Err(terr) = self
-            .cx
+        if let Err(terr) = self.cx
             .eq_types(constant.literal.ty, constant.ty, location.boring())
         {
             span_mirbug!(
@@ -902,6 +917,24 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> {
                         terr
                     );
                 }
+
+                if let Some(user_ty) = self.rvalue_user_ty(rv) {
+                    if let Err(terr) = self.eq_canonical_type_and_type(
+                        user_ty,
+                        rv_ty,
+                        location.boring(),
+                    ) {
+                        span_mirbug!(
+                            self,
+                            stmt,
+                            "bad user type on rvalue ({:?} = {:?}): {:?}",
+                            user_ty,
+                            rv_ty,
+                            terr
+                        );
+                    }
+                }
+
                 self.check_rvalue(mir, rv, location);
                 if !self.tcx().features().unsized_locals {
                     let trait_ref = ty::TraitRef {
@@ -1376,7 +1409,7 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> {
         let tcx = self.tcx();
 
         match *ak {
-            AggregateKind::Adt(def, variant_index, substs, active_field_index) => {
+            AggregateKind::Adt(def, variant_index, substs, _, active_field_index) => {
                 let variant = &def.variants[variant_index];
                 let adj_field_index = active_field_index.unwrap_or(field_index);
                 if let Some(field) = variant.fields.get(adj_field_index) {
@@ -1542,6 +1575,36 @@ 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>> {
+        match rvalue {
+            Rvalue::Use(_) |
+            Rvalue::Repeat(..) |
+            Rvalue::Ref(..) |
+            Rvalue::Len(..) |
+            Rvalue::Cast(..) |
+            Rvalue::BinaryOp(..) |
+            Rvalue::CheckedBinaryOp(..) |
+            Rvalue::NullaryOp(..) |
+            Rvalue::UnaryOp(..) |
+            Rvalue::Discriminant(..) =>
+                None,
+
+            Rvalue::Aggregate(aggregate, _) => match **aggregate {
+                AggregateKind::Adt(_, _, _, user_ty, _) => user_ty,
+                AggregateKind::Array(_) => None,
+                AggregateKind::Tuple => None,
+                AggregateKind::Closure(_, _) => None,
+                AggregateKind::Generator(_, _, _) => None,
+            }
+        }
+    }
+
     fn check_aggregate_rvalue(
         &mut self,
         mir: &Mir<'tcx>,
@@ -1735,7 +1798,7 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> {
         );
 
         let instantiated_predicates = match aggregate_kind {
-            AggregateKind::Adt(def, _, substs, _) => {
+            AggregateKind::Adt(def, _, substs, _, _) => {
                 tcx.predicates_of(def.did).instantiate(tcx, substs)
             }
 
diff --git a/src/librustc_mir/build/expr/as_constant.rs b/src/librustc_mir/build/expr/as_constant.rs
index a57f1b95494..1106f750d6d 100644
--- a/src/librustc_mir/build/expr/as_constant.rs
+++ b/src/librustc_mir/build/expr/as_constant.rs
@@ -31,8 +31,8 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
         match kind {
             ExprKind::Scope { region_scope: _, lint_level: _, value } =>
                 this.as_constant(value),
-            ExprKind::Literal { literal } =>
-                Constant { span: span, ty: ty, literal: literal },
+            ExprKind::Literal { literal, user_ty } =>
+                Constant { span, ty, user_ty, literal },
             _ =>
                 span_bug!(
                     span,
diff --git a/src/librustc_mir/build/expr/as_rvalue.rs b/src/librustc_mir/build/expr/as_rvalue.rs
index 68009e962a3..b90a58f2a7e 100644
--- a/src/librustc_mir/build/expr/as_rvalue.rs
+++ b/src/librustc_mir/build/expr/as_rvalue.rs
@@ -239,6 +239,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
                         operands.push(Operand::Constant(box Constant {
                             span: expr_span,
                             ty: this.hir.tcx().types.u32,
+                            user_ty: None,
                             literal: ty::Const::from_bits(
                                 this.hir.tcx(),
                                 0,
@@ -254,7 +255,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
                 block.and(Rvalue::Aggregate(result, operands))
             }
             ExprKind::Adt {
-                adt_def, variant_index, substs, fields, base
+                adt_def, variant_index, substs, user_ty, fields, base
             } => { // see (*) above
                 let is_union = adt_def.is_union();
                 let active_field_index = if is_union { Some(fields[0].name.index()) } else { None };
@@ -284,8 +285,13 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
                     field_names.iter().filter_map(|n| fields_map.get(n).cloned()).collect()
                 };
 
-                let adt =
-                    box AggregateKind::Adt(adt_def, variant_index, substs, active_field_index);
+                let adt = box AggregateKind::Adt(
+                    adt_def,
+                    variant_index,
+                    substs,
+                    user_ty,
+                    active_field_index,
+                );
                 block.and(Rvalue::Aggregate(adt, fields))
             }
             ExprKind::Assign { .. } |
diff --git a/src/librustc_mir/build/expr/into.rs b/src/librustc_mir/build/expr/into.rs
index 2b05e2c023a..3cd1270d7ef 100644
--- a/src/librustc_mir/build/expr/into.rs
+++ b/src/librustc_mir/build/expr/into.rs
@@ -128,6 +128,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
                     Constant {
                         span: expr_span,
                         ty: this.hir.bool_ty(),
+                        user_ty: None,
                         literal: this.hir.true_literal(),
                     });
 
@@ -136,6 +137,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
                     Constant {
                         span: expr_span,
                         ty: this.hir.bool_ty(),
+                        user_ty: None,
                         literal: this.hir.false_literal(),
                     });
 
diff --git a/src/librustc_mir/build/matches/test.rs b/src/librustc_mir/build/matches/test.rs
index 15a983635f7..4a0b4b0c885 100644
--- a/src/librustc_mir/build/matches/test.rs
+++ b/src/librustc_mir/build/matches/test.rs
@@ -344,7 +344,16 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
                         func: Operand::Constant(box Constant {
                             span: test.span,
                             ty: mty,
-                            literal: method
+
+                            // FIXME(#47184): This constant comes from user
+                            // input (a constant in a pattern).  Are
+                            // there forms where users can add type
+                            // annotations here?  For example, an
+                            // associated constant? Need to
+                            // experiment.
+                            user_ty: None,
+
+                            literal: method,
                         }),
                         args: vec![val, expect],
                         destination: Some((eq_result.clone(), eq_block)),
diff --git a/src/librustc_mir/build/misc.rs b/src/librustc_mir/build/misc.rs
index ae8070698c2..9405f43c056 100644
--- a/src/librustc_mir/build/misc.rs
+++ b/src/librustc_mir/build/misc.rs
@@ -32,6 +32,8 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
         place
     }
 
+    /// Convenience function for creating a literal operand, one
+    /// without any user type annotation.
     pub fn literal_operand(&mut self,
                            span: Span,
                            ty: Ty<'tcx>,
@@ -40,6 +42,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
         let constant = box Constant {
             span,
             ty,
+            user_ty: None,
             literal,
         };
         Operand::Constant(constant)
@@ -69,6 +72,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
             Constant {
                 span: source_info.span,
                 ty: self.hir.usize_ty(),
+                user_ty: None,
                 literal: self.hir.usize_literal(value),
             });
         temp
diff --git a/src/librustc_mir/hair/cx/expr.rs b/src/librustc_mir/hair/cx/expr.rs
index 04a3b5c115f..7153a388467 100644
--- a/src/librustc_mir/hair/cx/expr.rs
+++ b/src/librustc_mir/hair/cx/expr.rs
@@ -256,6 +256,16 @@ fn make_mirror_unadjusted<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>,
                 };
                 if let Some((adt_def, index)) = adt_data {
                     let substs = cx.tables().node_substs(fun.hir_id);
+
+                    let user_ty = cx.tables().user_substs(fun.hir_id)
+                        .map(|user_substs| {
+                            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)
+                            })
+                        });
+
                     let field_refs = args.iter()
                         .enumerate()
                         .map(|(idx, e)| {
@@ -270,6 +280,7 @@ fn make_mirror_unadjusted<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>,
                         substs,
                         variant_index: index,
                         fields: field_refs,
+                        user_ty,
                         base: None,
                     }
                 } else {
@@ -317,6 +328,7 @@ fn make_mirror_unadjusted<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>,
 
         hir::ExprKind::Lit(ref lit) => ExprKind::Literal {
             literal: cx.const_eval_literal(&lit.node, expr_ty, lit.span, false),
+            user_ty: None,
         },
 
         hir::ExprKind::Binary(op, ref lhs, ref rhs) => {
@@ -406,6 +418,7 @@ fn make_mirror_unadjusted<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>,
                 if let hir::ExprKind::Lit(ref lit) = arg.node {
                     ExprKind::Literal {
                         literal: cx.const_eval_literal(&lit.node, expr_ty, lit.span, true),
+                        user_ty: None,
                     }
                 } else {
                     ExprKind::Unary {
@@ -425,6 +438,7 @@ fn make_mirror_unadjusted<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>,
                                 adt_def: adt,
                                 variant_index: 0,
                                 substs,
+                                user_ty: user_annotated_ty_for_adt(cx, expr.hir_id, adt),
                                 fields: field_refs(cx, fields),
                                 base: base.as_ref().map(|base| {
                                     FruInfo {
@@ -450,6 +464,7 @@ fn make_mirror_unadjusted<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>,
                                         adt_def: adt,
                                         variant_index: index,
                                         substs,
+                                        user_ty: user_annotated_ty_for_adt(cx, expr.hir_id, adt),
                                         fields: field_refs(cx, fields),
                                         base: None,
                                     }
@@ -631,7 +646,7 @@ fn make_mirror_unadjusted<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>,
                         temp_lifetime,
                         ty,
                         span: expr.span,
-                        kind: ExprKind::Literal { literal },
+                        kind: ExprKind::Literal { literal, user_ty: None },
                     }.to_ref();
                     let offset = mk_const(ty::Const::from_bits(
                         cx.tcx,
@@ -684,18 +699,77 @@ fn make_mirror_unadjusted<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>,
     }
 }
 
-fn method_callee<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>,
-                                 expr: &hir::Expr,
-                                 custom_callee: Option<(DefId, &'tcx Substs<'tcx>)>)
-                                 -> Expr<'tcx> {
+fn user_annotated_ty_for_def(
+    cx: &mut Cx<'a, 'gcx, 'tcx>,
+    hir_id: hir::HirId,
+    def: &Def,
+) -> Option<CanonicalTy<'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
+        // `Fn` but with the user-given substitutions.
+        Def::Fn(_) |
+        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)
+            })),
+
+        Def::Const(_def_id) |
+        Def::AssociatedConst(_def_id) =>
+            bug!("unimplemented"),
+
+        // A unit struct/variant which is used as a value (e.g.,
+        // `None`). This has the type of the enum/struct that defines
+        // this variant -- but with the substitutions given by the
+        // user.
+        Def::StructCtor(_def_id, CtorKind::Const) |
+        Def::VariantCtor(_def_id, CtorKind::Const) =>
+            match &cx.tables().node_id_to_type(hir_id).sty {
+                ty::Adt(adt_def, _) => user_annotated_ty_for_adt(cx, hir_id, adt_def),
+                sty => bug!("unexpected sty: {:?}", sty),
+            },
+
+        _ =>
+            bug!("user_annotated_ty_for_def: unexpected def {:?} at {:?}", def, hir_id)
+    }
+}
+
+fn user_annotated_ty_for_adt(
+    cx: &mut Cx<'a, 'gcx, 'tcx>,
+    hir_id: hir::HirId,
+    adt_def: &'tcx AdtDef,
+) -> Option<CanonicalTy<'tcx>> {
+    let user_substs = cx.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.
+        cx.tcx().mk_adt(adt_def, user_substs)
+    }))
+}
+
+fn method_callee<'a, 'gcx, 'tcx>(
+    cx: &mut Cx<'a, 'gcx, 'tcx>,
+    expr: &hir::Expr,
+    overloaded_callee: Option<(DefId, &'tcx Substs<'tcx>)>,
+) -> Expr<'tcx> {
     let temp_lifetime = cx.region_scope_tree.temporary_scope(expr.hir_id.local_id);
-    let (def_id, substs) = custom_callee.unwrap_or_else(|| {
-        if let Some(def) = cx.tables().type_dependent_defs().get(expr.hir_id) {
-            (def.def_id(), cx.tables().node_substs(expr.hir_id))
-        } else {
-            span_bug!(expr.span, "no type-dependent def for method callee")
+    let (def_id, substs, user_ty) = match overloaded_callee {
+        Some((def_id, substs)) => (def_id, substs, None),
+        None => {
+            let type_dependent_defs = cx.tables().type_dependent_defs();
+            let def = type_dependent_defs
+                .get(expr.hir_id)
+                .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);
+            (def.def_id(), cx.tables().node_substs(expr.hir_id), user_ty)
         }
-    });
+    };
     let ty = cx.tcx().mk_fn_def(def_id, substs);
     Expr {
         temp_lifetime,
@@ -703,6 +777,7 @@ fn method_callee<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>,
         span: expr.span,
         kind: ExprKind::Literal {
             literal: ty::Const::zero_sized(cx.tcx(), ty),
+            user_ty,
         },
     }
 }
@@ -753,11 +828,15 @@ fn convert_path_expr<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>,
         Def::Fn(_) |
         Def::Method(_) |
         Def::StructCtor(_, CtorKind::Fn) |
-        Def::VariantCtor(_, CtorKind::Fn) => ExprKind::Literal {
-            literal: ty::Const::zero_sized(
-                cx.tcx,
-                cx.tables().node_id_to_type(expr.hir_id),
-            ),
+        Def::VariantCtor(_, CtorKind::Fn) => {
+            let user_ty = user_annotated_ty_for_def(cx, expr.hir_id, &def);
+            ExprKind::Literal {
+                literal: ty::Const::zero_sized(
+                    cx.tcx,
+                    cx.tables().node_id_to_type(expr.hir_id),
+                ),
+                user_ty,
+            }
         },
 
         Def::Const(def_id) |
@@ -768,6 +847,7 @@ fn convert_path_expr<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>,
                 substs,
                 cx.tables().node_id_to_type(expr.hir_id),
             ),
+            user_ty: None, // FIXME(#47184) -- user given type annot on constants
         },
 
         Def::StructCtor(def_id, CtorKind::Const) |
@@ -780,6 +860,7 @@ fn convert_path_expr<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>,
                         adt_def,
                         variant_index: adt_def.variant_index_with_id(def_id),
                         substs,
+                        user_ty: user_annotated_ty_for_adt(cx, expr.hir_id, adt_def),
                         fields: vec![],
                         base: None,
                     }
@@ -958,12 +1039,13 @@ fn overloaded_operator<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>,
     }
 }
 
-fn overloaded_place<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>,
-                                     expr: &'tcx hir::Expr,
-                                     place_ty: Ty<'tcx>,
-                                     custom_callee: Option<(DefId, &'tcx Substs<'tcx>)>,
-                                     args: Vec<ExprRef<'tcx>>)
-                                     -> ExprKind<'tcx> {
+fn overloaded_place<'a, 'gcx, 'tcx>(
+    cx: &mut Cx<'a, 'gcx, 'tcx>,
+    expr: &'tcx hir::Expr,
+    place_ty: Ty<'tcx>,
+    overloaded_callee: Option<(DefId, &'tcx Substs<'tcx>)>,
+    args: Vec<ExprRef<'tcx>>,
+) -> ExprKind<'tcx> {
     // For an overloaded *x or x[y] expression of type T, the method
     // call returns an &T and we must add the deref so that the types
     // line up (this is because `*x` and `x[y]` represent places):
@@ -988,7 +1070,7 @@ fn overloaded_place<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>,
     // construct the complete expression `foo()` for the overloaded call,
     // which will yield the &T type
     let temp_lifetime = cx.region_scope_tree.temporary_scope(expr.hir_id.local_id);
-    let fun = method_callee(cx, expr, custom_callee);
+    let fun = method_callee(cx, expr, overloaded_callee);
     let ref_expr = Expr {
         temp_lifetime,
         ty: ref_ty,
diff --git a/src/librustc_mir/hair/mod.rs b/src/librustc_mir/hair/mod.rs
index c39aa9ca780..d6037adb53b 100644
--- a/src/librustc_mir/hair/mod.rs
+++ b/src/librustc_mir/hair/mod.rs
@@ -18,7 +18,7 @@ use rustc::mir::{BinOp, BorrowKind, Field, UnOp};
 use rustc::hir::def_id::DefId;
 use rustc::middle::region;
 use rustc::ty::subst::Substs;
-use rustc::ty::{AdtDef, UpvarSubsts, Region, Ty, Const};
+use rustc::ty::{AdtDef, CanonicalTy, UpvarSubsts, Region, Ty, Const};
 use rustc::hir;
 use syntax::ast;
 use syntax_pos::Span;
@@ -261,6 +261,11 @@ pub enum ExprKind<'tcx> {
         adt_def: &'tcx AdtDef,
         variant_index: usize,
         substs: &'tcx Substs<'tcx>,
+
+        /// Optional user-given substs: for something like `let x =
+        /// Bar::<T> { ... }`.
+        user_ty: Option<CanonicalTy<'tcx>>,
+
         fields: Vec<FieldExprRef<'tcx>>,
         base: Option<FruInfo<'tcx>>
     },
@@ -272,6 +277,13 @@ 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>>,
     },
     InlineAsm {
         asm: &'tcx hir::InlineAsm,
diff --git a/src/librustc_mir/interpret/step.rs b/src/librustc_mir/interpret/step.rs
index f39a5ee3e4e..db556db2417 100644
--- a/src/librustc_mir/interpret/step.rs
+++ b/src/librustc_mir/interpret/step.rs
@@ -208,7 +208,7 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> {
 
             Aggregate(ref kind, ref operands) => {
                 let (dest, active_field_index) = match **kind {
-                    mir::AggregateKind::Adt(adt_def, variant_index, _, active_field_index) => {
+                    mir::AggregateKind::Adt(adt_def, variant_index, _, _, active_field_index) => {
                         self.write_discriminant_value(variant_index, dest)?;
                         if adt_def.is_enum() {
                             (self.place_downcast(dest, variant_index)?, active_field_index)
diff --git a/src/librustc_mir/shim.rs b/src/librustc_mir/shim.rs
index 765a47e729e..7e7e7cfade6 100644
--- a/src/librustc_mir/shim.rs
+++ b/src/librustc_mir/shim.rs
@@ -440,6 +440,7 @@ impl<'a, 'tcx> CloneShimBuilder<'a, 'tcx> {
         let func = Operand::Constant(box Constant {
             span: self.span,
             ty: func_ty,
+            user_ty: None,
             literal: ty::Const::zero_sized(self.tcx, func_ty),
         });
 
@@ -498,6 +499,7 @@ impl<'a, 'tcx> CloneShimBuilder<'a, 'tcx> {
         box Constant {
             span: self.span,
             ty: self.tcx.types.usize,
+            user_ty: None,
             literal: ty::Const::from_usize(self.tcx, value),
         }
     }
@@ -725,6 +727,7 @@ fn build_call_shim<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
             (Operand::Constant(box Constant {
                 span,
                 ty,
+                user_ty: None,
                 literal: ty::Const::zero_sized(tcx, ty),
              }),
              vec![rcvr])
@@ -847,7 +850,7 @@ pub fn build_adt_ctor<'a, 'gcx, 'tcx>(infcx: &infer::InferCtxt<'a, 'gcx, 'tcx>,
             kind: StatementKind::Assign(
                 Place::Local(RETURN_PLACE),
                 Rvalue::Aggregate(
-                    box AggregateKind::Adt(adt_def, variant_no, substs, None),
+                    box AggregateKind::Adt(adt_def, variant_no, substs, None, None),
                     (1..sig.inputs().len()+1).map(|i| {
                         Operand::Move(Place::Local(Local::new(i)))
                     }).collect()
diff --git a/src/librustc_mir/transform/deaggregator.rs b/src/librustc_mir/transform/deaggregator.rs
index 8b2b9ef7e81..cff098c7b73 100644
--- a/src/librustc_mir/transform/deaggregator.rs
+++ b/src/librustc_mir/transform/deaggregator.rs
@@ -48,7 +48,7 @@ impl MirPass for Deaggregator {
 
                 let mut set_discriminant = None;
                 let active_field_index = match *kind {
-                    AggregateKind::Adt(adt_def, variant_index, _, active_field_index) => {
+                    AggregateKind::Adt(adt_def, variant_index, _, _, active_field_index) => {
                         if adt_def.is_enum() {
                             set_discriminant = Some(Statement {
                                 kind: StatementKind::SetDiscriminant {
diff --git a/src/librustc_mir/transform/elaborate_drops.rs b/src/librustc_mir/transform/elaborate_drops.rs
index bbf896e624f..225de03a329 100644
--- a/src/librustc_mir/transform/elaborate_drops.rs
+++ b/src/librustc_mir/transform/elaborate_drops.rs
@@ -543,6 +543,7 @@ impl<'b, 'tcx> ElaborateDropsCtxt<'b, 'tcx> {
         Rvalue::Use(Operand::Constant(Box::new(Constant {
             span,
             ty: self.tcx.types.bool,
+            user_ty: None,
             literal: ty::Const::from_bool(self.tcx, val),
         })))
     }
diff --git a/src/librustc_mir/transform/generator.rs b/src/librustc_mir/transform/generator.rs
index dc657f228c9..db588884d8e 100644
--- a/src/librustc_mir/transform/generator.rs
+++ b/src/librustc_mir/transform/generator.rs
@@ -157,7 +157,7 @@ struct TransformVisitor<'a, 'tcx: 'a> {
 impl<'a, 'tcx> TransformVisitor<'a, 'tcx> {
     // Make a GeneratorState rvalue
     fn make_state(&self, idx: usize, val: Operand<'tcx>) -> Rvalue<'tcx> {
-        let adt = AggregateKind::Adt(self.state_adt_ref, idx, self.state_substs, None);
+        let adt = AggregateKind::Adt(self.state_adt_ref, idx, self.state_substs, None, None);
         Rvalue::Aggregate(box adt, vec![val])
     }
 
@@ -177,6 +177,7 @@ impl<'a, 'tcx> TransformVisitor<'a, 'tcx> {
         let val = Operand::Constant(box Constant {
             span: source_info.span,
             ty: self.tcx.types.u32,
+            user_ty: None,
             literal: ty::Const::from_bits(
                 self.tcx,
                 state_disc.into(),
@@ -710,6 +711,7 @@ fn insert_panic_block<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
         cond: Operand::Constant(box Constant {
             span: mir.span,
             ty: tcx.types.bool,
+            user_ty: None,
             literal: ty::Const::from_bool(tcx, false),
         }),
         expected: true,
diff --git a/src/librustc_mir/transform/instcombine.rs b/src/librustc_mir/transform/instcombine.rs
index 4cf4a8f23a4..12780ef8be9 100644
--- a/src/librustc_mir/transform/instcombine.rs
+++ b/src/librustc_mir/transform/instcombine.rs
@@ -103,7 +103,7 @@ impl<'b, 'a, 'tcx> Visitor<'tcx> for OptimizationFinder<'b, 'a, 'tcx> {
             if let TyKind::Array(_, len) = place_ty.sty {
                 let span = self.mir.source_info(location).span;
                 let ty = self.tcx.types.usize;
-                let constant = Constant { span, ty, literal: len };
+                let constant = Constant { span, ty, literal: len, user_ty: None };
                 self.optimizations.arrays_lengths.insert(location, constant);
             }
         }
diff --git a/src/librustc_mir/util/elaborate_drops.rs b/src/librustc_mir/util/elaborate_drops.rs
index 45e405cb55e..1c0c98d621c 100644
--- a/src/librustc_mir/util/elaborate_drops.rs
+++ b/src/librustc_mir/util/elaborate_drops.rs
@@ -969,6 +969,7 @@ impl<'l, 'b, 'tcx, D> DropCtxt<'l, 'b, 'tcx, D>
         Operand::Constant(box Constant {
             span: self.source_info.span,
             ty: self.tcx().types.usize,
+            user_ty: None,
             literal: ty::Const::from_usize(self.tcx(), val.into()),
         })
     }
diff --git a/src/librustc_mir/util/pretty.rs b/src/librustc_mir/util/pretty.rs
index 886f83b8f2f..e0643d8f978 100644
--- a/src/librustc_mir/util/pretty.rs
+++ b/src/librustc_mir/util/pretty.rs
@@ -397,10 +397,13 @@ impl<'cx, 'gcx, 'tcx> ExtraComments<'cx, 'gcx, 'tcx> {
 impl<'cx, 'gcx, 'tcx> Visitor<'tcx> for ExtraComments<'cx, 'gcx, 'tcx> {
     fn visit_constant(&mut self, constant: &Constant<'tcx>, location: Location) {
         self.super_constant(constant, location);
-        let Constant { span, ty, literal } = constant;
+        let Constant { span, ty, user_ty, literal } = constant;
         self.push("mir::Constant");
         self.push(&format!("+ span: {:?}", span));
         self.push(&format!("+ ty: {:?}", ty));
+        if let Some(user_ty) = user_ty {
+            self.push(&format!("+ user_ty: {:?}", user_ty));
+        }
         self.push(&format!("+ literal: {:?}", literal));
     }
 
@@ -429,6 +432,11 @@ impl<'cx, 'gcx, 'tcx> Visitor<'tcx> for ExtraComments<'cx, 'gcx, 'tcx> {
                     self.push(&format!("+ movability: {:?}", movability));
                 }
 
+                AggregateKind::Adt(_, _, _, Some(user_ty), _) => {
+                    self.push("adt");
+                    self.push(&format!("+ user_ty: {:?}", user_ty));
+                }
+
                 _ => {}
             },
 
diff --git a/src/librustc_typeck/astconv.rs b/src/librustc_typeck/astconv.rs
index d0778a729ad..9d4481ce6d4 100644
--- a/src/librustc_typeck/astconv.rs
+++ b/src/librustc_typeck/astconv.rs
@@ -1367,7 +1367,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> dyn AstConv<'gcx, 'tcx>+'o {
                      -> Ty<'tcx> {
         let tcx = self.tcx();
 
-        debug!("base_def_to_ty(def={:?}, opt_self_ty={:?}, path_segments={:?})",
+        debug!("def_to_ty(def={:?}, opt_self_ty={:?}, path_segments={:?})",
                path.def, opt_self_ty, path.segments);
 
         let span = path.span;
diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs
index b2c324d260e..819827abd05 100644
--- a/src/librustc_typeck/check/mod.rs
+++ b/src/librustc_typeck/check/mod.rs
@@ -95,7 +95,7 @@ use rustc::infer::anon_types::AnonTypeDecl;
 use rustc::infer::type_variable::{TypeVariableOrigin};
 use rustc::middle::region;
 use rustc::mir::interpret::{GlobalId};
-use rustc::ty::subst::{UnpackedKind, Subst, Substs};
+use rustc::ty::subst::{CanonicalSubsts, UnpackedKind, Subst, Substs};
 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};
@@ -122,6 +122,7 @@ use std::ops::{self, Deref};
 use rustc_target::spec::abi::Abi;
 use syntax::ast;
 use syntax::attr;
+use syntax::source_map::DUMMY_SP;
 use syntax::source_map::original_sp;
 use syntax::feature_gate::{GateIssue, emit_feature_err};
 use syntax::ptr::P;
@@ -2058,11 +2059,47 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
     pub fn write_method_call(&self,
                              hir_id: hir::HirId,
                              method: MethodCallee<'tcx>) {
+        debug!("write_method_call(hir_id={:?}, method={:?})", hir_id, method);
         self.tables
             .borrow_mut()
             .type_dependent_defs_mut()
             .insert(hir_id, Def::Method(method.def_id));
+
         self.write_substs(hir_id, method.substs);
+
+        // When the method is confirmed, the `method.substs` includes
+        // parameters from not just the method, but also the impl of
+        // the method -- in particular, the `Self` type will be fully
+        // resolved. However, those are not something that the "user
+        // specified" -- i.e., those types come from the inferred type
+        // of the receiver, not something the user wrote. So when we
+        // create the user-substs, we want to replace those earlier
+        // types with just the types that the user actually wrote --
+        // that is, those that appear on the *method itself*.
+        //
+        // As an example, if the user wrote something like
+        // `foo.bar::<u32>(...)` -- the `Self` type here will be the
+        // type of `foo` (possibly adjusted), but we don't want to
+        // include that. We want just the `[_, u32]` part.
+        if !method.substs.is_noop() {
+            let method_generics = self.tcx.generics_of(method.def_id);
+            if !method_generics.params.is_empty() {
+                let user_substs = self.infcx.probe(|_| {
+                    let just_method_substs = Substs::for_item(self.tcx, method.def_id, |param, _| {
+                        let i = param.index as usize;
+                        if i < method_generics.parent_count {
+                            self.infcx.var_for_def(DUMMY_SP, param)
+                        } else {
+                            method.substs[i]
+                        }
+                    });
+                    self.infcx.canonicalize_response(&just_method_substs)
+                });
+
+                debug!("write_method_call: user_substs = {:?}", user_substs);
+                self.write_user_substs(hir_id, user_substs);
+            }
+        }
     }
 
     pub fn write_substs(&self, node_id: hir::HirId, substs: &'tcx Substs<'tcx>) {
@@ -2076,6 +2113,36 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
         }
     }
 
+    /// Given the substs that we just converted from the HIR, try to
+    /// canonicalize them and store them as user-given substitutions
+    /// (i.e., substitutions that must be respected by the NLL check).
+    ///
+    /// 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>) {
+        if !substs.is_noop() {
+            let user_substs = self.infcx.canonicalize_response(&substs);
+            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>) {
+        debug!(
+            "write_user_substs({:?}, {:?}) in fcx {}",
+            hir_id,
+            substs,
+            self.tag(),
+        );
+
+        if !substs.is_identity() {
+            self.tables.borrow_mut().user_substs_mut().insert(hir_id, substs);
+        } else {
+            debug!("write_user_substs: skipping identity substs");
+        }
+    }
+
     pub fn apply_adjustments(&self, expr: &hir::Expr, adj: Vec<Adjustment<'tcx>>) {
         debug!("apply_adjustments(expr={:?}, adj={:?})", expr, adj);
 
@@ -3544,6 +3611,10 @@ 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);
+
             // Check bounds on type arguments used in the path.
             let bounds = self.instantiate_bounds(path_span, did, substs);
             let cause = traits::ObligationCause::new(path_span, self.body_id,
@@ -5083,7 +5154,11 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
         debug!("instantiate_value_path: type of {:?} is {:?}",
                node_id,
                ty_substituted);
-        self.write_substs(self.tcx.hir.node_to_hir_id(node_id), substs);
+        let hir_id = self.tcx.hir.node_to_hir_id(node_id);
+        self.write_substs(hir_id, substs);
+
+        self.write_user_substs_from_substs(hir_id, substs);
+
         ty_substituted
     }
 
diff --git a/src/librustc_typeck/check/writeback.rs b/src/librustc_typeck/check/writeback.rs
index 319de51713b..0d8401c1c86 100644
--- a/src/librustc_typeck/check/writeback.rs
+++ b/src/librustc_typeck/check/writeback.rs
@@ -35,7 +35,11 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
         let item_id = self.tcx.hir.body_owner(body.id());
         let item_def_id = self.tcx.hir.local_def_id(item_id);
 
-        let mut wbcx = WritebackCx::new(self, body);
+        // This attribute causes us to dump some writeback information
+        // in the form of errors, which is used for unit tests.
+        let rustc_dump_user_substs = self.tcx.has_attr(item_def_id, "rustc_dump_user_substs");
+
+        let mut wbcx = WritebackCx::new(self, body, rustc_dump_user_substs);
         for arg in &body.arguments {
             wbcx.visit_node_id(arg.pat.span, arg.hir_id);
         }
@@ -84,12 +88,15 @@ struct WritebackCx<'cx, 'gcx: 'cx + 'tcx, 'tcx: 'cx> {
     tables: ty::TypeckTables<'gcx>,
 
     body: &'gcx hir::Body,
+
+    rustc_dump_user_substs: bool,
 }
 
 impl<'cx, 'gcx, 'tcx> WritebackCx<'cx, 'gcx, 'tcx> {
     fn new(
         fcx: &'cx FnCtxt<'cx, 'gcx, 'tcx>,
         body: &'gcx hir::Body,
+        rustc_dump_user_substs: bool,
     ) -> WritebackCx<'cx, 'gcx, 'tcx> {
         let owner = fcx.tcx.hir.definitions().node_to_hir_id(body.id().node_id);
 
@@ -97,6 +104,7 @@ impl<'cx, 'gcx, 'tcx> WritebackCx<'cx, 'gcx, 'tcx> {
             fcx,
             tables: ty::TypeckTables::empty(Some(DefId::local(owner.owner))),
             body,
+            rustc_dump_user_substs,
         }
     }
 
@@ -558,6 +566,22 @@ impl<'cx, 'gcx, 'tcx> WritebackCx<'cx, 'gcx, 'tcx> {
             assert!(!substs.needs_infer() && !substs.has_skol());
             self.tables.node_substs_mut().insert(hir_id, substs);
         }
+
+        // Copy over any user-substs
+        if let Some(user_substs) = self.fcx.tables.borrow().user_substs(hir_id) {
+            let user_substs = self.tcx().lift_to_global(&user_substs).unwrap();
+            self.tables.user_substs_mut().insert(hir_id, user_substs);
+
+            // Unit-testing mechanism:
+            if self.rustc_dump_user_substs {
+                let node_id = self.tcx().hir.hir_to_node_id(hir_id);
+                let span = self.tcx().hir.span(node_id);
+                self.tcx().sess.span_err(
+                    span,
+                    &format!("user substs: {:?}", user_substs),
+                );
+            }
+        }
     }
 
     fn visit_adjustments(&mut self, span: Span, hir_id: hir::HirId) {
diff --git a/src/libsyntax/feature_gate.rs b/src/libsyntax/feature_gate.rs
index 4ed96d26906..e2a22167b7e 100644
--- a/src/libsyntax/feature_gate.rs
+++ b/src/libsyntax/feature_gate.rs
@@ -865,6 +865,12 @@ pub const BUILTIN_ATTRIBUTES: &'static [(&'static str, AttributeType, AttributeG
                                         is just used for rustc unit tests \
                                         and will never be stable",
                                        cfg_fn!(rustc_attrs))),
+    ("rustc_dump_user_substs", Whitelisted, Gated(Stability::Unstable,
+                                       "rustc_attrs",
+                                       "this attribute \
+                                        is just used for rustc unit tests \
+                                        and will never be stable",
+                                       cfg_fn!(rustc_attrs))),
     ("rustc_if_this_changed", Whitelisted, Gated(Stability::Unstable,
                                                  "rustc_attrs",
                                                  "the `#[rustc_if_this_changed]` attribute \
diff --git a/src/test/ui/hr-subtype/hr-subtype.free_inv_x_vs_free_inv_y.nll.stderr b/src/test/ui/hr-subtype/hr-subtype.free_inv_x_vs_free_inv_y.nll.stderr
index 1999df909ed..bb4e922fdc0 100644
--- a/src/test/ui/hr-subtype/hr-subtype.free_inv_x_vs_free_inv_y.nll.stderr
+++ b/src/test/ui/hr-subtype/hr-subtype.free_inv_x_vs_free_inv_y.nll.stderr
@@ -18,17 +18,33 @@ LL | / check! { free_inv_x_vs_free_inv_y: (fn(Inv<'x>),
 LL | |                                     fn(Inv<'y>)) }
    | |__________________________________________________- in this macro invocation
 
-error: compilation successful
-  --> $DIR/hr-subtype.rs:110:1
+error: unsatisfied lifetime constraints
+  --> $DIR/hr-subtype.rs:43:13
    |
-LL | / fn main() {
-LL | | //[bound_a_vs_bound_a]~^ ERROR compilation successful
-LL | | //[bound_a_vs_bound_b]~^^ ERROR compilation successful
-LL | | //[bound_inv_a_vs_bound_inv_b]~^^^ ERROR compilation successful
-LL | | //[bound_co_a_vs_bound_co_b]~^^^^ ERROR compilation successful
-LL | | //[free_x_vs_free_x]~^^^^^ ERROR compilation successful
-LL | | }
-   | |_^
+LL |           fn subtype<'x,'y:'x,'z:'y>() {
+   |                      -- -- lifetime `'y` defined here
+   |                      |
+   |                      lifetime `'x` defined here
+LL |               gimme::<$t2>(None::<$t1>);
+   |               ^^^^^^^^^^^^^^^^^^^^^^^^^ argument requires that `'x` must outlive `'y`
+...
+LL | / check! { free_inv_x_vs_free_inv_y: (fn(Inv<'x>),
+LL | |                                     fn(Inv<'y>)) }
+   | |__________________________________________________- in this macro invocation
+
+error: unsatisfied lifetime constraints
+  --> $DIR/hr-subtype.rs:49:13
+   |
+LL |           fn supertype<'x,'y:'x,'z:'y>() {
+   |                        -- -- lifetime `'y` defined here
+   |                        |
+   |                        lifetime `'x` defined here
+LL |               gimme::<$t1>(None::<$t2>);
+   |               ^^^^^^^^^^^^^^^^^^^^^^^^^ argument requires that `'x` must outlive `'y`
+...
+LL | / check! { free_inv_x_vs_free_inv_y: (fn(Inv<'x>),
+LL | |                                     fn(Inv<'y>)) }
+   | |__________________________________________________- in this macro invocation
 
-error: aborting due to previous error
+error: aborting due to 2 previous errors
 
diff --git a/src/test/ui/hr-subtype/hr-subtype.free_x_vs_free_y.nll.stderr b/src/test/ui/hr-subtype/hr-subtype.free_x_vs_free_y.nll.stderr
index f76b26b5191..c33e6fbfde7 100644
--- a/src/test/ui/hr-subtype/hr-subtype.free_x_vs_free_y.nll.stderr
+++ b/src/test/ui/hr-subtype/hr-subtype.free_x_vs_free_y.nll.stderr
@@ -8,17 +8,19 @@ LL | / check! { free_x_vs_free_y: (fn(&'x u32),
 LL | |                             fn(&'y u32)) }
    | |__________________________________________- in this macro invocation
 
-error: compilation successful
-  --> $DIR/hr-subtype.rs:110:1
+error: unsatisfied lifetime constraints
+  --> $DIR/hr-subtype.rs:49:13
    |
-LL | / fn main() {
-LL | | //[bound_a_vs_bound_a]~^ ERROR compilation successful
-LL | | //[bound_a_vs_bound_b]~^^ ERROR compilation successful
-LL | | //[bound_inv_a_vs_bound_inv_b]~^^^ ERROR compilation successful
-LL | | //[bound_co_a_vs_bound_co_b]~^^^^ ERROR compilation successful
-LL | | //[free_x_vs_free_x]~^^^^^ ERROR compilation successful
-LL | | }
-   | |_^
+LL |           fn supertype<'x,'y:'x,'z:'y>() {
+   |                        -- -- lifetime `'y` defined here
+   |                        |
+   |                        lifetime `'x` defined here
+LL |               gimme::<$t1>(None::<$t2>);
+   |               ^^^^^^^^^^^^^^^^^^^^^^^^^ argument requires that `'x` must outlive `'y`
+...
+LL | / check! { free_x_vs_free_y: (fn(&'x u32),
+LL | |                             fn(&'y u32)) }
+   | |__________________________________________- in this macro invocation
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/nll/user-annotations/adt-brace-enums.rs b/src/test/ui/nll/user-annotations/adt-brace-enums.rs
new file mode 100644
index 00000000000..4465be414bc
--- /dev/null
+++ b/src/test/ui/nll/user-annotations/adt-brace-enums.rs
@@ -0,0 +1,62 @@
+// 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.
+
+// Unit test for the "user substitutions" that are annotated on each
+// node.
+
+#![feature(nll)]
+
+enum SomeEnum<T> {
+    SomeVariant { t: T }
+}
+
+fn no_annot() {
+    let c = 66;
+    SomeEnum::SomeVariant { t: &c };
+}
+
+fn annot_underscore() {
+    let c = 66;
+    SomeEnum::SomeVariant::<_> { t: &c };
+}
+
+fn annot_reference_any_lifetime() {
+    let c = 66;
+    SomeEnum::SomeVariant::<&u32> { t: &c };
+}
+
+fn annot_reference_static_lifetime() {
+    let c = 66;
+    SomeEnum::SomeVariant::<&'static u32> { t: &c }; //~ ERROR
+}
+
+fn annot_reference_named_lifetime<'a>(_d: &'a u32) {
+    let c = 66;
+    SomeEnum::SomeVariant::<&'a u32> { t: &c }; //~ ERROR
+}
+
+fn annot_reference_named_lifetime_ok<'a>(c: &'a u32) {
+    SomeEnum::SomeVariant::<&'a u32> { t: c };
+}
+
+fn annot_reference_named_lifetime_in_closure<'a>(_: &'a u32) {
+    let _closure = || {
+        let c = 66;
+        SomeEnum::SomeVariant::<&'a u32> { t: &c }; //~ ERROR
+    };
+}
+
+fn annot_reference_named_lifetime_in_closure_ok<'a>(c: &'a u32) {
+    let _closure = || {
+        SomeEnum::SomeVariant::<&'a u32> { t: c };
+    };
+}
+
+fn main() { }
diff --git a/src/test/ui/nll/user-annotations/adt-brace-enums.stderr b/src/test/ui/nll/user-annotations/adt-brace-enums.stderr
new file mode 100644
index 00000000000..842bb622bc3
--- /dev/null
+++ b/src/test/ui/nll/user-annotations/adt-brace-enums.stderr
@@ -0,0 +1,41 @@
+error[E0597]: `c` does not live long enough
+  --> $DIR/adt-brace-enums.rs:37:48
+   |
+LL |     SomeEnum::SomeVariant::<&'static u32> { t: &c }; //~ ERROR
+   |                                                ^^ borrowed value does not live long enough
+LL | }
+   | - `c` dropped here while still borrowed
+   |
+   = note: borrowed value must be valid for the static lifetime...
+
+error[E0597]: `c` does not live long enough
+  --> $DIR/adt-brace-enums.rs:42:43
+   |
+LL |     SomeEnum::SomeVariant::<&'a u32> { t: &c }; //~ ERROR
+   |                                           ^^ borrowed value does not live long enough
+LL | }
+   | - `c` dropped here while still borrowed
+   |
+note: borrowed value must be valid for the lifetime 'a as defined on the function body at 40:35...
+  --> $DIR/adt-brace-enums.rs:40:35
+   |
+LL | fn annot_reference_named_lifetime<'a>(_d: &'a u32) {
+   |                                   ^^
+
+error[E0597]: `c` does not live long enough
+  --> $DIR/adt-brace-enums.rs:52:47
+   |
+LL |         SomeEnum::SomeVariant::<&'a u32> { t: &c }; //~ ERROR
+   |                                               ^^ borrowed value does not live long enough
+LL |     };
+   |     - `c` dropped here while still borrowed
+   |
+note: borrowed value must be valid for the lifetime 'a as defined on the function body at 49:46...
+  --> $DIR/adt-brace-enums.rs:49:46
+   |
+LL | fn annot_reference_named_lifetime_in_closure<'a>(_: &'a u32) {
+   |                                              ^^
+
+error: aborting due to 3 previous errors
+
+For more information about this error, try `rustc --explain E0597`.
diff --git a/src/test/ui/nll/user-annotations/adt-brace-structs.rs b/src/test/ui/nll/user-annotations/adt-brace-structs.rs
new file mode 100644
index 00000000000..c479e050564
--- /dev/null
+++ b/src/test/ui/nll/user-annotations/adt-brace-structs.rs
@@ -0,0 +1,60 @@
+// 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.
+
+// Unit test for the "user substitutions" that are annotated on each
+// node.
+
+#![feature(nll)]
+
+struct SomeStruct<T> { t: T }
+
+fn no_annot() {
+    let c = 66;
+    SomeStruct { t: &c };
+}
+
+fn annot_underscore() {
+    let c = 66;
+    SomeStruct::<_> { t: &c };
+}
+
+fn annot_reference_any_lifetime() {
+    let c = 66;
+    SomeStruct::<&u32> { t: &c };
+}
+
+fn annot_reference_static_lifetime() {
+    let c = 66;
+    SomeStruct::<&'static u32> { t: &c }; //~ ERROR
+}
+
+fn annot_reference_named_lifetime<'a>(_d: &'a u32) {
+    let c = 66;
+    SomeStruct::<&'a u32> { t: &c }; //~ ERROR
+}
+
+fn annot_reference_named_lifetime_ok<'a>(c: &'a u32) {
+    SomeStruct::<&'a u32> { t: c };
+}
+
+fn annot_reference_named_lifetime_in_closure<'a>(_: &'a u32) {
+    let _closure = || {
+        let c = 66;
+        SomeStruct::<&'a u32> { t: &c }; //~ ERROR
+    };
+}
+
+fn annot_reference_named_lifetime_in_closure_ok<'a>(c: &'a u32) {
+    let _closure = || {
+        SomeStruct::<&'a u32> { t: c };
+    };
+}
+
+fn main() { }
diff --git a/src/test/ui/nll/user-annotations/adt-brace-structs.stderr b/src/test/ui/nll/user-annotations/adt-brace-structs.stderr
new file mode 100644
index 00000000000..7ba76212dc5
--- /dev/null
+++ b/src/test/ui/nll/user-annotations/adt-brace-structs.stderr
@@ -0,0 +1,41 @@
+error[E0597]: `c` does not live long enough
+  --> $DIR/adt-brace-structs.rs:35:37
+   |
+LL |     SomeStruct::<&'static u32> { t: &c }; //~ ERROR
+   |                                     ^^ borrowed value does not live long enough
+LL | }
+   | - `c` dropped here while still borrowed
+   |
+   = note: borrowed value must be valid for the static lifetime...
+
+error[E0597]: `c` does not live long enough
+  --> $DIR/adt-brace-structs.rs:40:32
+   |
+LL |     SomeStruct::<&'a u32> { t: &c }; //~ ERROR
+   |                                ^^ borrowed value does not live long enough
+LL | }
+   | - `c` dropped here while still borrowed
+   |
+note: borrowed value must be valid for the lifetime 'a as defined on the function body at 38:35...
+  --> $DIR/adt-brace-structs.rs:38:35
+   |
+LL | fn annot_reference_named_lifetime<'a>(_d: &'a u32) {
+   |                                   ^^
+
+error[E0597]: `c` does not live long enough
+  --> $DIR/adt-brace-structs.rs:50:36
+   |
+LL |         SomeStruct::<&'a u32> { t: &c }; //~ ERROR
+   |                                    ^^ borrowed value does not live long enough
+LL |     };
+   |     - `c` dropped here while still borrowed
+   |
+note: borrowed value must be valid for the lifetime 'a as defined on the function body at 47:46...
+  --> $DIR/adt-brace-structs.rs:47:46
+   |
+LL | fn annot_reference_named_lifetime_in_closure<'a>(_: &'a u32) {
+   |                                              ^^
+
+error: aborting due to 3 previous errors
+
+For more information about this error, try `rustc --explain E0597`.
diff --git a/src/test/ui/nll/user-annotations/adt-nullary-enums.rs b/src/test/ui/nll/user-annotations/adt-nullary-enums.rs
new file mode 100644
index 00000000000..df62b67a459
--- /dev/null
+++ b/src/test/ui/nll/user-annotations/adt-nullary-enums.rs
@@ -0,0 +1,80 @@
+// 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.
+
+// Unit test for the "user substitutions" that are annotated on each
+// node.
+
+#![feature(nll)]
+#![allow(warnings)]
+
+use std::cell::Cell;
+
+enum SomeEnum<T> {
+    SomeVariant(T),
+    SomeOtherVariant,
+}
+
+fn combine<T>(_: T, _: T) { }
+
+fn no_annot() {
+    let c = 66;
+    combine(SomeEnum::SomeVariant(Cell::new(&c)), SomeEnum::SomeOtherVariant);
+}
+
+fn annot_underscore() {
+    let c = 66;
+    combine(SomeEnum::SomeVariant(Cell::new(&c)), SomeEnum::SomeOtherVariant::<Cell<_>>);
+}
+
+fn annot_reference_any_lifetime() {
+    let c = 66;
+    combine(SomeEnum::SomeVariant(Cell::new(&c)), SomeEnum::SomeOtherVariant::<Cell<&u32>>);
+}
+
+fn annot_reference_static_lifetime() {
+    let c = 66;
+    combine(
+        SomeEnum::SomeVariant(Cell::new(&c)), //~ ERROR
+        SomeEnum::SomeOtherVariant::<Cell<&'static u32>>,
+    );
+}
+
+fn annot_reference_named_lifetime<'a>(_d: &'a u32) {
+    let c = 66;
+    combine(
+        SomeEnum::SomeVariant(Cell::new(&c)), //~ ERROR
+        SomeEnum::SomeOtherVariant::<Cell<&'a u32>>,
+    );
+}
+
+fn annot_reference_named_lifetime_ok<'a>(c: &'a u32) {
+    combine(SomeEnum::SomeVariant(Cell::new(c)), SomeEnum::SomeOtherVariant::<Cell<&'a u32>>);
+}
+
+fn annot_reference_named_lifetime_in_closure<'a>(_: &'a u32) {
+    let _closure = || {
+        let c = 66;
+        combine(
+            SomeEnum::SomeVariant(Cell::new(&c)), //~ ERROR
+            SomeEnum::SomeOtherVariant::<Cell<&'a u32>>,
+        );
+    };
+}
+
+fn annot_reference_named_lifetime_in_closure_ok<'a>(c: &'a u32) {
+    let _closure = || {
+        combine(
+            SomeEnum::SomeVariant(Cell::new(c)),
+            SomeEnum::SomeOtherVariant::<Cell<&'a u32>>,
+        );
+    };
+}
+
+fn main() { }
diff --git a/src/test/ui/nll/user-annotations/adt-nullary-enums.stderr b/src/test/ui/nll/user-annotations/adt-nullary-enums.stderr
new file mode 100644
index 00000000000..fa251f3df17
--- /dev/null
+++ b/src/test/ui/nll/user-annotations/adt-nullary-enums.stderr
@@ -0,0 +1,44 @@
+error[E0597]: `c` does not live long enough
+  --> $DIR/adt-nullary-enums.rs:44:41
+   |
+LL |         SomeEnum::SomeVariant(Cell::new(&c)), //~ ERROR
+   |                                         ^^ borrowed value does not live long enough
+...
+LL | }
+   | - `c` dropped here while still borrowed
+   |
+   = note: borrowed value must be valid for the static lifetime...
+
+error[E0597]: `c` does not live long enough
+  --> $DIR/adt-nullary-enums.rs:52:41
+   |
+LL |         SomeEnum::SomeVariant(Cell::new(&c)), //~ ERROR
+   |                                         ^^ borrowed value does not live long enough
+...
+LL | }
+   | - `c` dropped here while still borrowed
+   |
+note: borrowed value must be valid for the lifetime 'a as defined on the function body at 49:35...
+  --> $DIR/adt-nullary-enums.rs:49:35
+   |
+LL | fn annot_reference_named_lifetime<'a>(_d: &'a u32) {
+   |                                   ^^
+
+error[E0597]: `c` does not live long enough
+  --> $DIR/adt-nullary-enums.rs:65:45
+   |
+LL |             SomeEnum::SomeVariant(Cell::new(&c)), //~ ERROR
+   |                                             ^^ borrowed value does not live long enough
+...
+LL |     };
+   |     - `c` dropped here while still borrowed
+   |
+note: borrowed value must be valid for the lifetime 'a as defined on the function body at 61:46...
+  --> $DIR/adt-nullary-enums.rs:61:46
+   |
+LL | fn annot_reference_named_lifetime_in_closure<'a>(_: &'a u32) {
+   |                                              ^^
+
+error: aborting due to 3 previous errors
+
+For more information about this error, try `rustc --explain E0597`.
diff --git a/src/test/ui/nll/user-annotations/adt-tuple-enums.rs b/src/test/ui/nll/user-annotations/adt-tuple-enums.rs
new file mode 100644
index 00000000000..ae75a54f649
--- /dev/null
+++ b/src/test/ui/nll/user-annotations/adt-tuple-enums.rs
@@ -0,0 +1,64 @@
+// 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.
+
+// Unit test for the "user substitutions" that are annotated on each
+// node.
+
+#![feature(nll)]
+#![allow(warnings)]
+
+enum SomeEnum<T> {
+    SomeVariant(T),
+    SomeOtherVariant,
+}
+
+fn no_annot() {
+    let c = 66;
+    SomeEnum::SomeVariant(&c);
+}
+
+fn annot_underscore() {
+    let c = 66;
+    SomeEnum::SomeVariant::<_>(&c);
+}
+
+fn annot_reference_any_lifetime() {
+    let c = 66;
+    SomeEnum::SomeVariant::<&u32>(&c);
+}
+
+fn annot_reference_static_lifetime() {
+    let c = 66;
+    SomeEnum::SomeVariant::<&'static u32>(&c); //~ ERROR
+}
+
+fn annot_reference_named_lifetime<'a>(_d: &'a u32) {
+    let c = 66;
+    SomeEnum::SomeVariant::<&'a u32>(&c); //~ ERROR
+}
+
+fn annot_reference_named_lifetime_ok<'a>(c: &'a u32) {
+    SomeEnum::SomeVariant::<&'a u32>(c);
+}
+
+fn annot_reference_named_lifetime_in_closure<'a>(_: &'a u32) {
+    let _closure = || {
+        let c = 66;
+        SomeEnum::SomeVariant::<&'a u32>(&c); //~ ERROR
+    };
+}
+
+fn annot_reference_named_lifetime_in_closure_ok<'a>(c: &'a u32) {
+    let _closure = || {
+        SomeEnum::SomeVariant::<&'a u32>(c);
+    };
+}
+
+fn main() { }
diff --git a/src/test/ui/nll/user-annotations/adt-tuple-enums.stderr b/src/test/ui/nll/user-annotations/adt-tuple-enums.stderr
new file mode 100644
index 00000000000..18d1cc7e087
--- /dev/null
+++ b/src/test/ui/nll/user-annotations/adt-tuple-enums.stderr
@@ -0,0 +1,41 @@
+error[E0597]: `c` does not live long enough
+  --> $DIR/adt-tuple-enums.rs:39:43
+   |
+LL |     SomeEnum::SomeVariant::<&'static u32>(&c); //~ ERROR
+   |                                           ^^ borrowed value does not live long enough
+LL | }
+   | - `c` dropped here while still borrowed
+   |
+   = note: borrowed value must be valid for the static lifetime...
+
+error[E0597]: `c` does not live long enough
+  --> $DIR/adt-tuple-enums.rs:44:38
+   |
+LL |     SomeEnum::SomeVariant::<&'a u32>(&c); //~ ERROR
+   |                                      ^^ borrowed value does not live long enough
+LL | }
+   | - `c` dropped here while still borrowed
+   |
+note: borrowed value must be valid for the lifetime 'a as defined on the function body at 42:35...
+  --> $DIR/adt-tuple-enums.rs:42:35
+   |
+LL | fn annot_reference_named_lifetime<'a>(_d: &'a u32) {
+   |                                   ^^
+
+error[E0597]: `c` does not live long enough
+  --> $DIR/adt-tuple-enums.rs:54:42
+   |
+LL |         SomeEnum::SomeVariant::<&'a u32>(&c); //~ ERROR
+   |                                          ^^ borrowed value does not live long enough
+LL |     };
+   |     - `c` dropped here while still borrowed
+   |
+note: borrowed value must be valid for the lifetime 'a as defined on the function body at 51:46...
+  --> $DIR/adt-tuple-enums.rs:51:46
+   |
+LL | fn annot_reference_named_lifetime_in_closure<'a>(_: &'a u32) {
+   |                                              ^^
+
+error: aborting due to 3 previous errors
+
+For more information about this error, try `rustc --explain E0597`.
diff --git a/src/test/ui/nll/user-annotations/adt-tuple-struct.rs b/src/test/ui/nll/user-annotations/adt-tuple-struct.rs
new file mode 100644
index 00000000000..401a71c1fe5
--- /dev/null
+++ b/src/test/ui/nll/user-annotations/adt-tuple-struct.rs
@@ -0,0 +1,60 @@
+// 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.
+
+// Unit test for the "user substitutions" that are annotated on each
+// node.
+
+#![feature(nll)]
+
+struct SomeStruct<T>(T);
+
+fn no_annot() {
+    let c = 66;
+    SomeStruct(&c);
+}
+
+fn annot_underscore() {
+    let c = 66;
+    SomeStruct::<_>(&c);
+}
+
+fn annot_reference_any_lifetime() {
+    let c = 66;
+    SomeStruct::<&u32>(&c);
+}
+
+fn annot_reference_static_lifetime() {
+    let c = 66;
+    SomeStruct::<&'static u32>(&c); //~ ERROR
+}
+
+fn annot_reference_named_lifetime<'a>(_d: &'a u32) {
+    let c = 66;
+    SomeStruct::<&'a u32>(&c); //~ ERROR
+}
+
+fn annot_reference_named_lifetime_ok<'a>(c: &'a u32) {
+    SomeStruct::<&'a u32>(c);
+}
+
+fn annot_reference_named_lifetime_in_closure<'a>(_: &'a u32) {
+    let _closure = || {
+        let c = 66;
+        SomeStruct::<&'a u32>(&c); //~ ERROR
+    };
+}
+
+fn annot_reference_named_lifetime_in_closure_ok<'a>(c: &'a u32) {
+    let _closure = || {
+        SomeStruct::<&'a u32>(c);
+    };
+}
+
+fn main() { }
diff --git a/src/test/ui/nll/user-annotations/adt-tuple-struct.stderr b/src/test/ui/nll/user-annotations/adt-tuple-struct.stderr
new file mode 100644
index 00000000000..397016e52d0
--- /dev/null
+++ b/src/test/ui/nll/user-annotations/adt-tuple-struct.stderr
@@ -0,0 +1,41 @@
+error[E0597]: `c` does not live long enough
+  --> $DIR/adt-tuple-struct.rs:35:32
+   |
+LL |     SomeStruct::<&'static u32>(&c); //~ ERROR
+   |                                ^^ borrowed value does not live long enough
+LL | }
+   | - `c` dropped here while still borrowed
+   |
+   = note: borrowed value must be valid for the static lifetime...
+
+error[E0597]: `c` does not live long enough
+  --> $DIR/adt-tuple-struct.rs:40:27
+   |
+LL |     SomeStruct::<&'a u32>(&c); //~ ERROR
+   |                           ^^ borrowed value does not live long enough
+LL | }
+   | - `c` dropped here while still borrowed
+   |
+note: borrowed value must be valid for the lifetime 'a as defined on the function body at 38:35...
+  --> $DIR/adt-tuple-struct.rs:38:35
+   |
+LL | fn annot_reference_named_lifetime<'a>(_d: &'a u32) {
+   |                                   ^^
+
+error[E0597]: `c` does not live long enough
+  --> $DIR/adt-tuple-struct.rs:50:31
+   |
+LL |         SomeStruct::<&'a u32>(&c); //~ ERROR
+   |                               ^^ borrowed value does not live long enough
+LL |     };
+   |     - `c` dropped here while still borrowed
+   |
+note: borrowed value must be valid for the lifetime 'a as defined on the function body at 47:46...
+  --> $DIR/adt-tuple-struct.rs:47:46
+   |
+LL | fn annot_reference_named_lifetime_in_closure<'a>(_: &'a u32) {
+   |                                              ^^
+
+error: aborting due to 3 previous errors
+
+For more information about this error, try `rustc --explain E0597`.
diff --git a/src/test/ui/nll/user-annotations/dump-adt-brace-struct.rs b/src/test/ui/nll/user-annotations/dump-adt-brace-struct.rs
new file mode 100644
index 00000000000..970fbf98af4
--- /dev/null
+++ b/src/test/ui/nll/user-annotations/dump-adt-brace-struct.rs
@@ -0,0 +1,29 @@
+// 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.
+
+// Unit test for the "user substitutions" that are annotated on each
+// node.
+
+// compile-flags:-Zverbose
+
+#![allow(warnings)]
+#![feature(nll)]
+#![feature(rustc_attrs)]
+
+struct SomeStruct<T> { t: T }
+
+#[rustc_dump_user_substs]
+fn main() {
+    SomeStruct { t: 22 }; // Nothing given, no annotation.
+
+    SomeStruct::<_> { t: 22 }; // Nothing interesting given, no annotation.
+
+    SomeStruct::<u32> { t: 22 }; //~ ERROR [u32]
+}
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
new file mode 100644
index 00000000000..2b0e5039d8d
--- /dev/null
+++ b/src/test/ui/nll/user-annotations/dump-adt-brace-struct.stderr
@@ -0,0 +1,8 @@
+error: user substs: Canonical { variables: [], value: [u32] }
+  --> $DIR/dump-adt-brace-struct.rs:28:5
+   |
+LL |     SomeStruct::<u32> { t: 22 }; //~ ERROR [u32]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to previous error
+
diff --git a/src/test/ui/nll/user-annotations/dump-fn-method.rs b/src/test/ui/nll/user-annotations/dump-fn-method.rs
new file mode 100644
index 00000000000..7f726d13a33
--- /dev/null
+++ b/src/test/ui/nll/user-annotations/dump-fn-method.rs
@@ -0,0 +1,59 @@
+// 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.
+
+// Unit test for the "user substitutions" that are annotated on each
+// node.
+
+// compile-flags:-Zverbose
+
+#![feature(nll)]
+#![feature(rustc_attrs)]
+
+// Note: we reference the names T and U in the comments below.
+trait Bazoom<T> {
+    fn method<U>(&self, arg: T, arg2: U) { }
+}
+
+impl<T, U> Bazoom<U> for T {
+}
+
+fn foo<'a, T>(_: T) { }
+
+#[rustc_dump_user_substs]
+fn main() {
+    // Here: nothing is given, so we don't have any annotation.
+    let x = foo;
+    x(22);
+
+    // Here: `u32` is given.
+    let x = foo::<u32>; //~ ERROR [u32]
+    x(22);
+
+    // Here: we only want the `T` to be given, the rest should be variables.
+    //
+    // (`T` refers to the declaration of `Bazoom`)
+    let x = <_ as Bazoom<u32>>::method::<_>; //~ ERROR [?0, u32, ?1]
+    x(&22, 44, 66);
+
+    // Here: all are given
+    let x = <u8 as Bazoom<u16>>::method::<u32>; //~ ERROR [u8, u16, u32]
+    x(&22, 44, 66);
+
+    // Here: we want in particular that *only* the method `U`
+    // annotation is given, the rest are variables.
+    //
+    // (`U` refers to the declaration of `Bazoom`)
+    let y = 22_u32;
+    y.method::<u32>(44, 66); //~ ERROR [?0, ?1, u32]
+
+    // Here: nothing is given, so we don't have any annotation.
+    let y = 22_u32;
+    y.method(44, 66);
+}
diff --git a/src/test/ui/nll/user-annotations/dump-fn-method.stderr b/src/test/ui/nll/user-annotations/dump-fn-method.stderr
new file mode 100644
index 00000000000..6531f87dd98
--- /dev/null
+++ b/src/test/ui/nll/user-annotations/dump-fn-method.stderr
@@ -0,0 +1,26 @@
+error: user substs: Canonical { variables: [], value: [u32] }
+  --> $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] }
+  --> $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] }
+  --> $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] }
+  --> $DIR/dump-fn-method.rs:54:5
+   |
+LL |     y.method::<u32>(44, 66); //~ ERROR [?0, ?1, u32]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to 4 previous errors
+
diff --git a/src/test/ui/nll/user-annotations/fns.rs b/src/test/ui/nll/user-annotations/fns.rs
new file mode 100644
index 00000000000..4f26d5422b0
--- /dev/null
+++ b/src/test/ui/nll/user-annotations/fns.rs
@@ -0,0 +1,60 @@
+// 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.
+
+// Unit test for the "user substitutions" that are annotated on each
+// node.
+
+#![feature(nll)]
+
+fn some_fn<T>(arg: T) { }
+
+fn no_annot() {
+    let c = 66;
+    some_fn(&c); // OK
+}
+
+fn annot_underscore() {
+    let c = 66;
+    some_fn::<_>(&c); // OK
+}
+
+fn annot_reference_any_lifetime() {
+    let c = 66;
+    some_fn::<&u32>(&c); // OK
+}
+
+fn annot_reference_static_lifetime() {
+    let c = 66;
+    some_fn::<&'static u32>(&c); //~ ERROR
+}
+
+fn annot_reference_named_lifetime<'a>(_d: &'a u32) {
+    let c = 66;
+    some_fn::<&'a u32>(&c); //~ ERROR
+}
+
+fn annot_reference_named_lifetime_ok<'a>(c: &'a u32) {
+    some_fn::<&'a u32>(c);
+}
+
+fn annot_reference_named_lifetime_in_closure<'a>(_: &'a u32) {
+    let _closure = || {
+        let c = 66;
+        some_fn::<&'a u32>(&c); //~ ERROR
+    };
+}
+
+fn annot_reference_named_lifetime_in_closure_ok<'a>(c: &'a u32) {
+    let _closure = || {
+        some_fn::<&'a u32>(c);
+    };
+}
+
+fn main() { }
diff --git a/src/test/ui/nll/user-annotations/fns.stderr b/src/test/ui/nll/user-annotations/fns.stderr
new file mode 100644
index 00000000000..b6ef336567c
--- /dev/null
+++ b/src/test/ui/nll/user-annotations/fns.stderr
@@ -0,0 +1,41 @@
+error[E0597]: `c` does not live long enough
+  --> $DIR/fns.rs:35:29
+   |
+LL |     some_fn::<&'static u32>(&c); //~ ERROR
+   |                             ^^ borrowed value does not live long enough
+LL | }
+   | - `c` dropped here while still borrowed
+   |
+   = note: borrowed value must be valid for the static lifetime...
+
+error[E0597]: `c` does not live long enough
+  --> $DIR/fns.rs:40:24
+   |
+LL |     some_fn::<&'a u32>(&c); //~ ERROR
+   |                        ^^ borrowed value does not live long enough
+LL | }
+   | - `c` dropped here while still borrowed
+   |
+note: borrowed value must be valid for the lifetime 'a as defined on the function body at 38:35...
+  --> $DIR/fns.rs:38:35
+   |
+LL | fn annot_reference_named_lifetime<'a>(_d: &'a u32) {
+   |                                   ^^
+
+error[E0597]: `c` does not live long enough
+  --> $DIR/fns.rs:50:28
+   |
+LL |         some_fn::<&'a u32>(&c); //~ ERROR
+   |                            ^^ borrowed value does not live long enough
+LL |     };
+   |     - `c` dropped here while still borrowed
+   |
+note: borrowed value must be valid for the lifetime 'a as defined on the function body at 47:46...
+  --> $DIR/fns.rs:47:46
+   |
+LL | fn annot_reference_named_lifetime_in_closure<'a>(_: &'a u32) {
+   |                                              ^^
+
+error: aborting due to 3 previous errors
+
+For more information about this error, try `rustc --explain E0597`.
diff --git a/src/test/ui/nll/user-annotations/method-call.rs b/src/test/ui/nll/user-annotations/method-call.rs
new file mode 100644
index 00000000000..9a03679bef0
--- /dev/null
+++ b/src/test/ui/nll/user-annotations/method-call.rs
@@ -0,0 +1,81 @@
+// 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.
+
+// Unit test for the "user substitutions" that are annotated on each
+// node.
+
+#![feature(nll)]
+
+trait Bazoom<T> {
+    fn method<U>(&self, arg: T, arg2: U) { }
+}
+
+impl<T, U> Bazoom<U> for T {
+}
+
+fn no_annot() {
+    let a = 22;
+    let b = 44;
+    let c = 66;
+    a.method(b,  &c); // OK
+}
+
+fn annot_underscore() {
+    let a = 22;
+    let b = 44;
+    let c = 66;
+    a.method::<_>(b,  &c); // OK
+}
+
+fn annot_reference_any_lifetime() {
+    let a = 22;
+    let b = 44;
+    let c = 66;
+    a.method::<&u32>(b,  &c); // OK
+}
+
+fn annot_reference_static_lifetime() {
+    let a = 22;
+    let b = 44;
+    let c = 66;
+    a.method::<&'static u32>(b,  &c); //~ ERROR
+}
+
+fn annot_reference_named_lifetime<'a>(_d: &'a u32) {
+    let a = 22;
+    let b = 44;
+    let c = 66;
+    a.method::<&'a u32>(b,  &c); //~ ERROR
+}
+
+fn annot_reference_named_lifetime_ok<'a>(c: &'a u32) {
+    let a = 22;
+    let b = 44;
+    a.method::<&'a u32>(b,  c);
+}
+
+fn annot_reference_named_lifetime_in_closure<'a>(_: &'a u32) {
+    let a = 22;
+    let b = 44;
+    let _closure = || {
+        let c = 66;
+        a.method::<&'a u32>(b,  &c); //~ ERROR
+    };
+}
+
+fn annot_reference_named_lifetime_in_closure_ok<'a>(c: &'a u32) {
+    let a = 22;
+    let b = 44;
+    let _closure = || {
+        a.method::<&'a u32>(b,  c);
+    };
+}
+
+fn main() { }
diff --git a/src/test/ui/nll/user-annotations/method-call.stderr b/src/test/ui/nll/user-annotations/method-call.stderr
new file mode 100644
index 00000000000..f1c7ff1e0fb
--- /dev/null
+++ b/src/test/ui/nll/user-annotations/method-call.stderr
@@ -0,0 +1,41 @@
+error[E0597]: `c` does not live long enough
+  --> $DIR/method-call.rs:48:34
+   |
+LL |     a.method::<&'static u32>(b,  &c); //~ ERROR
+   |                                  ^^ borrowed value does not live long enough
+LL | }
+   | - `c` dropped here while still borrowed
+   |
+   = note: borrowed value must be valid for the static lifetime...
+
+error[E0597]: `c` does not live long enough
+  --> $DIR/method-call.rs:55:29
+   |
+LL |     a.method::<&'a u32>(b,  &c); //~ ERROR
+   |                             ^^ borrowed value does not live long enough
+LL | }
+   | - `c` dropped here while still borrowed
+   |
+note: borrowed value must be valid for the lifetime 'a as defined on the function body at 51:35...
+  --> $DIR/method-call.rs:51:35
+   |
+LL | fn annot_reference_named_lifetime<'a>(_d: &'a u32) {
+   |                                   ^^
+
+error[E0597]: `c` does not live long enough
+  --> $DIR/method-call.rs:69:33
+   |
+LL |         a.method::<&'a u32>(b,  &c); //~ ERROR
+   |                                 ^^ borrowed value does not live long enough
+LL |     };
+   |     - `c` dropped here while still borrowed
+   |
+note: borrowed value must be valid for the lifetime 'a as defined on the function body at 64:46...
+  --> $DIR/method-call.rs:64:46
+   |
+LL | fn annot_reference_named_lifetime_in_closure<'a>(_: &'a u32) {
+   |                                              ^^
+
+error: aborting due to 3 previous errors
+
+For more information about this error, try `rustc --explain E0597`.
diff --git a/src/test/ui/nll/user-annotations/method-ufcs-1.rs b/src/test/ui/nll/user-annotations/method-ufcs-1.rs
new file mode 100644
index 00000000000..5ac2ba5fa48
--- /dev/null
+++ b/src/test/ui/nll/user-annotations/method-ufcs-1.rs
@@ -0,0 +1,75 @@
+// 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.
+
+// Unit test for the "user substitutions" that are annotated on each
+// node.
+
+#![feature(nll)]
+
+trait Bazoom<T>: Sized {
+    fn method<U>(self, arg: T, arg2: U) { }
+}
+
+impl<T, U> Bazoom<U> for T {
+}
+
+fn annot_underscore() {
+    let a = 22;
+    let b = 44;
+    let c = 66;
+    <_ as Bazoom<_>>::method::<_>(&a, b, c); // OK
+}
+
+fn annot_reference_any_lifetime() {
+    let a = 22;
+    let b = 44;
+    let c = 66;
+    <&u32 as Bazoom<_>>::method(&a, b, c); // OK
+}
+
+fn annot_reference_static_lifetime() {
+    let a = 22;
+    let b = 44;
+    let c = 66;
+    let x = <&'static u32 as Bazoom<_>>::method;
+    x(&a, b, c); //~ ERROR
+}
+
+fn annot_reference_named_lifetime<'a>(_d: &'a u32) {
+    let a = 22;
+    let b = 44;
+    let c = 66;
+    <&'a u32 as Bazoom<_>>::method(&a, b, c); //~ ERROR
+}
+
+fn annot_reference_named_lifetime_ok<'a>(a: &'a u32) {
+    let b = 44;
+    let c = 66;
+    <&'a u32 as Bazoom<_>>::method(&a, b, c);
+}
+
+fn annot_reference_named_lifetime_in_closure<'a>(_: &'a u32) {
+    let a = 22;
+    let b = 44;
+    let _closure = || {
+        let c = 66;
+        <&'a u32 as Bazoom<_>>::method(&a, b, c); //~ ERROR
+    };
+}
+
+fn annot_reference_named_lifetime_in_closure_ok<'a>(a: &'a u32) {
+    let b = 44;
+    let c = 66;
+    let _closure = || {
+        <&'a u32 as Bazoom<_>>::method(&a, b, c);
+    };
+}
+
+fn main() { }
diff --git a/src/test/ui/nll/user-annotations/method-ufcs-1.stderr b/src/test/ui/nll/user-annotations/method-ufcs-1.stderr
new file mode 100644
index 00000000000..f439748ef97
--- /dev/null
+++ b/src/test/ui/nll/user-annotations/method-ufcs-1.stderr
@@ -0,0 +1,45 @@
+error[E0597]: `a` does not live long enough
+  --> $DIR/method-ufcs-1.rs:42:7
+   |
+LL |     x(&a, b, c); //~ ERROR
+   |       ^^ borrowed value does not live long enough
+LL | }
+   | - `a` dropped here while still borrowed
+   |
+   = note: borrowed value must be valid for the static lifetime...
+
+error[E0597]: `a` does not live long enough
+  --> $DIR/method-ufcs-1.rs:49:36
+   |
+LL |     <&'a u32 as Bazoom<_>>::method(&a, b, c); //~ ERROR
+   |                                    ^^ borrowed value does not live long enough
+LL | }
+   | - `a` dropped here while still borrowed
+   |
+note: borrowed value must be valid for the lifetime 'a as defined on the function body at 45:35...
+  --> $DIR/method-ufcs-1.rs:45:35
+   |
+LL | fn annot_reference_named_lifetime<'a>(_d: &'a u32) {
+   |                                   ^^
+
+error[E0597]: `a` does not live long enough
+  --> $DIR/method-ufcs-1.rs:63:41
+   |
+LL |     let _closure = || {
+   |                    -- value captured here
+LL |         let c = 66;
+LL |         <&'a u32 as Bazoom<_>>::method(&a, b, c); //~ ERROR
+   |                                         ^ borrowed value does not live long enough
+LL |     };
+LL | }
+   | - `a` dropped here while still borrowed
+   |
+note: borrowed value must be valid for the lifetime 'a as defined on the function body at 58:46...
+  --> $DIR/method-ufcs-1.rs:58:46
+   |
+LL | fn annot_reference_named_lifetime_in_closure<'a>(_: &'a u32) {
+   |                                              ^^
+
+error: aborting due to 3 previous errors
+
+For more information about this error, try `rustc --explain E0597`.
diff --git a/src/test/ui/nll/user-annotations/method-ufcs-2.rs b/src/test/ui/nll/user-annotations/method-ufcs-2.rs
new file mode 100644
index 00000000000..082cc561ae7
--- /dev/null
+++ b/src/test/ui/nll/user-annotations/method-ufcs-2.rs
@@ -0,0 +1,75 @@
+// 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.
+
+// Unit test for the "user substitutions" that are annotated on each
+// node.
+
+#![feature(nll)]
+
+trait Bazoom<T>: Sized {
+    fn method<U>(self, arg: T, arg2: U) { }
+}
+
+impl<T, U> Bazoom<U> for T {
+}
+
+fn annot_underscore() {
+    let a = 22;
+    let b = 44;
+    let c = 66;
+    <_ as Bazoom<_>>::method(a, &b, c); // OK
+}
+
+fn annot_reference_any_lifetime() {
+    let a = 22;
+    let b = 44;
+    let c = 66;
+    <_ as Bazoom<&u32>>::method(a, &b, c); // OK
+}
+
+fn annot_reference_static_lifetime() {
+    let a = 22;
+    let b = 44;
+    let c = 66;
+    let x = <&'static u32 as Bazoom<_>>::method;
+    x(&a, b, c); //~ ERROR
+}
+
+fn annot_reference_named_lifetime<'a>(_d: &'a u32) {
+    let a = 22;
+    let b = 44;
+    let c = 66;
+    <_ as Bazoom<&'a u32>>::method(a, &b, c); //~ ERROR
+}
+
+fn annot_reference_named_lifetime_ok<'a>(b: &'a u32) {
+    let a = 44;
+    let c = 66;
+    <_ as Bazoom<&'a u32>>::method(a, &b, c);
+}
+
+fn annot_reference_named_lifetime_in_closure<'a>(_: &'a u32) {
+    let a = 22;
+    let b = 44;
+    let _closure = || {
+        let c = 66;
+        <_ as Bazoom<&'a u32>>::method(a, &b, c); //~ ERROR
+    };
+}
+
+fn annot_reference_named_lifetime_in_closure_ok<'a>(b: &'a u32) {
+    let a = 44;
+    let c = 66;
+    let _closure = || {
+        <_ as Bazoom<&'a u32>>::method(a, &b, c);
+    };
+}
+
+fn main() { }
diff --git a/src/test/ui/nll/user-annotations/method-ufcs-2.stderr b/src/test/ui/nll/user-annotations/method-ufcs-2.stderr
new file mode 100644
index 00000000000..dc0f5596590
--- /dev/null
+++ b/src/test/ui/nll/user-annotations/method-ufcs-2.stderr
@@ -0,0 +1,45 @@
+error[E0597]: `a` does not live long enough
+  --> $DIR/method-ufcs-2.rs:42:7
+   |
+LL |     x(&a, b, c); //~ ERROR
+   |       ^^ borrowed value does not live long enough
+LL | }
+   | - `a` dropped here while still borrowed
+   |
+   = note: borrowed value must be valid for the static lifetime...
+
+error[E0597]: `b` does not live long enough
+  --> $DIR/method-ufcs-2.rs:49:39
+   |
+LL |     <_ as Bazoom<&'a u32>>::method(a, &b, c); //~ ERROR
+   |                                       ^^ borrowed value does not live long enough
+LL | }
+   | - `b` dropped here while still borrowed
+   |
+note: borrowed value must be valid for the lifetime 'a as defined on the function body at 45:35...
+  --> $DIR/method-ufcs-2.rs:45:35
+   |
+LL | fn annot_reference_named_lifetime<'a>(_d: &'a u32) {
+   |                                   ^^
+
+error[E0597]: `b` does not live long enough
+  --> $DIR/method-ufcs-2.rs:63:44
+   |
+LL |     let _closure = || {
+   |                    -- value captured here
+LL |         let c = 66;
+LL |         <_ as Bazoom<&'a u32>>::method(a, &b, c); //~ ERROR
+   |                                            ^ borrowed value does not live long enough
+LL |     };
+LL | }
+   | - `b` dropped here while still borrowed
+   |
+note: borrowed value must be valid for the lifetime 'a as defined on the function body at 58:46...
+  --> $DIR/method-ufcs-2.rs:58:46
+   |
+LL | fn annot_reference_named_lifetime_in_closure<'a>(_: &'a u32) {
+   |                                              ^^
+
+error: aborting due to 3 previous errors
+
+For more information about this error, try `rustc --explain E0597`.
diff --git a/src/test/ui/nll/user-annotations/method-ufcs-3.rs b/src/test/ui/nll/user-annotations/method-ufcs-3.rs
new file mode 100644
index 00000000000..f4fdb3ee572
--- /dev/null
+++ b/src/test/ui/nll/user-annotations/method-ufcs-3.rs
@@ -0,0 +1,81 @@
+// 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.
+
+// Unit test for the "user substitutions" that are annotated on each
+// node.
+
+#![feature(nll)]
+
+trait Bazoom<T> {
+    fn method<U>(&self, arg: T, arg2: U) { }
+}
+
+impl<T, U> Bazoom<U> for T {
+}
+
+fn no_annot() {
+    let a = 22;
+    let b = 44;
+    let c = 66;
+    <_ as Bazoom<_>>::method(&a, b, &c); // OK
+}
+
+fn annot_underscore() {
+    let a = 22;
+    let b = 44;
+    let c = 66;
+    <_ as Bazoom<_>>::method::<_>(&a, b, &c); // OK
+}
+
+fn annot_reference_any_lifetime() {
+    let a = 22;
+    let b = 44;
+    let c = 66;
+    <_ as Bazoom<_>>::method::<&u32>(&a, b, &c); // OK
+}
+
+fn annot_reference_static_lifetime() {
+    let a = 22;
+    let b = 44;
+    let c = 66;
+    <_ as Bazoom<_>>::method::<&'static u32>(&a, b, &c); //~ ERROR
+}
+
+fn annot_reference_named_lifetime<'a>(_d: &'a u32) {
+    let a = 22;
+    let b = 44;
+    let c = 66;
+    <_ as Bazoom<_>>::method::<&'a u32>(&a, b, &c); //~ ERROR
+}
+
+fn annot_reference_named_lifetime_ok<'a>(c: &'a u32) {
+    let a = 22;
+    let b = 44;
+    <_ as Bazoom<_>>::method::<&'a u32>(&a, b, c);
+}
+
+fn annot_reference_named_lifetime_in_closure<'a>(_: &'a u32) {
+    let a = 22;
+    let b = 44;
+    let _closure = || {
+        let c = 66;
+        <_ as Bazoom<_>>::method::<&'a u32>(&a, b, &c); //~ ERROR
+    };
+}
+
+fn annot_reference_named_lifetime_in_closure_ok<'a>(c: &'a u32) {
+    let a = 22;
+    let b = 44;
+    let _closure = || {
+        <_ as Bazoom<_>>::method::<&'a u32>(&a, b, c);
+    };
+}
+
+fn main() { }
diff --git a/src/test/ui/nll/user-annotations/method-ufcs-3.stderr b/src/test/ui/nll/user-annotations/method-ufcs-3.stderr
new file mode 100644
index 00000000000..7ddea3eb2c6
--- /dev/null
+++ b/src/test/ui/nll/user-annotations/method-ufcs-3.stderr
@@ -0,0 +1,41 @@
+error[E0597]: `c` does not live long enough
+  --> $DIR/method-ufcs-3.rs:48:53
+   |
+LL |     <_ as Bazoom<_>>::method::<&'static u32>(&a, b, &c); //~ ERROR
+   |                                                     ^^ borrowed value does not live long enough
+LL | }
+   | - `c` dropped here while still borrowed
+   |
+   = note: borrowed value must be valid for the static lifetime...
+
+error[E0597]: `c` does not live long enough
+  --> $DIR/method-ufcs-3.rs:55:48
+   |
+LL |     <_ as Bazoom<_>>::method::<&'a u32>(&a, b, &c); //~ ERROR
+   |                                                ^^ borrowed value does not live long enough
+LL | }
+   | - `c` dropped here while still borrowed
+   |
+note: borrowed value must be valid for the lifetime 'a as defined on the function body at 51:35...
+  --> $DIR/method-ufcs-3.rs:51:35
+   |
+LL | fn annot_reference_named_lifetime<'a>(_d: &'a u32) {
+   |                                   ^^
+
+error[E0597]: `c` does not live long enough
+  --> $DIR/method-ufcs-3.rs:69:52
+   |
+LL |         <_ as Bazoom<_>>::method::<&'a u32>(&a, b, &c); //~ ERROR
+   |                                                    ^^ borrowed value does not live long enough
+LL |     };
+   |     - `c` dropped here while still borrowed
+   |
+note: borrowed value must be valid for the lifetime 'a as defined on the function body at 64:46...
+  --> $DIR/method-ufcs-3.rs:64:46
+   |
+LL | fn annot_reference_named_lifetime_in_closure<'a>(_: &'a u32) {
+   |                                              ^^
+
+error: aborting due to 3 previous errors
+
+For more information about this error, try `rustc --explain E0597`.