about summary refs log tree commit diff
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2018-10-09 10:15:44 +0000
committerbors <bors@rust-lang.org>2018-10-09 10:15:44 +0000
commite1643a8968753226dab7ab3c9fee826f097550f2 (patch)
tree47923832365dfd597748cd44b3ef4e72df319c63
parent607243b6f9b3890b01d5aa4bbea75be728a371be (diff)
parentccba716099c61816734f8daa7459001f6fdea0af (diff)
downloadrust-e1643a8968753226dab7ab3c9fee826f097550f2.tar.gz
rust-e1643a8968753226dab7ab3c9fee826f097550f2.zip
Auto merge of #54757 - nikomatsakis:nll-issue-54573-user-annot, r=pnkfelix
user annotations in patterns

Fixes https://github.com/rust-lang/rust/issues/54573

r? @pnkfelix
-rw-r--r--src/librustc/mir/visit.rs6
-rw-r--r--src/librustc_mir/borrow_check/nll/renumber.rs23
-rw-r--r--src/librustc_mir/build/matches/mod.rs8
-rw-r--r--src/librustc_mir/hair/cx/expr.rs46
-rw-r--r--src/librustc_mir/hair/cx/mod.rs11
-rw-r--r--src/librustc_mir/hair/mod.rs2
-rw-r--r--src/librustc_mir/hair/pattern/mod.rs47
-rw-r--r--src/librustc_mir/hair/util.rs56
-rw-r--r--src/librustc_typeck/astconv.rs43
-rw-r--r--src/librustc_typeck/check/mod.rs30
-rw-r--r--src/test/ui/nll/user-annotations/pattern_substs_on_brace_enum_variant.rs24
-rw-r--r--src/test/ui/nll/user-annotations/pattern_substs_on_brace_enum_variant.stderr25
-rw-r--r--src/test/ui/nll/user-annotations/pattern_substs_on_brace_struct.rs22
-rw-r--r--src/test/ui/nll/user-annotations/pattern_substs_on_brace_struct.stderr25
-rw-r--r--src/test/ui/nll/user-annotations/pattern_substs_on_tuple_enum_variant.rs24
-rw-r--r--src/test/ui/nll/user-annotations/pattern_substs_on_tuple_enum_variant.stderr25
-rw-r--r--src/test/ui/nll/user-annotations/pattern_substs_on_tuple_struct.rs22
-rw-r--r--src/test/ui/nll/user-annotations/pattern_substs_on_tuple_struct.stderr25
18 files changed, 387 insertions, 77 deletions
diff --git a/src/librustc/mir/visit.rs b/src/librustc/mir/visit.rs
index 7d8227053b3..d2b0a6a37a7 100644
--- a/src/librustc/mir/visit.rs
+++ b/src/librustc/mir/visit.rs
@@ -214,7 +214,7 @@ macro_rules! make_mir_visitor {
                 self.super_ty(ty);
             }
 
-            fn visit_canonical_ty(&mut self, ty: & $($mutability)* CanonicalTy<'tcx>) {
+            fn visit_user_ty(&mut self, ty: & $($mutability)* CanonicalTy<'tcx>) {
                 self.super_canonical_ty(ty);
             }
 
@@ -640,7 +640,7 @@ macro_rules! make_mir_visitor {
                                      c_ty: & $($mutability)* CanonicalTy<'tcx>,
                                      location: Location) {
                 self.visit_place(place, PlaceContext::Validate, location);
-                self.visit_canonical_ty(c_ty);
+                self.visit_user_ty(c_ty);
             }
 
             fn super_place(&mut self,
@@ -736,7 +736,7 @@ macro_rules! make_mir_visitor {
                     source_info: *source_info,
                 });
                 if let Some(user_ty) = user_ty {
-                    self.visit_canonical_ty(user_ty);
+                    self.visit_user_ty(user_ty);
                 }
                 self.visit_source_info(source_info);
                 self.visit_source_scope(visibility_scope);
diff --git a/src/librustc_mir/borrow_check/nll/renumber.rs b/src/librustc_mir/borrow_check/nll/renumber.rs
index d77863d598f..15a60badc93 100644
--- a/src/librustc_mir/borrow_check/nll/renumber.rs
+++ b/src/librustc_mir/borrow_check/nll/renumber.rs
@@ -10,7 +10,7 @@
 
 use rustc::ty::subst::Substs;
 use rustc::ty::{self, CanonicalTy, ClosureSubsts, GeneratorSubsts, Ty, TypeFoldable};
-use rustc::mir::{BasicBlock, Location, Mir, Place, Statement, StatementKind};
+use rustc::mir::{BasicBlock, Location, Mir, Statement, StatementKind};
 use rustc::mir::visit::{MutVisitor, TyContext};
 use rustc::infer::{InferCtxt, NLLRegionVariableOrigin};
 
@@ -65,6 +65,14 @@ impl<'a, 'gcx, 'tcx> MutVisitor<'tcx> for NLLVisitor<'a, 'gcx, 'tcx> {
         debug!("visit_ty: ty={:?}", ty);
     }
 
+    fn visit_user_ty(&mut self, _ty: &mut CanonicalTy<'tcx>) {
+        // `user_ty` annotations represent the types that the user
+        // wrote in the progarm. We don't want to erase the regions
+        // from these types: rather, we want to add them as
+        // constraints at type-check time.
+        debug!("visit_user_ty: skipping renumber");
+    }
+
     fn visit_substs(&mut self, substs: &mut &'tcx Substs<'tcx>, location: Location) {
         debug!("visit_substs(substs={:?}, location={:?})", substs, location);
 
@@ -112,19 +120,6 @@ impl<'a, 'gcx, 'tcx> MutVisitor<'tcx> for NLLVisitor<'a, 'gcx, 'tcx> {
         debug!("visit_closure_substs: substs={:?}", substs);
     }
 
-    fn visit_ascribe_user_ty(
-        &mut self,
-        _place: &mut Place<'tcx>,
-        _variance: &mut ty::Variance,
-        _c_ty: &mut CanonicalTy<'tcx>,
-        _location: Location,
-    ) {
-        // User-assert-ty statements represent types that the user added explicitly.
-        // We don't want to erase the regions from these types: rather, we want to
-        // add them as constraints at type-check time.
-        debug!("visit_user_assert_ty: skipping renumber");
-    }
-
     fn visit_statement(
         &mut self,
         block: BasicBlock,
diff --git a/src/librustc_mir/build/matches/mod.rs b/src/librustc_mir/build/matches/mod.rs
index 656c78a46ed..c2a7172d54c 100644
--- a/src/librustc_mir/build/matches/mod.rs
+++ b/src/librustc_mir/build/matches/mod.rs
@@ -1307,6 +1307,14 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
     ) {
         for ascription in ascriptions {
             let source_info = self.source_info(ascription.span);
+
+            debug!(
+                "adding user ascription at span {:?} of place {:?} and {:?}",
+                source_info.span,
+                ascription.source,
+                ascription.user_ty,
+            );
+
             self.cfg.push(
                 block,
                 Statement {
diff --git a/src/librustc_mir/hair/cx/expr.rs b/src/librustc_mir/hair/cx/expr.rs
index 8d50fbbdc6b..c969a3ef348 100644
--- a/src/librustc_mir/hair/cx/expr.rs
+++ b/src/librustc_mir/hair/cx/expr.rs
@@ -13,6 +13,7 @@ use rustc_data_structures::indexed_vec::Idx;
 use hair::cx::Cx;
 use hair::cx::block;
 use hair::cx::to_ref::ToRef;
+use hair::util::UserAnnotatedTyHelpers;
 use rustc::hir::def::{Def, CtorKind};
 use rustc::mir::interpret::GlobalId;
 use rustc::ty::{self, AdtKind, Ty};
@@ -475,7 +476,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),
+                                user_ty: cx.user_substs_applied_to_adt(expr.hir_id, adt),
                                 fields: field_refs(cx, fields),
                                 base: base.as_ref().map(|base| {
                                     FruInfo {
@@ -501,7 +502,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),
+                                        user_ty: cx.user_substs_applied_to_adt(expr.hir_id, adt),
                                         fields: field_refs(cx, fields),
                                         base: None,
                                     }
@@ -787,48 +788,17 @@ fn user_annotated_ty_for_def(
         // 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),
-            },
+            cx.user_substs_applied_to_ty_of_hir_id(hir_id),
 
         // `Self` is used in expression as a tuple struct constructor or an unit struct constructor
-        Def::SelfCtor(_) => {
-            let sty = &cx.tables().node_id_to_type(hir_id).sty;
-            match sty {
-                ty::FnDef(ref def_id, _) => {
-                    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_id, user_substs)
-                    }))
-                }
-                ty::Adt(ref adt_def, _) => {
-                    user_annotated_ty_for_adt(cx, hir_id, adt_def)
-                }
-                _ => {
-                    bug!("unexpected sty: {:?}", sty)
-                }
-            }
-        }
+        Def::SelfCtor(_) =>
+            cx.user_substs_applied_to_ty_of_hir_id(hir_id),
+
         _ =>
             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,
@@ -943,7 +913,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),
+                        user_ty: cx.user_substs_applied_to_adt(expr.hir_id, adt_def),
                         fields: vec![],
                         base: None,
                     }
diff --git a/src/librustc_mir/hair/cx/mod.rs b/src/librustc_mir/hair/cx/mod.rs
index 4d4a89fca8b..5f798135966 100644
--- a/src/librustc_mir/hair/cx/mod.rs
+++ b/src/librustc_mir/hair/cx/mod.rs
@@ -15,6 +15,7 @@
 //!
 
 use hair::*;
+use hair::util::UserAnnotatedTyHelpers;
 
 use rustc_data_structures::indexed_vec::Idx;
 use rustc::hir::def_id::{DefId, LOCAL_CRATE};
@@ -272,6 +273,16 @@ impl<'a, 'gcx, 'tcx> Cx<'a, 'gcx, 'tcx> {
     }
 }
 
+impl UserAnnotatedTyHelpers<'gcx, 'tcx> for Cx<'_, 'gcx, 'tcx> {
+    fn tcx(&self) -> TyCtxt<'_, 'gcx, 'tcx> {
+        self.tcx()
+    }
+
+    fn tables(&self) -> &ty::TypeckTables<'tcx> {
+        self.tables()
+    }
+}
+
 fn lint_level_for_hir_id(tcx: TyCtxt, mut id: ast::NodeId) -> ast::NodeId {
     // Right now we insert a `with_ignore` node in the dep graph here to
     // ignore the fact that `lint_levels` below depends on the entire crate.
diff --git a/src/librustc_mir/hair/mod.rs b/src/librustc_mir/hair/mod.rs
index eb73a202148..e4f88e4fcc3 100644
--- a/src/librustc_mir/hair/mod.rs
+++ b/src/librustc_mir/hair/mod.rs
@@ -29,6 +29,8 @@ pub mod cx;
 pub mod pattern;
 pub use self::pattern::{BindingMode, Pattern, PatternKind, FieldPattern};
 
+mod util;
+
 #[derive(Copy, Clone, Debug)]
 pub enum LintLevel {
     Inherited,
diff --git a/src/librustc_mir/hair/pattern/mod.rs b/src/librustc_mir/hair/pattern/mod.rs
index b22cc4a1a42..04090e5087f 100644
--- a/src/librustc_mir/hair/pattern/mod.rs
+++ b/src/librustc_mir/hair/pattern/mod.rs
@@ -18,6 +18,8 @@ pub(crate) use self::check_match::check_match;
 
 use const_eval::{const_field, const_variant_index};
 
+use hair::util::UserAnnotatedTyHelpers;
+
 use rustc::mir::{fmt_const_val, Field, BorrowKind, Mutability};
 use rustc::mir::interpret::{Scalar, GlobalId, ConstValue, sign_extend};
 use rustc::ty::{self, CanonicalTy, TyCtxt, AdtDef, Ty, Region};
@@ -529,8 +531,9 @@ impl<'a, 'tcx> PatternContext<'a, 'tcx> {
                                        field: Field::new(i),
                                        pattern: self.lower_pattern(field),
                                    })
-                                   .collect();
-                self.lower_variant_or_leaf(def, pat.span, ty, subpatterns)
+                    .collect();
+
+                self.lower_variant_or_leaf(def, pat.hir_id, pat.span, ty, subpatterns)
             }
 
             PatKind::Struct(ref qpath, ref fields, _) => {
@@ -546,7 +549,7 @@ impl<'a, 'tcx> PatternContext<'a, 'tcx> {
                           })
                           .collect();
 
-                self.lower_variant_or_leaf(def, pat.span, ty, subpatterns)
+                self.lower_variant_or_leaf(def, pat.hir_id, pat.span, ty, subpatterns)
             }
         };
 
@@ -637,12 +640,12 @@ impl<'a, 'tcx> PatternContext<'a, 'tcx> {
     fn lower_variant_or_leaf(
         &mut self,
         def: Def,
+        hir_id: hir::HirId,
         span: Span,
         ty: Ty<'tcx>,
-        subpatterns: Vec<FieldPattern<'tcx>>)
-        -> PatternKind<'tcx>
-    {
-        match def {
+        subpatterns: Vec<FieldPattern<'tcx>>,
+    ) -> PatternKind<'tcx> {
+        let mut kind = match def {
             Def::Variant(variant_id) | Def::VariantCtor(variant_id, ..) => {
                 let enum_id = self.tcx.parent_def_id(variant_id).unwrap();
                 let adt_def = self.tcx.adt_def(enum_id);
@@ -675,7 +678,24 @@ impl<'a, 'tcx> PatternContext<'a, 'tcx> {
                 self.errors.push(PatternError::NonConstPath(span));
                 PatternKind::Wild
             }
+        };
+
+        if let Some(user_ty) = self.user_substs_applied_to_ty_of_hir_id(hir_id) {
+            let subpattern = Pattern {
+                span,
+                ty,
+                kind: Box::new(kind),
+            };
+
+            debug!("pattern user_ty = {:?} for pattern at {:?}", user_ty, span);
+
+            kind = PatternKind::AscribeUserType {
+                subpattern,
+                user_ty,
+            };
         }
+
+        kind
     }
 
     /// Takes a HIR Path. If the path is a constant, evaluates it and feeds
@@ -729,7 +749,7 @@ impl<'a, 'tcx> PatternContext<'a, 'tcx> {
                     },
                 }
             }
-            _ => self.lower_variant_or_leaf(def, span, ty, vec![]),
+            _ => self.lower_variant_or_leaf(def, id, span, ty, vec![]),
         };
 
         Pattern {
@@ -894,6 +914,17 @@ impl<'a, 'tcx> PatternContext<'a, 'tcx> {
     }
 }
 
+impl UserAnnotatedTyHelpers<'tcx, 'tcx> for PatternContext<'_, 'tcx> {
+    fn tcx(&self) -> TyCtxt<'_, 'tcx, 'tcx> {
+        self.tcx
+    }
+
+    fn tables(&self) -> &ty::TypeckTables<'tcx> {
+        self.tables
+    }
+}
+
+
 pub trait PatternFoldable<'tcx> : Sized {
     fn fold_with<F: PatternFolder<'tcx>>(&self, folder: &mut F) -> Self {
         self.super_fold_with(folder)
diff --git a/src/librustc_mir/hair/util.rs b/src/librustc_mir/hair/util.rs
new file mode 100644
index 00000000000..48a2e67a3dc
--- /dev/null
+++ b/src/librustc_mir/hair/util.rs
@@ -0,0 +1,56 @@
+// Copyright 2016 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.
+
+use rustc::hir;
+use rustc::ty::{self, AdtDef, CanonicalTy, TyCtxt};
+
+crate trait UserAnnotatedTyHelpers<'gcx: 'tcx, 'tcx> {
+    fn tcx(&self) -> TyCtxt<'_, 'gcx, 'tcx>;
+
+    fn tables(&self) -> &ty::TypeckTables<'tcx>;
+
+    fn user_substs_applied_to_adt(
+        &self,
+        hir_id: hir::HirId,
+        adt_def: &'tcx AdtDef,
+    ) -> Option<CanonicalTy<'tcx>> {
+        let user_substs = self.tables().user_substs(hir_id)?;
+        Some(user_substs.unchecked_map(|user_substs| {
+            // Here, we just pair an `AdtDef` with the
+            // `user_substs`, so no new types etc are introduced.
+            self.tcx().mk_adt(adt_def, user_substs)
+        }))
+    }
+
+    /// Looks up the type associated with this hir-id and applies the
+    /// user-given substitutions; the hir-id must map to a suitable
+    /// type.
+    fn user_substs_applied_to_ty_of_hir_id(&self, hir_id: hir::HirId) -> Option<CanonicalTy<'tcx>> {
+        let user_substs = self.tables().user_substs(hir_id)?;
+        match &self.tables().node_id_to_type(hir_id).sty {
+            ty::Adt(adt_def, _) => Some(user_substs.unchecked_map(|user_substs| {
+                // Ok to call `unchecked_map` because we just pair an
+                // `AdtDef` with the `user_substs`, so no new types
+                // etc are introduced.
+                self.tcx().mk_adt(adt_def, user_substs)
+            })),
+            ty::FnDef(def_id, _) => Some(user_substs.unchecked_map(|user_substs| {
+                // Here, we just pair a `DefId` with the
+                // `user_substs`, so no new types etc are introduced.
+                self.tcx().mk_fn_def(*def_id, user_substs)
+            })),
+            sty => bug!(
+                "sty: {:?} should not have user-substs {:?} recorded ",
+                sty,
+                user_substs
+            ),
+        }
+    }
+}
diff --git a/src/librustc_typeck/astconv.rs b/src/librustc_typeck/astconv.rs
index 28d2ae413de..e4ad02595d1 100644
--- a/src/librustc_typeck/astconv.rs
+++ b/src/librustc_typeck/astconv.rs
@@ -402,21 +402,44 @@ impl<'o, 'gcx: 'tcx, 'tcx> dyn AstConv<'gcx, 'tcx>+'o {
     }
 
     /// Creates the relevant generic argument substitutions
-    /// corresponding to a set of generic parameters.
-    pub fn create_substs_for_generic_args<'a, 'b, A, P, I>(
+    /// corresponding to a set of generic parameters. This is a
+    /// rather complex little function. Let me try to explain the
+    /// role of each of its parameters:
+    ///
+    /// To start, we are given the `def_id` of the thing we are
+    /// creating the substitutions for, and a partial set of
+    /// substitutions `parent_substs`. In general, the substitutions
+    /// for an item begin with substitutions for all the "parents" of
+    /// that item -- so e.g. for a method it might include the
+    /// parameters from the impl.
+    ///
+    /// Therefore, the method begins by walking down these parents,
+    /// starting with the outermost parent and proceed inwards until
+    /// it reaches `def_id`. For each parent P, it will check `parent_substs`
+    /// first to see if the parent's substitutions are listed in there. If so,
+    /// we can append those and move on. Otherwise, it invokes the
+    /// three callback functions:
+    ///
+    /// - `args_for_def_id`: given the def-id P, supplies back the
+    ///   generic arguments that were given to that parent from within
+    ///   the path; so e.g. if you have `<T as Foo>::Bar`, the def-id
+    ///   might refer to the trait `Foo`, and the arguments might be
+    ///   `[T]`. The boolean value indicates whether to infer values
+    ///   for arguments whose values were not explicitly provided.
+    /// - `provided_kind`: given the generic parameter and the value from `args_for_def_id`,
+    ///   instantiate a `Kind`
+    /// - `inferred_kind`: if no parameter was provided, and inference is enabled, then
+    ///   creates a suitable inference variable.
+    pub fn create_substs_for_generic_args<'a, 'b>(
         tcx: TyCtxt<'a, 'gcx, 'tcx>,
         def_id: DefId,
         parent_substs: &[Kind<'tcx>],
         has_self: bool,
         self_ty: Option<Ty<'tcx>>,
-        args_for_def_id: A,
-        provided_kind: P,
-        inferred_kind: I,
-    ) -> &'tcx Substs<'tcx> where
-        A: Fn(DefId) -> (Option<&'b GenericArgs>, bool),
-        P: Fn(&GenericParamDef, &GenericArg) -> Kind<'tcx>,
-        I: Fn(Option<&[Kind<'tcx>]>, &GenericParamDef, bool) -> Kind<'tcx>
-    {
+        args_for_def_id: impl Fn(DefId) -> (Option<&'b GenericArgs>, bool),
+        provided_kind: impl Fn(&GenericParamDef, &GenericArg) -> Kind<'tcx>,
+        inferred_kind: impl Fn(Option<&[Kind<'tcx>]>, &GenericParamDef, bool) -> Kind<'tcx>,
+    ) -> &'tcx Substs<'tcx> {
         // Collect the segments of the path: we need to substitute arguments
         // for parameters throughout the entire path (wherever there are
         // generic parameters).
diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs
index 529f1e6161b..be8b16dd2f5 100644
--- a/src/librustc_typeck/check/mod.rs
+++ b/src/librustc_typeck/check/mod.rs
@@ -2164,6 +2164,13 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
     /// 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>) {
+        debug!(
+            "write_user_substs_from_substs({:?}, {:?}) in fcx {}",
+            hir_id,
+            substs,
+            self.tag(),
+        );
+
         if !substs.is_noop() {
             let user_substs = self.infcx.canonicalize_response(&substs);
             debug!("instantiate_value_path: user_substs = {:?}", user_substs);
@@ -3752,6 +3759,13 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
         expected: Expectation<'tcx>,
         needs: Needs
     ) -> Ty<'tcx> {
+        debug!(
+            "check_expr_kind(expr={:?}, expected={:?}, needs={:?})",
+            expr,
+            expected,
+            needs,
+        );
+
         let tcx = self.tcx;
         let id = expr.id;
         match expr.node {
@@ -4981,10 +4995,13 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                                   span: Span,
                                   node_id: ast::NodeId)
                                   -> (Ty<'tcx>, Def) {
-        debug!("instantiate_value_path(path={:?}, def={:?}, node_id={})",
-               segments,
-               def,
-               node_id);
+        debug!(
+            "instantiate_value_path(segments={:?}, self_ty={:?}, def={:?}, node_id={})",
+            segments,
+            self_ty,
+            def,
+            node_id,
+        );
 
         let path_segs = self.def_ids_for_path_segments(segments, def);
 
@@ -5194,6 +5211,11 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
         let hir_id = self.tcx.hir.node_to_hir_id(node_id);
         self.write_substs(hir_id, substs);
 
+        debug!(
+            "instantiate_value_path: id={:?} substs={:?}",
+            node_id,
+            substs,
+        );
         self.write_user_substs_from_substs(hir_id, substs);
 
         (ty_substituted, new_def)
diff --git a/src/test/ui/nll/user-annotations/pattern_substs_on_brace_enum_variant.rs b/src/test/ui/nll/user-annotations/pattern_substs_on_brace_enum_variant.rs
new file mode 100644
index 00000000000..526134b6e4b
--- /dev/null
+++ b/src/test/ui/nll/user-annotations/pattern_substs_on_brace_enum_variant.rs
@@ -0,0 +1,24 @@
+#![feature(nll)]
+
+enum Foo<'a> {
+    Bar { field: &'a u32 }
+}
+
+fn in_let() {
+    let y = 22;
+    let foo = Foo::Bar { field: &y };
+    //~^ ERROR `y` does not live long enough
+    let Foo::Bar::<'static> { field: _z } = foo;
+}
+
+fn in_match() {
+    let y = 22;
+    let foo = Foo::Bar { field: &y };
+    //~^ ERROR `y` does not live long enough
+    match foo {
+        Foo::Bar::<'static> { field: _z } => {
+        }
+    }
+}
+
+fn main() { }
diff --git a/src/test/ui/nll/user-annotations/pattern_substs_on_brace_enum_variant.stderr b/src/test/ui/nll/user-annotations/pattern_substs_on_brace_enum_variant.stderr
new file mode 100644
index 00000000000..5dbbf7c5b48
--- /dev/null
+++ b/src/test/ui/nll/user-annotations/pattern_substs_on_brace_enum_variant.stderr
@@ -0,0 +1,25 @@
+error[E0597]: `y` does not live long enough
+  --> $DIR/pattern_substs_on_brace_enum_variant.rs:9:33
+   |
+LL |     let foo = Foo::Bar { field: &y };
+   |                                 ^^ borrowed value does not live long enough
+...
+LL | }
+   | - `y` dropped here while still borrowed
+   |
+   = note: borrowed value must be valid for the static lifetime...
+
+error[E0597]: `y` does not live long enough
+  --> $DIR/pattern_substs_on_brace_enum_variant.rs:16:33
+   |
+LL |     let foo = Foo::Bar { field: &y };
+   |                                 ^^ borrowed value does not live long enough
+...
+LL | }
+   | - `y` dropped here while still borrowed
+   |
+   = note: borrowed value must be valid for the static lifetime...
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0597`.
diff --git a/src/test/ui/nll/user-annotations/pattern_substs_on_brace_struct.rs b/src/test/ui/nll/user-annotations/pattern_substs_on_brace_struct.rs
new file mode 100644
index 00000000000..1c92858eb3a
--- /dev/null
+++ b/src/test/ui/nll/user-annotations/pattern_substs_on_brace_struct.rs
@@ -0,0 +1,22 @@
+#![feature(nll)]
+
+struct Foo<'a> { field: &'a u32 }
+
+fn in_let() {
+    let y = 22;
+    let foo = Foo { field: &y };
+    //~^ ERROR `y` does not live long enough
+    let Foo::<'static> { field: _z } = foo;
+}
+
+fn in_main() {
+    let y = 22;
+    let foo = Foo { field: &y };
+    //~^ ERROR `y` does not live long enough
+    match foo {
+        Foo::<'static> { field: _z } => {
+        }
+    }
+}
+
+fn main() { }
diff --git a/src/test/ui/nll/user-annotations/pattern_substs_on_brace_struct.stderr b/src/test/ui/nll/user-annotations/pattern_substs_on_brace_struct.stderr
new file mode 100644
index 00000000000..0108a185b1f
--- /dev/null
+++ b/src/test/ui/nll/user-annotations/pattern_substs_on_brace_struct.stderr
@@ -0,0 +1,25 @@
+error[E0597]: `y` does not live long enough
+  --> $DIR/pattern_substs_on_brace_struct.rs:7:28
+   |
+LL |     let foo = Foo { field: &y };
+   |                            ^^ borrowed value does not live long enough
+...
+LL | }
+   | - `y` dropped here while still borrowed
+   |
+   = note: borrowed value must be valid for the static lifetime...
+
+error[E0597]: `y` does not live long enough
+  --> $DIR/pattern_substs_on_brace_struct.rs:14:28
+   |
+LL |     let foo = Foo { field: &y };
+   |                            ^^ borrowed value does not live long enough
+...
+LL | }
+   | - `y` dropped here while still borrowed
+   |
+   = note: borrowed value must be valid for the static lifetime...
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0597`.
diff --git a/src/test/ui/nll/user-annotations/pattern_substs_on_tuple_enum_variant.rs b/src/test/ui/nll/user-annotations/pattern_substs_on_tuple_enum_variant.rs
new file mode 100644
index 00000000000..d6c364f8e3f
--- /dev/null
+++ b/src/test/ui/nll/user-annotations/pattern_substs_on_tuple_enum_variant.rs
@@ -0,0 +1,24 @@
+#![feature(nll)]
+
+enum Foo<'a> {
+    Bar(&'a u32)
+}
+
+fn in_let() {
+    let y = 22;
+    let foo = Foo::Bar(&y);
+    //~^ ERROR `y` does not live long enough
+    let Foo::Bar::<'static>(_z) = foo;
+}
+
+fn in_match() {
+    let y = 22;
+    let foo = Foo::Bar(&y);
+    //~^ ERROR `y` does not live long enough
+    match foo {
+        Foo::Bar::<'static>(_z) => {
+        }
+    }
+}
+
+fn main() { }
diff --git a/src/test/ui/nll/user-annotations/pattern_substs_on_tuple_enum_variant.stderr b/src/test/ui/nll/user-annotations/pattern_substs_on_tuple_enum_variant.stderr
new file mode 100644
index 00000000000..b18fdc30ac2
--- /dev/null
+++ b/src/test/ui/nll/user-annotations/pattern_substs_on_tuple_enum_variant.stderr
@@ -0,0 +1,25 @@
+error[E0597]: `y` does not live long enough
+  --> $DIR/pattern_substs_on_tuple_enum_variant.rs:9:24
+   |
+LL |     let foo = Foo::Bar(&y);
+   |                        ^^ borrowed value does not live long enough
+...
+LL | }
+   | - `y` dropped here while still borrowed
+   |
+   = note: borrowed value must be valid for the static lifetime...
+
+error[E0597]: `y` does not live long enough
+  --> $DIR/pattern_substs_on_tuple_enum_variant.rs:16:24
+   |
+LL |     let foo = Foo::Bar(&y);
+   |                        ^^ borrowed value does not live long enough
+...
+LL | }
+   | - `y` dropped here while still borrowed
+   |
+   = note: borrowed value must be valid for the static lifetime...
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0597`.
diff --git a/src/test/ui/nll/user-annotations/pattern_substs_on_tuple_struct.rs b/src/test/ui/nll/user-annotations/pattern_substs_on_tuple_struct.rs
new file mode 100644
index 00000000000..626ca908797
--- /dev/null
+++ b/src/test/ui/nll/user-annotations/pattern_substs_on_tuple_struct.rs
@@ -0,0 +1,22 @@
+#![feature(nll)]
+
+struct Foo<'a>(&'a u32);
+
+fn in_let() {
+    let y = 22;
+    let foo = Foo(&y);
+    //~^ ERROR `y` does not live long enough
+    let Foo::<'static>(_z) = foo;
+}
+
+fn in_match() {
+    let y = 22;
+    let foo = Foo(&y);
+    //~^ ERROR `y` does not live long enough
+    match foo {
+        Foo::<'static>(_z) => {
+        }
+    }
+}
+
+fn main() { }
diff --git a/src/test/ui/nll/user-annotations/pattern_substs_on_tuple_struct.stderr b/src/test/ui/nll/user-annotations/pattern_substs_on_tuple_struct.stderr
new file mode 100644
index 00000000000..b72fda95580
--- /dev/null
+++ b/src/test/ui/nll/user-annotations/pattern_substs_on_tuple_struct.stderr
@@ -0,0 +1,25 @@
+error[E0597]: `y` does not live long enough
+  --> $DIR/pattern_substs_on_tuple_struct.rs:7:19
+   |
+LL |     let foo = Foo(&y);
+   |                   ^^ borrowed value does not live long enough
+...
+LL | }
+   | - `y` dropped here while still borrowed
+   |
+   = note: borrowed value must be valid for the static lifetime...
+
+error[E0597]: `y` does not live long enough
+  --> $DIR/pattern_substs_on_tuple_struct.rs:14:19
+   |
+LL |     let foo = Foo(&y);
+   |                   ^^ borrowed value does not live long enough
+...
+LL | }
+   | - `y` dropped here while still borrowed
+   |
+   = note: borrowed value must be valid for the static lifetime...
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0597`.