about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--src/librustc/ich/impls_ty.rs5
-rw-r--r--src/librustc/infer/canonical/canonicalizer.rs116
-rw-r--r--src/librustc/infer/canonical/mod.rs125
-rw-r--r--src/librustc/infer/canonical/query_response.rs32
-rw-r--r--src/librustc/infer/glb.rs24
-rw-r--r--src/librustc/infer/higher_ranked/mod.rs256
-rw-r--r--src/librustc/infer/lub.rs24
-rw-r--r--src/librustc/traits/query/type_op/implied_outlives_bounds.rs20
-rw-r--r--src/librustc/traits/query/type_op/outlives.rs16
-rw-r--r--src/librustc/traits/select.rs20
-rw-r--r--src/librustc/ty/error.rs11
-rw-r--r--src/librustc/ty/mod.rs11
-rw-r--r--src/librustc/ty/structural_impls.rs2
-rw-r--r--src/librustc_mir/borrow_check/nll/mod.rs6
-rw-r--r--src/librustc_mir/borrow_check/nll/region_infer/error_reporting/mod.rs360
-rw-r--r--src/librustc_mir/borrow_check/nll/region_infer/mod.rs17
-rw-r--r--src/librustc_mir/borrow_check/nll/type_check/constraint_conversion.rs54
-rw-r--r--src/librustc_mir/borrow_check/nll/type_check/free_region_relations.rs5
-rw-r--r--src/librustc_mir/borrow_check/nll/type_check/mod.rs54
-rw-r--r--src/librustc_mir/borrow_check/nll/type_check/relate_tys.rs14
-rw-r--r--src/librustc_typeck/check/closure.rs30
-rw-r--r--src/librustc_typeck/check/mod.rs6
-rw-r--r--src/test/mir-opt/basic_assignment.rs2
-rw-r--r--src/test/ui/lub-glb/old-lub-glb-hr.stderr2
-rw-r--r--src/test/ui/lub-glb/old-lub-glb-object.stderr2
-rw-r--r--src/test/ui/nll/user-annotations/dump-adt-brace-struct.stderr2
-rw-r--r--src/test/ui/nll/user-annotations/dump-fn-method.stderr8
27 files changed, 667 insertions, 557 deletions
diff --git a/src/librustc/ich/impls_ty.rs b/src/librustc/ich/impls_ty.rs
index 8f837327ddb..0c93b86ee4d 100644
--- a/src/librustc/ich/impls_ty.rs
+++ b/src/librustc/ich/impls_ty.rs
@@ -1229,7 +1229,7 @@ for traits::VtableGeneratorData<'gcx, N> where N: HashStable<StableHashingContex
 
 impl_stable_hash_for!(
     impl<'tcx, V> for struct infer::canonical::Canonical<'tcx, V> {
-        variables, value
+        max_universe, variables, value
     }
 );
 
@@ -1245,7 +1245,8 @@ impl_stable_hash_for!(struct infer::canonical::CanonicalVarInfo {
 
 impl_stable_hash_for!(enum infer::canonical::CanonicalVarKind {
     Ty(k),
-    Region
+    Region(ui),
+    PlaceholderRegion(placeholder),
 });
 
 impl_stable_hash_for!(enum infer::canonical::CanonicalTyVarKind {
diff --git a/src/librustc/infer/canonical/canonicalizer.rs b/src/librustc/infer/canonical/canonicalizer.rs
index 2b085a3407c..cc6e4df0710 100644
--- a/src/librustc/infer/canonical/canonicalizer.rs
+++ b/src/librustc/infer/canonical/canonicalizer.rs
@@ -107,6 +107,20 @@ impl<'cx, 'gcx, 'tcx> InferCtxt<'cx, 'gcx, 'tcx> {
         )
     }
 
+    pub fn canonicalize_user_type_annotation<V>(&self, value: &V) -> Canonicalized<'gcx, V>
+    where
+        V: TypeFoldable<'tcx> + Lift<'gcx>,
+    {
+        let mut query_state = OriginalQueryValues::default();
+        Canonicalizer::canonicalize(
+            value,
+            Some(self),
+            self.tcx,
+            &CanonicalizeUserTypeAnnotation,
+            &mut query_state,
+        )
+    }
+
     /// A hacky variant of `canonicalize_query` that does not
     /// canonicalize `'static`.  Unfortunately, the existing leak
     /// check treaks `'static` differently in some cases (see also
@@ -162,11 +176,26 @@ struct CanonicalizeQueryResponse;
 impl CanonicalizeRegionMode for CanonicalizeQueryResponse {
     fn canonicalize_free_region(
         &self,
-        _canonicalizer: &mut Canonicalizer<'_, '_, 'tcx>,
+        canonicalizer: &mut Canonicalizer<'_, '_, 'tcx>,
         r: ty::Region<'tcx>,
     ) -> ty::Region<'tcx> {
         match r {
             ty::ReFree(_) | ty::ReEmpty | ty::ReErased | ty::ReStatic | ty::ReEarlyBound(..) => r,
+            ty::RePlaceholder(placeholder) => canonicalizer.canonical_var_for_region(
+                CanonicalVarInfo {
+                    kind: CanonicalVarKind::PlaceholderRegion(*placeholder),
+                },
+                r,
+            ),
+            ty::ReVar(vid) => {
+                let universe = canonicalizer.region_var_universe(*vid);
+                canonicalizer.canonical_var_for_region(
+                    CanonicalVarInfo {
+                        kind: CanonicalVarKind::Region(universe),
+                    },
+                    r,
+                )
+            }
             _ => {
                 // Other than `'static` or `'empty`, the query
                 // response should be executing in a fully
@@ -182,6 +211,29 @@ impl CanonicalizeRegionMode for CanonicalizeQueryResponse {
     }
 }
 
+struct CanonicalizeUserTypeAnnotation;
+
+impl CanonicalizeRegionMode for CanonicalizeUserTypeAnnotation {
+    fn canonicalize_free_region(
+        &self,
+        canonicalizer: &mut Canonicalizer<'_, '_, 'tcx>,
+        r: ty::Region<'tcx>,
+    ) -> ty::Region<'tcx> {
+        match r {
+            ty::ReEarlyBound(_) | ty::ReFree(_) | ty::ReErased | ty::ReEmpty | ty::ReStatic => r,
+            ty::ReVar(_) => canonicalizer.canonical_var_for_region_in_root_universe(r),
+            _ => {
+                // We only expect region names that the user can type.
+                bug!("unexpected region in query response: `{:?}`", r)
+            }
+        }
+    }
+
+    fn any(&self) -> bool {
+        false
+    }
+}
+
 struct CanonicalizeAllFreeRegions;
 
 impl CanonicalizeRegionMode for CanonicalizeAllFreeRegions {
@@ -190,7 +242,7 @@ impl CanonicalizeRegionMode for CanonicalizeAllFreeRegions {
         canonicalizer: &mut Canonicalizer<'_, '_, 'tcx>,
         r: ty::Region<'tcx>,
     ) -> ty::Region<'tcx> {
-        canonicalizer.canonical_var_for_region(r)
+        canonicalizer.canonical_var_for_region_in_root_universe(r)
     }
 
     fn any(&self) -> bool {
@@ -209,7 +261,7 @@ impl CanonicalizeRegionMode for CanonicalizeFreeRegionsOtherThanStatic {
         if let ty::ReStatic = r {
             r
         } else {
-            canonicalizer.canonical_var_for_region(r)
+            canonicalizer.canonical_var_for_region_in_root_universe(r)
         }
     }
 
@@ -252,7 +304,8 @@ impl<'cx, 'gcx, 'tcx> TypeFolder<'gcx, 'tcx> for Canonicalizer<'cx, 'gcx, 'tcx>
                      opportunistically resolved to {:?}",
                     vid, r
                 );
-                self.canonical_var_for_region(r)
+                self.canonicalize_region_mode
+                    .canonicalize_free_region(self, r)
             }
 
             ty::ReStatic
@@ -261,7 +314,8 @@ impl<'cx, 'gcx, 'tcx> TypeFolder<'gcx, 'tcx> for Canonicalizer<'cx, 'gcx, 'tcx>
             | ty::ReScope(_)
             | ty::RePlaceholder(..)
             | ty::ReEmpty
-            | ty::ReErased => self.canonicalize_region_mode.canonicalize_free_region(self, r),
+            | ty::ReErased => self.canonicalize_region_mode
+                .canonicalize_free_region(self, r),
 
             ty::ReClosureBound(..) | ty::ReCanonical(_) => {
                 bug!("canonical region encountered during canonicalization")
@@ -353,6 +407,7 @@ impl<'cx, 'gcx, 'tcx> Canonicalizer<'cx, 'gcx, 'tcx> {
         if !value.has_type_flags(needs_canonical_flags) {
             let out_value = gcx.lift(value).unwrap();
             let canon_value = Canonical {
+                max_universe: ty::UniverseIndex::ROOT,
                 variables: List::empty(),
                 value: out_value,
             };
@@ -383,7 +438,14 @@ impl<'cx, 'gcx, 'tcx> Canonicalizer<'cx, 'gcx, 'tcx> {
 
         let canonical_variables = tcx.intern_canonical_var_infos(&canonicalizer.variables);
 
+        let max_universe = canonical_variables
+            .iter()
+            .map(|cvar| cvar.universe())
+            .max()
+            .unwrap_or(ty::UniverseIndex::ROOT);
+
         Canonical {
+            max_universe,
             variables: canonical_variables,
             value: out_value,
         }
@@ -450,10 +512,46 @@ impl<'cx, 'gcx, 'tcx> Canonicalizer<'cx, 'gcx, 'tcx> {
         }
     }
 
-    fn canonical_var_for_region(&mut self, r: ty::Region<'tcx>) -> ty::Region<'tcx> {
-        let info = CanonicalVarInfo {
-            kind: CanonicalVarKind::Region,
-        };
+    /// Shorthand helper that creates a canonical region variable for
+    /// `r` (always in the root universe). The reason that we always
+    /// put these variables into the root universe is because this
+    /// method is used during **query construction:** in that case, we
+    /// are taking all the regions and just putting them into the most
+    /// generic context we can. This may generate solutions that don't
+    /// fit (e.g., that equate some region variable with a placeholder
+    /// it can't name) on the caller side, but that's ok, the caller
+    /// can figure that out. In the meantime, it maximizes our
+    /// caching.
+    ///
+    /// (This works because unification never fails -- and hence trait
+    /// selection is never affected -- due to a universe mismatch.)
+    fn canonical_var_for_region_in_root_universe(
+        &mut self,
+        r: ty::Region<'tcx>,
+    ) -> ty::Region<'tcx> {
+        self.canonical_var_for_region(
+            CanonicalVarInfo {
+                kind: CanonicalVarKind::Region(ty::UniverseIndex::ROOT),
+            },
+            r,
+        )
+    }
+
+    /// Returns the universe in which `vid` is defined.
+    fn region_var_universe(&self, vid: ty::RegionVid) -> ty::UniverseIndex {
+        self.infcx
+            .unwrap()
+            .borrow_region_constraints()
+            .var_universe(vid)
+    }
+
+    /// Create a canonical variable (with the given `info`)
+    /// representing the region `r`; return a region referencing it.
+    fn canonical_var_for_region(
+        &mut self,
+        info: CanonicalVarInfo,
+        r: ty::Region<'tcx>,
+    ) -> ty::Region<'tcx> {
         let b = self.canonical_var(info, r.into());
         debug_assert_eq!(ty::INNERMOST, b.level);
         self.tcx().mk_region(ty::ReCanonical(b.var))
diff --git a/src/librustc/infer/canonical/mod.rs b/src/librustc/infer/canonical/mod.rs
index e3bd407d17a..f2b7c6e0d0d 100644
--- a/src/librustc/infer/canonical/mod.rs
+++ b/src/librustc/infer/canonical/mod.rs
@@ -33,14 +33,14 @@
 
 use infer::{InferCtxt, RegionVariableOrigin, TypeVariableOrigin};
 use rustc_data_structures::indexed_vec::IndexVec;
-use smallvec::SmallVec;
 use rustc_data_structures::sync::Lrc;
 use serialize::UseSpecializedDecodable;
+use smallvec::SmallVec;
 use std::ops::Index;
 use syntax::source_map::Span;
 use ty::fold::TypeFoldable;
 use ty::subst::Kind;
-use ty::{self, BoundTyIndex, Lift, Region, List, TyCtxt};
+use ty::{self, BoundTyIndex, Lift, List, Region, TyCtxt};
 
 mod canonicalizer;
 
@@ -53,6 +53,7 @@ mod substitute;
 /// numbered starting from 0 in order of first appearance.
 #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, RustcDecodable, RustcEncodable)]
 pub struct Canonical<'gcx, V> {
+    pub max_universe: ty::UniverseIndex,
     pub variables: CanonicalVarInfos<'gcx>,
     pub value: V,
 }
@@ -79,13 +80,31 @@ pub struct CanonicalVarValues<'tcx> {
 /// various parts of it with canonical variables. This struct stores
 /// those replaced bits to remember for when we process the query
 /// result.
-#[derive(Clone, Debug, Default, PartialEq, Eq, Hash, RustcDecodable, RustcEncodable)]
+#[derive(Clone, Debug, PartialEq, Eq, Hash, RustcDecodable, RustcEncodable)]
 pub struct OriginalQueryValues<'tcx> {
+    /// Map from the universes that appear in the query to the
+    /// universes in the caller context. For the time being, we only
+    /// ever put ROOT values into the query, so this map is very
+    /// simple.
+    pub universe_map: SmallVec<[ty::UniverseIndex; 4]>,
+
     /// This is equivalent to `CanonicalVarValues`, but using a
     /// `SmallVec` yields a significant performance win.
     pub var_values: SmallVec<[Kind<'tcx>; 8]>,
 }
 
+impl Default for OriginalQueryValues<'tcx> {
+    fn default() -> Self {
+        let mut universe_map = SmallVec::default();
+        universe_map.push(ty::UniverseIndex::ROOT);
+
+        Self {
+            universe_map,
+            var_values: SmallVec::default(),
+        }
+    }
+}
+
 /// Information about a canonical variable that is included with the
 /// canonical value. This is sufficient information for code to create
 /// a copy of the canonical value in some other inference context,
@@ -95,6 +114,20 @@ pub struct CanonicalVarInfo {
     pub kind: CanonicalVarKind,
 }
 
+impl CanonicalVarInfo {
+    pub fn universe(&self) -> ty::UniverseIndex {
+        self.kind.universe()
+    }
+
+    pub fn is_existential(&self) -> bool {
+        match self.kind {
+            CanonicalVarKind::Ty(_) => true,
+            CanonicalVarKind::Region(_) => true,
+            CanonicalVarKind::PlaceholderRegion(..) => false,
+        }
+    }
+}
+
 /// 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.
@@ -104,7 +137,27 @@ pub enum CanonicalVarKind {
     Ty(CanonicalTyVarKind),
 
     /// Region variable `'?R`.
-    Region,
+    Region(ty::UniverseIndex),
+
+    /// A "placeholder" that represents "any region". Created when you
+    /// are solving a goal like `for<'a> T: Foo<'a>` to represent the
+    /// bound region `'a`.
+    PlaceholderRegion(ty::Placeholder),
+}
+
+impl CanonicalVarKind {
+    pub fn universe(self) -> ty::UniverseIndex {
+        match self {
+            // At present, we don't support higher-ranked
+            // quantification over types, so all type variables are in
+            // the root universe.
+            CanonicalVarKind::Ty(_) => ty::UniverseIndex::ROOT,
+
+            // Region variables can be created in sub-universes.
+            CanonicalVarKind::Region(ui) => ui,
+            CanonicalVarKind::PlaceholderRegion(placeholder) => placeholder.universe,
+        }
+    }
 }
 
 /// Rust actually has more than one category of type variables;
@@ -220,8 +273,16 @@ impl<'gcx, V> Canonical<'gcx, V> {
     /// let b: Canonical<'tcx, (T, Ty<'tcx>)> = a.unchecked_map(|v| (v, ty));
     /// ```
     pub fn unchecked_map<W>(self, map_op: impl FnOnce(V) -> W) -> Canonical<'gcx, W> {
-        let Canonical { variables, value } = self;
-        Canonical { variables, value: map_op(value) }
+        let Canonical {
+            max_universe,
+            variables,
+            value,
+        } = self;
+        Canonical {
+            max_universe,
+            variables,
+            value: map_op(value),
+        }
     }
 }
 
@@ -249,35 +310,50 @@ impl<'cx, 'gcx, 'tcx> InferCtxt<'cx, 'gcx, 'tcx> {
     where
         T: TypeFoldable<'tcx>,
     {
+        // For each universe that is referred to in the incoming
+        // query, create a universe in our local inference context. In
+        // practice, as of this writing, all queries have no universes
+        // in them, so this code has no effect, but it is looking
+        // forward to the day when we *do* want to carry universes
+        // through into queries.
+        let universes: IndexVec<ty::UniverseIndex, _> = std::iter::once(ty::UniverseIndex::ROOT)
+            .chain((0..canonical.max_universe.as_u32()).map(|_| self.create_next_universe()))
+            .collect();
+
         let canonical_inference_vars =
-            self.fresh_inference_vars_for_canonical_vars(span, canonical.variables);
+            self.instantiate_canonical_vars(span, canonical.variables, |ui| universes[ui]);
         let result = canonical.substitute(self.tcx, &canonical_inference_vars);
         (result, canonical_inference_vars)
     }
 
     /// Given the "infos" about the canonical variables from some
-    /// canonical, creates fresh inference variables with the same
-    /// characteristics. You can then use `substitute` to instantiate
-    /// the canonical variable with these inference variables.
-    fn fresh_inference_vars_for_canonical_vars(
+    /// canonical, creates fresh variables with the same
+    /// characteristics (see `instantiate_canonical_var` for
+    /// details). You can then use `substitute` to instantiate the
+    /// canonical variable with these inference variables.
+    fn instantiate_canonical_vars(
         &self,
         span: Span,
         variables: &List<CanonicalVarInfo>,
+        universe_map: impl Fn(ty::UniverseIndex) -> ty::UniverseIndex,
     ) -> CanonicalVarValues<'tcx> {
         let var_values: IndexVec<BoundTyIndex, Kind<'tcx>> = variables
             .iter()
-            .map(|info| self.fresh_inference_var_for_canonical_var(span, *info))
+            .map(|info| self.instantiate_canonical_var(span, *info, &universe_map))
             .collect();
 
         CanonicalVarValues { var_values }
     }
 
     /// Given the "info" about a canonical variable, creates a fresh
-    /// inference variable with the same characteristics.
-    fn fresh_inference_var_for_canonical_var(
+    /// variable for it. If this is an existentially quantified
+    /// variable, then you'll get a new inference variable; if it is a
+    /// universally quantified variable, you get a placeholder.
+    fn instantiate_canonical_var(
         &self,
         span: Span,
         cv_info: CanonicalVarInfo,
+        universe_map: impl Fn(ty::UniverseIndex) -> ty::UniverseIndex,
     ) -> Kind<'tcx> {
         match cv_info.kind {
             CanonicalVarKind::Ty(ty_kind) => {
@@ -293,9 +369,21 @@ impl<'cx, 'gcx, 'tcx> InferCtxt<'cx, 'gcx, 'tcx> {
                 ty.into()
             }
 
-            CanonicalVarKind::Region => self
-                .next_region_var(RegionVariableOrigin::MiscVariable(span))
-                .into(),
+            CanonicalVarKind::Region(ui) => self.next_region_var_in_universe(
+                RegionVariableOrigin::MiscVariable(span),
+                universe_map(ui),
+            ).into(),
+
+            CanonicalVarKind::PlaceholderRegion(ty::Placeholder { universe, name }) => {
+                let universe_mapped = universe_map(universe);
+                let placeholder_mapped = ty::Placeholder {
+                    universe: universe_mapped,
+                    name,
+                };
+                self.tcx
+                    .mk_region(ty::RePlaceholder(placeholder_mapped))
+                    .into()
+            }
         }
     }
 }
@@ -314,6 +402,7 @@ CloneTypeFoldableImpls! {
 
 BraceStructTypeFoldableImpl! {
     impl<'tcx, C> TypeFoldable<'tcx> for Canonical<'tcx, C> {
+        max_universe,
         variables,
         value,
     } where C: TypeFoldable<'tcx>
@@ -322,7 +411,7 @@ BraceStructTypeFoldableImpl! {
 BraceStructLiftImpl! {
     impl<'a, 'tcx, T> Lift<'tcx> for Canonical<'a, T> {
         type Lifted = Canonical<'tcx, T::Lifted>;
-        variables, value
+        max_universe, variables, value
     } where T: Lift<'tcx>
 }
 
diff --git a/src/librustc/infer/canonical/query_response.rs b/src/librustc/infer/canonical/query_response.rs
index 38788186eb0..b3ce5eb7e56 100644
--- a/src/librustc/infer/canonical/query_response.rs
+++ b/src/librustc/infer/canonical/query_response.rs
@@ -394,6 +394,21 @@ impl<'cx, 'gcx, 'tcx> InferCtxt<'cx, 'gcx, 'tcx> {
             original_values, query_response,
         );
 
+        // For each new universe created in the query result that did
+        // not appear in the original query, create a local
+        // superuniverse.
+        let mut universe_map = original_values.universe_map.clone();
+        let num_universes_in_query = original_values.universe_map.len();
+        let num_universes_in_response = query_response.max_universe.as_usize() + 1;
+        for _ in num_universes_in_query..num_universes_in_response {
+            universe_map.push(self.create_next_universe());
+        }
+        assert!(universe_map.len() >= 1); // always have the root universe
+        assert_eq!(
+            universe_map[ty::UniverseIndex::ROOT.as_usize()],
+            ty::UniverseIndex::ROOT
+        );
+
         // Every canonical query result includes values for each of
         // the inputs to the query. Therefore, we begin by unifying
         // these values with the original inputs that were
@@ -440,9 +455,20 @@ impl<'cx, 'gcx, 'tcx> InferCtxt<'cx, 'gcx, 'tcx> {
                 .variables
                 .iter()
                 .enumerate()
-                .map(|(index, info)| opt_values[BoundTyIndex::new(index)].unwrap_or_else(||
-                    self.fresh_inference_var_for_canonical_var(cause.span, *info)
-                ))
+                .map(|(index, info)| {
+                    if info.is_existential() {
+                        match opt_values[BoundTyIndex::new(index)] {
+                            Some(k) => k,
+                            None => self.instantiate_canonical_var(cause.span, *info, |u| {
+                                universe_map[u.as_usize()]
+                            }),
+                        }
+                    } else {
+                        self.instantiate_canonical_var(cause.span, *info, |u| {
+                            universe_map[u.as_usize()]
+                        })
+                    }
+                })
                 .collect(),
         };
 
diff --git a/src/librustc/infer/glb.rs b/src/librustc/infer/glb.rs
index fd14e0e40e2..8968c5949b6 100644
--- a/src/librustc/infer/glb.rs
+++ b/src/librustc/infer/glb.rs
@@ -15,7 +15,6 @@ use super::Subtype;
 
 use traits::ObligationCause;
 use ty::{self, Ty, TyCtxt};
-use ty::error::TypeError;
 use ty::relate::{Relate, RelateResult, TypeRelation};
 
 /// "Greatest lower bound" (common subtype)
@@ -76,31 +75,12 @@ impl<'combine, 'infcx, 'gcx, 'tcx> TypeRelation<'infcx, 'gcx, 'tcx>
         where T: Relate<'tcx>
     {
         debug!("binders(a={:?}, b={:?})", a, b);
-        let was_error = self.infcx().probe(|_snapshot| {
-            // Subtle: use a fresh combine-fields here because we recover
-            // from Err. Doing otherwise could propagate obligations out
-            // through our `self.obligations` field.
-            self.infcx()
-                .combine_fields(self.fields.trace.clone(), self.fields.param_env)
-                .higher_ranked_glb(a, b, self.a_is_expected)
-                .is_err()
-        });
-        debug!("binders: was_error={:?}", was_error);
 
         // When higher-ranked types are involved, computing the LUB is
         // very challenging, switch to invariance. This is obviously
         // overly conservative but works ok in practice.
-        match self.relate_with_variance(ty::Variance::Invariant, a, b) {
-            Ok(_) => Ok(a.clone()),
-            Err(err) => {
-                debug!("binders: error occurred, was_error={:?}", was_error);
-                if !was_error {
-                    Err(TypeError::OldStyleLUB(Box::new(err)))
-                } else {
-                    Err(err)
-                }
-            }
-        }
+        self.relate_with_variance(ty::Variance::Invariant, a, b)?;
+        Ok(a.clone())
     }
 }
 
diff --git a/src/librustc/infer/higher_ranked/mod.rs b/src/librustc/infer/higher_ranked/mod.rs
index d85a3e84f85..3e08a4e021a 100644
--- a/src/librustc/infer/higher_ranked/mod.rs
+++ b/src/librustc/infer/higher_ranked/mod.rs
@@ -22,7 +22,6 @@ use super::region_constraints::{TaintDirections};
 use ty::{self, TyCtxt, Binder, TypeFoldable};
 use ty::error::TypeError;
 use ty::relate::{Relate, RelateResult, TypeRelation};
-use std::collections::BTreeMap;
 use syntax_pos::Span;
 use util::nodemap::{FxHashMap, FxHashSet};
 
@@ -202,261 +201,6 @@ impl<'a, 'gcx, 'tcx> CombineFields<'a, 'gcx, 'tcx> {
             Ok(HrMatchResult { value: a_value })
         });
     }
-
-    pub fn higher_ranked_lub<T>(&mut self, a: &Binder<T>, b: &Binder<T>, a_is_expected: bool)
-                                -> RelateResult<'tcx, Binder<T>>
-        where T: Relate<'tcx>
-    {
-        // Start a snapshot so we can examine "all bindings that were
-        // created as part of this type comparison".
-        return self.infcx.commit_if_ok(|snapshot| {
-            // Instantiate each bound region with a fresh region variable.
-            let span = self.trace.cause.span;
-            let (a_with_fresh, a_map) =
-                self.infcx.replace_late_bound_regions_with_fresh_var(
-                    span, HigherRankedType, a);
-            let (b_with_fresh, _) =
-                self.infcx.replace_late_bound_regions_with_fresh_var(
-                    span, HigherRankedType, b);
-
-            // Collect constraints.
-            let result0 =
-                self.lub(a_is_expected).relate(&a_with_fresh, &b_with_fresh)?;
-            let result0 =
-                self.infcx.resolve_type_vars_if_possible(&result0);
-            debug!("lub result0 = {:?}", result0);
-
-            // Generalize the regions appearing in result0 if possible
-            let new_vars = self.infcx.region_vars_confined_to_snapshot(snapshot);
-            let span = self.trace.cause.span;
-            let result1 =
-                fold_regions_in(
-                    self.tcx(),
-                    &result0,
-                    |r, debruijn| generalize_region(self.infcx, span, snapshot, debruijn,
-                                                    &new_vars, &a_map, r));
-
-            debug!("lub({:?},{:?}) = {:?}",
-                   a,
-                   b,
-                   result1);
-
-            Ok(ty::Binder::bind(result1))
-        });
-
-        fn generalize_region<'a, 'gcx, 'tcx>(infcx: &InferCtxt<'a, 'gcx, 'tcx>,
-                                             span: Span,
-                                             snapshot: &CombinedSnapshot<'a, 'tcx>,
-                                             debruijn: ty::DebruijnIndex,
-                                             new_vars: &[ty::RegionVid],
-                                             a_map: &BTreeMap<ty::BoundRegion, ty::Region<'tcx>>,
-                                             r0: ty::Region<'tcx>)
-                                             -> ty::Region<'tcx> {
-            // Regions that pre-dated the LUB computation stay as they are.
-            if !is_var_in_set(new_vars, r0) {
-                assert!(!r0.is_late_bound());
-                debug!("generalize_region(r0={:?}): not new variable", r0);
-                return r0;
-            }
-
-            let tainted = infcx.tainted_regions(snapshot, r0, TaintDirections::both());
-
-            // Variables created during LUB computation which are
-            // *related* to regions that pre-date the LUB computation
-            // stay as they are.
-            if !tainted.iter().all(|&r| is_var_in_set(new_vars, r)) {
-                debug!("generalize_region(r0={:?}): \
-                        non-new-variables found in {:?}",
-                       r0, tainted);
-                assert!(!r0.is_late_bound());
-                return r0;
-            }
-
-            // Otherwise, the variable must be associated with at
-            // least one of the variables representing bound regions
-            // in both A and B.  Replace the variable with the "first"
-            // bound region from A that we find it to be associated
-            // with.
-            for (a_br, a_r) in a_map {
-                if tainted.iter().any(|x| x == a_r) {
-                    debug!("generalize_region(r0={:?}): \
-                            replacing with {:?}, tainted={:?}",
-                           r0, *a_br, tainted);
-                    return infcx.tcx.mk_region(ty::ReLateBound(debruijn, *a_br));
-                }
-            }
-
-            span_bug!(
-                span,
-                "region {:?} is not associated with any bound region from A!",
-                r0)
-        }
-    }
-
-    pub fn higher_ranked_glb<T>(&mut self, a: &Binder<T>, b: &Binder<T>, a_is_expected: bool)
-                                -> RelateResult<'tcx, Binder<T>>
-        where T: Relate<'tcx>
-    {
-        debug!("higher_ranked_glb({:?}, {:?})",
-               a, b);
-
-        // Make a snapshot so we can examine "all bindings that were
-        // created as part of this type comparison".
-        return self.infcx.commit_if_ok(|snapshot| {
-            // Instantiate each bound region with a fresh region variable.
-            let (a_with_fresh, a_map) =
-                self.infcx.replace_late_bound_regions_with_fresh_var(
-                    self.trace.cause.span, HigherRankedType, a);
-            let (b_with_fresh, b_map) =
-                self.infcx.replace_late_bound_regions_with_fresh_var(
-                    self.trace.cause.span, HigherRankedType, b);
-            let a_vars = var_ids(self, &a_map);
-            let b_vars = var_ids(self, &b_map);
-
-            // Collect constraints.
-            let result0 =
-                self.glb(a_is_expected).relate(&a_with_fresh, &b_with_fresh)?;
-            let result0 =
-                self.infcx.resolve_type_vars_if_possible(&result0);
-            debug!("glb result0 = {:?}", result0);
-
-            // Generalize the regions appearing in result0 if possible
-            let new_vars = self.infcx.region_vars_confined_to_snapshot(snapshot);
-            let span = self.trace.cause.span;
-            let result1 =
-                fold_regions_in(
-                    self.tcx(),
-                    &result0,
-                    |r, debruijn| generalize_region(self.infcx, span, snapshot, debruijn,
-                                                    &new_vars,
-                                                    &a_map, &a_vars, &b_vars,
-                                                    r));
-
-            debug!("glb({:?},{:?}) = {:?}",
-                   a,
-                   b,
-                   result1);
-
-            Ok(ty::Binder::bind(result1))
-        });
-
-        fn generalize_region<'a, 'gcx, 'tcx>(infcx: &InferCtxt<'a, 'gcx, 'tcx>,
-                                             span: Span,
-                                             snapshot: &CombinedSnapshot<'a, 'tcx>,
-                                             debruijn: ty::DebruijnIndex,
-                                             new_vars: &[ty::RegionVid],
-                                             a_map: &BTreeMap<ty::BoundRegion, ty::Region<'tcx>>,
-                                             a_vars: &[ty::RegionVid],
-                                             b_vars: &[ty::RegionVid],
-                                             r0: ty::Region<'tcx>)
-                                             -> ty::Region<'tcx> {
-            if !is_var_in_set(new_vars, r0) {
-                assert!(!r0.is_late_bound());
-                return r0;
-            }
-
-            let tainted = infcx.tainted_regions(snapshot, r0, TaintDirections::both());
-
-            let mut a_r = None;
-            let mut b_r = None;
-            let mut only_new_vars = true;
-            for r in &tainted {
-                if is_var_in_set(a_vars, *r) {
-                    if a_r.is_some() {
-                        return fresh_bound_variable(infcx, debruijn);
-                    } else {
-                        a_r = Some(*r);
-                    }
-                } else if is_var_in_set(b_vars, *r) {
-                    if b_r.is_some() {
-                        return fresh_bound_variable(infcx, debruijn);
-                    } else {
-                        b_r = Some(*r);
-                    }
-                } else if !is_var_in_set(new_vars, *r) {
-                    only_new_vars = false;
-                }
-            }
-
-            // NB---I do not believe this algorithm computes
-            // (necessarily) the GLB.  As written it can
-            // spuriously fail. In particular, if there is a case
-            // like: |fn(&a)| and fn(fn(&b)), where a and b are
-            // free, it will return fn(&c) where c = GLB(a,b).  If
-            // however this GLB is not defined, then the result is
-            // an error, even though something like
-            // "fn<X>(fn(&X))" where X is bound would be a
-            // subtype of both of those.
-            //
-            // The problem is that if we were to return a bound
-            // variable, we'd be computing a lower-bound, but not
-            // necessarily the *greatest* lower-bound.
-            //
-            // Unfortunately, this problem is non-trivial to solve,
-            // because we do not know at the time of computing the GLB
-            // whether a GLB(a,b) exists or not, because we haven't
-            // run region inference (or indeed, even fully computed
-            // the region hierarchy!). The current algorithm seems to
-            // works ok in practice.
-
-            if a_r.is_some() && b_r.is_some() && only_new_vars {
-                // Related to exactly one bound variable from each fn:
-                return rev_lookup(infcx, span, a_map, a_r.unwrap());
-            } else if a_r.is_none() && b_r.is_none() {
-                // Not related to bound variables from either fn:
-                assert!(!r0.is_late_bound());
-                return r0;
-            } else {
-                // Other:
-                return fresh_bound_variable(infcx, debruijn);
-            }
-        }
-
-        fn rev_lookup<'a, 'gcx, 'tcx>(infcx: &InferCtxt<'a, 'gcx, 'tcx>,
-                                      span: Span,
-                                      a_map: &BTreeMap<ty::BoundRegion, ty::Region<'tcx>>,
-                                      r: ty::Region<'tcx>) -> ty::Region<'tcx>
-        {
-            for (a_br, a_r) in a_map {
-                if *a_r == r {
-                    return infcx.tcx.mk_region(ty::ReLateBound(ty::INNERMOST, *a_br));
-                }
-            }
-            span_bug!(
-                span,
-                "could not find original bound region for {:?}",
-                r);
-        }
-
-        fn fresh_bound_variable<'a, 'gcx, 'tcx>(infcx: &InferCtxt<'a, 'gcx, 'tcx>,
-                                                debruijn: ty::DebruijnIndex)
-                                                -> ty::Region<'tcx> {
-            infcx.borrow_region_constraints().new_bound(infcx.tcx, debruijn)
-        }
-    }
-}
-
-fn var_ids<'a, 'gcx, 'tcx>(fields: &CombineFields<'a, 'gcx, 'tcx>,
-                           map: &BTreeMap<ty::BoundRegion, ty::Region<'tcx>>)
-                           -> Vec<ty::RegionVid> {
-    map.iter()
-       .map(|(_, &r)| match *r {
-           ty::ReVar(r) => { r }
-           _ => {
-               span_bug!(
-                   fields.trace.cause.span,
-                   "found non-region-vid: {:?}",
-                   r);
-           }
-       })
-       .collect()
-}
-
-fn is_var_in_set(new_vars: &[ty::RegionVid], r: ty::Region<'_>) -> bool {
-    match *r {
-        ty::ReVar(ref v) => new_vars.iter().any(|x| x == v),
-        _ => false
-    }
 }
 
 fn fold_regions_in<'a, 'gcx, 'tcx, T, F>(tcx: TyCtxt<'a, 'gcx, 'tcx>,
diff --git a/src/librustc/infer/lub.rs b/src/librustc/infer/lub.rs
index 55c7eef607b..8875b4169dd 100644
--- a/src/librustc/infer/lub.rs
+++ b/src/librustc/infer/lub.rs
@@ -15,7 +15,6 @@ use super::Subtype;
 
 use traits::ObligationCause;
 use ty::{self, Ty, TyCtxt};
-use ty::error::TypeError;
 use ty::relate::{Relate, RelateResult, TypeRelation};
 
 /// "Least upper bound" (common supertype)
@@ -76,31 +75,12 @@ impl<'combine, 'infcx, 'gcx, 'tcx> TypeRelation<'infcx, 'gcx, 'tcx>
         where T: Relate<'tcx>
     {
         debug!("binders(a={:?}, b={:?})", a, b);
-        let was_error = self.infcx().probe(|_snapshot| {
-            // Subtle: use a fresh combine-fields here because we recover
-            // from Err. Doing otherwise could propagate obligations out
-            // through our `self.obligations` field.
-            self.infcx()
-                .combine_fields(self.fields.trace.clone(), self.fields.param_env)
-                .higher_ranked_lub(a, b, self.a_is_expected)
-                .is_err()
-        });
-        debug!("binders: was_error={:?}", was_error);
 
         // When higher-ranked types are involved, computing the LUB is
         // very challenging, switch to invariance. This is obviously
         // overly conservative but works ok in practice.
-        match self.relate_with_variance(ty::Variance::Invariant, a, b) {
-            Ok(_) => Ok(a.clone()),
-            Err(err) => {
-                debug!("binders: error occurred, was_error={:?}", was_error);
-                if !was_error {
-                    Err(TypeError::OldStyleLUB(Box::new(err)))
-                } else {
-                    Err(err)
-                }
-            }
-        }
+        self.relate_with_variance(ty::Variance::Invariant, a, b)?;
+        Ok(a.clone())
     }
 }
 
diff --git a/src/librustc/traits/query/type_op/implied_outlives_bounds.rs b/src/librustc/traits/query/type_op/implied_outlives_bounds.rs
index b113a322d37..d5233851db8 100644
--- a/src/librustc/traits/query/type_op/implied_outlives_bounds.rs
+++ b/src/librustc/traits/query/type_op/implied_outlives_bounds.rs
@@ -38,19 +38,13 @@ impl<'gcx: 'tcx, 'tcx> super::QueryTypeOp<'gcx, 'tcx> for ImpliedOutlivesBounds<
         tcx: TyCtxt<'_, 'gcx, 'tcx>,
         canonicalized: Canonicalized<'gcx, ParamEnvAnd<'tcx, Self>>,
     ) -> Fallible<CanonicalizedQueryResponse<'gcx, Self::QueryResponse>> {
-        // FIXME the query should take a `ImpliedOutlivesBounds`
-        let Canonical {
-            variables,
-            value:
-                ParamEnvAnd {
-                    param_env,
-                    value: ImpliedOutlivesBounds { ty },
-                },
-        } = canonicalized;
-        let canonicalized = Canonical {
-            variables,
-            value: param_env.and(ty),
-        };
+        // FIXME this `unchecked_map` is only necessary because the
+        // query is defined as taking a `ParamEnvAnd<Ty>`; it should
+        // take a `ImpliedOutlivesBounds` instead
+        let canonicalized = canonicalized.unchecked_map(|ParamEnvAnd { param_env, value }| {
+            let ImpliedOutlivesBounds { ty } = value;
+            param_env.and(ty)
+        });
 
         tcx.implied_outlives_bounds(canonicalized)
     }
diff --git a/src/librustc/traits/query/type_op/outlives.rs b/src/librustc/traits/query/type_op/outlives.rs
index a36c5accd2a..cd7c6d76eab 100644
--- a/src/librustc/traits/query/type_op/outlives.rs
+++ b/src/librustc/traits/query/type_op/outlives.rs
@@ -59,18 +59,10 @@ where
         // FIXME convert to the type expected by the `dropck_outlives`
         // query. This should eventually be fixed by changing the
         // *underlying query*.
-        let Canonical {
-            variables,
-            value:
-                ParamEnvAnd {
-                    param_env,
-                    value: DropckOutlives { dropped_ty },
-                },
-        } = canonicalized;
-        let canonicalized = Canonical {
-            variables,
-            value: param_env.and(dropped_ty),
-        };
+        let canonicalized = canonicalized.unchecked_map(|ParamEnvAnd { param_env, value }| {
+            let DropckOutlives { dropped_ty } = value;
+            param_env.and(dropped_ty)
+        });
 
         tcx.dropck_outlives(canonicalized)
     }
diff --git a/src/librustc/traits/select.rs b/src/librustc/traits/select.rs
index 2ea16823cc6..e2a5fdd3622 100644
--- a/src/librustc/traits/select.rs
+++ b/src/librustc/traits/select.rs
@@ -1368,7 +1368,8 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
 
         // Winnow, but record the exact outcome of evaluation, which
         // is needed for specialization. Propagate overflow if it occurs.
-        let mut candidates = candidates.into_iter()
+        let mut candidates = candidates
+            .into_iter()
             .map(|c| match self.evaluate_candidate(stack, &c) {
                 Ok(eval) if eval.may_apply() => Ok(Some(EvaluatedCandidate {
                     candidate: c,
@@ -1377,8 +1378,8 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
                 Ok(_) => Ok(None),
                 Err(OverflowError) => Err(Overflow),
             })
-           .flat_map(Result::transpose)
-           .collect::<Result<Vec<_>, _>>()?;
+            .flat_map(Result::transpose)
+            .collect::<Result<Vec<_>, _>>()?;
 
         debug!(
             "winnowed to {} candidates for {:?}: {:?}",
@@ -3004,9 +3005,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
         let self_ty = self.infcx
             .shallow_resolve(*obligation.self_ty().skip_binder());
         let poly_trait_ref = match self_ty.sty {
-            ty::Dynamic(ref data, ..) => {
-                data.principal().with_self_ty(self.tcx(), self_ty)
-            }
+            ty::Dynamic(ref data, ..) => data.principal().with_self_ty(self.tcx(), self_ty),
             _ => span_bug!(obligation.cause.span, "object candidate with non-object"),
         };
 
@@ -3666,8 +3665,17 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
         closure_def_id: DefId,
         substs: ty::ClosureSubsts<'tcx>,
     ) -> ty::PolyTraitRef<'tcx> {
+        debug!(
+            "closure_trait_ref_unnormalized(obligation={:?}, closure_def_id={:?}, substs={:?})",
+            obligation, closure_def_id, substs,
+        );
         let closure_type = self.infcx.closure_sig(closure_def_id, substs);
 
+        debug!(
+            "closure_trait_ref_unnormalized: closure_type = {:?}",
+            closure_type
+        );
+
         // (1) Feels icky to skip the binder here, but OTOH we know
         // that the self-type is an unboxed closure type and hence is
         // in fact unparameterized (or at least does not reference any
diff --git a/src/librustc/ty/error.rs b/src/librustc/ty/error.rs
index ed6e372fe76..855983042c0 100644
--- a/src/librustc/ty/error.rs
+++ b/src/librustc/ty/error.rs
@@ -53,8 +53,6 @@ pub enum TypeError<'tcx> {
     ProjectionMismatched(ExpectedFound<DefId>),
     ProjectionBoundsLength(ExpectedFound<usize>),
     ExistentialMismatch(ExpectedFound<&'tcx ty::List<ty::ExistentialPredicate<'tcx>>>),
-
-    OldStyleLUB(Box<TypeError<'tcx>>),
 }
 
 #[derive(Clone, RustcEncodable, RustcDecodable, PartialEq, Eq, Hash, Debug, Copy)]
@@ -166,9 +164,6 @@ impl<'tcx> fmt::Display for TypeError<'tcx> {
                 report_maybe_different(f, &format!("trait `{}`", values.expected),
                                        &format!("trait `{}`", values.found))
             }
-            OldStyleLUB(ref err) => {
-                write!(f, "{}", err)
-            }
         }
     }
 }
@@ -266,12 +261,6 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
                     }
                 }
             },
-            OldStyleLUB(err) => {
-                db.note("this was previously accepted by the compiler but has been phased out");
-                db.note("for more information, see https://github.com/rust-lang/rust/issues/45852");
-
-                self.note_and_explain_type_err(db, &err, sp);
-            }
             CyclicTy(ty) => {
                 // Watch out for various cases of cyclic types and try to explain.
                 if ty.is_closure() || ty.is_generator() {
diff --git a/src/librustc/ty/mod.rs b/src/librustc/ty/mod.rs
index f8fc2cc8303..ad26383df6a 100644
--- a/src/librustc/ty/mod.rs
+++ b/src/librustc/ty/mod.rs
@@ -1522,10 +1522,17 @@ impl UniverseIndex {
 
     /// True if `self` can name a name from `other` -- in other words,
     /// if the set of names in `self` is a superset of those in
-    /// `other`.
+    /// `other` (`self >= other`).
     pub fn can_name(self, other: UniverseIndex) -> bool {
         self.private >= other.private
     }
+
+    /// True if `self` cannot name some names from `other` -- in other
+    /// words, if the set of names in `self` is a strict subset of
+    /// those in `other` (`self < other`).
+    pub fn cannot_name(self, other: UniverseIndex) -> bool {
+        self.private < other.private
+    }
 }
 
 /// The "placeholder index" fully defines a placeholder region.
@@ -1540,6 +1547,8 @@ pub struct Placeholder {
     pub name: BoundRegion,
 }
 
+impl_stable_hash_for!(struct Placeholder { universe, name });
+
 /// When type checking, we use the `ParamEnv` to track
 /// details about the set of where-clauses that are in scope at this
 /// particular point.
diff --git a/src/librustc/ty/structural_impls.rs b/src/librustc/ty/structural_impls.rs
index ba5b714a0e7..05f5f923557 100644
--- a/src/librustc/ty/structural_impls.rs
+++ b/src/librustc/ty/structural_impls.rs
@@ -455,7 +455,6 @@ impl<'a, 'tcx> Lift<'tcx> for ty::error::TypeError<'a> {
             ProjectionMismatched(x) => ProjectionMismatched(x),
             ProjectionBoundsLength(x) => ProjectionBoundsLength(x),
             Sorts(ref x) => return tcx.lift(x).map(Sorts),
-            OldStyleLUB(ref x) => return tcx.lift(x).map(OldStyleLUB),
             ExistentialMismatch(ref x) => return tcx.lift(x).map(ExistentialMismatch)
         })
     }
@@ -1003,7 +1002,6 @@ EnumTypeFoldableImpl! {
         (ty::error::TypeError::ProjectionBoundsLength)(x),
         (ty::error::TypeError::Sorts)(x),
         (ty::error::TypeError::ExistentialMismatch)(x),
-        (ty::error::TypeError::OldStyleLUB)(x),
     }
 }
 
diff --git a/src/librustc_mir/borrow_check/nll/mod.rs b/src/librustc_mir/borrow_check/nll/mod.rs
index 8fc54b6ff92..0c4140caee8 100644
--- a/src/librustc_mir/borrow_check/nll/mod.rs
+++ b/src/librustc_mir/borrow_check/nll/mod.rs
@@ -107,7 +107,6 @@ pub(in borrow_check) fn compute_regions<'cx, 'gcx, 'tcx>(
     // Run the MIR type-checker.
     let MirTypeckResults {
         constraints,
-        placeholder_indices,
         universal_region_relations,
     } = type_check::type_check(
         infcx,
@@ -123,8 +122,6 @@ pub(in borrow_check) fn compute_regions<'cx, 'gcx, 'tcx>(
         elements,
     );
 
-    let placeholder_indices = Rc::new(placeholder_indices);
-
     if let Some(all_facts) = &mut all_facts {
         all_facts
             .universal_region
@@ -136,11 +133,14 @@ pub(in borrow_check) fn compute_regions<'cx, 'gcx, 'tcx>(
     // base constraints generated by the type-check.
     let var_origins = infcx.take_region_var_origins();
     let MirTypeckRegionConstraints {
+        placeholder_indices,
+        placeholder_index_to_region: _,
         mut liveness_constraints,
         outlives_constraints,
         closure_bounds_mapping,
         type_tests,
     } = constraints;
+    let placeholder_indices = Rc::new(placeholder_indices);
 
     constraint_generation::generate_constraints(
         infcx,
diff --git a/src/librustc_mir/borrow_check/nll/region_infer/error_reporting/mod.rs b/src/librustc_mir/borrow_check/nll/region_infer/error_reporting/mod.rs
index ccb44c670f7..3358e5851f9 100644
--- a/src/librustc_mir/borrow_check/nll/region_infer/error_reporting/mod.rs
+++ b/src/librustc_mir/borrow_check/nll/region_infer/error_reporting/mod.rs
@@ -8,23 +8,24 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-use borrow_check::nll::ConstraintDescription;
-use borrow_check::nll::constraints::{OutlivesConstraint};
+use borrow_check::nll::constraints::OutlivesConstraint;
 use borrow_check::nll::region_infer::RegionInferenceContext;
 use borrow_check::nll::type_check::Locations;
 use borrow_check::nll::universal_regions::DefiningTy;
-use util::borrowck_errors::{BorrowckErrors, Origin};
+use borrow_check::nll::ConstraintDescription;
 use rustc::hir::def_id::DefId;
 use rustc::infer::error_reporting::nice_region_error::NiceRegionError;
 use rustc::infer::InferCtxt;
+use rustc::infer::NLLRegionVariableOrigin;
 use rustc::mir::{ConstraintCategory, Location, Mir};
 use rustc::ty::{self, RegionVid};
 use rustc_data_structures::indexed_vec::IndexVec;
 use rustc_errors::{Diagnostic, DiagnosticBuilder};
 use std::collections::VecDeque;
+use syntax::errors::Applicability;
 use syntax::symbol::keywords;
 use syntax_pos::Span;
-use syntax::errors::Applicability;
+use util::borrowck_errors::{BorrowckErrors, Origin};
 
 mod region_name;
 mod var_name;
@@ -76,9 +77,9 @@ impl<'tcx> RegionInferenceContext<'tcx> {
         debug!("best_blame_constraint(from_region={:?})", from_region);
 
         // Find all paths
-        let (path, target_region) = self
-            .find_constraint_paths_between_regions(from_region, target_test)
-            .unwrap();
+        let (path, target_region) =
+            self.find_constraint_paths_between_regions(from_region, target_test)
+                .unwrap();
         debug!(
             "best_blame_constraint: path={:#?}",
             path.iter()
@@ -92,8 +93,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
         );
 
         // Classify each of the constraints along the path.
-        let mut categorized_path: Vec<(ConstraintCategory, bool, Span)> = path
-            .iter()
+        let mut categorized_path: Vec<(ConstraintCategory, bool, Span)> = path.iter()
             .map(|constraint| {
                 if constraint.category == ConstraintCategory::ClosureBounds {
                     self.retrieve_closure_constraint_info(mir, &constraint)
@@ -137,13 +137,12 @@ impl<'tcx> RegionInferenceContext<'tcx> {
                 | ConstraintCategory::Boring
                 | ConstraintCategory::BoringNoLocation
                 | ConstraintCategory::Internal => false,
-                ConstraintCategory::TypeAnnotation
-                | ConstraintCategory::Return => true,
+                ConstraintCategory::TypeAnnotation | ConstraintCategory::Return => true,
                 _ => constraint_sup_scc != target_scc,
             }
         });
         if let Some(i) = best_choice {
-            return categorized_path[i]
+            return categorized_path[i];
         }
 
         // If that search fails, that is.. unusual. Maybe everything
@@ -179,6 +178,13 @@ impl<'tcx> RegionInferenceContext<'tcx> {
         deque.push_back(from_region);
 
         while let Some(r) = deque.pop_front() {
+            debug!(
+                "find_constraint_paths_between_regions: from_region={:?} r={:?} value={}",
+                from_region,
+                r,
+                self.region_value_str(r),
+            );
+
             // Check if we reached the region we were looking for. If so,
             // we can reconstruct the path that led to it and return it.
             if target_test(r) {
@@ -206,9 +212,9 @@ impl<'tcx> RegionInferenceContext<'tcx> {
             // enqueue any regions we find, keeping track of how we
             // reached them.
             let fr_static = self.universal_regions.fr_static;
-            for constraint in self.constraint_graph.outgoing_edges(r,
-                                                                   &self.constraints,
-                                                                   fr_static) {
+            for constraint in self.constraint_graph
+                .outgoing_edges(r, &self.constraints, fr_static)
+            {
                 assert_eq!(constraint.sup, r);
                 let sub_region = constraint.sub;
                 if let Trace::NotVisited = context[sub_region] {
@@ -240,11 +246,9 @@ impl<'tcx> RegionInferenceContext<'tcx> {
     ) {
         debug!("report_error(fr={:?}, outlived_fr={:?})", fr, outlived_fr);
 
-        let (category, _, span) = self.best_blame_constraint(
-            mir,
-            fr,
-            |r| r == outlived_fr
-        );
+        let (category, _, span) = self.best_blame_constraint(mir, fr, |r| {
+            self.provides_universal_region(r, fr, outlived_fr)
+        });
 
         // Check if we can use one of the "nice region errors".
         if let (Some(f), Some(o)) = (self.to_error_region(fr), self.to_error_region(outlived_fr)) {
@@ -260,23 +264,75 @@ impl<'tcx> RegionInferenceContext<'tcx> {
             self.universal_regions.is_local_free_region(outlived_fr),
         );
 
-        debug!("report_error: fr_is_local={:?} outlived_fr_is_local={:?} category={:?}",
-               fr_is_local, outlived_fr_is_local, category);
+        debug!(
+            "report_error: fr_is_local={:?} outlived_fr_is_local={:?} category={:?}",
+            fr_is_local, outlived_fr_is_local, category
+        );
         match (category, fr_is_local, outlived_fr_is_local) {
-            (ConstraintCategory::Return, true, false) if self.is_closure_fn_mut(infcx, fr) =>
-                self.report_fnmut_error(mir, infcx, mir_def_id, fr, outlived_fr, span,
-                                        errors_buffer),
-            (ConstraintCategory::Assignment, true, false) |
-            (ConstraintCategory::CallArgument, true, false) =>
-                self.report_escaping_data_error(mir, infcx, mir_def_id, fr, outlived_fr,
-                                                category, span, errors_buffer),
-            _ =>
-                self.report_general_error(mir, infcx, mir_def_id, fr, fr_is_local,
-                                          outlived_fr, outlived_fr_is_local,
-                                          category, span, errors_buffer),
+            (ConstraintCategory::Return, true, false) if self.is_closure_fn_mut(infcx, fr) => {
+                self.report_fnmut_error(
+                    mir,
+                    infcx,
+                    mir_def_id,
+                    fr,
+                    outlived_fr,
+                    span,
+                    errors_buffer,
+                )
+            }
+            (ConstraintCategory::Assignment, true, false)
+            | (ConstraintCategory::CallArgument, true, false) => self.report_escaping_data_error(
+                mir,
+                infcx,
+                mir_def_id,
+                fr,
+                outlived_fr,
+                category,
+                span,
+                errors_buffer,
+            ),
+            _ => self.report_general_error(
+                mir,
+                infcx,
+                mir_def_id,
+                fr,
+                fr_is_local,
+                outlived_fr,
+                outlived_fr_is_local,
+                category,
+                span,
+                errors_buffer,
+            ),
         };
     }
 
+    /// We have a constraint `fr1: fr2` that is not satisfied, where
+    /// `fr2` represents some universal region. Here, `r` is some
+    /// region where we know that `fr1: r` and this function has the
+    /// job of determining whether `r` is "to blame" for the fact that
+    /// `fr1: fr2` is required.
+    ///
+    /// This is true under two conditions:
+    ///
+    /// - `r == fr2`
+    /// - `fr2` is `'static` and `r` is some placeholder in a universe
+    ///   that cannot be named by `fr1`; in that case, we will require
+    ///   that `fr1: 'static` because it is the only way to `fr1: r` to
+    ///   be satisfied. (See `add_incompatible_universe`.)
+    fn provides_universal_region(&self, r: RegionVid, fr1: RegionVid, fr2: RegionVid) -> bool {
+        debug!(
+            "provides_universal_region(r={:?}, fr1={:?}, fr2={:?})",
+            r, fr1, fr2
+        );
+        let result = {
+            r == fr2 || {
+                fr2 == self.universal_regions.fr_static && self.cannot_name_placeholder(fr1, r)
+            }
+        };
+        debug!("provides_universal_region: result = {:?}", result);
+        result
+    }
+
     /// Report a specialized error when `FnMut` closures return a reference to a captured variable.
     /// This function expects `fr` to be local and `outlived_fr` to not be local.
     ///
@@ -303,10 +359,10 @@ impl<'tcx> RegionInferenceContext<'tcx> {
         span: Span,
         errors_buffer: &mut Vec<Diagnostic>,
     ) {
-        let mut diag = infcx.tcx.sess.struct_span_err(
-            span,
-            "captured variable cannot escape `FnMut` closure body",
-        );
+        let mut diag = infcx
+            .tcx
+            .sess
+            .struct_span_err(span, "captured variable cannot escape `FnMut` closure body");
 
         // We should check if the return type of this closure is in fact a closure - in that
         // case, we can special case the error further.
@@ -318,27 +374,28 @@ impl<'tcx> RegionInferenceContext<'tcx> {
             "returns a reference to a captured variable which escapes the closure body"
         };
 
-        diag.span_label(
-            span,
-            message,
-        );
+        diag.span_label(span, message);
 
-        match self.give_region_a_name(infcx, mir, mir_def_id, outlived_fr, &mut 1).source {
-            RegionNameSource::NamedEarlyBoundRegion(fr_span) |
-            RegionNameSource::NamedFreeRegion(fr_span) |
-            RegionNameSource::SynthesizedFreeEnvRegion(fr_span, _) |
-            RegionNameSource::CannotMatchHirTy(fr_span, _) |
-            RegionNameSource::MatchedHirTy(fr_span) |
-            RegionNameSource::MatchedAdtAndSegment(fr_span) |
-            RegionNameSource::AnonRegionFromUpvar(fr_span, _) |
-            RegionNameSource::AnonRegionFromOutput(fr_span, _, _) => {
+        match self.give_region_a_name(infcx, mir, mir_def_id, outlived_fr, &mut 1)
+            .source
+        {
+            RegionNameSource::NamedEarlyBoundRegion(fr_span)
+            | RegionNameSource::NamedFreeRegion(fr_span)
+            | RegionNameSource::SynthesizedFreeEnvRegion(fr_span, _)
+            | RegionNameSource::CannotMatchHirTy(fr_span, _)
+            | RegionNameSource::MatchedHirTy(fr_span)
+            | RegionNameSource::MatchedAdtAndSegment(fr_span)
+            | RegionNameSource::AnonRegionFromUpvar(fr_span, _)
+            | RegionNameSource::AnonRegionFromOutput(fr_span, _, _) => {
                 diag.span_label(fr_span, "inferred to be a `FnMut` closure");
-            },
-            _ => {},
+            }
+            _ => {}
         }
 
-        diag.note("`FnMut` closures only have access to their captured variables while they are \
-                   executing...");
+        diag.note(
+            "`FnMut` closures only have access to their captured variables while they are \
+             executing...",
+        );
         diag.note("...therefore, they cannot allow references to captured variables to escape");
 
         diag.buffer(errors_buffer);
@@ -375,7 +432,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
             DefiningTy::Closure(..) => "closure",
             DefiningTy::Generator(..) => "generator",
             DefiningTy::FnDef(..) => "function",
-            DefiningTy::Const(..) => "const"
+            DefiningTy::Const(..) => "const",
         };
 
         // Revert to the normal error in these cases.
@@ -384,12 +441,23 @@ impl<'tcx> RegionInferenceContext<'tcx> {
             || (category == ConstraintCategory::Assignment && escapes_from == "function")
             || escapes_from == "const"
         {
-            return self.report_general_error(mir, infcx, mir_def_id,
-                                             fr, true, outlived_fr, false,
-                                             category, span, errors_buffer);
+            return self.report_general_error(
+                mir,
+                infcx,
+                mir_def_id,
+                fr,
+                true,
+                outlived_fr,
+                false,
+                category,
+                span,
+                errors_buffer,
+            );
         }
 
-        let mut diag = infcx.tcx.borrowed_data_escapes_closure(span, escapes_from, Origin::Mir);
+        let mut diag = infcx
+            .tcx
+            .borrowed_data_escapes_closure(span, escapes_from, Origin::Mir);
 
         if let Some((Some(outlived_fr_name), outlived_fr_span)) = outlived_fr_name_and_span {
             diag.span_label(
@@ -410,7 +478,10 @@ impl<'tcx> RegionInferenceContext<'tcx> {
                 ),
             );
 
-            diag.span_label(span, format!("`{}` escapes the {} body here", fr_name, escapes_from));
+            diag.span_label(
+                span,
+                format!("`{}` escapes the {} body here", fr_name, escapes_from),
+            );
         }
 
         diag.buffer(errors_buffer);
@@ -452,31 +523,41 @@ impl<'tcx> RegionInferenceContext<'tcx> {
         let counter = &mut 1;
         let fr_name = self.give_region_a_name(infcx, mir, mir_def_id, fr, counter);
         fr_name.highlight_region_name(&mut diag);
-        let outlived_fr_name = self.give_region_a_name(
-            infcx, mir, mir_def_id, outlived_fr, counter);
+        let outlived_fr_name =
+            self.give_region_a_name(infcx, mir, mir_def_id, outlived_fr, counter);
         outlived_fr_name.highlight_region_name(&mut diag);
 
-        let mir_def_name = if infcx.tcx.is_closure(mir_def_id) { "closure" } else { "function" };
+        let mir_def_name = if infcx.tcx.is_closure(mir_def_id) {
+            "closure"
+        } else {
+            "function"
+        };
 
         match (category, outlived_fr_is_local, fr_is_local) {
             (ConstraintCategory::Return, true, _) => {
-                diag.span_label(span, format!(
-                    "{} was supposed to return data with lifetime `{}` but it is returning \
-                    data with lifetime `{}`",
-                    mir_def_name, outlived_fr_name, fr_name
-                ));
-            },
+                diag.span_label(
+                    span,
+                    format!(
+                        "{} was supposed to return data with lifetime `{}` but it is returning \
+                         data with lifetime `{}`",
+                        mir_def_name, outlived_fr_name, fr_name
+                    ),
+                );
+            }
             _ => {
-                diag.span_label(span, format!(
-                    "{}requires that `{}` must outlive `{}`",
-                    category.description(), fr_name, outlived_fr_name,
-                ));
-            },
+                diag.span_label(
+                    span,
+                    format!(
+                        "{}requires that `{}` must outlive `{}`",
+                        category.description(),
+                        fr_name,
+                        outlived_fr_name,
+                    ),
+                );
+            }
         }
 
-        self.add_static_impl_trait_suggestion(
-            infcx, &mut diag, fr, fr_name, outlived_fr,
-        );
+        self.add_static_impl_trait_suggestion(infcx, &mut diag, fr, fr_name, outlived_fr);
 
         diag.buffer(errors_buffer);
     }
@@ -499,17 +580,18 @@ impl<'tcx> RegionInferenceContext<'tcx> {
         fr_name: RegionName,
         outlived_fr: RegionVid,
     ) {
-        if let (
-            Some(f),
-            Some(ty::RegionKind::ReStatic)
-        ) = (self.to_error_region(fr), self.to_error_region(outlived_fr)) {
+        if let (Some(f), Some(ty::RegionKind::ReStatic)) =
+            (self.to_error_region(fr), self.to_error_region(outlived_fr))
+        {
             if let Some(ty::TyS {
                 sty: ty::TyKind::Opaque(did, substs),
                 ..
-            }) = infcx.tcx.is_suitable_region(f)
-                    .map(|r| r.def_id)
-                    .map(|id| infcx.tcx.return_type_impl_trait(id))
-                    .unwrap_or(None)
+            }) = infcx
+                .tcx
+                .is_suitable_region(f)
+                .map(|r| r.def_id)
+                .map(|id| infcx.tcx.return_type_impl_trait(id))
+                .unwrap_or(None)
             {
                 // Check whether or not the impl trait return type is intended to capture
                 // data with the static lifetime.
@@ -522,10 +604,9 @@ impl<'tcx> RegionInferenceContext<'tcx> {
                     let mut found = false;
                     for predicate in bounds.predicates {
                         if let ty::Predicate::TypeOutlives(binder) = predicate {
-                            if let ty::OutlivesPredicate(
-                                _,
-                                ty::RegionKind::ReStatic
-                            ) = binder.skip_binder() {
+                            if let ty::OutlivesPredicate(_, ty::RegionKind::ReStatic) =
+                                binder.skip_binder()
+                            {
                                 found = true;
                                 break;
                             }
@@ -535,18 +616,18 @@ impl<'tcx> RegionInferenceContext<'tcx> {
                     found
                 };
 
-                debug!("add_static_impl_trait_suggestion: has_static_predicate={:?}",
-                       has_static_predicate);
+                debug!(
+                    "add_static_impl_trait_suggestion: has_static_predicate={:?}",
+                    has_static_predicate
+                );
                 let static_str = keywords::StaticLifetime.name();
                 // If there is a static predicate, then the only sensible suggestion is to replace
                 // fr with `'static`.
                 if has_static_predicate {
-                    diag.help(
-                        &format!(
-                            "consider replacing `{}` with `{}`",
-                            fr_name, static_str,
-                        ),
-                    );
+                    diag.help(&format!(
+                        "consider replacing `{}` with `{}`",
+                        fr_name, static_str,
+                    ));
                 } else {
                     // Otherwise, we should suggest adding a constraint on the return type.
                     let span = infcx.tcx.def_span(*did);
@@ -581,25 +662,48 @@ impl<'tcx> RegionInferenceContext<'tcx> {
         borrow_region: RegionVid,
         outlived_region: RegionVid,
     ) -> (ConstraintCategory, bool, Span, RegionName) {
-        let (category, from_closure, span) = self.best_blame_constraint(
-            mir,
-            borrow_region,
-            |r| r == outlived_region
-        );
-        let outlived_fr_name = self.give_region_a_name(
-            infcx, mir, mir_def_id, outlived_region, &mut 1);
+        let (category, from_closure, span) =
+            self.best_blame_constraint(mir, borrow_region, |r| r == outlived_region);
+        let outlived_fr_name =
+            self.give_region_a_name(infcx, mir, mir_def_id, outlived_region, &mut 1);
         (category, from_closure, span, outlived_fr_name)
     }
 
     // Finds some region R such that `fr1: R` and `R` is live at
     // `elem`.
     crate fn find_sub_region_live_at(&self, fr1: RegionVid, elem: Location) -> RegionVid {
-        // Find all paths
-        let (_path, r) =
-            self.find_constraint_paths_between_regions(fr1, |r| {
-                self.liveness_constraints.contains(r, elem)
-            }).unwrap();
-        r
+        debug!("find_sub_region_live_at(fr1={:?}, elem={:?})", fr1, elem);
+        self.find_constraint_paths_between_regions(fr1, |r| {
+            // First look for some `r` such that `fr1: r` and `r` is live at `elem`
+            debug!(
+                "find_sub_region_live_at: liveness_constraints for {:?} are {:?}",
+                r,
+                self.liveness_constraints.region_value_str(r),
+            );
+            self.liveness_constraints.contains(r, elem)
+        }).or_else(|| {
+                // If we fail to find that, we may find some `r` such that
+                // `fr1: r` and `r` is a placeholder from some universe
+                // `fr1` cannot name. This would force `fr1` to be
+                // `'static`.
+                self.find_constraint_paths_between_regions(fr1, |r| {
+                    self.cannot_name_placeholder(fr1, r)
+                })
+            })
+            .or_else(|| {
+                // If we fail to find THAT, it may be that `fr1` is a
+                // placeholder that cannot "fit" into its SCC. In that
+                // case, there should be some `r` where `fr1: r`, both
+                // `fr1` and `r` are in the same SCC, and `fr1` is a
+                // placeholder that `r` cannot name. We can blame that
+                // edge.
+                self.find_constraint_paths_between_regions(fr1, |r| {
+                    self.constraint_sccs.scc(fr1) == self.constraint_sccs.scc(r)
+                        && self.cannot_name_placeholder(r, fr1)
+                })
+            })
+            .map(|(_path, r)| r)
+            .unwrap()
     }
 
     // Finds a good span to blame for the fact that `fr1` outlives `fr2`.
@@ -609,34 +713,30 @@ impl<'tcx> RegionInferenceContext<'tcx> {
         fr1: RegionVid,
         fr2: RegionVid,
     ) -> (ConstraintCategory, Span) {
-        let (category, _, span) = self.best_blame_constraint(mir, fr1, |r| r == fr2);
+        let (category, _, span) =
+            self.best_blame_constraint(mir, fr1, |r| self.provides_universal_region(r, fr1, fr2));
         (category, span)
     }
 
     fn retrieve_closure_constraint_info(
         &self,
         mir: &Mir<'tcx>,
-        constraint: &OutlivesConstraint
+        constraint: &OutlivesConstraint,
     ) -> (ConstraintCategory, bool, Span) {
         let loc = match constraint.locations {
             Locations::All(span) => return (constraint.category, false, span),
             Locations::Single(loc) => loc,
         };
 
-        let opt_span_category = self
-            .closure_bounds_mapping[&loc]
-            .get(&(constraint.sup, constraint.sub));
+        let opt_span_category =
+            self.closure_bounds_mapping[&loc].get(&(constraint.sup, constraint.sub));
         opt_span_category
             .map(|&(category, span)| (category, true, span))
             .unwrap_or((constraint.category, false, mir.source_info(loc).span))
     }
 
     /// Returns `true` if a closure is inferred to be an `FnMut` closure.
-    crate fn is_closure_fn_mut(
-        &self,
-        infcx: &InferCtxt<'_, '_, 'tcx>,
-        fr: RegionVid,
-    ) -> bool {
+    crate fn is_closure_fn_mut(&self, infcx: &InferCtxt<'_, '_, 'tcx>, fr: RegionVid) -> bool {
         if let Some(ty::ReFree(free_region)) = self.to_error_region(fr) {
             if let ty::BoundRegion::BrEnv = free_region.bound_region {
                 if let DefiningTy::Closure(def_id, substs) = self.universal_regions.defining_ty {
@@ -648,4 +748,24 @@ impl<'tcx> RegionInferenceContext<'tcx> {
 
         false
     }
+
+    /// If `r2` represents a placeholder region, then this returns
+    /// true if `r1` cannot name that placeholder in its
+    /// value. Otherwise, returns false.
+    fn cannot_name_placeholder(&self, r1: RegionVid, r2: RegionVid) -> bool {
+        debug!("cannot_name_value_of(r1={:?}, r2={:?})", r1, r2);
+
+        match self.definitions[r2].origin {
+            NLLRegionVariableOrigin::Placeholder(placeholder) => {
+                let universe1 = self.definitions[r1].universe;
+                debug!(
+                    "cannot_name_value_of: universe1={:?} placeholder={:?}",
+                    universe1, placeholder
+                );
+                universe1.cannot_name(placeholder.universe)
+            }
+
+            NLLRegionVariableOrigin::FreeRegion | NLLRegionVariableOrigin::Existential => false,
+        }
+    }
 }
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 50fd4afcd7e..376f4459242 100644
--- a/src/librustc_mir/borrow_check/nll/region_infer/mod.rs
+++ b/src/librustc_mir/borrow_check/nll/region_infer/mod.rs
@@ -345,6 +345,13 @@ impl<'tcx> RegionInferenceContext<'tcx> {
                     if scc_universe.can_name(placeholder.universe) {
                         self.scc_values.add_element(scc, placeholder);
                     } else {
+                        debug!(
+                            "init_free_and_bound_regions: placeholder {:?} is \
+                             not compatible with universe {:?} of its SCC {:?}",
+                            placeholder,
+                            scc_universe,
+                            scc,
+                        );
                         self.add_incompatible_universe(scc);
                     }
                 }
@@ -471,6 +478,9 @@ impl<'tcx> RegionInferenceContext<'tcx> {
             let mut constraints: Vec<_> = self.constraints.iter().collect();
             constraints.sort();
             constraints
+                .into_iter()
+                .map(|c| (c, self.constraint_sccs.scc(c.sup), self.constraint_sccs.scc(c.sub)))
+                .collect::<Vec<_>>()
         });
 
         // To propagate constraints, we walk the DAG induced by the
@@ -560,6 +570,8 @@ impl<'tcx> RegionInferenceContext<'tcx> {
     /// `'a` with `'b` and not `'static`. But it will have to do for
     /// now.
     fn add_incompatible_universe(&mut self, scc: ConstraintSccIndex) {
+        debug!("add_incompatible_universe(scc={:?})", scc);
+
         let fr_static = self.universal_regions.fr_static;
         self.scc_values.add_all_points(scc);
         self.scc_values.add_element(scc, fr_static);
@@ -1226,6 +1238,10 @@ impl<'tcx> RegionInferenceContext<'tcx> {
         );
 
         let longer_fr_scc = self.constraint_sccs.scc(longer_fr);
+        debug!(
+            "check_bound_universal_region: longer_fr_scc={:?}",
+            longer_fr_scc,
+        );
 
         // If we have some bound universal region `'a`, then the only
         // elements it can contain is itself -- we don't know anything
@@ -1242,6 +1258,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
             Some(v) => v,
             None => return,
         };
+        debug!("check_bound_universal_region: error_element = {:?}", error_element);
 
         // Find the region that introduced this `error_element`.
         let error_region = match error_element {
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 994f20a011d..5904138ef60 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
@@ -8,21 +8,23 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-use borrow_check::nll::constraints::{ConstraintSet, OutlivesConstraint};
+use borrow_check::nll::constraints::OutlivesConstraint;
 use borrow_check::nll::region_infer::TypeTest;
-use borrow_check::nll::type_check::Locations;
+use borrow_check::nll::type_check::{Locations, MirTypeckRegionConstraints};
 use borrow_check::nll::universal_regions::UniversalRegions;
+use borrow_check::nll::ToRegionVid;
 use rustc::infer::canonical::QueryRegionConstraint;
 use rustc::infer::outlives::env::RegionBoundPairs;
 use rustc::infer::outlives::obligations::{TypeOutlives, TypeOutlivesDelegate};
 use rustc::infer::region_constraints::{GenericKind, VerifyBound};
-use rustc::infer::{self, SubregionOrigin};
+use rustc::infer::{self, InferCtxt, SubregionOrigin};
 use rustc::mir::ConstraintCategory;
 use rustc::ty::subst::UnpackedKind;
 use rustc::ty::{self, TyCtxt};
 use syntax_pos::DUMMY_SP;
 
 crate struct ConstraintConversion<'a, 'gcx: 'tcx, 'tcx: 'a> {
+    infcx: &'a InferCtxt<'a, 'gcx, 'tcx>,
     tcx: TyCtxt<'a, 'gcx, 'tcx>,
     universal_regions: &'a UniversalRegions<'tcx>,
     region_bound_pairs: &'a RegionBoundPairs<'tcx>,
@@ -30,32 +32,30 @@ crate struct ConstraintConversion<'a, 'gcx: 'tcx, 'tcx: 'a> {
     param_env: ty::ParamEnv<'tcx>,
     locations: Locations,
     category: ConstraintCategory,
-    outlives_constraints: &'a mut ConstraintSet,
-    type_tests: &'a mut Vec<TypeTest<'tcx>>,
+    constraints: &'a mut MirTypeckRegionConstraints<'tcx>,
 }
 
 impl<'a, 'gcx, 'tcx> ConstraintConversion<'a, 'gcx, 'tcx> {
     crate fn new(
-        tcx: TyCtxt<'a, 'gcx, 'tcx>,
+        infcx: &'a InferCtxt<'a, 'gcx, 'tcx>,
         universal_regions: &'a UniversalRegions<'tcx>,
         region_bound_pairs: &'a RegionBoundPairs<'tcx>,
         implicit_region_bound: Option<ty::Region<'tcx>>,
         param_env: ty::ParamEnv<'tcx>,
         locations: Locations,
         category: ConstraintCategory,
-        outlives_constraints: &'a mut ConstraintSet,
-        type_tests: &'a mut Vec<TypeTest<'tcx>>,
+        constraints: &'a mut MirTypeckRegionConstraints<'tcx>,
     ) -> Self {
         Self {
-            tcx,
+            infcx,
+            tcx: infcx.tcx,
             universal_regions,
             region_bound_pairs,
             implicit_region_bound,
             param_env,
             locations,
             category,
-            outlives_constraints,
-            type_tests,
+            constraints,
         }
     }
 
@@ -113,7 +113,7 @@ impl<'a, 'gcx, 'tcx> ConstraintConversion<'a, 'gcx, 'tcx> {
     }
 
     fn verify_to_type_test(
-        &self,
+        &mut self,
         generic_kind: GenericKind<'tcx>,
         region: ty::Region<'tcx>,
         verify_bound: VerifyBound<'tcx>,
@@ -128,22 +128,30 @@ impl<'a, 'gcx, 'tcx> ConstraintConversion<'a, 'gcx, 'tcx> {
         }
     }
 
-    fn to_region_vid(&self, r: ty::Region<'tcx>) -> ty::RegionVid {
-        self.universal_regions.to_region_vid(r)
+    fn to_region_vid(&mut self, r: ty::Region<'tcx>) -> ty::RegionVid {
+        if let ty::RePlaceholder(placeholder) = r {
+            self.constraints
+                .placeholder_region(self.infcx, *placeholder)
+                .to_region_vid()
+        } else {
+            self.universal_regions.to_region_vid(r)
+        }
     }
 
     fn add_outlives(&mut self, sup: ty::RegionVid, sub: ty::RegionVid) {
-        self.outlives_constraints.push(OutlivesConstraint {
-            locations: self.locations,
-            category: self.category,
-            sub,
-            sup,
-        });
+        self.constraints
+            .outlives_constraints
+            .push(OutlivesConstraint {
+                locations: self.locations,
+                category: self.category,
+                sub,
+                sup,
+            });
     }
 
     fn add_type_test(&mut self, type_test: TypeTest<'tcx>) {
         debug!("add_type_test(type_test={:?})", type_test);
-        self.type_tests.push(type_test);
+        self.constraints.type_tests.push(type_test);
     }
 }
 
@@ -156,8 +164,8 @@ impl<'a, 'b, 'gcx, 'tcx> TypeOutlivesDelegate<'tcx>
         a: ty::Region<'tcx>,
         b: ty::Region<'tcx>,
     ) {
-        let b = self.universal_regions.to_region_vid(b);
-        let a = self.universal_regions.to_region_vid(a);
+        let b = self.to_region_vid(b);
+        let a = self.to_region_vid(a);
         self.add_outlives(b, a);
     }
 
diff --git a/src/librustc_mir/borrow_check/nll/type_check/free_region_relations.rs b/src/librustc_mir/borrow_check/nll/type_check/free_region_relations.rs
index f8c839e4d3f..3d0f3d9fc7d 100644
--- a/src/librustc_mir/borrow_check/nll/type_check/free_region_relations.rs
+++ b/src/librustc_mir/borrow_check/nll/type_check/free_region_relations.rs
@@ -271,15 +271,14 @@ impl UniversalRegionRelationsBuilder<'cx, 'gcx, 'tcx> {
 
         for data in constraint_sets {
             constraint_conversion::ConstraintConversion::new(
-                self.infcx.tcx,
+                self.infcx,
                 &self.universal_regions,
                 &self.region_bound_pairs,
                 self.implicit_region_bound,
                 self.param_env,
                 Locations::All(DUMMY_SP),
                 ConstraintCategory::Internal,
-                &mut self.constraints.outlives_constraints,
-                &mut self.constraints.type_tests,
+                &mut self.constraints,
             ).convert_all(&data);
         }
 
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 3098acffa23..0a873cd84ff 100644
--- a/src/librustc_mir/borrow_check/nll/type_check/mod.rs
+++ b/src/librustc_mir/borrow_check/nll/type_check/mod.rs
@@ -16,6 +16,7 @@ use borrow_check::location::LocationTable;
 use borrow_check::nll::constraints::{ConstraintSet, OutlivesConstraint};
 use borrow_check::nll::facts::AllFacts;
 use borrow_check::nll::region_infer::values::LivenessValues;
+use borrow_check::nll::region_infer::values::PlaceholderIndex;
 use borrow_check::nll::region_infer::values::PlaceholderIndices;
 use borrow_check::nll::region_infer::values::RegionValueElements;
 use borrow_check::nll::region_infer::{ClosureRegionRequirementsExt, TypeTest};
@@ -28,11 +29,12 @@ use borrow_check::nll::ToRegionVid;
 use dataflow::move_paths::MoveData;
 use dataflow::FlowAtLocation;
 use dataflow::MaybeInitializedPlaces;
+use either::Either;
 use rustc::hir;
 use rustc::hir::def_id::DefId;
 use rustc::infer::canonical::QueryRegionConstraint;
 use rustc::infer::outlives::env::RegionBoundPairs;
-use rustc::infer::{InferCtxt, InferOk, LateBoundRegionConversionTime};
+use rustc::infer::{InferCtxt, InferOk, LateBoundRegionConversionTime, NLLRegionVariableOrigin};
 use rustc::mir::interpret::EvalErrorKind::BoundsCheck;
 use rustc::mir::tcx::PlaceTy;
 use rustc::mir::visit::{PlaceContext, Visitor, MutatingUseContext, NonMutatingUseContext};
@@ -44,14 +46,13 @@ use rustc::traits::{ObligationCause, PredicateObligations};
 use rustc::ty::fold::TypeFoldable;
 use rustc::ty::subst::{Subst, Substs, UnpackedKind};
 use rustc::ty::{self, RegionVid, ToPolyTraitRef, Ty, TyCtxt, TyKind};
+use rustc_data_structures::fx::{FxHashMap, FxHashSet};
+use rustc_data_structures::indexed_vec::IndexVec;
 use std::rc::Rc;
 use std::{fmt, iter};
 use syntax_pos::{Span, DUMMY_SP};
 use transform::{MirPass, MirSource};
 
-use either::Either;
-use rustc_data_structures::fx::{FxHashMap, FxHashSet};
-
 macro_rules! span_mirbug {
     ($context:expr, $elem:expr, $($message:tt)*) => ({
         $crate::borrow_check::nll::type_check::mirbug(
@@ -126,12 +127,13 @@ pub(crate) fn type_check<'gcx, 'tcx>(
 ) -> MirTypeckResults<'tcx> {
     let implicit_region_bound = infcx.tcx.mk_region(ty::ReVar(universal_regions.fr_fn_body));
     let mut constraints = MirTypeckRegionConstraints {
+        placeholder_indices: PlaceholderIndices::default(),
+        placeholder_index_to_region: IndexVec::default(),
         liveness_constraints: LivenessValues::new(elements),
         outlives_constraints: ConstraintSet::default(),
         closure_bounds_mapping: Default::default(),
         type_tests: Vec::default(),
     };
-    let mut placeholder_indices = PlaceholderIndices::default();
 
     let CreateResult {
         universal_region_relations,
@@ -151,7 +153,6 @@ pub(crate) fn type_check<'gcx, 'tcx>(
         borrow_set,
         all_facts,
         constraints: &mut constraints,
-        placeholder_indices: &mut placeholder_indices,
     };
 
     type_check_internal(
@@ -175,7 +176,6 @@ pub(crate) fn type_check<'gcx, 'tcx>(
 
     MirTypeckResults {
         constraints,
-        placeholder_indices,
         universal_region_relations,
     }
 }
@@ -730,18 +730,30 @@ struct BorrowCheckContext<'a, 'tcx: 'a> {
     all_facts: &'a mut Option<AllFacts>,
     borrow_set: &'a BorrowSet<'tcx>,
     constraints: &'a mut MirTypeckRegionConstraints<'tcx>,
-    placeholder_indices: &'a mut PlaceholderIndices,
 }
 
 crate struct MirTypeckResults<'tcx> {
     crate constraints: MirTypeckRegionConstraints<'tcx>,
-    crate placeholder_indices: PlaceholderIndices,
     crate universal_region_relations: Rc<UniversalRegionRelations<'tcx>>,
 }
 
 /// A collection of region constraints that must be satisfied for the
 /// program to be considered well-typed.
 crate struct MirTypeckRegionConstraints<'tcx> {
+    /// Maps from a `ty::Placeholder` to the corresponding
+    /// `PlaceholderIndex` bit that we will use for it.
+    ///
+    /// To keep everything in sync, do not insert this set
+    /// directly. Instead, use the `placeholder_region` helper.
+    crate placeholder_indices: PlaceholderIndices,
+
+    /// Each time we add a placeholder to `placeholder_indices`, we
+    /// also create a corresponding "representative" region vid for
+    /// that wraps it. This vector tracks those. This way, when we
+    /// convert the same `ty::RePlaceholder(p)` twice, we can map to
+    /// the same underlying `RegionVid`.
+    crate placeholder_index_to_region: IndexVec<PlaceholderIndex, ty::Region<'tcx>>,
+
     /// In general, the type-checker is not responsible for enforcing
     /// liveness constraints; this job falls to the region inferencer,
     /// which performs a liveness analysis. However, in some limited
@@ -759,6 +771,25 @@ crate struct MirTypeckRegionConstraints<'tcx> {
     crate type_tests: Vec<TypeTest<'tcx>>,
 }
 
+impl MirTypeckRegionConstraints<'tcx> {
+    fn placeholder_region(
+        &mut self,
+        infcx: &InferCtxt<'_, '_, 'tcx>,
+        placeholder: ty::Placeholder,
+    ) -> ty::Region<'tcx> {
+        let placeholder_index = self.placeholder_indices.insert(placeholder);
+        match self.placeholder_index_to_region.get(placeholder_index) {
+            Some(&v) => v,
+            None => {
+                let origin = NLLRegionVariableOrigin::Placeholder(placeholder);
+                let region = infcx.next_nll_region_var_in_universe(origin, placeholder.universe);
+                self.placeholder_index_to_region.push(region);
+                region
+            }
+        }
+    }
+}
+
 /// The `Locations` type summarizes *where* region constraints are
 /// required to hold. Normally, this is at a particular point which
 /// created the obligation, but for constraints that the user gave, we
@@ -888,15 +919,14 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> {
 
         if let Some(ref mut borrowck_context) = self.borrowck_context {
             constraint_conversion::ConstraintConversion::new(
-                self.infcx.tcx,
+                self.infcx,
                 borrowck_context.universal_regions,
                 self.region_bound_pairs,
                 self.implicit_region_bound,
                 self.param_env,
                 locations,
                 category,
-                &mut borrowck_context.constraints.outlives_constraints,
-                &mut borrowck_context.constraints.type_tests,
+                &mut borrowck_context.constraints,
             ).convert_all(&data);
         }
     }
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 13ebf46bdb1..b82efb29f6e 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
@@ -76,16 +76,20 @@ impl TypeRelatingDelegate<'tcx> for NllTypeRelatingDelegate<'_, '_, '_, 'tcx> {
     }
 
     fn next_existential_region_var(&mut self) -> ty::Region<'tcx> {
-        let origin = NLLRegionVariableOrigin::Existential;
-        self.infcx.next_nll_region_var(origin)
+        if let Some(_) = &mut self.borrowck_context {
+            let origin = NLLRegionVariableOrigin::Existential;
+            self.infcx.next_nll_region_var(origin)
+        } else {
+            self.infcx.tcx.types.re_erased
+        }
     }
 
     fn next_placeholder_region(&mut self, placeholder: ty::Placeholder) -> ty::Region<'tcx> {
-        let origin = NLLRegionVariableOrigin::Placeholder(placeholder);
         if let Some(borrowck_context) = &mut self.borrowck_context {
-            borrowck_context.placeholder_indices.insert(placeholder);
+            borrowck_context.constraints.placeholder_region(self.infcx, placeholder)
+        } else {
+            self.infcx.tcx.types.re_erased
         }
-        self.infcx.next_nll_region_var(origin)
     }
 
     fn generalize_existential(&mut self, universe: ty::UniverseIndex) -> ty::Region<'tcx> {
diff --git a/src/librustc_typeck/check/closure.rs b/src/librustc_typeck/check/closure.rs
index 3f4d187813d..fb7c237a536 100644
--- a/src/librustc_typeck/check/closure.rs
+++ b/src/librustc_typeck/check/closure.rs
@@ -13,10 +13,12 @@
 use super::{check_fn, Expectation, FnCtxt, GeneratorTypes};
 
 use astconv::AstConv;
+use middle::region;
 use rustc::hir::def_id::DefId;
 use rustc::infer::{InferOk, InferResult};
 use rustc::infer::LateBoundRegionConversionTime;
 use rustc::infer::type_variable::TypeVariableOrigin;
+use rustc::traits::Obligation;
 use rustc::traits::error_reporting::ArgKind;
 use rustc::ty::{self, ToPolyTraitRef, Ty, GenericParamDefKind};
 use rustc::ty::fold::TypeFoldable;
@@ -479,7 +481,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
         // Along the way, it also writes out entries for types that the user
         // wrote into our tables, which are then later used by the privacy
         // check.
-        match self.check_supplied_sig_against_expectation(expr_def_id, decl, &closure_sigs) {
+        match self.check_supplied_sig_against_expectation(expr_def_id, decl, body, &closure_sigs) {
             Ok(infer_ok) => self.register_infer_ok_obligations(infer_ok),
             Err(_) => return self.sig_of_closure_no_expectation(expr_def_id, decl, body),
         }
@@ -523,6 +525,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
         &self,
         expr_def_id: DefId,
         decl: &hir::FnDecl,
+        body: &hir::Body,
         expected_sigs: &ClosureSignatures<'tcx>,
     ) -> InferResult<'tcx, ()> {
         // Get the signature S that the user gave.
@@ -575,6 +578,31 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                 } = self.at(cause, self.param_env)
                     .eq(*expected_ty, supplied_ty)?;
                 all_obligations.extend(obligations);
+
+                // Also, require that the supplied type must outlive
+                // the closure body.
+                let closure_body_region = self.tcx.mk_region(
+                    ty::ReScope(
+                        region::Scope {
+                            id: body.value.hir_id.local_id,
+                            data: region::ScopeData::Node,
+                        },
+                    ),
+                );
+                all_obligations.push(
+                    Obligation::new(
+                        cause.clone(),
+                        self.param_env,
+                        ty::Predicate::TypeOutlives(
+                            ty::Binder::dummy(
+                                ty::OutlivesPredicate(
+                                    supplied_ty,
+                                    closure_body_region,
+                                ),
+                            ),
+                        ),
+                    ),
+                );
             }
 
             let (supplied_output_ty, _) = self.infcx.replace_late_bound_regions_with_fresh_var(
diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs
index 17784a4681d..9ac733b159b 100644
--- a/src/librustc_typeck/check/mod.rs
+++ b/src/librustc_typeck/check/mod.rs
@@ -976,7 +976,7 @@ impl<'a, 'gcx, 'tcx> Visitor<'gcx> for GatherLocalsVisitor<'a, 'gcx, 'tcx> {
                     o_ty
                 };
 
-                let c_ty = self.fcx.inh.infcx.canonicalize_response(&revealed_ty);
+                let c_ty = self.fcx.inh.infcx.canonicalize_user_type_annotation(&revealed_ty);
                 debug!("visit_local: ty.hir_id={:?} o_ty={:?} revealed_ty={:?} c_ty={:?}",
                        ty.hir_id, o_ty, revealed_ty, c_ty);
                 self.fcx.tables.borrow_mut().user_provided_tys_mut().insert(ty.hir_id, c_ty);
@@ -2137,7 +2137,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                             method.substs[i]
                         }
                     });
-                    self.infcx.canonicalize_response(&UserSubsts {
+                    self.infcx.canonicalize_user_type_annotation(&UserSubsts {
                         substs: just_method_substs,
                         user_self_ty: None, // not relevant here
                     })
@@ -2181,7 +2181,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
         );
 
         if !substs.is_noop() {
-            let user_substs = self.infcx.canonicalize_response(&UserSubsts {
+            let user_substs = self.infcx.canonicalize_user_type_annotation(&UserSubsts {
                 substs,
                 user_self_ty,
             });
diff --git a/src/test/mir-opt/basic_assignment.rs b/src/test/mir-opt/basic_assignment.rs
index 7ca1d01f20b..75f19d133e0 100644
--- a/src/test/mir-opt/basic_assignment.rs
+++ b/src/test/mir-opt/basic_assignment.rs
@@ -56,7 +56,7 @@ fn main() {
 //        StorageLive(_4);
 //        _4 = std::option::Option<std::boxed::Box<u32>>::None;
 //        FakeRead(ForLet, _4);
-//        AscribeUserType(_4, o, UserTypeProjection { base: Ty(Canonical { variables: [], value: std::option::Option<std::boxed::Box<u32>> }), projs: [] });
+//        AscribeUserType(_4, o, UserTypeProjection { base: Ty(Canonical { max_universe: U0, variables: [], value: std::option::Option<std::boxed::Box<u32>> }), projs: [] });
 //        StorageLive(_5);
 //        StorageLive(_6);
 //        _6 = move _4;
diff --git a/src/test/ui/lub-glb/old-lub-glb-hr.stderr b/src/test/ui/lub-glb/old-lub-glb-hr.stderr
index 9b40062bd57..4182b525888 100644
--- a/src/test/ui/lub-glb/old-lub-glb-hr.stderr
+++ b/src/test/ui/lub-glb/old-lub-glb-hr.stderr
@@ -11,8 +11,6 @@ LL | |     };
    |
    = note: expected type `for<'r, 's> fn(&'r u8, &'s u8)`
               found type `for<'a> fn(&'a u8, &'a u8)`
-   = note: this was previously accepted by the compiler but has been phased out
-   = note: for more information, see https://github.com/rust-lang/rust/issues/45852
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/lub-glb/old-lub-glb-object.stderr b/src/test/ui/lub-glb/old-lub-glb-object.stderr
index 79442bd108a..bb8cb45eec3 100644
--- a/src/test/ui/lub-glb/old-lub-glb-object.stderr
+++ b/src/test/ui/lub-glb/old-lub-glb-object.stderr
@@ -11,8 +11,6 @@ LL | |     };
    |
    = note: expected type `&dyn for<'a, 'b> Foo<&'a u8, &'b u8>`
               found type `&dyn for<'a> Foo<&'a u8, &'a u8>`
-   = note: this was previously accepted by the compiler but has been phased out
-   = note: for more information, see https://github.com/rust-lang/rust/issues/45852
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/nll/user-annotations/dump-adt-brace-struct.stderr b/src/test/ui/nll/user-annotations/dump-adt-brace-struct.stderr
index 901ace59d33..88383190cbc 100644
--- a/src/test/ui/nll/user-annotations/dump-adt-brace-struct.stderr
+++ b/src/test/ui/nll/user-annotations/dump-adt-brace-struct.stderr
@@ -1,4 +1,4 @@
-error: user substs: Canonical { variables: [], value: UserSubsts { substs: [u32], user_self_ty: None } }
+error: user substs: Canonical { max_universe: U0, variables: [], value: UserSubsts { substs: [u32], user_self_ty: None } }
   --> $DIR/dump-adt-brace-struct.rs:28:5
    |
 LL |     SomeStruct::<u32> { t: 22 }; //~ ERROR [u32]
diff --git a/src/test/ui/nll/user-annotations/dump-fn-method.stderr b/src/test/ui/nll/user-annotations/dump-fn-method.stderr
index a26be359fc4..3beb994a4e8 100644
--- a/src/test/ui/nll/user-annotations/dump-fn-method.stderr
+++ b/src/test/ui/nll/user-annotations/dump-fn-method.stderr
@@ -1,22 +1,22 @@
-error: user substs: Canonical { variables: [], value: UserSubsts { substs: [u32], user_self_ty: None } }
+error: user substs: Canonical { max_universe: U0, variables: [], value: UserSubsts { substs: [u32], user_self_ty: None } }
   --> $DIR/dump-fn-method.rs:36:13
    |
 LL |     let x = foo::<u32>; //~ ERROR [u32]
    |             ^^^^^^^^^^
 
-error: user substs: Canonical { variables: [CanonicalVarInfo { kind: Ty(General) }, CanonicalVarInfo { kind: Ty(General) }], value: UserSubsts { substs: [?0, u32, ?1], user_self_ty: None } }
+error: user substs: Canonical { max_universe: U0, variables: [CanonicalVarInfo { kind: Ty(General) }, CanonicalVarInfo { kind: Ty(General) }], value: UserSubsts { substs: [?0, u32, ?1], user_self_ty: None } }
   --> $DIR/dump-fn-method.rs:42:13
    |
 LL |     let x = <_ as Bazoom<u32>>::method::<_>; //~ ERROR [?0, u32, ?1]
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
-error: user substs: Canonical { variables: [], value: UserSubsts { substs: [u8, u16, u32], user_self_ty: None } }
+error: user substs: Canonical { max_universe: U0, variables: [], value: UserSubsts { substs: [u8, u16, u32], user_self_ty: None } }
   --> $DIR/dump-fn-method.rs:46:13
    |
 LL |     let x = <u8 as Bazoom<u16>>::method::<u32>; //~ ERROR [u8, u16, u32]
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
-error: user substs: Canonical { variables: [CanonicalVarInfo { kind: Ty(General) }, CanonicalVarInfo { kind: Ty(General) }], value: UserSubsts { substs: [?0, ?1, u32], user_self_ty: None } }
+error: user substs: Canonical { max_universe: U0, variables: [CanonicalVarInfo { kind: Ty(General) }, CanonicalVarInfo { kind: Ty(General) }], value: UserSubsts { substs: [?0, ?1, u32], user_self_ty: None } }
   --> $DIR/dump-fn-method.rs:54:5
    |
 LL |     y.method::<u32>(44, 66); //~ ERROR [?0, ?1, u32]