about summary refs log tree commit diff
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2018-03-24 02:08:22 +0000
committerbors <bors@rust-lang.org>2018-03-24 02:08:22 +0000
commitab0ef145ac993d01a73c1c4a5decb1f68b3aad36 (patch)
treec8fd55cdca02993e94e4b255c2d0b8e2d1bffce6
parent4be5d360cd8a9338d1408b3998874313240db395 (diff)
parent4161ae747740e9d61426d26da3e9f3f74fbabaca (diff)
downloadrust-ab0ef145ac993d01a73c1c4a5decb1f68b3aad36.tar.gz
rust-ab0ef145ac993d01a73c1c4a5decb1f68b3aad36.zip
Auto merge of #48482 - davidtwco:issue-47184, r=nikomatsakis
NLL should identify and respect the lifetime annotations that the user wrote

Part of #47184.

r? @nikomatsakis
-rw-r--r--src/librustc/ich/impls_mir.rs4
-rw-r--r--src/librustc/infer/canonical.rs29
-rw-r--r--src/librustc/mir/mod.rs22
-rw-r--r--src/librustc/mir/visit.rs20
-rw-r--r--src/librustc/session/config.rs2
-rw-r--r--src/librustc/ty/codec.rs23
-rw-r--r--src/librustc/ty/context.rs40
-rw-r--r--src/librustc/ty/mod.rs12
-rw-r--r--src/librustc_mir/borrow_check/mod.rs8
-rw-r--r--src/librustc_mir/borrow_check/nll/constraint_generation.rs7
-rw-r--r--src/librustc_mir/borrow_check/nll/renumber.rs12
-rw-r--r--src/librustc_mir/borrow_check/nll/type_check/mod.rs16
-rw-r--r--src/librustc_mir/borrow_check/nll/universal_regions.rs6
-rw-r--r--src/librustc_mir/build/block.rs12
-rw-r--r--src/librustc_mir/build/matches/mod.rs23
-rw-r--r--src/librustc_mir/dataflow/impls/borrows.rs1
-rw-r--r--src/librustc_mir/dataflow/move_paths/builder.rs1
-rw-r--r--src/librustc_mir/hair/cx/block.rs2
-rw-r--r--src/librustc_mir/hair/mod.rs7
-rw-r--r--src/librustc_mir/interpret/step.rs2
-rw-r--r--src/librustc_mir/transform/check_unsafety.rs1
-rw-r--r--src/librustc_mir/transform/cleanup_post_borrowck.rs (renamed from src/librustc_mir/transform/clean_end_regions.rs)49
-rw-r--r--src/librustc_mir/transform/mod.rs6
-rw-r--r--src/librustc_mir/transform/qualify_consts.rs1
-rw-r--r--src/librustc_mir/transform/remove_noop_landing_pads.rs1
-rw-r--r--src/librustc_mir/transform/rustc_peek.rs1
-rw-r--r--src/librustc_passes/mir_stats.rs1
-rw-r--r--src/librustc_trans/mir/statement.rs1
-rw-r--r--src/librustc_typeck/check/mod.rs13
-rw-r--r--src/librustc_typeck/check/writeback.rs28
-rw-r--r--src/test/incremental/hashes/let_expressions.rs2
-rw-r--r--src/test/mir-opt/basic_assignment.rs3
-rw-r--r--src/test/mir-opt/nll/reborrow-basic.rs4
-rw-r--r--src/test/run-pass/generator/yield-subtype.rs1
-rw-r--r--src/test/ui/issue-47184.rs16
-rw-r--r--src/test/ui/issue-47184.stderr14
36 files changed, 358 insertions, 33 deletions
diff --git a/src/librustc/ich/impls_mir.rs b/src/librustc/ich/impls_mir.rs
index 1e6dadae363..c73f171806e 100644
--- a/src/librustc/ich/impls_mir.rs
+++ b/src/librustc/ich/impls_mir.rs
@@ -277,6 +277,10 @@ for mir::StatementKind<'gcx> {
                 op.hash_stable(hcx, hasher);
                 places.hash_stable(hcx, hasher);
             }
+            mir::StatementKind::UserAssertTy(ref c_ty, ref local) => {
+                c_ty.hash_stable(hcx, hasher);
+                local.hash_stable(hcx, hasher);
+            }
             mir::StatementKind::Nop => {}
             mir::StatementKind::InlineAsm { ref asm, ref outputs, ref inputs } => {
                 asm.hash_stable(hcx, hasher);
diff --git a/src/librustc/infer/canonical.rs b/src/librustc/infer/canonical.rs
index 22526c7751d..debddd708ea 100644
--- a/src/librustc/infer/canonical.rs
+++ b/src/librustc/infer/canonical.rs
@@ -33,6 +33,7 @@
 
 use infer::{InferCtxt, InferOk, InferResult, RegionVariableOrigin, TypeVariableOrigin};
 use rustc_data_structures::indexed_vec::Idx;
+use serialize::UseSpecializedDecodable;
 use std::fmt::Debug;
 use std::ops::Index;
 use syntax::codemap::Span;
@@ -49,7 +50,7 @@ use rustc_data_structures::fx::FxHashMap;
 /// A "canonicalized" type `V` is one where all free inference
 /// variables have been rewriten to "canonical vars". These are
 /// numbered starting from 0 in order of first appearance.
-#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
+#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, RustcDecodable, RustcEncodable)]
 pub struct Canonical<'gcx, V> {
     pub variables: CanonicalVarInfos<'gcx>,
     pub value: V,
@@ -57,6 +58,8 @@ pub struct Canonical<'gcx, V> {
 
 pub type CanonicalVarInfos<'gcx> = &'gcx Slice<CanonicalVarInfo>;
 
+impl<'gcx> UseSpecializedDecodable for CanonicalVarInfos<'gcx> { }
+
 /// A set of values corresponding to the canonical variables from some
 /// `Canonical`. You can give these values to
 /// `canonical_value.substitute` to substitute them into the canonical
@@ -69,7 +72,7 @@ pub type CanonicalVarInfos<'gcx> = &'gcx Slice<CanonicalVarInfo>;
 /// You can also use `infcx.fresh_inference_vars_for_canonical_vars`
 /// to get back a `CanonicalVarValues` containing fresh inference
 /// variables.
-#[derive(Clone, Debug, PartialEq, Eq, Hash)]
+#[derive(Clone, Debug, PartialEq, Eq, Hash, RustcDecodable, RustcEncodable)]
 pub struct CanonicalVarValues<'tcx> {
     pub var_values: IndexVec<CanonicalVar, Kind<'tcx>>,
 }
@@ -78,7 +81,7 @@ pub struct CanonicalVarValues<'tcx> {
 /// canonical value. This is sufficient information for code to create
 /// a copy of the canonical value in some other inference context,
 /// with fresh inference variables replacing the canonical values.
-#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
+#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, RustcDecodable, RustcEncodable)]
 pub struct CanonicalVarInfo {
     pub kind: CanonicalVarKind,
 }
@@ -86,7 +89,7 @@ pub struct CanonicalVarInfo {
 /// Describes the "kind" of the canonical variable. This is a "kind"
 /// in the type-theory sense of the term -- i.e., a "meta" type system
 /// that analyzes type-like values.
-#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
+#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, RustcDecodable, RustcEncodable)]
 pub enum CanonicalVarKind {
     /// Some kind of type inference variable.
     Ty(CanonicalTyVarKind),
@@ -100,7 +103,7 @@ pub enum CanonicalVarKind {
 /// 22.) can only be instantiated with integral/float types (e.g.,
 /// usize or f32). In order to faithfully reproduce a type, we need to
 /// know what set of types a given type variable can be unified with.
-#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
+#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, RustcDecodable, RustcEncodable)]
 pub enum CanonicalTyVarKind {
     /// General type variable `?T` that can be unified with arbitrary types.
     General,
@@ -855,11 +858,14 @@ impl<'cx, 'gcx, 'tcx> TypeFolder<'gcx, 'tcx> for CanonicalVarValuesSubst<'cx, 'g
 }
 
 CloneTypeFoldableAndLiftImpls! {
+    ::infer::canonical::Certainty,
+    ::infer::canonical::CanonicalVarInfo,
+    ::infer::canonical::CanonicalVarKind,
+}
+
+CloneTypeFoldableImpls! {
     for <'tcx> {
-        ::infer::canonical::Certainty,
-        ::infer::canonical::CanonicalVarInfo,
         ::infer::canonical::CanonicalVarInfos<'tcx>,
-        ::infer::canonical::CanonicalVarKind,
     }
 }
 
@@ -870,6 +876,13 @@ BraceStructTypeFoldableImpl! {
     } where C: TypeFoldable<'tcx>
 }
 
+BraceStructLiftImpl! {
+    impl<'a, 'tcx, T> Lift<'tcx> for Canonical<'a, T> {
+        type Lifted = Canonical<'tcx, T::Lifted>;
+        variables, value
+    } where T: Lift<'tcx>
+}
+
 impl<'tcx> CanonicalVarValues<'tcx> {
     fn iter<'a>(&'a self) -> impl Iterator<Item = Kind<'tcx>> + 'a {
         self.var_values.iter().cloned()
diff --git a/src/librustc/mir/mod.rs b/src/librustc/mir/mod.rs
index 64a1729982a..9ed4e6a8e00 100644
--- a/src/librustc/mir/mod.rs
+++ b/src/librustc/mir/mod.rs
@@ -27,7 +27,7 @@ use hir::def_id::DefId;
 use mir::visit::MirVisitable;
 use mir::interpret::{Value, PrimVal};
 use ty::subst::{Subst, Substs};
-use ty::{self, AdtDef, ClosureSubsts, Region, Ty, TyCtxt, GeneratorInterior};
+use ty::{self, AdtDef, CanonicalTy, ClosureSubsts, Region, Ty, TyCtxt, GeneratorInterior};
 use ty::fold::{TypeFoldable, TypeFolder, TypeVisitor};
 use ty::TypeAndMut;
 use util::ppaux;
@@ -1253,6 +1253,23 @@ pub enum StatementKind<'tcx> {
     /// (The starting point(s) arise implicitly from borrows.)
     EndRegion(region::Scope),
 
+    /// Encodes a user's type assertion. These need to be preserved intact so that NLL can respect
+    /// them. For example:
+    ///
+    ///     let (a, b): (T, U) = y;
+    ///
+    /// Here we would insert a `UserAssertTy<(T, U)>(y)` instruction to check that the type of `y`
+    /// is the right thing.
+    ///
+    /// `CanonicalTy` is used to capture "inference variables" from the user's types. For example:
+    ///
+    ///     let x: Vec<_> = ...;
+    ///     let y: &u32 = ...;
+    ///
+    /// would result in `Vec<?0>` and `&'?0 u32` respectively (where `?0` is a canonicalized
+    /// variable).
+    UserAssertTy(CanonicalTy<'tcx>, Local),
+
     /// No-op. Useful for deleting instructions without affecting statement indices.
     Nop,
 }
@@ -1324,6 +1341,8 @@ impl<'tcx> Debug for Statement<'tcx> {
             InlineAsm { ref asm, ref outputs, ref inputs } => {
                 write!(fmt, "asm!({:?} : {:?} : {:?})", asm, outputs, inputs)
             },
+            UserAssertTy(ref c_ty, ref local) => write!(fmt, "UserAssertTy({:?}, {:?})",
+                                                        c_ty, local),
             Nop => write!(fmt, "nop"),
         }
     }
@@ -2184,6 +2203,7 @@ EnumTypeFoldableImpl! {
         (StatementKind::InlineAsm) { asm, outputs, inputs },
         (StatementKind::Validate)(a, b),
         (StatementKind::EndRegion)(a),
+        (StatementKind::UserAssertTy)(a, b),
         (StatementKind::Nop),
     }
 }
diff --git a/src/librustc/mir/visit.rs b/src/librustc/mir/visit.rs
index 650af8dc4d9..a3fdb6f73ab 100644
--- a/src/librustc/mir/visit.rs
+++ b/src/librustc/mir/visit.rs
@@ -10,7 +10,7 @@
 
 use hir::def_id::DefId;
 use ty::subst::Substs;
-use ty::{ClosureSubsts, Region, Ty, GeneratorInterior};
+use ty::{CanonicalTy, ClosureSubsts, Region, Ty, GeneratorInterior};
 use mir::*;
 use syntax_pos::Span;
 
@@ -144,6 +144,13 @@ macro_rules! make_mir_visitor {
                 self.super_operand(operand, location);
             }
 
+            fn visit_user_assert_ty(&mut self,
+                                    c_ty: & $($mutability)* CanonicalTy<'tcx>,
+                                    local: & $($mutability)* Local,
+                                    location: Location) {
+                self.super_user_assert_ty(c_ty, local, location);
+            }
+
             fn visit_place(&mut self,
                             place: & $($mutability)* Place<'tcx>,
                             context: PlaceContext<'tcx>,
@@ -376,6 +383,10 @@ macro_rules! make_mir_visitor {
                             self.visit_operand(input, location);
                         }
                     }
+                    StatementKind::UserAssertTy(ref $($mutability)* c_ty,
+                                                ref $($mutability)* local) => {
+                        self.visit_user_assert_ty(c_ty, local, location);
+                    }
                     StatementKind::Nop => {}
                 }
             }
@@ -619,6 +630,13 @@ macro_rules! make_mir_visitor {
                 }
             }
 
+            fn super_user_assert_ty(&mut self,
+                                    _c_ty: & $($mutability)* CanonicalTy<'tcx>,
+                                    local: & $($mutability)* Local,
+                                    location: Location) {
+                self.visit_local(local, PlaceContext::Validate, location);
+            }
+
             fn super_place(&mut self,
                             place: & $($mutability)* Place<'tcx>,
                             context: PlaceContext<'tcx>,
diff --git a/src/librustc/session/config.rs b/src/librustc/session/config.rs
index 4ba634f8b25..d24da1ff7c8 100644
--- a/src/librustc/session/config.rs
+++ b/src/librustc/session/config.rs
@@ -1251,6 +1251,8 @@ options! {DebuggingOptions, DebuggingSetter, basic_debugging_options,
         "choose which RELRO level to use"),
     nll: bool = (false, parse_bool, [UNTRACKED],
                  "run the non-lexical lifetimes MIR pass"),
+    disable_nll_user_type_assert: bool = (false, parse_bool, [UNTRACKED],
+        "disable user provided type assertion in NLL"),
     trans_time_graph: bool = (false, parse_bool, [UNTRACKED],
         "generate a graphical HTML report of time spent in trans and LLVM"),
     thinlto: Option<bool> = (None, parse_opt_bool, [TRACKED],
diff --git a/src/librustc/ty/codec.rs b/src/librustc/ty/codec.rs
index f98bc953560..4e15f0711a5 100644
--- a/src/librustc/ty/codec.rs
+++ b/src/librustc/ty/codec.rs
@@ -17,6 +17,7 @@
 // persisting to incr. comp. caches.
 
 use hir::def_id::{DefId, CrateNum};
+use infer::canonical::{CanonicalVarInfo, CanonicalVarInfos};
 use rustc_data_structures::fx::FxHashMap;
 use rustc_serialize::{Decodable, Decoder, Encoder, Encodable, opaque};
 use std::hash::Hash;
@@ -240,6 +241,19 @@ pub fn decode_existential_predicate_slice<'a, 'tcx, D>(decoder: &mut D)
 }
 
 #[inline]
+pub fn decode_canonical_var_infos<'a, 'tcx, D>(decoder: &mut D)
+    -> Result<CanonicalVarInfos<'tcx>, D::Error>
+    where D: TyDecoder<'a, 'tcx>,
+          'tcx: 'a,
+{
+    let len = decoder.read_usize()?;
+    let interned: Result<Vec<CanonicalVarInfo>, _> = (0..len).map(|_| Decodable::decode(decoder))
+                                                             .collect();
+    Ok(decoder.tcx()
+              .intern_canonical_var_infos(interned?.as_slice()))
+}
+
+#[inline]
 pub fn decode_const<'a, 'tcx, D>(decoder: &mut D)
                                  -> Result<&'tcx ty::Const<'tcx>, D::Error>
     where D: TyDecoder<'a, 'tcx>,
@@ -262,6 +276,7 @@ macro_rules! implement_ty_decoder {
     ($DecoderName:ident <$($typaram:tt),*>) => {
         mod __ty_decoder_impl {
             use super::$DecoderName;
+            use $crate::infer::canonical::CanonicalVarInfos;
             use $crate::ty;
             use $crate::ty::codec::*;
             use $crate::ty::subst::Substs;
@@ -364,6 +379,14 @@ macro_rules! implement_ty_decoder {
                 }
             }
 
+            impl<$($typaram),*> SpecializedDecoder<CanonicalVarInfos<'tcx>>
+                for $DecoderName<$($typaram),*> {
+                fn specialized_decode(&mut self)
+                    -> Result<CanonicalVarInfos<'tcx>, Self::Error> {
+                    decode_canonical_var_infos(self)
+                }
+            }
+
             impl<$($typaram),*> SpecializedDecoder<&'tcx $crate::ty::Const<'tcx>>
             for $DecoderName<$($typaram),*> {
                 fn specialized_decode(&mut self) -> Result<&'tcx ty::Const<'tcx>, Self::Error> {
diff --git a/src/librustc/ty/context.rs b/src/librustc/ty/context.rs
index 966c96e594f..460593d9cb4 100644
--- a/src/librustc/ty/context.rs
+++ b/src/librustc/ty/context.rs
@@ -48,6 +48,7 @@ use ty::layout::{LayoutDetails, TargetDataLayout};
 use ty::maps;
 use ty::steal::Steal;
 use ty::BindingMode;
+use ty::CanonicalTy;
 use util::nodemap::{NodeMap, DefIdSet, ItemLocalMap};
 use util::nodemap::{FxHashMap, FxHashSet};
 use rustc_data_structures::accumulate_vec::AccumulateVec;
@@ -344,6 +345,10 @@ pub struct TypeckTables<'tcx> {
     /// method calls, including those of overloaded operators.
     type_dependent_defs: ItemLocalMap<Def>,
 
+    /// Stores the canonicalized types provided by the user. See also `UserAssertTy` statement in
+    /// MIR.
+    user_provided_tys: ItemLocalMap<CanonicalTy<'tcx>>,
+
     /// Stores the types for various nodes in the AST.  Note that this table
     /// is not guaranteed to be populated until after typeck.  See
     /// typeck::check::fn_ctxt for details.
@@ -420,6 +425,7 @@ impl<'tcx> TypeckTables<'tcx> {
         TypeckTables {
             local_id_root,
             type_dependent_defs: ItemLocalMap(),
+            user_provided_tys: ItemLocalMap(),
             node_types: ItemLocalMap(),
             node_substs: ItemLocalMap(),
             adjustments: ItemLocalMap(),
@@ -461,6 +467,20 @@ impl<'tcx> TypeckTables<'tcx> {
         }
     }
 
+    pub fn user_provided_tys(&self) -> LocalTableInContext<CanonicalTy<'tcx>> {
+        LocalTableInContext {
+            local_id_root: self.local_id_root,
+            data: &self.user_provided_tys
+        }
+    }
+
+    pub fn user_provided_tys_mut(&mut self) -> LocalTableInContextMut<CanonicalTy<'tcx>> {
+        LocalTableInContextMut {
+            local_id_root: self.local_id_root,
+            data: &mut self.user_provided_tys
+        }
+    }
+
     pub fn node_types(&self) -> LocalTableInContext<Ty<'tcx>> {
         LocalTableInContext {
             local_id_root: self.local_id_root,
@@ -685,6 +705,7 @@ impl<'a, 'gcx> HashStable<StableHashingContext<'a>> for TypeckTables<'gcx> {
         let ty::TypeckTables {
             local_id_root,
             ref type_dependent_defs,
+            ref user_provided_tys,
             ref node_types,
             ref node_substs,
             ref adjustments,
@@ -704,6 +725,7 @@ impl<'a, 'gcx> HashStable<StableHashingContext<'a>> for TypeckTables<'gcx> {
 
         hcx.with_node_id_hashing_mode(NodeIdHashingMode::HashDefPath, |hcx| {
             type_dependent_defs.hash_stable(hcx, hasher);
+            user_provided_tys.hash_stable(hcx, hasher);
             node_types.hash_stable(hcx, hasher);
             node_substs.hash_stable(hcx, hasher);
             adjustments.hash_stable(hcx, hasher);
@@ -1637,6 +1659,24 @@ impl<'a, 'tcx> Lift<'tcx> for &'a Slice<Predicate<'a>> {
     }
 }
 
+impl<'a, 'tcx> Lift<'tcx> for &'a Slice<CanonicalVarInfo> {
+    type Lifted = &'tcx Slice<CanonicalVarInfo>;
+    fn lift_to_tcx<'b, 'gcx>(&self, tcx: TyCtxt<'b, 'gcx, 'tcx>) -> Option<Self::Lifted> {
+        if self.len() == 0 {
+            return Some(Slice::empty());
+        }
+        if tcx.interners.arena.in_arena(*self as *const _) {
+            return Some(unsafe { mem::transmute(*self) });
+        }
+        // Also try in the global tcx if we're not that.
+        if !tcx.is_global() {
+            self.lift_to_tcx(tcx.global_tcx())
+        } else {
+            None
+        }
+    }
+}
+
 pub mod tls {
     use super::{CtxtInterners, GlobalCtxt, TyCtxt};
 
diff --git a/src/librustc/ty/mod.rs b/src/librustc/ty/mod.rs
index 643155ef778..e1925d964b3 100644
--- a/src/librustc/ty/mod.rs
+++ b/src/librustc/ty/mod.rs
@@ -21,6 +21,7 @@ use hir::map::DefPathData;
 use hir::svh::Svh;
 use ich::Fingerprint;
 use ich::StableHashingContext;
+use infer::canonical::{Canonical, Canonicalize};
 use middle::const_val::ConstVal;
 use middle::lang_items::{FnTraitLangItem, FnMutTraitLangItem, FnOnceTraitLangItem};
 use middle::privacy::AccessLevels;
@@ -554,6 +555,17 @@ pub type Ty<'tcx> = &'tcx TyS<'tcx>;
 impl<'tcx> serialize::UseSpecializedEncodable for Ty<'tcx> {}
 impl<'tcx> serialize::UseSpecializedDecodable for Ty<'tcx> {}
 
+pub type CanonicalTy<'gcx> = Canonical<'gcx, Ty<'gcx>>;
+
+impl <'gcx: 'tcx, 'tcx> Canonicalize<'gcx, 'tcx> for Ty<'tcx> {
+    type Canonicalized = CanonicalTy<'gcx>;
+
+    fn intern(_gcx: TyCtxt<'_, 'gcx, 'gcx>,
+              value: Canonical<'gcx, Self::Lifted>) -> Self::Canonicalized {
+        value
+    }
+}
+
 /// A wrapper for slices with the additional invariant
 /// that the slice is interned and no other slice with
 /// the same contents can exist in the same context.
diff --git a/src/librustc_mir/borrow_check/mod.rs b/src/librustc_mir/borrow_check/mod.rs
index 6e1a798910d..305df37466d 100644
--- a/src/librustc_mir/borrow_check/mod.rs
+++ b/src/librustc_mir/borrow_check/mod.rs
@@ -392,11 +392,13 @@ impl<'cx, 'gcx, 'tcx> DataflowResultsConsumer<'cx, 'tcx> for MirBorrowckCtxt<'cx
                 // ignored when consuming results (update to
                 // flow_state already handled).
             }
-            StatementKind::Nop | StatementKind::Validate(..) | StatementKind::StorageLive(..) => {
-                // `Nop`, `Validate`, and `StorageLive` are irrelevant
+            StatementKind::Nop |
+            StatementKind::UserAssertTy(..) |
+            StatementKind::Validate(..) |
+            StatementKind::StorageLive(..) => {
+                // `Nop`, `UserAssertTy`, `Validate`, and `StorageLive` are irrelevant
                 // to borrow check.
             }
-
             StatementKind::StorageDead(local) => {
                 self.access_place(
                     ContextKind::StorageDead.new(location),
diff --git a/src/librustc_mir/borrow_check/nll/constraint_generation.rs b/src/librustc_mir/borrow_check/nll/constraint_generation.rs
index 3a39eb5c908..afaedecdf0a 100644
--- a/src/librustc_mir/borrow_check/nll/constraint_generation.rs
+++ b/src/librustc_mir/borrow_check/nll/constraint_generation.rs
@@ -12,10 +12,10 @@ use rustc::hir;
 use rustc::mir::{BasicBlock, BasicBlockData, Location, Place, Mir, Rvalue};
 use rustc::mir::visit::Visitor;
 use rustc::mir::Place::Projection;
-use rustc::mir::{PlaceProjection, ProjectionElem};
+use rustc::mir::{Local, PlaceProjection, ProjectionElem};
 use rustc::mir::visit::TyContext;
 use rustc::infer::InferCtxt;
-use rustc::ty::{self, ClosureSubsts};
+use rustc::ty::{self, CanonicalTy, ClosureSubsts};
 use rustc::ty::subst::Substs;
 use rustc::ty::fold::TypeFoldable;
 
@@ -106,6 +106,9 @@ impl<'cg, 'cx, 'gcx, 'tcx> Visitor<'tcx> for ConstraintGeneration<'cg, 'cx, 'gcx
 
         self.super_rvalue(rvalue, location);
     }
+
+    fn visit_user_assert_ty(&mut self, _c_ty: &CanonicalTy<'tcx>,
+                            _local: &Local, _location: Location) { }
 }
 
 impl<'cx, 'cg, 'gcx, 'tcx> ConstraintGeneration<'cx, 'cg, 'gcx, 'tcx> {
diff --git a/src/librustc_mir/borrow_check/nll/renumber.rs b/src/librustc_mir/borrow_check/nll/renumber.rs
index c54acda8a62..04c206b5c0c 100644
--- a/src/librustc_mir/borrow_check/nll/renumber.rs
+++ b/src/librustc_mir/borrow_check/nll/renumber.rs
@@ -9,8 +9,8 @@
 // except according to those terms.
 
 use rustc::ty::subst::Substs;
-use rustc::ty::{self, ClosureSubsts, GeneratorInterior, Ty, TypeFoldable};
-use rustc::mir::{BasicBlock, Location, Mir, Statement, StatementKind};
+use rustc::ty::{self, CanonicalTy, ClosureSubsts, GeneratorInterior, Ty, TypeFoldable};
+use rustc::mir::{BasicBlock, Local, Location, Mir, Statement, StatementKind};
 use rustc::mir::visit::{MutVisitor, TyContext};
 use rustc::infer::{InferCtxt, NLLRegionVariableOrigin};
 
@@ -118,6 +118,14 @@ impl<'a, 'gcx, 'tcx> MutVisitor<'tcx> for NLLVisitor<'a, 'gcx, 'tcx> {
         debug!("visit_closure_substs: substs={:?}", substs);
     }
 
+    fn visit_user_assert_ty(&mut self, _c_ty: &mut CanonicalTy<'tcx>, _local: &mut Local,
+                            _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/borrow_check/nll/type_check/mod.rs b/src/librustc_mir/borrow_check/nll/type_check/mod.rs
index 022831b5a92..80a439b1830 100644
--- a/src/librustc_mir/borrow_check/nll/type_check/mod.rs
+++ b/src/librustc_mir/borrow_check/nll/type_check/mod.rs
@@ -761,6 +761,22 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> {
                     );
                 };
             }
+            StatementKind::UserAssertTy(ref c_ty, ref local) => {
+                let local_ty = mir.local_decls()[*local].ty;
+                let (ty, _) = self.infcx.instantiate_canonical_with_fresh_inference_vars(
+                    stmt.source_info.span, c_ty);
+                debug!("check_stmt: user_assert_ty ty={:?} local_ty={:?}", ty, local_ty);
+                if let Err(terr) = self.eq_types(ty, local_ty, location.at_self()) {
+                    span_mirbug!(
+                        self,
+                        stmt,
+                        "bad type assert ({:?} = {:?}): {:?}",
+                        ty,
+                        local_ty,
+                        terr
+                    );
+                }
+            }
             StatementKind::StorageLive(_)
             | StatementKind::StorageDead(_)
             | StatementKind::InlineAsm { .. }
diff --git a/src/librustc_mir/borrow_check/nll/universal_regions.rs b/src/librustc_mir/borrow_check/nll/universal_regions.rs
index afd33858139..39dc29ba18b 100644
--- a/src/librustc_mir/borrow_check/nll/universal_regions.rs
+++ b/src/librustc_mir/borrow_check/nll/universal_regions.rs
@@ -777,6 +777,11 @@ impl<'cx, 'gcx, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'cx, 'gcx, 'tcx> {
     where
         T: TypeFoldable<'tcx>,
     {
+        debug!(
+            "replace_bound_regions_with_nll_infer_vars(value={:?}, all_outlive_scope={:?})",
+            value,
+            all_outlive_scope,
+        );
         let (value, _map) = self.tcx.replace_late_bound_regions(value, |br| {
             let liberated_region = self.tcx.mk_region(ty::ReFree(ty::FreeRegion {
                 scope: all_outlive_scope,
@@ -784,6 +789,7 @@ impl<'cx, 'gcx, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'cx, 'gcx, 'tcx> {
             }));
             let region_vid = self.next_nll_region_var(origin);
             indices.insert_late_bound_region(liberated_region, region_vid.to_region_vid());
+            debug!("liberated_region={:?} => {:?}", liberated_region, region_vid);
             region_vid
         });
         value
diff --git a/src/librustc_mir/build/block.rs b/src/librustc_mir/build/block.rs
index 7281fb59663..94702927d26 100644
--- a/src/librustc_mir/build/block.rs
+++ b/src/librustc_mir/build/block.rs
@@ -102,6 +102,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
                     remainder_scope,
                     init_scope,
                     pattern,
+                    ty,
                     initializer,
                     lint_level
                 } => {
@@ -120,10 +121,19 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
                             opt_destruction_scope.map(|de|(de, source_info)), block, |this| {
                                 let scope = (init_scope, source_info);
                                 this.in_scope(scope, lint_level, block, |this| {
-                                    this.expr_into_pattern(block, pattern, init)
+                                    this.expr_into_pattern(block, ty, pattern, init)
                                 })
                             }));
                     } else {
+                        // FIXME(#47184): We currently only insert `UserAssertTy` statements for
+                        // patterns that are bindings, this is as we do not want to deconstruct
+                        // the type being assertion to match the pattern.
+                        if let PatternKind::Binding { var, .. } = *pattern.kind {
+                            if let Some(ty) = ty {
+                                this.user_assert_ty(block, ty, var, span);
+                            }
+                        }
+
                         this.visit_bindings(&pattern, &mut |this, _, _, node, span, _| {
                             this.storage_live_binding(block, node, span);
                             this.schedule_drop_for_binding(node, span);
diff --git a/src/librustc_mir/build/matches/mod.rs b/src/librustc_mir/build/matches/mod.rs
index 229e33dcd78..7eb52a3cdee 100644
--- a/src/librustc_mir/build/matches/mod.rs
+++ b/src/librustc_mir/build/matches/mod.rs
@@ -145,8 +145,26 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
         end_block.unit()
     }
 
+    pub fn user_assert_ty(&mut self, block: BasicBlock, hir_id: hir::HirId,
+                          var: NodeId, span: Span) {
+        if self.hir.tcx().sess.opts.debugging_opts.disable_nll_user_type_assert { return; }
+
+        let local_id = self.var_indices[&var];
+        let source_info = self.source_info(span);
+
+        debug!("user_assert_ty: local_id={:?}", hir_id.local_id);
+        if let Some(c_ty) = self.hir.tables.user_provided_tys().get(hir_id) {
+            debug!("user_assert_ty: c_ty={:?}", c_ty);
+            self.cfg.push(block, Statement {
+                source_info,
+                kind: StatementKind::UserAssertTy(*c_ty, local_id),
+            });
+        }
+    }
+
     pub fn expr_into_pattern(&mut self,
                              mut block: BasicBlock,
+                             ty: Option<hir::HirId>,
                              irrefutable_pat: Pattern<'tcx>,
                              initializer: ExprRef<'tcx>)
                              -> BlockAnd<()> {
@@ -156,6 +174,11 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
                                    var,
                                    subpattern: None, .. } => {
                 let place = self.storage_live_binding(block, var, irrefutable_pat.span);
+
+                if let Some(ty) = ty {
+                    self.user_assert_ty(block, ty, var, irrefutable_pat.span);
+                }
+
                 unpack!(block = self.into(&place, block, initializer));
                 self.schedule_drop_for_binding(var, irrefutable_pat.span);
                 block.unit()
diff --git a/src/librustc_mir/dataflow/impls/borrows.rs b/src/librustc_mir/dataflow/impls/borrows.rs
index 499ed55fad4..fb3042014df 100644
--- a/src/librustc_mir/dataflow/impls/borrows.rs
+++ b/src/librustc_mir/dataflow/impls/borrows.rs
@@ -678,6 +678,7 @@ impl<'a, 'gcx, 'tcx> BitDenotation for Borrows<'a, 'gcx, 'tcx> {
             mir::StatementKind::SetDiscriminant { .. } |
             mir::StatementKind::StorageLive(..) |
             mir::StatementKind::Validate(..) |
+            mir::StatementKind::UserAssertTy(..) |
             mir::StatementKind::Nop => {}
 
         }
diff --git a/src/librustc_mir/dataflow/move_paths/builder.rs b/src/librustc_mir/dataflow/move_paths/builder.rs
index d6f419f6cfb..cbf4c822769 100644
--- a/src/librustc_mir/dataflow/move_paths/builder.rs
+++ b/src/librustc_mir/dataflow/move_paths/builder.rs
@@ -298,6 +298,7 @@ impl<'b, 'a, 'gcx, 'tcx> Gatherer<'b, 'a, 'gcx, 'tcx> {
             }
             StatementKind::EndRegion(_) |
             StatementKind::Validate(..) |
+            StatementKind::UserAssertTy(..) |
             StatementKind::Nop => {}
         }
     }
diff --git a/src/librustc_mir/hair/cx/block.rs b/src/librustc_mir/hair/cx/block.rs
index 6f6258f52f7..14aa307f0ae 100644
--- a/src/librustc_mir/hair/cx/block.rs
+++ b/src/librustc_mir/hair/cx/block.rs
@@ -76,12 +76,14 @@ fn mirror_stmts<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>,
                             first_statement_index: region::FirstStatementIndex::new(index),
                         });
 
+                        let ty = local.ty.clone().map(|ty| ty.hir_id);
                         let pattern = cx.pattern_from_hir(&local.pat);
                         result.push(StmtRef::Mirror(Box::new(Stmt {
                             kind: StmtKind::Let {
                                 remainder_scope: remainder_scope,
                                 init_scope: region::Scope::Node(hir_id.local_id),
                                 pattern,
+                                ty,
                                 initializer: local.init.to_ref(),
                                 lint_level: cx.lint_level_of(local.id),
                             },
diff --git a/src/librustc_mir/hair/mod.rs b/src/librustc_mir/hair/mod.rs
index 5f60a134fb1..fe82b8158f7 100644
--- a/src/librustc_mir/hair/mod.rs
+++ b/src/librustc_mir/hair/mod.rs
@@ -93,10 +93,13 @@ pub enum StmtKind<'tcx> {
         /// lifetime of temporaries
         init_scope: region::Scope,
 
-        /// let <PAT> = ...
+        /// let <PAT>: ty = ...
         pattern: Pattern<'tcx>,
 
-        /// let pat = <INIT> ...
+        /// let pat: <TY> = init ...
+        ty: Option<hir::HirId>,
+
+        /// let pat: ty = <INIT> ...
         initializer: Option<ExprRef<'tcx>>,
 
         /// the lint level for this let-statement
diff --git a/src/librustc_mir/interpret/step.rs b/src/librustc_mir/interpret/step.rs
index 4e1750caf26..f1d58ff5e88 100644
--- a/src/librustc_mir/interpret/step.rs
+++ b/src/librustc_mir/interpret/step.rs
@@ -89,6 +89,8 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> {
                 M::end_region(self, Some(ce))?;
             }
 
+            UserAssertTy(..) => {}
+
             // Defined to do nothing. These are added by optimization passes, to avoid changing the
             // size of MIR constantly.
             Nop => {}
diff --git a/src/librustc_mir/transform/check_unsafety.rs b/src/librustc_mir/transform/check_unsafety.rs
index 86d08dec2b9..02c70399664 100644
--- a/src/librustc_mir/transform/check_unsafety.rs
+++ b/src/librustc_mir/transform/check_unsafety.rs
@@ -105,6 +105,7 @@ impl<'a, 'tcx> Visitor<'tcx> for UnsafetyChecker<'a, 'tcx> {
             StatementKind::StorageDead(..) |
             StatementKind::EndRegion(..) |
             StatementKind::Validate(..) |
+            StatementKind::UserAssertTy(..) |
             StatementKind::Nop => {
                 // safe (at least as emitted during MIR construction)
             }
diff --git a/src/librustc_mir/transform/clean_end_regions.rs b/src/librustc_mir/transform/cleanup_post_borrowck.rs
index 6e8985d99d2..256b1fd66e9 100644
--- a/src/librustc_mir/transform/clean_end_regions.rs
+++ b/src/librustc_mir/transform/cleanup_post_borrowck.rs
@@ -8,16 +8,27 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-//! This module provides one pass, `CleanEndRegions`, that reduces the
-//! set of `EndRegion` statements in the MIR.
+//! This module provides two passes:
 //!
-//! The "pass" is actually implemented as two traversals (aka visits)
-//! of the input MIR. The first traversal, `GatherBorrowedRegions`,
-//! finds all of the regions in the MIR that are involved in a borrow.
+//!   - `CleanEndRegions`, that reduces the set of `EndRegion` statements
+//!     in the MIR.
+//!   - `CleanUserAssertTy`, that replaces all `UserAssertTy` statements
+//!     with `Nop`.
+//!
+//! The `CleanEndRegions` "pass" is actually implemented as two
+//! traversals (aka visits) of the input MIR. The first traversal,
+//! `GatherBorrowedRegions`, finds all of the regions in the MIR
+//! that are involved in a borrow.
 //!
 //! The second traversal, `DeleteTrivialEndRegions`, walks over the
 //! MIR and removes any `EndRegion` that is applied to a region that
 //! was not seen in the previous pass.
+//!
+//! The `CleanUserAssertTy` pass runs at a distinct time from the
+//! `CleanEndRegions` pass. It is important that the `CleanUserAssertTy`
+//! pass runs after the MIR borrowck so that the NLL type checker can
+//! perform the type assertion when it encounters the `UserAssertTy`
+//! statements.
 
 use rustc_data_structures::fx::FxHashSet;
 
@@ -93,7 +104,33 @@ impl<'a, 'tcx> MutVisitor<'tcx> for DeleteTrivialEndRegions<'a> {
         }
 
         if delete_it {
-            statement.kind = StatementKind::Nop;
+            statement.make_nop();
+        }
+        self.super_statement(block, statement, location);
+    }
+}
+
+pub struct CleanUserAssertTy;
+
+pub struct DeleteUserAssertTy;
+
+impl MirPass for CleanUserAssertTy {
+    fn run_pass<'a, 'tcx>(&self,
+                          _tcx: TyCtxt<'a, 'tcx, 'tcx>,
+                          _source: MirSource,
+                          mir: &mut Mir<'tcx>) {
+        let mut delete = DeleteUserAssertTy;
+        delete.visit_mir(mir);
+    }
+}
+
+impl<'tcx> MutVisitor<'tcx> for DeleteUserAssertTy {
+    fn visit_statement(&mut self,
+                       block: BasicBlock,
+                       statement: &mut Statement<'tcx>,
+                       location: Location) {
+        if let StatementKind::UserAssertTy(..) = statement.kind {
+            statement.make_nop();
         }
         self.super_statement(block, statement, location);
     }
diff --git a/src/librustc_mir/transform/mod.rs b/src/librustc_mir/transform/mod.rs
index 81b740c917b..63ca35aa0e7 100644
--- a/src/librustc_mir/transform/mod.rs
+++ b/src/librustc_mir/transform/mod.rs
@@ -25,7 +25,7 @@ use syntax_pos::Span;
 
 pub mod add_validation;
 pub mod add_moves_for_packed_drops;
-pub mod clean_end_regions;
+pub mod cleanup_post_borrowck;
 pub mod check_unsafety;
 pub mod simplify_branches;
 pub mod simplify;
@@ -193,7 +193,7 @@ fn mir_const<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) -> &'tcx Stea
     let mut mir = tcx.mir_built(def_id).steal();
     run_passes![tcx, mir, def_id, 0;
         // Remove all `EndRegion` statements that are not involved in borrows.
-        clean_end_regions::CleanEndRegions,
+        cleanup_post_borrowck::CleanEndRegions,
 
         // What we need to do constant evaluation.
         simplify::SimplifyCfg::new("initial"),
@@ -234,6 +234,8 @@ fn optimized_mir<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) -> &'tcx
         simplify_branches::SimplifyBranches::new("initial"),
         remove_noop_landing_pads::RemoveNoopLandingPads,
         simplify::SimplifyCfg::new("early-opt"),
+        // Remove all `UserAssertTy` statements.
+        cleanup_post_borrowck::CleanUserAssertTy,
 
         // These next passes must be executed together
         add_call_guards::CriticalCallEdges,
diff --git a/src/librustc_mir/transform/qualify_consts.rs b/src/librustc_mir/transform/qualify_consts.rs
index 59a872a23b0..8e2f98d2769 100644
--- a/src/librustc_mir/transform/qualify_consts.rs
+++ b/src/librustc_mir/transform/qualify_consts.rs
@@ -1099,6 +1099,7 @@ This does not pose a problem by itself because they can't be accessed directly."
                 StatementKind::InlineAsm {..} |
                 StatementKind::EndRegion(_) |
                 StatementKind::Validate(..) |
+                StatementKind::UserAssertTy(..) |
                 StatementKind::Nop => {}
             }
         });
diff --git a/src/librustc_mir/transform/remove_noop_landing_pads.rs b/src/librustc_mir/transform/remove_noop_landing_pads.rs
index cd80d25c410..6d365012525 100644
--- a/src/librustc_mir/transform/remove_noop_landing_pads.rs
+++ b/src/librustc_mir/transform/remove_noop_landing_pads.rs
@@ -50,6 +50,7 @@ impl RemoveNoopLandingPads {
                 StatementKind::StorageLive(_) |
                 StatementKind::StorageDead(_) |
                 StatementKind::EndRegion(_) |
+                StatementKind::UserAssertTy(..) |
                 StatementKind::Nop => {
                     // These are all nops in a landing pad (there's some
                     // borrowck interaction between EndRegion and storage
diff --git a/src/librustc_mir/transform/rustc_peek.rs b/src/librustc_mir/transform/rustc_peek.rs
index 76283edac72..45e7a0d3f4c 100644
--- a/src/librustc_mir/transform/rustc_peek.rs
+++ b/src/librustc_mir/transform/rustc_peek.rs
@@ -163,6 +163,7 @@ fn each_block<'a, 'tcx, O>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
             mir::StatementKind::InlineAsm { .. } |
             mir::StatementKind::EndRegion(_) |
             mir::StatementKind::Validate(..) |
+            mir::StatementKind::UserAssertTy(..) |
             mir::StatementKind::Nop => continue,
             mir::StatementKind::SetDiscriminant{ .. } =>
                 span_bug!(stmt.source_info.span,
diff --git a/src/librustc_passes/mir_stats.rs b/src/librustc_passes/mir_stats.rs
index 4a4ce63cc1d..a4e056c6b58 100644
--- a/src/librustc_passes/mir_stats.rs
+++ b/src/librustc_passes/mir_stats.rs
@@ -90,6 +90,7 @@ impl<'a, 'tcx> mir_visit::Visitor<'tcx> for StatCollector<'a, 'tcx> {
             StatementKind::StorageLive(..) => "StatementKind::StorageLive",
             StatementKind::StorageDead(..) => "StatementKind::StorageDead",
             StatementKind::InlineAsm { .. } => "StatementKind::InlineAsm",
+            StatementKind::UserAssertTy(..) => "StatementKind::UserAssertTy",
             StatementKind::Nop => "StatementKind::Nop",
         }, &statement.kind);
         self.super_statement(block, statement, location);
diff --git a/src/librustc_trans/mir/statement.rs b/src/librustc_trans/mir/statement.rs
index b5b74849401..579b07929a2 100644
--- a/src/librustc_trans/mir/statement.rs
+++ b/src/librustc_trans/mir/statement.rs
@@ -84,6 +84,7 @@ impl<'a, 'tcx> FunctionCx<'a, 'tcx> {
             }
             mir::StatementKind::EndRegion(_) |
             mir::StatementKind::Validate(..) |
+            mir::StatementKind::UserAssertTy(..) |
             mir::StatementKind::Nop => bx,
         }
     }
diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs
index f86fe1fb756..937dd876d6b 100644
--- a/src/librustc_typeck/check/mod.rs
+++ b/src/librustc_typeck/check/mod.rs
@@ -960,10 +960,19 @@ impl<'a, 'gcx, 'tcx> Visitor<'gcx> for GatherLocalsVisitor<'a, 'gcx, 'tcx> {
     // Add explicitly-declared locals.
     fn visit_local(&mut self, local: &'gcx hir::Local) {
         let o_ty = match local.ty {
-            Some(ref ty) => Some(self.fcx.to_ty(&ty)),
-            None => None
+            Some(ref ty) => {
+                let o_ty = self.fcx.to_ty(&ty);
+
+                let (c_ty, _orig_values) = self.fcx.inh.infcx.canonicalize_response(&o_ty);
+                debug!("visit_local: ty.hir_id={:?} o_ty={:?} c_ty={:?}", ty.hir_id, o_ty, c_ty);
+                self.fcx.tables.borrow_mut().user_provided_tys_mut().insert(ty.hir_id, c_ty);
+
+                Some(o_ty)
+            },
+            None => None,
         };
         self.assign(local.span, local.id, o_ty);
+
         debug!("Local variable {:?} is assigned type {}",
                local.pat,
                self.fcx.ty_to_string(
diff --git a/src/librustc_typeck/check/writeback.rs b/src/librustc_typeck/check/writeback.rs
index 862b15743c7..bbd04e0b19a 100644
--- a/src/librustc_typeck/check/writeback.rs
+++ b/src/librustc_typeck/check/writeback.rs
@@ -46,6 +46,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
         wbcx.visit_anon_types();
         wbcx.visit_cast_types();
         wbcx.visit_free_region_map();
+        wbcx.visit_user_provided_tys();
 
         let used_trait_imports = mem::replace(
             &mut self.tables.borrow_mut().used_trait_imports,
@@ -341,6 +342,33 @@ impl<'cx, 'gcx, 'tcx> WritebackCx<'cx, 'gcx, 'tcx> {
         self.tables.free_region_map = free_region_map;
     }
 
+    fn visit_user_provided_tys(&mut self) {
+        let fcx_tables = self.fcx.tables.borrow();
+        debug_assert_eq!(fcx_tables.local_id_root, self.tables.local_id_root);
+        let common_local_id_root = fcx_tables.local_id_root.unwrap();
+
+        for (&local_id, c_ty) in fcx_tables.user_provided_tys().iter() {
+            let hir_id = hir::HirId {
+                owner: common_local_id_root.index,
+                local_id,
+            };
+
+            let c_ty = if let Some(c_ty) = self.tcx().lift_to_global(c_ty) {
+                c_ty
+            } else {
+                span_bug!(
+                    hir_id.to_span(&self.fcx.tcx),
+                    "writeback: `{:?}` missing from the global type context",
+                    c_ty
+                );
+            };
+
+            self.tables
+                .user_provided_tys_mut()
+                .insert(hir_id, c_ty.clone());
+        }
+    }
+
     fn visit_anon_types(&mut self) {
         let gcx = self.tcx().global_tcx();
         for (&def_id, anon_defn) in self.fcx.anon_types.borrow().iter() {
diff --git a/src/test/incremental/hashes/let_expressions.rs b/src/test/incremental/hashes/let_expressions.rs
index 851b13c7055..2f49500c391 100644
--- a/src/test/incremental/hashes/let_expressions.rs
+++ b/src/test/incremental/hashes/let_expressions.rs
@@ -49,7 +49,7 @@ pub fn add_type() {
 
 #[cfg(not(cfail1))]
 #[rustc_clean(cfg="cfail2",
-    except="HirBody,TypeckTables")]
+    except="HirBody,TypeckTables,MirValidated")]
 #[rustc_clean(cfg="cfail3")]
 pub fn add_type() {
     let _x: u32 = 2u32;
diff --git a/src/test/mir-opt/basic_assignment.rs b/src/test/mir-opt/basic_assignment.rs
index 321c05c4903..3c236ddcf04 100644
--- a/src/test/mir-opt/basic_assignment.rs
+++ b/src/test/mir-opt/basic_assignment.rs
@@ -23,6 +23,8 @@
 // tend to be absent in simple code, so subtle breakage in them can
 // leave a quite hard-to-find trail of destruction.
 
+// ignore-tidy-linelength
+
 fn main() {
     let nodrop_x = false;
     let nodrop_y;
@@ -46,6 +48,7 @@ fn main() {
 //         _2 = move _3;
 //         StorageDead(_3);
 //         StorageLive(_4);
+//         UserAssertTy(Canonical { variables: Slice([]), value: std::option::Option<std::boxed::Box<u32>> }, _4);
 //         _4 = std::option::Option<std::boxed::Box<u32>>::None;
 //         StorageLive(_5);
 //         StorageLive(_6);
diff --git a/src/test/mir-opt/nll/reborrow-basic.rs b/src/test/mir-opt/nll/reborrow-basic.rs
index f69c51c3562..92e42a73bbb 100644
--- a/src/test/mir-opt/nll/reborrow-basic.rs
+++ b/src/test/mir-opt/nll/reborrow-basic.rs
@@ -28,9 +28,9 @@ fn main() {
 
 // END RUST SOURCE
 // START rustc.main.nll.0.mir
-// | '_#7r    | {bb0[6..=14]}
+// | '_#7r    | {bb0[4], bb0[8..=17]}
 // ...
-// | '_#9r    | {bb0[11..=14]}
+// | '_#9r    | {bb0[10], bb0[14..=17]}
 // ...
 // let _2: &'_#7r mut i32;
 // ...
diff --git a/src/test/run-pass/generator/yield-subtype.rs b/src/test/run-pass/generator/yield-subtype.rs
index 7e8a0d1e2b9..c4134169044 100644
--- a/src/test/run-pass/generator/yield-subtype.rs
+++ b/src/test/run-pass/generator/yield-subtype.rs
@@ -9,6 +9,7 @@
 // except according to those terms.
 
 // revisions:lexical nll
+//[nll]compile-flags: -Z disable-nll-user-type-assert
 #![cfg_attr(nll, feature(nll))]
 
 #![feature(generators)]
diff --git a/src/test/ui/issue-47184.rs b/src/test/ui/issue-47184.rs
new file mode 100644
index 00000000000..0831b7e0af8
--- /dev/null
+++ b/src/test/ui/issue-47184.rs
@@ -0,0 +1,16 @@
+// Copyright 2015 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.
+
+#![feature(nll)]
+
+fn main() {
+    let _vec: Vec<&'static String> = vec![&String::new()];
+    //~^ ERROR borrowed value does not live long enough [E0597]
+}
diff --git a/src/test/ui/issue-47184.stderr b/src/test/ui/issue-47184.stderr
new file mode 100644
index 00000000000..a9eb33f01e3
--- /dev/null
+++ b/src/test/ui/issue-47184.stderr
@@ -0,0 +1,14 @@
+error[E0597]: borrowed value does not live long enough
+  --> $DIR/issue-47184.rs:14:44
+   |
+LL |     let _vec: Vec<&'static String> = vec![&String::new()];
+   |                                            ^^^^^^^^^^^^^ temporary value does not live long enough
+LL |     //~^ ERROR borrowed value does not live long enough [E0597]
+LL | }
+   | - temporary value only lives until here
+   |
+   = note: borrowed value must be valid for the static lifetime...
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0597`.