about summary refs log tree commit diff
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2018-10-19 20:20:12 +0000
committerbors <bors@rust-lang.org>2018-10-19 20:20:12 +0000
commit78ff609d7375ee2a2c6d0222776ac612eb1b75be (patch)
tree96657ab509a45e40af4d17261b53244a67d1293c
parent74ff7dcb1388e60a613cd6050bcd372a3cc4998b (diff)
parent9a7bb0ef249258aacf144d04f5d437ba70533128 (diff)
downloadrust-78ff609d7375ee2a2c6d0222776ac612eb1b75be.tar.gz
rust-78ff609d7375ee2a2c6d0222776ac612eb1b75be.zip
Auto merge of #55152 - nikomatsakis:nll-issue-54571-type-annot-in-constants, r=pnkfelix
support type annot in constants, casts

Fixes #54571
Fixes #54332
Fixes #55183

r? @pnkfelix
-rw-r--r--src/librustc/ich/impls_mir.rs6
-rw-r--r--src/librustc/infer/canonical/query_response.rs9
-rw-r--r--src/librustc/infer/region_constraints/mod.rs2
-rw-r--r--src/librustc/mir/mod.rs9
-rw-r--r--src/librustc_mir/borrow_check/nll/region_infer/mod.rs38
-rw-r--r--src/librustc_mir/borrow_check/nll/type_check/constraint_conversion.rs1
-rw-r--r--src/librustc_mir/borrow_check/nll/type_check/mod.rs227
-rw-r--r--src/librustc_mir/borrow_check/nll/type_check/relate_tys.rs134
-rw-r--r--src/librustc_mir/build/expr/as_place.rs48
-rw-r--r--src/librustc_mir/hair/cx/expr.rs99
-rw-r--r--src/librustc_mir/hair/mod.rs4
-rw-r--r--src/librustc_mir/hair/util.rs6
-rw-r--r--src/librustc_typeck/check/mod.rs24
-rw-r--r--src/test/ui/consts/const-eval/conditional_array_execution.rs4
-rw-r--r--src/test/ui/nll/user-annotations/cast_static_lifetime.rs17
-rw-r--r--src/test/ui/nll/user-annotations/cast_static_lifetime.stderr13
-rw-r--r--src/test/ui/nll/user-annotations/constant-in-expr-inherent-1.rs15
-rw-r--r--src/test/ui/nll/user-annotations/constant-in-expr-inherent-1.stderr10
-rw-r--r--src/test/ui/nll/user-annotations/constant-in-expr-normalize.rs24
-rw-r--r--src/test/ui/nll/user-annotations/constant-in-expr-normalize.stderr10
-rw-r--r--src/test/ui/nll/user-annotations/constant-in-expr-trait-item-1.rs16
-rw-r--r--src/test/ui/nll/user-annotations/constant-in-expr-trait-item-1.stderr10
-rw-r--r--src/test/ui/nll/user-annotations/constant-in-expr-trait-item-2.rs16
-rw-r--r--src/test/ui/nll/user-annotations/constant-in-expr-trait-item-2.stderr10
-rw-r--r--src/test/ui/nll/user-annotations/constant-in-expr-trait-item-3.rs16
-rw-r--r--src/test/ui/nll/user-annotations/constant-in-expr-trait-item-3.stderr10
-rw-r--r--src/test/ui/nll/user-annotations/normalization.rs13
-rw-r--r--src/test/ui/nll/user-annotations/normalization.stderr13
-rw-r--r--src/test/ui/nll/user-annotations/normalize-self-ty.rs25
29 files changed, 553 insertions, 276 deletions
diff --git a/src/librustc/ich/impls_mir.rs b/src/librustc/ich/impls_mir.rs
index b660187945c..a82a8ca6bdf 100644
--- a/src/librustc/ich/impls_mir.rs
+++ b/src/librustc/ich/impls_mir.rs
@@ -597,11 +597,7 @@ impl<'a, 'gcx> HashStable<StableHashingContext<'a>> for mir::UserTypeAnnotation<
             mir::UserTypeAnnotation::Ty(ref ty) => {
                 ty.hash_stable(hcx, hasher);
             }
-            mir::UserTypeAnnotation::FnDef(ref def_id, ref substs) => {
-                def_id.hash_stable(hcx, hasher);
-                substs.hash_stable(hcx, hasher);
-            }
-            mir::UserTypeAnnotation::AdtDef(ref def_id, ref substs) => {
+            mir::UserTypeAnnotation::TypeOf(ref def_id, ref substs) => {
                 def_id.hash_stable(hcx, hasher);
                 substs.hash_stable(hcx, hasher);
             }
diff --git a/src/librustc/infer/canonical/query_response.rs b/src/librustc/infer/canonical/query_response.rs
index c29a75c34cf..b9edc9f51ea 100644
--- a/src/librustc/infer/canonical/query_response.rs
+++ b/src/librustc/infer/canonical/query_response.rs
@@ -19,7 +19,7 @@
 
 use infer::canonical::substitute::substitute_value;
 use infer::canonical::{
-    Canonical, CanonicalVarKind, CanonicalVarValues, CanonicalizedQueryResponse, Certainty,
+    Canonical, CanonicalVarValues, CanonicalizedQueryResponse, Certainty,
     OriginalQueryValues, QueryRegionConstraint, QueryResponse,
 };
 use infer::region_constraints::{Constraint, RegionConstraintData};
@@ -262,13 +262,6 @@ impl<'cx, 'gcx, 'tcx> InferCtxt<'cx, 'gcx, 'tcx> {
     where
         R: Debug + TypeFoldable<'tcx>,
     {
-        // In an NLL query, there should be no type variables in the
-        // query, only region variables.
-        debug_assert!(query_response.variables.iter().all(|v| match v.kind {
-            CanonicalVarKind::Ty(_) => false,
-            CanonicalVarKind::Region => true,
-        }));
-
         let result_subst =
             self.query_response_substitution_guess(cause, original_values, query_response);
 
diff --git a/src/librustc/infer/region_constraints/mod.rs b/src/librustc/infer/region_constraints/mod.rs
index 525ae03dfaf..df30ad36006 100644
--- a/src/librustc/infer/region_constraints/mod.rs
+++ b/src/librustc/infer/region_constraints/mod.rs
@@ -149,7 +149,7 @@ pub struct Verify<'tcx> {
     pub bound: VerifyBound<'tcx>,
 }
 
-#[derive(Copy, Clone, PartialEq, Eq)]
+#[derive(Copy, Clone, PartialEq, Eq, Hash)]
 pub enum GenericKind<'tcx> {
     Param(ty::ParamTy),
     Projection(ty::ProjectionTy<'tcx>),
diff --git a/src/librustc/mir/mod.rs b/src/librustc/mir/mod.rs
index 9a0623ca539..34fc81a495e 100644
--- a/src/librustc/mir/mod.rs
+++ b/src/librustc/mir/mod.rs
@@ -2425,15 +2425,16 @@ pub struct Constant<'tcx> {
 #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, RustcEncodable, RustcDecodable)]
 pub enum UserTypeAnnotation<'tcx> {
     Ty(CanonicalTy<'tcx>),
-    FnDef(DefId, CanonicalUserSubsts<'tcx>),
-    AdtDef(&'tcx AdtDef, CanonicalUserSubsts<'tcx>),
+
+    /// The canonical type is the result of `type_of(def_id)` with the
+    /// given substitutions applied.
+    TypeOf(DefId, CanonicalUserSubsts<'tcx>),
 }
 
 EnumTypeFoldableImpl! {
     impl<'tcx> TypeFoldable<'tcx> for UserTypeAnnotation<'tcx> {
         (UserTypeAnnotation::Ty)(ty),
-        (UserTypeAnnotation::FnDef)(def, substs),
-        (UserTypeAnnotation::AdtDef)(def, substs),
+        (UserTypeAnnotation::TypeOf)(def, substs),
     }
 }
 
diff --git a/src/librustc_mir/borrow_check/nll/region_infer/mod.rs b/src/librustc_mir/borrow_check/nll/region_infer/mod.rs
index 0fabcfe4564..2c84a9e014e 100644
--- a/src/librustc_mir/borrow_check/nll/region_infer/mod.rs
+++ b/src/librustc_mir/borrow_check/nll/region_infer/mod.rs
@@ -25,7 +25,7 @@ use rustc::mir::{
 use rustc::ty::{self, RegionVid, Ty, TyCtxt, TypeFoldable};
 use rustc::util::common;
 use rustc_data_structures::bit_set::BitSet;
-use rustc_data_structures::fx::FxHashMap;
+use rustc_data_structures::fx::{FxHashMap, FxHashSet};
 use rustc_data_structures::graph::scc::Sccs;
 use rustc_data_structures::indexed_vec::IndexVec;
 use rustc_errors::{Diagnostic, DiagnosticBuilder};
@@ -67,10 +67,8 @@ pub struct RegionInferenceContext<'tcx> {
     constraint_sccs: Rc<Sccs<RegionVid, ConstraintSccIndex>>,
 
     /// Map closure bounds to a `Span` that should be used for error reporting.
-    closure_bounds_mapping: FxHashMap<
-        Location,
-        FxHashMap<(RegionVid, RegionVid), (ConstraintCategory, Span)>,
-    >,
+    closure_bounds_mapping:
+        FxHashMap<Location, FxHashMap<(RegionVid, RegionVid), (ConstraintCategory, Span)>>,
 
     /// Contains the minimum universe of any variable within the same
     /// SCC. We will ensure that no SCC contains values that are not
@@ -580,6 +578,11 @@ impl<'tcx> RegionInferenceContext<'tcx> {
     ) {
         let tcx = infcx.tcx;
 
+        // Sometimes we register equivalent type-tests that would
+        // result in basically the exact same error being reported to
+        // the user. Avoid that.
+        let mut deduplicate_errors = FxHashSet::default();
+
         for type_test in &self.type_tests {
             debug!("check_type_test: {:?}", type_test);
 
@@ -605,11 +608,31 @@ impl<'tcx> RegionInferenceContext<'tcx> {
                 }
             }
 
-            // Oh the humanity. Obviously we will do better than this error eventually.
+            // Type-test failed. Report the error.
+
+            // Try to convert the lower-bound region into something named we can print for the user.
             let lower_bound_region = self.to_error_region(type_test.lower_bound);
+
+            // Skip duplicate-ish errors.
+            let type_test_span = type_test.locations.span(mir);
+            let erased_generic_kind = tcx.erase_regions(&type_test.generic_kind);
+            if !deduplicate_errors.insert((
+                erased_generic_kind,
+                lower_bound_region,
+                type_test.locations,
+            )) {
+                continue;
+            } else {
+                debug!(
+                    "check_type_test: reporting error for erased_generic_kind={:?}, \
+                     lower_bound_region={:?}, \
+                     type_test.locations={:?}",
+                    erased_generic_kind, lower_bound_region, type_test.locations,
+                );
+            }
+
             if let Some(lower_bound_region) = lower_bound_region {
                 let region_scope_tree = &tcx.region_scope_tree(mir_def_id);
-                let type_test_span = type_test.locations.span(mir);
                 infcx
                     .construct_generic_bound_failure(
                         region_scope_tree,
@@ -629,7 +652,6 @@ impl<'tcx> RegionInferenceContext<'tcx> {
                 // to report it; we could probably handle it by
                 // iterating over the universal regions and reporting
                 // an error that multiple bounds are required.
-                let type_test_span = type_test.locations.span(mir);
                 tcx.sess
                     .struct_span_err(
                         type_test_span,
diff --git a/src/librustc_mir/borrow_check/nll/type_check/constraint_conversion.rs b/src/librustc_mir/borrow_check/nll/type_check/constraint_conversion.rs
index 4ab0f952bde..994f20a011d 100644
--- a/src/librustc_mir/borrow_check/nll/type_check/constraint_conversion.rs
+++ b/src/librustc_mir/borrow_check/nll/type_check/constraint_conversion.rs
@@ -142,6 +142,7 @@ impl<'a, 'gcx, 'tcx> ConstraintConversion<'a, 'gcx, 'tcx> {
     }
 
     fn add_type_test(&mut self, type_test: TypeTest<'tcx>) {
+        debug!("add_type_test(type_test={:?})", type_test);
         self.type_tests.push(type_test);
     }
 }
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 c5758cde949..7737fcc765d 100644
--- a/src/librustc_mir/borrow_check/nll/type_check/mod.rs
+++ b/src/librustc_mir/borrow_check/nll/type_check/mod.rs
@@ -42,7 +42,7 @@ use rustc::traits::query::type_op::custom::CustomTypeOp;
 use rustc::traits::query::{Fallible, NoSolution};
 use rustc::traits::{ObligationCause, PredicateObligations};
 use rustc::ty::fold::TypeFoldable;
-use rustc::ty::subst::{Subst, Substs, UnpackedKind};
+use rustc::ty::subst::{Subst, Substs, UnpackedKind, UserSelfTy, UserSubsts};
 use rustc::ty::{self, RegionVid, ToPolyTraitRef, Ty, TyCtxt, TyKind};
 use std::rc::Rc;
 use std::{fmt, iter};
@@ -753,10 +753,8 @@ crate struct MirTypeckRegionConstraints<'tcx> {
 
     crate outlives_constraints: ConstraintSet,
 
-    crate closure_bounds_mapping: FxHashMap<
-        Location,
-        FxHashMap<(RegionVid, RegionVid), (ConstraintCategory, Span)>,
-    >,
+    crate closure_bounds_mapping:
+        FxHashMap<Location, FxHashMap<(RegionVid, RegionVid), (ConstraintCategory, Span)>>,
 
     crate type_tests: Vec<TypeTest<'tcx>>,
 }
@@ -866,7 +864,7 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> {
         &mut self,
         locations: Locations,
         category: ConstraintCategory,
-        op: impl type_op::TypeOp<'gcx, 'tcx, Output=R>,
+        op: impl type_op::TypeOp<'gcx, 'tcx, Output = R>,
     ) -> Fallible<R> {
         let (r, opt_data) = op.fully_perform(self.infcx)?;
 
@@ -903,23 +901,37 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> {
         }
     }
 
-    fn sub_types(
+    /// Convenient wrapper around `relate_tys::relate_types` -- see
+    /// that fn for docs.
+    fn relate_types(
         &mut self,
-        sub: Ty<'tcx>,
-        sup: Ty<'tcx>,
+        a: Ty<'tcx>,
+        v: ty::Variance,
+        b: Ty<'tcx>,
         locations: Locations,
         category: ConstraintCategory,
     ) -> Fallible<()> {
-        relate_tys::sub_types(
+        relate_tys::relate_types(
             self.infcx,
-            sub,
-            sup,
+            a,
+            v,
+            b,
             locations,
             category,
             self.borrowck_context.as_mut().map(|x| &mut **x),
         )
     }
 
+    fn sub_types(
+        &mut self,
+        sub: Ty<'tcx>,
+        sup: Ty<'tcx>,
+        locations: Locations,
+        category: ConstraintCategory,
+    ) -> Fallible<()> {
+        self.relate_types(sub, ty::Variance::Covariant, sup, locations, category)
+    }
+
     /// Try to relate `sub <: sup`; if this fails, instantiate opaque
     /// variables in `sub` with their inferred definitions and try
     /// again. This is used for opaque types in places (e.g., `let x:
@@ -952,41 +964,133 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> {
         locations: Locations,
         category: ConstraintCategory,
     ) -> Fallible<()> {
-        relate_tys::eq_types(
-            self.infcx,
-            a,
-            b,
-            locations,
-            category,
-            self.borrowck_context.as_mut().map(|x| &mut **x),
-        )
+        self.relate_types(a, ty::Variance::Invariant, b, locations, category)
     }
 
     fn relate_type_and_user_type(
         &mut self,
         a: Ty<'tcx>,
         v: ty::Variance,
-        b: UserTypeAnnotation<'tcx>,
+        user_ty: UserTypeAnnotation<'tcx>,
         locations: Locations,
         category: ConstraintCategory,
     ) -> Fallible<()> {
-        let ty = relate_tys::relate_type_and_user_type(
-            self.infcx,
-            a,
-            v,
-            b,
-            locations,
-            category,
-            self.borrowck_context.as_mut().map(|x| &mut **x),
-        )?;
-        self.prove_predicate(
-            ty::Predicate::WellFormed(ty),
-            locations,
-            category,
+        let tcx = self.tcx();
+
+        debug!(
+            "relate_type_and_user_type(a={:?}, v={:?}, b={:?}, locations={:?})",
+            a, v, user_ty, locations
         );
+
+        // The `TypeRelating` code assumes that "unresolved inference
+        // variables" appear in the "a" side, so flip `Contravariant`
+        // ambient variance to get the right relationship.
+        let v1 = ty::Contravariant.xform(v);
+
+        match user_ty {
+            UserTypeAnnotation::Ty(canonical_ty) => {
+                let (ty, _) = self.infcx
+                    .instantiate_canonical_with_fresh_inference_vars(DUMMY_SP, &canonical_ty);
+
+                self.relate_types(ty, v1, a, locations, category)?;
+
+                self.prove_predicate(ty::Predicate::WellFormed(ty), locations, category);
+            }
+            UserTypeAnnotation::TypeOf(def_id, canonical_substs) => {
+                let (
+                    UserSubsts {
+                        substs,
+                        user_self_ty,
+                    },
+                    _,
+                ) = self.infcx
+                    .instantiate_canonical_with_fresh_inference_vars(DUMMY_SP, &canonical_substs);
+
+                let ty = self.tcx().type_of(def_id);
+                let ty = ty.subst(tcx, substs);
+                let ty = self.normalize(ty, locations);
+
+                self.relate_types(ty, v1, a, locations, category)?;
+
+                if let Some(UserSelfTy {
+                    impl_def_id,
+                    self_ty,
+                }) = user_self_ty
+                {
+                    let impl_self_ty = tcx.type_of(impl_def_id);
+                    let impl_self_ty = impl_self_ty.subst(tcx, &substs);
+                    let impl_self_ty = self.normalize(impl_self_ty, locations);
+
+                    // There may be type variables in `substs` and hence
+                    // in `impl_self_ty`, but they should all have been
+                    // resolved to some fixed value during the first call
+                    // to `relate`, above. Therefore, if we use
+                    // `resolve_type_vars_if_possible` we should get to
+                    // something without type variables. This is important
+                    // because the `b` type in `relate_with_variance`
+                    // below is not permitted to have inference variables.
+                    let impl_self_ty = self.infcx.resolve_type_vars_if_possible(&impl_self_ty);
+                    assert!(!impl_self_ty.has_infer_types());
+
+                    self.eq_types(self_ty, impl_self_ty, locations, category)?;
+                }
+
+                // Prove the predicates coming along with `def_id`.
+                //
+                // Also, normalize the `instantiated_predicates`
+                // because otherwise we wind up with duplicate "type
+                // outlives" error messages.
+                let instantiated_predicates = tcx.predicates_of(def_id).instantiate(tcx, substs);
+                let instantiated_predicates = self.fold_to_region_vid(instantiated_predicates);
+                self.normalize_and_prove_instantiated_predicates(
+                    instantiated_predicates,
+                    locations,
+                );
+
+                // In addition to proving the predicates, we have to
+                // prove that `ty` is well-formed -- this is because
+                // the WF of `ty` is predicated on the substs being
+                // well-formed, and we haven't proven *that*. We don't
+                // want to prove the WF of types from  `substs` directly because they
+                // haven't been normalized.
+                //
+                // FIXME(nmatsakis): Well, perhaps we should normalize
+                // them?  This would only be relevant if some input
+                // type were ill-formed but did not appear in `ty`,
+                // which...could happen with normalization...
+                self.prove_predicate(ty::Predicate::WellFormed(ty), locations, category);
+            }
+        }
+
         Ok(())
     }
 
+    /// Replace all free regions in `value` with their NLL `RegionVid`
+    /// equivalents; if not in NLL, does nothing. This is never
+    /// particularly necessary -- we'll do it lazilly as we process
+    /// the value anyway -- but in some specific cases it is useful to
+    /// normalize so we can suppress duplicate error messages.
+    fn fold_to_region_vid<T>(
+        &self,
+        value: T
+    ) -> T
+    where T: TypeFoldable<'tcx>
+    {
+        if let Some(borrowck_context) = &self.borrowck_context {
+            self.tcx().fold_regions(&value, &mut false, |r, _debruijn| {
+                if r.has_free_regions() {
+                    self.tcx().mk_region(ty::RegionKind::ReVar(
+                        borrowck_context.universal_regions.to_region_vid(r),
+                    ))
+                } else {
+                    r
+                }
+            })
+        } else {
+            value
+        }
+    }
+
     fn eq_opaque_type_and_type(
         &mut self,
         revealed_ty: Ty<'tcx>,
@@ -1115,9 +1219,9 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> {
                 let place_ty = place.ty(mir, tcx).to_ty(tcx);
                 let rv_ty = rv.ty(mir, tcx);
                 if let Err(terr) =
-                self.sub_types_or_anon(rv_ty, place_ty, location.to_locations(), category)
-                    {
-                        span_mirbug!(
+                    self.sub_types_or_anon(rv_ty, place_ty, location.to_locations(), category)
+                {
+                    span_mirbug!(
                         self,
                         stmt,
                         "bad assignment ({:?} = {:?}): {:?}",
@@ -1125,7 +1229,7 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> {
                         rv_ty,
                         terr
                     );
-                    }
+                }
 
                 if let Some(user_ty) = self.rvalue_user_ty(rv) {
                     if let Err(terr) = self.relate_type_and_user_type(
@@ -1245,9 +1349,9 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> {
 
                 let locations = term_location.to_locations();
                 if let Err(terr) =
-                self.sub_types(rv_ty, place_ty, locations, ConstraintCategory::Assignment)
-                    {
-                        span_mirbug!(
+                    self.sub_types(rv_ty, place_ty, locations, ConstraintCategory::Assignment)
+                {
+                    span_mirbug!(
                         self,
                         term,
                         "bad DropAndReplace ({:?} = {:?}): {:?}",
@@ -1255,7 +1359,7 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> {
                         rv_ty,
                         terr
                     );
-                    }
+                }
             }
             TerminatorKind::SwitchInt {
                 ref discr,
@@ -1399,9 +1503,9 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> {
                 let locations = term_location.to_locations();
 
                 if let Err(terr) =
-                self.sub_types_or_anon(sig.output(), dest_ty, locations, category)
-                    {
-                        span_mirbug!(
+                    self.sub_types_or_anon(sig.output(), dest_ty, locations, category)
+                {
+                    span_mirbug!(
                         self,
                         term,
                         "call dest mismatch ({:?} <- {:?}): {:?}",
@@ -1409,7 +1513,7 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> {
                         sig.output(),
                         terr
                     );
-                    }
+                }
 
                 // When `#![feature(unsized_locals)]` is not enabled,
                 // this check is done at `check_local`.
@@ -2050,7 +2154,7 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> {
             aggregate_kind, location
         );
 
-        let instantiated_predicates = match aggregate_kind  {
+        let instantiated_predicates = match aggregate_kind {
             AggregateKind::Adt(def, _, substs, _, _) => {
                 tcx.predicates_of(def.did).instantiate(tcx, substs)
             }
@@ -2096,15 +2200,9 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> {
         substs: &'tcx Substs<'tcx>,
         location: Location,
     ) -> ty::InstantiatedPredicates<'tcx> {
-        if let Some(closure_region_requirements) =
-            tcx.mir_borrowck(def_id).closure_requirements
-        {
-            let closure_constraints = closure_region_requirements.apply_requirements(
-                tcx,
-                location,
-                def_id,
-                substs,
-            );
+        if let Some(closure_region_requirements) = tcx.mir_borrowck(def_id).closure_requirements {
+            let closure_constraints =
+                closure_region_requirements.apply_requirements(tcx, location, def_id, substs);
 
             if let Some(ref mut borrowck_context) = self.borrowck_context {
                 let bounds_mapping = closure_constraints
@@ -2113,10 +2211,7 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> {
                     .filter_map(|(idx, constraint)| {
                         let ty::OutlivesPredicate(k1, r2) =
                             constraint.no_late_bound_regions().unwrap_or_else(|| {
-                                bug!(
-                                    "query_constraint {:?} contained bound regions",
-                                    constraint,
-                                );
+                                bug!("query_constraint {:?} contained bound regions", constraint,);
                             });
 
                         match k1.unpack() {
@@ -2124,8 +2219,8 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> {
                                 // constraint is r1: r2
                                 let r1_vid = borrowck_context.universal_regions.to_region_vid(r1);
                                 let r2_vid = borrowck_context.universal_regions.to_region_vid(r2);
-                                let outlives_requirements = &closure_region_requirements
-                                    .outlives_requirements[idx];
+                                let outlives_requirements =
+                                    &closure_region_requirements.outlives_requirements[idx];
                                 Some((
                                     (r1_vid, r2_vid),
                                     (
@@ -2139,10 +2234,14 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> {
                     })
                     .collect();
 
-                let existing = borrowck_context.constraints
+                let existing = borrowck_context
+                    .constraints
                     .closure_bounds_mapping
                     .insert(location, bounds_mapping);
-                assert!(existing.is_none(), "Multiple closures at the same location.");
+                assert!(
+                    existing.is_none(),
+                    "Multiple closures at the same location."
+                );
             }
 
             self.push_region_constraints(
diff --git a/src/librustc_mir/borrow_check/nll/type_check/relate_tys.rs b/src/librustc_mir/borrow_check/nll/type_check/relate_tys.rs
index 72120eb1841..13ebf46bdb1 100644
--- a/src/librustc_mir/borrow_check/nll/type_check/relate_tys.rs
+++ b/src/librustc_mir/borrow_check/nll/type_check/relate_tys.rs
@@ -12,35 +12,23 @@ use borrow_check::nll::constraints::OutlivesConstraint;
 use borrow_check::nll::type_check::{BorrowCheckContext, Locations};
 use rustc::infer::nll_relate::{TypeRelating, TypeRelatingDelegate};
 use rustc::infer::{InferCtxt, NLLRegionVariableOrigin};
-use rustc::mir::{ConstraintCategory, UserTypeAnnotation};
+use rustc::mir::ConstraintCategory;
 use rustc::traits::query::Fallible;
 use rustc::ty::relate::TypeRelation;
-use rustc::ty::subst::{Subst, UserSelfTy, UserSubsts};
-use rustc::ty::{self, Ty, TypeFoldable};
-use syntax_pos::DUMMY_SP;
-
-/// Adds sufficient constraints to ensure that `a <: b`.
-pub(super) fn sub_types<'tcx>(
-    infcx: &InferCtxt<'_, '_, 'tcx>,
-    a: Ty<'tcx>,
-    b: Ty<'tcx>,
-    locations: Locations,
-    category: ConstraintCategory,
-    borrowck_context: Option<&mut BorrowCheckContext<'_, 'tcx>>,
-) -> Fallible<()> {
-    debug!("sub_types(a={:?}, b={:?}, locations={:?})", a, b, locations);
-    TypeRelating::new(
-        infcx,
-        NllTypeRelatingDelegate::new(infcx, borrowck_context, locations, category),
-        ty::Variance::Covariant,
-    ).relate(&a, &b)?;
-    Ok(())
-}
-
-/// Adds sufficient constraints to ensure that `a == b`.
-pub(super) fn eq_types<'tcx>(
+use rustc::ty::{self, Ty};
+
+/// Adds sufficient constraints to ensure that `a R b` where `R` depends on `v`:
+///
+/// - "Covariant" `a <: b`
+/// - "Invariant" `a == b`
+/// - "Contravariant" `a :> b`
+///
+/// NB. The type `a` is permitted to have unresolved inference
+/// variables, but not the type `b`.
+pub(super) fn relate_types<'tcx>(
     infcx: &InferCtxt<'_, '_, 'tcx>,
     a: Ty<'tcx>,
+    v: ty::Variance,
     b: Ty<'tcx>,
     locations: Locations,
     category: ConstraintCategory,
@@ -50,105 +38,11 @@ pub(super) fn eq_types<'tcx>(
     TypeRelating::new(
         infcx,
         NllTypeRelatingDelegate::new(infcx, borrowck_context, locations, category),
-        ty::Variance::Invariant,
+        v,
     ).relate(&a, &b)?;
     Ok(())
 }
 
-/// Adds sufficient constraints to ensure that `a <: b`, where `b` is
-/// a user-given type (which means it may have canonical variables
-/// encoding things like `_`).
-pub(super) fn relate_type_and_user_type<'tcx>(
-    infcx: &InferCtxt<'_, '_, 'tcx>,
-    a: Ty<'tcx>,
-    v: ty::Variance,
-    user_ty: UserTypeAnnotation<'tcx>,
-    locations: Locations,
-    category: ConstraintCategory,
-    borrowck_context: Option<&mut BorrowCheckContext<'_, 'tcx>>,
-) -> Fallible<Ty<'tcx>> {
-    debug!(
-        "relate_type_and_user_type(a={:?}, v={:?}, b={:?}, locations={:?})",
-        a, v, user_ty, locations
-    );
-
-    // The `TypeRelating` code assumes that the "canonical variables"
-    // appear in the "a" side, so flip `Contravariant` ambient
-    // variance to get the right relationship.
-    let v1 = ty::Contravariant.xform(v);
-
-    let mut type_relating = TypeRelating::new(
-        infcx,
-        NllTypeRelatingDelegate::new(infcx, borrowck_context, locations, category),
-        v1,
-    );
-
-    match user_ty {
-        UserTypeAnnotation::Ty(canonical_ty) => {
-            let (ty, _) =
-                infcx.instantiate_canonical_with_fresh_inference_vars(DUMMY_SP, &canonical_ty);
-            type_relating.relate(&ty, &a)?;
-            Ok(ty)
-        }
-        UserTypeAnnotation::FnDef(def_id, canonical_substs) => {
-            let (
-                UserSubsts {
-                    substs,
-                    user_self_ty,
-                },
-                _,
-            ) = infcx.instantiate_canonical_with_fresh_inference_vars(DUMMY_SP, &canonical_substs);
-            let ty = infcx.tcx.mk_fn_def(def_id, substs);
-
-            type_relating.relate(&ty, &a)?;
-
-            if let Some(UserSelfTy {
-                impl_def_id,
-                self_ty,
-            }) = user_self_ty
-            {
-                let impl_self_ty = infcx.tcx.type_of(impl_def_id);
-                let impl_self_ty = impl_self_ty.subst(infcx.tcx, &substs);
-
-                // There may be type variables in `substs` and hence
-                // in `impl_self_ty`, but they should all have been
-                // resolved to some fixed value during the first call
-                // to `relate`, above. Therefore, if we use
-                // `resolve_type_vars_if_possible` we should get to
-                // something without type variables. This is important
-                // because the `b` type in `relate_with_variance`
-                // below is not permitted to have inference variables.
-                let impl_self_ty = infcx.resolve_type_vars_if_possible(&impl_self_ty);
-                assert!(!impl_self_ty.has_infer_types());
-
-                type_relating.relate_with_variance(
-                    ty::Variance::Invariant,
-                    &self_ty,
-                    &impl_self_ty,
-                )?;
-            }
-
-            Ok(ty)
-        }
-        UserTypeAnnotation::AdtDef(adt_def, canonical_substs) => {
-            let (
-                UserSubsts {
-                    substs,
-                    user_self_ty,
-                },
-                _,
-            ) = infcx.instantiate_canonical_with_fresh_inference_vars(DUMMY_SP, &canonical_substs);
-
-            // We don't extract adt-defs with a self-type.
-            assert!(user_self_ty.is_none());
-
-            let ty = infcx.tcx.mk_adt(adt_def, substs);
-            type_relating.relate(&ty, &a)?;
-            Ok(ty)
-        }
-    }
-}
-
 struct NllTypeRelatingDelegate<'me, 'bccx: 'me, 'gcx: 'tcx, 'tcx: 'bccx> {
     infcx: &'me InferCtxt<'me, 'gcx, 'tcx>,
     borrowck_context: Option<&'me mut BorrowCheckContext<'bccx, 'tcx>>,
diff --git a/src/librustc_mir/build/expr/as_place.rs b/src/librustc_mir/build/expr/as_place.rs
index 29c3fb69339..820822b7f5b 100644
--- a/src/librustc_mir/build/expr/as_place.rs
+++ b/src/librustc_mir/build/expr/as_place.rs
@@ -139,17 +139,19 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
 
             ExprKind::PlaceTypeAscription { source, user_ty } => {
                 let place = unpack!(block = this.as_place(block, source));
-                this.cfg.push(
-                    block,
-                    Statement {
-                        source_info,
-                        kind: StatementKind::AscribeUserType(
-                            place.clone(),
-                            Variance::Invariant,
-                            user_ty,
-                        ),
-                    },
-                );
+                if let Some(user_ty) = user_ty {
+                    this.cfg.push(
+                        block,
+                        Statement {
+                            source_info,
+                            kind: StatementKind::AscribeUserType(
+                                place.clone(),
+                                Variance::Invariant,
+                                user_ty,
+                            ),
+                        },
+                    );
+                }
                 block.and(place)
             }
             ExprKind::ValueTypeAscription { source, user_ty } => {
@@ -157,17 +159,19 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
                 let temp = unpack!(
                     block = this.as_temp(block, source.temp_lifetime, source, mutability)
                 );
-                this.cfg.push(
-                    block,
-                    Statement {
-                        source_info,
-                        kind: StatementKind::AscribeUserType(
-                            Place::Local(temp.clone()),
-                            Variance::Invariant,
-                            user_ty,
-                        ),
-                    },
-                );
+                if let Some(user_ty) = user_ty {
+                    this.cfg.push(
+                        block,
+                        Statement {
+                            source_info,
+                            kind: StatementKind::AscribeUserType(
+                                Place::Local(temp.clone()),
+                                Variance::Invariant,
+                                user_ty,
+                            ),
+                        },
+                    );
+                }
                 block.and(Place::Local(temp))
             }
 
diff --git a/src/librustc_mir/hair/cx/expr.rs b/src/librustc_mir/hair/cx/expr.rs
index 56a29f29d68..1df5f789751 100644
--- a/src/librustc_mir/hair/cx/expr.rs
+++ b/src/librustc_mir/hair/cx/expr.rs
@@ -295,7 +295,7 @@ fn make_mirror_unadjusted<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>,
                     let substs = cx.tables().node_substs(fun.hir_id);
 
                     let user_ty = cx.tables().user_substs(fun.hir_id)
-                        .map(|user_substs| UserTypeAnnotation::AdtDef(adt_def, user_substs));
+                        .map(|user_substs| UserTypeAnnotation::TypeOf(adt_def.did, user_substs));
 
                     let field_refs = args.iter()
                         .enumerate()
@@ -637,12 +637,25 @@ fn make_mirror_unadjusted<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>,
                 name: Field::new(cx.tcx.field_index(expr.id, cx.tables)),
             }
         }
-        hir::ExprKind::Cast(ref source, _) => {
+        hir::ExprKind::Cast(ref source, ref cast_ty) => {
+            // Check for a user-given type annotation on this `cast`
+            let user_ty = cx.tables.user_provided_tys().get(cast_ty.hir_id)
+                .map(|&t| UserTypeAnnotation::Ty(t));
+
+            debug!(
+                "cast({:?}) has ty w/ hir_id {:?} and user provided ty {:?}",
+                expr,
+                cast_ty.hir_id,
+                user_ty,
+            );
+
             // Check to see if this cast is a "coercion cast", where the cast is actually done
             // using a coercion (or is a no-op).
-            if let Some(&TyCastKind::CoercionCast) = cx.tables()
-                                                    .cast_kinds()
-                                                    .get(source.hir_id) {
+            let cast = if let Some(&TyCastKind::CoercionCast) =
+                cx.tables()
+                .cast_kinds()
+                .get(source.hir_id)
+            {
                 // Convert the lexpr to a vexpr.
                 ExprKind::Use { source: source.to_ref() }
             } else {
@@ -679,24 +692,30 @@ fn make_mirror_unadjusted<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>,
                 } else {
                     None
                 };
-                let source = if let Some((did, offset, ty)) = var {
+
+                let source = if let Some((did, offset, var_ty)) = var {
                     let mk_const = |literal| Expr {
                         temp_lifetime,
-                        ty,
+                        ty: var_ty,
                         span: expr.span,
                         kind: ExprKind::Literal { literal, user_ty: None },
                     }.to_ref();
                     let offset = mk_const(ty::Const::from_bits(
                         cx.tcx,
                         offset as u128,
-                        cx.param_env.and(ty),
+                        cx.param_env.and(var_ty),
                     ));
                     match did {
                         Some(did) => {
                             // in case we are offsetting from a computed discriminant
                             // and not the beginning of discriminants (which is always `0`)
                             let substs = Substs::identity_for_item(cx.tcx(), did);
-                            let lhs = mk_const(ty::Const::unevaluated(cx.tcx(), did, substs, ty));
+                            let lhs = mk_const(ty::Const::unevaluated(
+                                cx.tcx(),
+                                did,
+                                substs,
+                                var_ty,
+                            ));
                             let bin = ExprKind::Binary {
                                 op: BinOp::Add,
                                 lhs,
@@ -704,7 +723,7 @@ fn make_mirror_unadjusted<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>,
                             };
                             Expr {
                                 temp_lifetime,
-                                ty,
+                                ty: var_ty,
                                 span: expr.span,
                                 kind: bin,
                             }.to_ref()
@@ -714,20 +733,33 @@ fn make_mirror_unadjusted<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>,
                 } else {
                     source.to_ref()
                 };
+
                 ExprKind::Cast { source }
+            };
+
+            if let Some(user_ty) = user_ty {
+                // NOTE: Creating a new Expr and wrapping a Cast inside of it may be
+                //       inefficient, revisit this when performance becomes an issue.
+                let cast_expr = Expr {
+                    temp_lifetime,
+                    ty: expr_ty,
+                    span: expr.span,
+                    kind: cast,
+                };
+
+                ExprKind::ValueTypeAscription {
+                    source: cast_expr.to_ref(),
+                    user_ty: Some(user_ty),
+                }
+            } else {
+                cast
             }
         }
         hir::ExprKind::Type(ref source, ref ty) => {
             let user_provided_tys = cx.tables.user_provided_tys();
-            let user_ty = UserTypeAnnotation::Ty(
-                *user_provided_tys
-                    .get(ty.hir_id)
-                    .expect(&format!(
-                        "{:?} not found in user_provided_tys, source: {:?}",
-                        ty,
-                        source,
-                    ))
-            );
+            let user_ty = user_provided_tys
+                .get(ty.hir_id)
+                .map(|&c_ty| UserTypeAnnotation::Ty(c_ty));
             if source.is_place_expr() {
                 ExprKind::PlaceTypeAscription {
                     source: source.to_ref(),
@@ -771,12 +803,10 @@ fn user_substs_applied_to_def(
         Def::Fn(_) |
         Def::Method(_) |
         Def::StructCtor(_, CtorKind::Fn) |
-        Def::VariantCtor(_, CtorKind::Fn) =>
-            Some(UserTypeAnnotation::FnDef(def.def_id(), cx.tables().user_substs(hir_id)?)),
-
-        Def::Const(_def_id) |
-        Def::AssociatedConst(_def_id) =>
-            bug!("unimplemented"),
+        Def::VariantCtor(_, CtorKind::Fn) |
+        Def::Const(_) |
+        Def::AssociatedConst(_) =>
+            Some(UserTypeAnnotation::TypeOf(def.def_id(), cx.tables().user_substs(hir_id)?)),
 
         // A unit struct/variant which is used as a value (e.g.,
         // `None`). This has the type of the enum/struct that defines
@@ -889,14 +919,17 @@ fn convert_path_expr<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>,
         },
 
         Def::Const(def_id) |
-        Def::AssociatedConst(def_id) => ExprKind::Literal {
-            literal: ty::Const::unevaluated(
-                cx.tcx,
-                def_id,
-                substs,
-                cx.tables().node_id_to_type(expr.hir_id),
-            ),
-            user_ty: None, // FIXME(#47184) -- user given type annot on constants
+        Def::AssociatedConst(def_id) => {
+            let user_ty = user_substs_applied_to_def(cx, expr.hir_id, &def);
+            ExprKind::Literal {
+                literal: ty::Const::unevaluated(
+                    cx.tcx,
+                    def_id,
+                    substs,
+                    cx.tables().node_id_to_type(expr.hir_id),
+                ),
+                user_ty,
+            }
         },
 
         Def::StructCtor(def_id, CtorKind::Const) |
diff --git a/src/librustc_mir/hair/mod.rs b/src/librustc_mir/hair/mod.rs
index 781b6c92aa1..788db5c0b7e 100644
--- a/src/librustc_mir/hair/mod.rs
+++ b/src/librustc_mir/hair/mod.rs
@@ -276,12 +276,12 @@ pub enum ExprKind<'tcx> {
     PlaceTypeAscription {
         source: ExprRef<'tcx>,
         /// Type that the user gave to this expression
-        user_ty: UserTypeAnnotation<'tcx>,
+        user_ty: Option<UserTypeAnnotation<'tcx>>,
     },
     ValueTypeAscription {
         source: ExprRef<'tcx>,
         /// Type that the user gave to this expression
-        user_ty: UserTypeAnnotation<'tcx>,
+        user_ty: Option<UserTypeAnnotation<'tcx>>,
     },
     Closure {
         closure_id: DefId,
diff --git a/src/librustc_mir/hair/util.rs b/src/librustc_mir/hair/util.rs
index 71cbac6b7c8..f81a0fa5dfa 100644
--- a/src/librustc_mir/hair/util.rs
+++ b/src/librustc_mir/hair/util.rs
@@ -23,7 +23,7 @@ crate trait UserAnnotatedTyHelpers<'gcx: 'tcx, 'tcx> {
         adt_def: &'tcx AdtDef,
     ) -> Option<UserTypeAnnotation<'tcx>> {
         let user_substs = self.tables().user_substs(hir_id)?;
-        Some(UserTypeAnnotation::AdtDef(adt_def, user_substs))
+        Some(UserTypeAnnotation::TypeOf(adt_def.did, user_substs))
     }
 
     /// Looks up the type associated with this hir-id and applies the
@@ -35,8 +35,8 @@ crate trait UserAnnotatedTyHelpers<'gcx: 'tcx, 'tcx> {
     ) -> Option<UserTypeAnnotation<'tcx>> {
         let user_substs = self.tables().user_substs(hir_id)?;
         match &self.tables().node_id_to_type(hir_id).sty {
-            ty::Adt(adt_def, _) => Some(UserTypeAnnotation::AdtDef(adt_def, user_substs)),
-            ty::FnDef(def_id, _) => Some(UserTypeAnnotation::FnDef(*def_id, user_substs)),
+            ty::Adt(adt_def, _) => Some(UserTypeAnnotation::TypeOf(adt_def.did, user_substs)),
+            ty::FnDef(def_id, _) => Some(UserTypeAnnotation::TypeOf(*def_id, user_substs)),
             sty => bug!(
                 "sty: {:?} should not have user-substs {:?} recorded ",
                 sty,
diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs
index 14ce1bb4ccd..ffa21e1fc22 100644
--- a/src/librustc_typeck/check/mod.rs
+++ b/src/librustc_typeck/check/mod.rs
@@ -2357,6 +2357,24 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
         t
     }
 
+    pub fn to_ty_saving_user_provided_ty(&self, ast_ty: &hir::Ty) -> Ty<'tcx> {
+        let ty = self.to_ty(ast_ty);
+
+        // If the type given by the user has free regions, save it for
+        // later, since NLL would like to enforce those. Also pass in
+        // types that involve projections, since those can resolve to
+        // `'static` bounds (modulo #54940, which hopefully will be
+        // fixed by the time you see this comment, dear reader,
+        // although I have my doubts). Other sorts of things are
+        // already sufficiently enforced with erased regions. =)
+        if ty.has_free_regions() || ty.has_projections() {
+            let c_ty = self.infcx.canonicalize_response(&ty);
+            self.tables.borrow_mut().user_provided_tys_mut().insert(ast_ty.hir_id, c_ty);
+        }
+
+        ty
+    }
+
     pub fn node_ty(&self, id: hir::HirId) -> Ty<'tcx> {
         match self.tables.borrow().node_types().get(id) {
             Some(&t) => t,
@@ -4153,7 +4171,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
             hir::ExprKind::Cast(ref e, ref t) => {
                 // Find the type of `e`. Supply hints based on the type we are casting to,
                 // if appropriate.
-                let t_cast = self.to_ty(t);
+                let t_cast = self.to_ty_saving_user_provided_ty(t);
                 let t_cast = self.resolve_type_vars_if_possible(&t_cast);
                 let t_expr = self.check_expr_with_expectation(e, ExpectCastableToType(t_cast));
                 let t_cast = self.resolve_type_vars_if_possible(&t_cast);
@@ -4176,10 +4194,8 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                 }
             }
             hir::ExprKind::Type(ref e, ref t) => {
-                let ty = self.to_ty(&t);
+                let ty = self.to_ty_saving_user_provided_ty(&t);
                 self.check_expr_eq_type(&e, ty);
-                let c_ty = self.infcx.canonicalize_response(&ty);
-                self.tables.borrow_mut().user_provided_tys_mut().insert(t.hir_id, c_ty);
                 ty
             }
             hir::ExprKind::Array(ref args) => {
diff --git a/src/test/ui/consts/const-eval/conditional_array_execution.rs b/src/test/ui/consts/const-eval/conditional_array_execution.rs
index b3f56f27f63..8142ed0155a 100644
--- a/src/test/ui/consts/const-eval/conditional_array_execution.rs
+++ b/src/test/ui/consts/const-eval/conditional_array_execution.rs
@@ -17,6 +17,6 @@ const FOO: u32 = [X - Y, Y - X][(X < Y) as usize];
 
 fn main() {
     println!("{}", FOO);
-    //~^ ERROR erroneous constant used
-    //~| E0080
+    //~^ ERROR
+    //~| ERROR
 }
diff --git a/src/test/ui/nll/user-annotations/cast_static_lifetime.rs b/src/test/ui/nll/user-annotations/cast_static_lifetime.rs
new file mode 100644
index 00000000000..aa2cf85dfd9
--- /dev/null
+++ b/src/test/ui/nll/user-annotations/cast_static_lifetime.rs
@@ -0,0 +1,17 @@
+// 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.
+
+#![allow(warnings)]
+#![feature(nll)]
+
+fn main() {
+    let x = 22_u32;
+    let y: &u32 = (&x) as &'static u32;
+}
diff --git a/src/test/ui/nll/user-annotations/cast_static_lifetime.stderr b/src/test/ui/nll/user-annotations/cast_static_lifetime.stderr
new file mode 100644
index 00000000000..a35035b07ba
--- /dev/null
+++ b/src/test/ui/nll/user-annotations/cast_static_lifetime.stderr
@@ -0,0 +1,13 @@
+error[E0597]: `x` does not live long enough
+  --> $DIR/cast_static_lifetime.rs:16:19
+   |
+LL |     let y: &u32 = (&x) as &'static u32;
+   |                   ^^^^ borrowed value does not live long enough
+LL | }
+   | - `x` dropped here while still borrowed
+   |
+   = note: borrowed value must be valid for the static lifetime...
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0597`.
diff --git a/src/test/ui/nll/user-annotations/constant-in-expr-inherent-1.rs b/src/test/ui/nll/user-annotations/constant-in-expr-inherent-1.rs
new file mode 100644
index 00000000000..058ebaee9e5
--- /dev/null
+++ b/src/test/ui/nll/user-annotations/constant-in-expr-inherent-1.rs
@@ -0,0 +1,15 @@
+#![feature(nll)]
+
+struct Foo<'a> { x: &'a u32 }
+
+impl<'a> Foo<'a> {
+    const C: &'a u32 = &22;
+}
+
+fn foo<'a>(_: &'a u32) -> &'static u32 {
+    <Foo<'a>>::C //~ ERROR
+}
+
+fn main() {
+}
+
diff --git a/src/test/ui/nll/user-annotations/constant-in-expr-inherent-1.stderr b/src/test/ui/nll/user-annotations/constant-in-expr-inherent-1.stderr
new file mode 100644
index 00000000000..94fbe017724
--- /dev/null
+++ b/src/test/ui/nll/user-annotations/constant-in-expr-inherent-1.stderr
@@ -0,0 +1,10 @@
+error: unsatisfied lifetime constraints
+  --> $DIR/constant-in-expr-inherent-1.rs:10:5
+   |
+LL | fn foo<'a>(_: &'a u32) -> &'static u32 {
+   |        -- lifetime `'a` defined here
+LL |     <Foo<'a>>::C //~ ERROR
+   |     ^^^^^^^^^^^^ returning this value requires that `'a` must outlive `'static`
+
+error: aborting due to previous error
+
diff --git a/src/test/ui/nll/user-annotations/constant-in-expr-normalize.rs b/src/test/ui/nll/user-annotations/constant-in-expr-normalize.rs
new file mode 100644
index 00000000000..4292fc710e9
--- /dev/null
+++ b/src/test/ui/nll/user-annotations/constant-in-expr-normalize.rs
@@ -0,0 +1,24 @@
+#![feature(nll)]
+
+trait Mirror {
+    type Me;
+}
+
+impl<T> Mirror for T {
+    type Me = T;
+}
+
+trait Foo<'a> {
+    const C: <&'a u32 as Mirror>::Me;
+}
+
+impl<'a, T> Foo<'a> for T {
+    const C: &'a u32 = &22;
+}
+
+fn foo<'a>(_: &'a u32) -> &'static u32 {
+    <() as Foo<'a>>::C //~ ERROR
+}
+
+fn main() {
+}
diff --git a/src/test/ui/nll/user-annotations/constant-in-expr-normalize.stderr b/src/test/ui/nll/user-annotations/constant-in-expr-normalize.stderr
new file mode 100644
index 00000000000..7aeb276eeb9
--- /dev/null
+++ b/src/test/ui/nll/user-annotations/constant-in-expr-normalize.stderr
@@ -0,0 +1,10 @@
+error: unsatisfied lifetime constraints
+  --> $DIR/constant-in-expr-normalize.rs:20:5
+   |
+LL | fn foo<'a>(_: &'a u32) -> &'static u32 {
+   |        -- lifetime `'a` defined here
+LL |     <() as Foo<'a>>::C //~ ERROR
+   |     ^^^^^^^^^^^^^^^^^^ returning this value requires that `'a` must outlive `'static`
+
+error: aborting due to previous error
+
diff --git a/src/test/ui/nll/user-annotations/constant-in-expr-trait-item-1.rs b/src/test/ui/nll/user-annotations/constant-in-expr-trait-item-1.rs
new file mode 100644
index 00000000000..daa0d7bc241
--- /dev/null
+++ b/src/test/ui/nll/user-annotations/constant-in-expr-trait-item-1.rs
@@ -0,0 +1,16 @@
+#![feature(nll)]
+
+trait Foo<'a> {
+    const C: &'a u32;
+}
+
+impl<'a, T> Foo<'a> for T {
+    const C: &'a u32 = &22;
+}
+
+fn foo<'a>(_: &'a u32) -> &'static u32 {
+    <() as Foo<'a>>::C //~ ERROR
+}
+
+fn main() {
+}
diff --git a/src/test/ui/nll/user-annotations/constant-in-expr-trait-item-1.stderr b/src/test/ui/nll/user-annotations/constant-in-expr-trait-item-1.stderr
new file mode 100644
index 00000000000..fee9abc1ed8
--- /dev/null
+++ b/src/test/ui/nll/user-annotations/constant-in-expr-trait-item-1.stderr
@@ -0,0 +1,10 @@
+error: unsatisfied lifetime constraints
+  --> $DIR/constant-in-expr-trait-item-1.rs:12:5
+   |
+LL | fn foo<'a>(_: &'a u32) -> &'static u32 {
+   |        -- lifetime `'a` defined here
+LL |     <() as Foo<'a>>::C //~ ERROR
+   |     ^^^^^^^^^^^^^^^^^^ returning this value requires that `'a` must outlive `'static`
+
+error: aborting due to previous error
+
diff --git a/src/test/ui/nll/user-annotations/constant-in-expr-trait-item-2.rs b/src/test/ui/nll/user-annotations/constant-in-expr-trait-item-2.rs
new file mode 100644
index 00000000000..cd66e7a49cb
--- /dev/null
+++ b/src/test/ui/nll/user-annotations/constant-in-expr-trait-item-2.rs
@@ -0,0 +1,16 @@
+#![feature(nll)]
+
+trait Foo<'a> {
+    const C: &'a u32;
+}
+
+impl<'a, T> Foo<'a> for T {
+    const C: &'a u32 = &22;
+}
+
+fn foo<'a, T: Foo<'a>>() -> &'static u32 {
+    <T as Foo<'a>>::C //~ ERROR
+}
+
+fn main() {
+}
diff --git a/src/test/ui/nll/user-annotations/constant-in-expr-trait-item-2.stderr b/src/test/ui/nll/user-annotations/constant-in-expr-trait-item-2.stderr
new file mode 100644
index 00000000000..047aad98319
--- /dev/null
+++ b/src/test/ui/nll/user-annotations/constant-in-expr-trait-item-2.stderr
@@ -0,0 +1,10 @@
+error: unsatisfied lifetime constraints
+  --> $DIR/constant-in-expr-trait-item-2.rs:12:5
+   |
+LL | fn foo<'a, T: Foo<'a>>() -> &'static u32 {
+   |        -- lifetime `'a` defined here
+LL |     <T as Foo<'a>>::C //~ ERROR
+   |     ^^^^^^^^^^^^^^^^^ returning this value requires that `'a` must outlive `'static`
+
+error: aborting due to previous error
+
diff --git a/src/test/ui/nll/user-annotations/constant-in-expr-trait-item-3.rs b/src/test/ui/nll/user-annotations/constant-in-expr-trait-item-3.rs
new file mode 100644
index 00000000000..f83ae2438e6
--- /dev/null
+++ b/src/test/ui/nll/user-annotations/constant-in-expr-trait-item-3.rs
@@ -0,0 +1,16 @@
+#![feature(nll)]
+
+trait Foo<'a> {
+    const C: &'a u32;
+}
+
+impl<'a, T> Foo<'a> for T {
+    const C: &'a u32 = &22;
+}
+
+fn foo<'a, T: Foo<'a>>() -> &'static u32 {
+    T::C //~ ERROR
+}
+
+fn main() {
+}
diff --git a/src/test/ui/nll/user-annotations/constant-in-expr-trait-item-3.stderr b/src/test/ui/nll/user-annotations/constant-in-expr-trait-item-3.stderr
new file mode 100644
index 00000000000..b373cebacb0
--- /dev/null
+++ b/src/test/ui/nll/user-annotations/constant-in-expr-trait-item-3.stderr
@@ -0,0 +1,10 @@
+error: unsatisfied lifetime constraints
+  --> $DIR/constant-in-expr-trait-item-3.rs:12:5
+   |
+LL | fn foo<'a, T: Foo<'a>>() -> &'static u32 {
+   |        -- lifetime `'a` defined here
+LL |     T::C //~ ERROR
+   |     ^^^^ returning this value requires that `'a` must outlive `'static`
+
+error: aborting due to previous error
+
diff --git a/src/test/ui/nll/user-annotations/normalization.rs b/src/test/ui/nll/user-annotations/normalization.rs
new file mode 100644
index 00000000000..51d9adccd73
--- /dev/null
+++ b/src/test/ui/nll/user-annotations/normalization.rs
@@ -0,0 +1,13 @@
+// Test that we enforce a `&'static` requirement that is only visible
+// after normalization.
+
+#![feature(nll)]
+#![ignore(unused)]
+
+trait Foo { type Out; }
+impl Foo for () { type Out = &'static u32; }
+
+fn main() {
+    let a = 22;
+    let b: <() as Foo>::Out = &a; //~ ERROR
+}
diff --git a/src/test/ui/nll/user-annotations/normalization.stderr b/src/test/ui/nll/user-annotations/normalization.stderr
new file mode 100644
index 00000000000..489f9feb044
--- /dev/null
+++ b/src/test/ui/nll/user-annotations/normalization.stderr
@@ -0,0 +1,13 @@
+error[E0597]: `a` does not live long enough
+  --> $DIR/normalization.rs:12:31
+   |
+LL |     let b: <() as Foo>::Out = &a; //~ 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: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0597`.
diff --git a/src/test/ui/nll/user-annotations/normalize-self-ty.rs b/src/test/ui/nll/user-annotations/normalize-self-ty.rs
new file mode 100644
index 00000000000..d97cc88dd9a
--- /dev/null
+++ b/src/test/ui/nll/user-annotations/normalize-self-ty.rs
@@ -0,0 +1,25 @@
+// Regression test for #55183: check a case where the self type from
+// the inherent impl requires normalization to be equal to the
+// user-provided type.
+//
+// run-pass
+
+#![feature(nll)]
+
+trait Mirror {
+    type Me;
+}
+
+impl<T> Mirror for T {
+    type Me = T;
+}
+
+struct Foo<A, B>(A, B);
+
+impl<A> Foo<A, <A as Mirror>::Me> {
+    fn m(b: A) { }
+}
+
+fn main() {
+    <Foo<&'static u32, &u32>>::m(&22);
+}