about summary refs log tree commit diff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/librustc_infer/infer/higher_ranked/mod.rs23
-rw-r--r--src/librustc_infer/infer/mod.rs11
-rw-r--r--src/librustc_infer/infer/nll_relate/mod.rs8
-rw-r--r--src/librustc_infer/infer/region_constraints/leak_check.rs522
-rw-r--r--src/librustc_infer/lib.rs3
-rw-r--r--src/librustc_mir/borrow_check/type_check/relate_tys.rs2
-rw-r--r--src/librustc_trait_selection/traits/coherence.rs10
-rw-r--r--src/librustc_trait_selection/traits/project.rs7
-rw-r--r--src/librustc_trait_selection/traits/select/candidate_assembly.rs10
-rw-r--r--src/librustc_trait_selection/traits/select/confirmation.rs25
-rw-r--r--src/librustc_trait_selection/traits/select/mod.rs42
-rw-r--r--src/librustc_typeck/check/coercion.rs20
-rw-r--r--src/test/mir-opt/address-of/rustc.address_of_reborrow.SimplifyCfg-initial.after.mir4
-rw-r--r--src/test/ui/associated-types/associated-types-eq-hr.nll.stderr33
-rw-r--r--src/test/ui/associated-types/associated-types-eq-hr.rs37
-rw-r--r--src/test/ui/associated-types/associated-types-eq-hr.stderr125
-rw-r--r--src/test/ui/associated-types/cache/project-fn-ret-invariant.krisskross.nll.stderr20
-rw-r--r--src/test/ui/associated-types/cache/project-fn-ret-invariant.krisskross.stderr30
-rw-r--r--src/test/ui/associated-types/cache/project-fn-ret-invariant.ok.stderr6
-rw-r--r--src/test/ui/associated-types/cache/project-fn-ret-invariant.oneuse.nll.stderr22
-rw-r--r--src/test/ui/associated-types/cache/project-fn-ret-invariant.oneuse.stderr14
-rw-r--r--src/test/ui/associated-types/cache/project-fn-ret-invariant.rs41
-rw-r--r--src/test/ui/associated-types/cache/project-fn-ret-invariant.transmute.nll.stderr8
-rw-r--r--src/test/ui/associated-types/cache/project-fn-ret-invariant.transmute.stderr26
-rw-r--r--src/test/ui/associated-types/higher-ranked-projection.bad.nll.stderr8
-rw-r--r--src/test/ui/associated-types/higher-ranked-projection.bad.stderr14
-rw-r--r--src/test/ui/associated-types/higher-ranked-projection.rs2
-rw-r--r--src/test/ui/closure-expected-type/expect-fn-supply-fn.nll.stderr63
-rw-r--r--src/test/ui/closure-expected-type/expect-fn-supply-fn.rs17
-rw-r--r--src/test/ui/closure-expected-type/expect-fn-supply-fn.stderr71
-rw-r--r--src/test/ui/closures/issue-41366.rs3
-rw-r--r--src/test/ui/closures/issue-41366.stderr21
-rw-r--r--src/test/ui/coherence/coherence-fn-covariant-bound-vs-static.rs26
-rw-r--r--src/test/ui/coherence/coherence-fn-covariant-bound-vs-static.stderr13
-rw-r--r--src/test/ui/coherence/coherence-fn-implied-bounds.rs26
-rw-r--r--src/test/ui/coherence/coherence-fn-implied-bounds.stderr20
-rw-r--r--src/test/ui/coherence/coherence-fn-inputs.rs25
-rw-r--r--src/test/ui/coherence/coherence-fn-inputs.stderr13
-rw-r--r--src/test/ui/coherence/coherence-free-vs-bound-region.rs21
-rw-r--r--src/test/ui/coherence/coherence-free-vs-bound-region.stderr20
-rw-r--r--src/test/ui/coherence/coherence-wasm-bindgen.rs37
-rw-r--r--src/test/ui/coherence/coherence-wasm-bindgen.stderr32
-rw-r--r--src/test/ui/generator/resume-arg-late-bound.nll.stderr8
-rw-r--r--src/test/ui/generator/resume-arg-late-bound.rs3
-rw-r--r--src/test/ui/generator/resume-arg-late-bound.stderr28
-rw-r--r--src/test/ui/hr-subtype/hr-subtype.bound_a_b_ret_a_vs_bound_a_ret_a.nll.stderr14
-rw-r--r--src/test/ui/hr-subtype/hr-subtype.bound_a_b_ret_a_vs_bound_a_ret_a.stderr8
-rw-r--r--src/test/ui/hr-subtype/hr-subtype.bound_a_b_vs_bound_a.stderr23
-rw-r--r--src/test/ui/hr-subtype/hr-subtype.bound_a_vs_bound_a.stderr4
-rw-r--r--src/test/ui/hr-subtype/hr-subtype.bound_a_vs_bound_b.stderr4
-rw-r--r--src/test/ui/hr-subtype/hr-subtype.bound_a_vs_free_x.nll.stderr14
-rw-r--r--src/test/ui/hr-subtype/hr-subtype.bound_a_vs_free_x.stderr8
-rw-r--r--src/test/ui/hr-subtype/hr-subtype.bound_co_a_b_vs_bound_co_a.stderr23
-rw-r--r--src/test/ui/hr-subtype/hr-subtype.bound_co_a_co_b_ret_contra_a.stderr23
-rw-r--r--src/test/ui/hr-subtype/hr-subtype.bound_co_a_vs_bound_co_b.stderr4
-rw-r--r--src/test/ui/hr-subtype/hr-subtype.bound_contra_a_contra_b_ret_co_a.stderr23
-rw-r--r--src/test/ui/hr-subtype/hr-subtype.bound_inv_a_b_vs_bound_inv_a.nll.stderr26
-rw-r--r--src/test/ui/hr-subtype/hr-subtype.bound_inv_a_b_vs_bound_inv_a.stderr8
-rw-r--r--src/test/ui/hr-subtype/hr-subtype.bound_inv_a_vs_bound_inv_b.stderr4
-rw-r--r--src/test/ui/hr-subtype/hr-subtype.free_inv_x_vs_free_inv_y.nll.stderr20
-rw-r--r--src/test/ui/hr-subtype/hr-subtype.free_inv_x_vs_free_inv_y.stderr56
-rw-r--r--src/test/ui/hr-subtype/hr-subtype.free_x_vs_free_x.stderr4
-rw-r--r--src/test/ui/hr-subtype/hr-subtype.free_x_vs_free_y.nll.stderr10
-rw-r--r--src/test/ui/hr-subtype/hr-subtype.free_x_vs_free_y.stderr28
-rw-r--r--src/test/ui/hr-subtype/hr-subtype.rs66
-rw-r--r--src/test/ui/hr-subtype/return-static.rs13
-rw-r--r--src/test/ui/hrtb/hrtb-conflate-regions.nll.stderr14
-rw-r--r--src/test/ui/hrtb/hrtb-conflate-regions.stderr21
-rw-r--r--src/test/ui/hrtb/hrtb-exists-forall-fn.nll.stderr8
-rw-r--r--src/test/ui/hrtb/hrtb-exists-forall-fn.stderr4
-rw-r--r--src/test/ui/hrtb/hrtb-exists-forall-trait-contravariant.nll.stderr8
-rw-r--r--src/test/ui/hrtb/hrtb-exists-forall-trait-contravariant.rs2
-rw-r--r--src/test/ui/hrtb/hrtb-exists-forall-trait-contravariant.stderr18
-rw-r--r--src/test/ui/hrtb/hrtb-exists-forall-trait-covariant.rs5
-rw-r--r--src/test/ui/hrtb/hrtb-exists-forall-trait-covariant.stderr18
-rw-r--r--src/test/ui/hrtb/hrtb-exists-forall-trait-invariant.nll.stderr8
-rw-r--r--src/test/ui/hrtb/hrtb-exists-forall-trait-invariant.rs2
-rw-r--r--src/test/ui/hrtb/hrtb-exists-forall-trait-invariant.stderr18
-rw-r--r--src/test/ui/hrtb/hrtb-just-for-static.nll.stderr24
-rw-r--r--src/test/ui/hrtb/hrtb-just-for-static.stderr41
-rw-r--r--src/test/ui/hrtb/issue-30786.migrate.stderr50
-rw-r--r--src/test/ui/hrtb/issue-30786.nll.stderr99
-rw-r--r--src/test/ui/hrtb/issue-30786.rs102
-rw-r--r--src/test/ui/hrtb/issue-46989.nll.stderr8
-rw-r--r--src/test/ui/hrtb/issue-46989.rs8
-rw-r--r--src/test/ui/hrtb/issue-46989.stderr15
-rw-r--r--src/test/ui/issues/issue-40000.nll.stderr8
-rw-r--r--src/test/ui/issues/issue-40000.stderr6
-rw-r--r--src/test/ui/issues/issue-43623.rs7
-rw-r--r--src/test/ui/issues/issue-43623.stderr29
-rw-r--r--src/test/ui/issues/issue-57362-2.stderr2
-rw-r--r--src/test/ui/issues/issue-60283.rs8
-rw-r--r--src/test/ui/issues/issue-60283.stderr29
-rw-r--r--src/test/ui/lub-glb/old-lub-glb-hr-eq.rs (renamed from src/test/ui/lub-glb/old-lub-glb-hr.rs)21
-rw-r--r--src/test/ui/lub-glb/old-lub-glb-hr-noteq1.nll.stderr8
-rw-r--r--src/test/ui/lub-glb/old-lub-glb-hr-noteq1.rs24
-rw-r--r--src/test/ui/lub-glb/old-lub-glb-hr-noteq1.stderr18
-rw-r--r--src/test/ui/lub-glb/old-lub-glb-hr-noteq2.rs33
-rw-r--r--src/test/ui/lub-glb/old-lub-glb-hr-noteq2.stderr18
-rw-r--r--src/test/ui/lub-glb/old-lub-glb-hr.stderr18
-rw-r--r--src/test/ui/lub-glb/old-lub-glb-object.nll.stderr14
-rw-r--r--src/test/ui/lub-glb/old-lub-glb-object.rs18
-rw-r--r--src/test/ui/lub-glb/old-lub-glb-object.stderr15
-rw-r--r--src/test/ui/mismatched_types/closure-arg-type-mismatch.nll.stderr27
-rw-r--r--src/test/ui/mismatched_types/closure-arg-type-mismatch.rs7
-rw-r--r--src/test/ui/mismatched_types/closure-arg-type-mismatch.stderr49
-rw-r--r--src/test/ui/mismatched_types/closure-mismatch.nll.stderr14
-rw-r--r--src/test/ui/mismatched_types/closure-mismatch.rs3
-rw-r--r--src/test/ui/mismatched_types/closure-mismatch.stderr28
-rw-r--r--src/test/ui/regions-fn-subtyping-return-static-fail.nll.stderr8
-rw-r--r--src/test/ui/regions-fn-subtyping-return-static-fail.rs11
-rw-r--r--src/test/ui/regions-fn-subtyping-return-static-fail.stderr15
-rw-r--r--src/test/ui/regions/region-lifetime-bounds-on-fns-where-clause.nll.stderr44
-rw-r--r--src/test/ui/regions/region-lifetime-bounds-on-fns-where-clause.stderr6
-rw-r--r--src/test/ui/regions/region-multiple-lifetime-bounds-on-fns-where-clause.nll.stderr50
-rw-r--r--src/test/ui/regions/region-multiple-lifetime-bounds-on-fns-where-clause.stderr6
-rw-r--r--src/test/ui/regions/regions-fn-subtyping-return-static.rs13
-rw-r--r--src/test/ui/regions/regions-fn-subtyping-return-static.stderr12
-rw-r--r--src/test/ui/regions/regions-lifetime-bounds-on-fns.nll.stderr44
-rw-r--r--src/test/ui/regions/regions-lifetime-bounds-on-fns.stderr6
-rw-r--r--src/test/ui/rfc1623.nll.stderr68
-rw-r--r--src/test/ui/rfc1623.rs8
-rw-r--r--src/test/ui/rfc1623.stderr46
-rw-r--r--src/test/ui/type-alias-impl-trait/issue-57611-trait-alias.nll.stderr14
-rw-r--r--src/test/ui/type-alias-impl-trait/issue-57611-trait-alias.rs4
-rw-r--r--src/test/ui/type-alias-impl-trait/issue-57611-trait-alias.stderr23
-rw-r--r--src/test/ui/unboxed-closures/unboxed-closures-unsafe-extern-fn.rs22
-rw-r--r--src/test/ui/unboxed-closures/unboxed-closures-unsafe-extern-fn.stderr44
-rw-r--r--src/test/ui/unboxed-closures/unboxed-closures-wrong-abi.rs22
-rw-r--r--src/test/ui/unboxed-closures/unboxed-closures-wrong-abi.stderr44
-rw-r--r--src/test/ui/unboxed-closures/unboxed-closures-wrong-arg-type-extern-fn.rs22
-rw-r--r--src/test/ui/unboxed-closures/unboxed-closures-wrong-arg-type-extern-fn.stderr44
-rw-r--r--src/test/ui/where-clauses/where-for-self-2.nll.stderr8
-rw-r--r--src/test/ui/where-clauses/where-for-self-2.rs8
-rw-r--r--src/test/ui/where-clauses/where-for-self-2.stderr21
135 files changed, 2143 insertions, 1250 deletions
diff --git a/src/librustc_infer/infer/higher_ranked/mod.rs b/src/librustc_infer/infer/higher_ranked/mod.rs
index 0499dc9ed22..b6251e34008 100644
--- a/src/librustc_infer/infer/higher_ranked/mod.rs
+++ b/src/librustc_infer/infer/higher_ranked/mod.rs
@@ -30,10 +30,10 @@ impl<'a, 'tcx> CombineFields<'a, 'tcx> {
 
         let span = self.trace.cause.span;
 
-        self.infcx.commit_if_ok(|snapshot| {
+        self.infcx.commit_if_ok(|_| {
             // First, we instantiate each bound region in the supertype with a
             // fresh placeholder region.
-            let (b_prime, placeholder_map) = self.infcx.replace_bound_vars_with_placeholders(b);
+            let (b_prime, _) = self.infcx.replace_bound_vars_with_placeholders(b);
 
             // Next, we instantiate each bound region in the subtype
             // with a fresh region variable. These region variables --
@@ -48,8 +48,6 @@ impl<'a, 'tcx> CombineFields<'a, 'tcx> {
             // Compare types now that bound regions have been replaced.
             let result = self.sub(a_is_expected).relate(&a_prime, &b_prime)?;
 
-            self.infcx.leak_check(!a_is_expected, &placeholder_map, snapshot)?;
-
             debug!("higher_ranked_sub: OK result={:?}", result);
 
             Ok(ty::Binder::bind(result))
@@ -75,7 +73,12 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
     where
         T: TypeFoldable<'tcx>,
     {
-        let next_universe = self.create_next_universe();
+        // Figure out what the next universe will be, but don't actually create
+        // it until after we've done the substitution (in particular there may
+        // be no bound variables). This is a performance optimization, since the
+        // leak check for example can be skipped if no new universes are created
+        // (i.e., if there are no placeholders).
+        let next_universe = self.universe().next_universe();
 
         let fld_r = |br| {
             self.tcx.mk_region(ty::RePlaceholder(ty::PlaceholderRegion {
@@ -103,6 +106,13 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
 
         let (result, map) = self.tcx.replace_bound_vars(binder, fld_r, fld_t, fld_c);
 
+        // If there were higher-ranked regions to replace, then actually create
+        // the next universe (this avoids needlessly creating universes).
+        if !map.is_empty() {
+            let n_u = self.create_next_universe();
+            assert_eq!(n_u, next_universe);
+        }
+
         debug!(
             "replace_bound_vars_with_placeholders(\
              next_universe={:?}, \
@@ -119,7 +129,6 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
     pub fn leak_check(
         &self,
         overly_polymorphic: bool,
-        placeholder_map: &PlaceholderMap<'tcx>,
         snapshot: &CombinedSnapshot<'_, 'tcx>,
     ) -> RelateResult<'tcx, ()> {
         // If the user gave `-Zno-leak-check`, or we have been
@@ -135,7 +144,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
         self.inner.borrow_mut().unwrap_region_constraints().leak_check(
             self.tcx,
             overly_polymorphic,
-            placeholder_map,
+            self.universe(),
             snapshot,
         )
     }
diff --git a/src/librustc_infer/infer/mod.rs b/src/librustc_infer/infer/mod.rs
index 91f4b3323f3..8f8ce03d638 100644
--- a/src/librustc_infer/infer/mod.rs
+++ b/src/librustc_infer/infer/mod.rs
@@ -991,14 +991,12 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
             return None;
         }
 
-        Some(self.commit_if_ok(|snapshot| {
-            let (ty::SubtypePredicate { a_is_expected, a, b }, placeholder_map) =
+        Some(self.commit_if_ok(|_snapshot| {
+            let (ty::SubtypePredicate { a_is_expected, a, b }, _) =
                 self.replace_bound_vars_with_placeholders(&predicate);
 
             let ok = self.at(cause, param_env).sub_exp(a_is_expected, a, b)?;
 
-            self.leak_check(false, &placeholder_map, snapshot)?;
-
             Ok(ok.unit())
         }))
     }
@@ -1008,14 +1006,13 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
         cause: &traits::ObligationCause<'tcx>,
         predicate: ty::PolyRegionOutlivesPredicate<'tcx>,
     ) -> UnitResult<'tcx> {
-        self.commit_if_ok(|snapshot| {
-            let (ty::OutlivesPredicate(r_a, r_b), placeholder_map) =
+        self.commit_if_ok(|_snapshot| {
+            let (ty::OutlivesPredicate(r_a, r_b), _) =
                 self.replace_bound_vars_with_placeholders(&predicate);
             let origin = SubregionOrigin::from_obligation_cause(cause, || {
                 RelateRegionParamBound(cause.span)
             });
             self.sub_regions(origin, r_b, r_a); // `b : a` ==> `a <= b`
-            self.leak_check(false, &placeholder_map, snapshot)?;
             Ok(())
         })
     }
diff --git a/src/librustc_infer/infer/nll_relate/mod.rs b/src/librustc_infer/infer/nll_relate/mod.rs
index 8de89251006..2350c28dfaa 100644
--- a/src/librustc_infer/infer/nll_relate/mod.rs
+++ b/src/librustc_infer/infer/nll_relate/mod.rs
@@ -522,7 +522,13 @@ where
         }
 
         if a == b {
-            return Ok(a);
+            // Subtle: if a or b has a bound variable that we are lazilly
+            // substituting, then even if a == b, it could be that the values we
+            // will substitute for those bound variables are *not* the same, and
+            // hence returning `Ok(a)` is incorrect.
+            if !a.has_escaping_bound_vars() && !b.has_escaping_bound_vars() {
+                return Ok(a);
+            }
         }
 
         match (&a.kind, &b.kind) {
diff --git a/src/librustc_infer/infer/region_constraints/leak_check.rs b/src/librustc_infer/infer/region_constraints/leak_check.rs
index 91c39a0e78f..32e708bf52b 100644
--- a/src/librustc_infer/infer/region_constraints/leak_check.rs
+++ b/src/librustc_infer/infer/region_constraints/leak_check.rs
@@ -1,158 +1,446 @@
 use super::*;
-use crate::infer::{CombinedSnapshot, PlaceholderMap};
-use rustc_data_structures::undo_log::UndoLogs;
+use crate::infer::CombinedSnapshot;
+use rustc_data_structures::{
+    graph::{scc::Sccs, vec_graph::VecGraph},
+    undo_log::UndoLogs,
+};
+use rustc_index::vec::Idx;
 use rustc_middle::ty::error::TypeError;
 use rustc_middle::ty::relate::RelateResult;
 
 impl<'tcx> RegionConstraintCollector<'_, 'tcx> {
-    /// Searches region constraints created since `snapshot` that
-    /// affect one of the placeholders in `placeholder_map`, returning
-    /// an error if any of the placeholders are related to another
-    /// placeholder or would have to escape into some parent universe
-    /// that cannot name them.
+    /// Searches new universes created during `snapshot`, looking for
+    /// placeholders that may "leak" out from the universes they are contained
+    /// in. If any leaking placeholders are found, then an `Err` is returned
+    /// (typically leading to the snapshot being reversed).
     ///
-    /// This is a temporary backwards compatibility measure to try and
-    /// retain the older (arguably incorrect) behavior of the
-    /// compiler.
+    /// The leak check *used* to be the only way we had to handle higher-ranked
+    /// obligations. Now that we have integrated universes into the region
+    /// solvers, this is no longer the case, but we retain the leak check for
+    /// backwards compatibility purposes. In particular, it lets us make "early"
+    /// decisions about whether a region error will be reported that are used in
+    /// coherence and elsewhere -- see #56105 and #59490 for more details. The
+    /// eventual fate of the leak checker is not yet settled.
     ///
-    /// NB. Although `_snapshot` isn't used, it's passed in to prove
-    /// that we are in a snapshot, which guarantees that we can just
-    /// search the "undo log" for edges. This is mostly an efficiency
-    /// thing -- we could search *all* region constraints, but that'd be
-    /// a bigger set and the data structures are not setup for that. If
-    /// we wind up keeping some form of this check long term, it would
-    /// probably be better to remove the snapshot parameter and to
-    /// refactor the constraint set.
+    /// The leak checker works by searching for the following error patterns:
+    ///
+    /// * P1: P2, where P1 != P2
+    /// * P1: R, where R is in some universe that cannot name P1
+    ///
+    /// The idea here is that each of these patterns represents something that
+    /// the region solver would eventually report as an error, so we can detect
+    /// the error early. There is a fly in the ointment, though, in that this is
+    /// not entirely true. In particular, in the future, we may extend the
+    /// environment with implied bounds or other info about how placeholders
+    /// relate to regions in outer universes. In that case, `P1: R` for example
+    /// might become solveable.
+    ///
+    /// # Summary of the implementation
+    ///
+    /// The leak checks as follows. First, we construct a graph where `R2: R1`
+    /// implies `R2 -> R1`, and we compute the SCCs.
+    ///
+    /// For each SCC S, we compute:
+    ///
+    /// * what placeholder P it must be equal to, if any
+    ///   * if there are multiple placeholders that must be equal, report an error because `P1: P2`
+    /// * the minimum universe of its constituents
+    ///
+    /// Then we walk the SCCs in dependency order and compute
+    ///
+    /// * what placeholder they must outlive transitively
+    ///   * if they must also be equal to a placeholder, report an error because `P1: P2`
+    /// * minimum universe U of all SCCs they must outlive
+    ///   * if they must also be equal to a placeholder P, and U cannot name P, report an error, as that
+    ///     indicates `P: R` and `R` is in an incompatible universe
+    ///
+    /// # Historical note
+    ///
+    /// Older variants of the leak check used to report errors for these
+    /// patterns, but we no longer do:
+    ///
+    /// * R: P1, even if R cannot name P1, because R = 'static is a valid sol'n
+    /// * R: P1, R: P2, as above
     pub fn leak_check(
         &mut self,
         tcx: TyCtxt<'tcx>,
         overly_polymorphic: bool,
-        placeholder_map: &PlaceholderMap<'tcx>,
-        _snapshot: &CombinedSnapshot<'_, 'tcx>,
+        max_universe: ty::UniverseIndex,
+        snapshot: &CombinedSnapshot<'_, 'tcx>,
     ) -> RelateResult<'tcx, ()> {
-        debug!("leak_check(placeholders={:?})", placeholder_map);
+        debug!(
+            "leak_check(max_universe={:?}, snapshot.universe={:?}, overly_polymorphic={:?})",
+            max_universe, snapshot.universe, overly_polymorphic
+        );
 
         assert!(UndoLogs::<super::UndoLog<'_>>::in_snapshot(&self.undo_log));
 
-        // Go through each placeholder that we created.
-        for &placeholder_region in placeholder_map.values() {
-            // Find the universe this placeholder inhabits.
-            let placeholder = match placeholder_region {
-                ty::RePlaceholder(p) => p,
-                _ => bug!("leak_check: expected placeholder found {:?}", placeholder_region,),
-            };
-
-            // Find all regions that are related to this placeholder
-            // in some way. This means any region that either outlives
-            // or is outlived by a placeholder.
-            let mut taint_set = TaintSet::new(TaintDirections::both(), placeholder_region);
-            taint_set.fixed_point(
-                tcx,
-                self.undo_log.region_constraints(),
-                &self.storage.data.verifys,
-            );
-            let tainted_regions = taint_set.into_set();
-
-            // Report an error if two placeholders in the same universe
-            // are related to one another, or if a placeholder is related
-            // to something from a parent universe.
-            for &tainted_region in &tainted_regions {
-                if let ty::RePlaceholder(_) = tainted_region {
-                    // Two placeholders cannot be related:
-                    if tainted_region == placeholder_region {
-                        continue;
-                    }
-                } else if self.universe(tainted_region).can_name(placeholder.universe) {
-                    continue;
-                }
-
-                return Err(if overly_polymorphic {
-                    debug!("overly polymorphic!");
-                    TypeError::RegionsOverlyPolymorphic(placeholder.name, tainted_region)
-                } else {
-                    debug!("not as polymorphic!");
-                    TypeError::RegionsInsufficientlyPolymorphic(placeholder.name, tainted_region)
-                });
-            }
+        let universe_at_start_of_snapshot = snapshot.universe;
+        if universe_at_start_of_snapshot == max_universe {
+            return Ok(());
         }
 
+        let mini_graph =
+            &MiniGraph::new(tcx, self.undo_log.region_constraints(), &self.storage.data.verifys);
+
+        let mut leak_check = LeakCheck::new(
+            tcx,
+            universe_at_start_of_snapshot,
+            max_universe,
+            overly_polymorphic,
+            mini_graph,
+            self,
+        );
+        leak_check.assign_placeholder_values()?;
+        leak_check.propagate_scc_value()?;
         Ok(())
     }
 }
 
-#[derive(Debug)]
-struct TaintSet<'tcx> {
-    directions: TaintDirections,
-    regions: FxHashSet<ty::Region<'tcx>>,
+struct LeakCheck<'me, 'tcx> {
+    tcx: TyCtxt<'tcx>,
+    universe_at_start_of_snapshot: ty::UniverseIndex,
+    overly_polymorphic: bool,
+    mini_graph: &'me MiniGraph<'tcx>,
+    rcc: &'me RegionConstraintCollector<'me, 'tcx>,
+
+    // Initially, for each SCC S, stores a placeholder `P` such that `S = P`
+    // must hold.
+    //
+    // Later, during the [`LeakCheck::propagate_scc_value`] function, this array
+    // is repurposed to store some placeholder `P` such that the weaker
+    // condition `S: P` must hold. (This is true if `S: S1` transitively and `S1
+    // = P`.)
+    scc_placeholders: IndexVec<LeakCheckScc, Option<ty::PlaceholderRegion>>,
+
+    // For each SCC S, track the minimum universe that flows into it. Note that
+    // this is both the minimum of the universes for every region that is a
+    // member of the SCC, but also if you have `R1: R2`, then the universe of
+    // `R2` must be less than the universe of `R1` (i.e., `R1` flows `R2`). To
+    // see that, imagine that you have `P1: R` -- in that case, `R` must be
+    // either the placeholder `P1` or the empty region in that same universe.
+    //
+    // To detect errors, we look for an SCC S where the values in
+    // `scc_values[S]` (if any) cannot be stored into `scc_universes[S]`.
+    scc_universes: IndexVec<LeakCheckScc, SccUniverse<'tcx>>,
 }
 
-impl<'tcx> TaintSet<'tcx> {
-    fn new(directions: TaintDirections, initial_region: ty::Region<'tcx>) -> Self {
-        let mut regions = FxHashSet::default();
-        regions.insert(initial_region);
-        TaintSet { directions, regions }
+impl<'me, 'tcx> LeakCheck<'me, 'tcx> {
+    fn new(
+        tcx: TyCtxt<'tcx>,
+        universe_at_start_of_snapshot: ty::UniverseIndex,
+        max_universe: ty::UniverseIndex,
+        overly_polymorphic: bool,
+        mini_graph: &'me MiniGraph<'tcx>,
+        rcc: &'me RegionConstraintCollector<'me, 'tcx>,
+    ) -> Self {
+        let dummy_scc_universe = SccUniverse { universe: max_universe, region: None };
+        Self {
+            tcx,
+            universe_at_start_of_snapshot,
+            overly_polymorphic,
+            mini_graph,
+            rcc,
+            scc_placeholders: IndexVec::from_elem_n(None, mini_graph.sccs.num_sccs()),
+            scc_universes: IndexVec::from_elem_n(dummy_scc_universe, mini_graph.sccs.num_sccs()),
+        }
+    }
+
+    /// Compute what placeholders (if any) each SCC must be equal to.
+    /// Also compute the minimum universe of all the regions in each SCC.
+    fn assign_placeholder_values(&mut self) -> RelateResult<'tcx, ()> {
+        // First walk: find each placeholder that is from a newly created universe.
+        for (region, leak_check_node) in &self.mini_graph.nodes {
+            let scc = self.mini_graph.sccs.scc(*leak_check_node);
+
+            // Set the universe of each SCC to be the minimum of its constituent universes
+            let universe = self.rcc.universe(region);
+            debug!(
+                "assign_placeholder_values: scc={:?} universe={:?} region={:?}",
+                scc, universe, region
+            );
+            self.scc_universes[scc].take_min(universe, region);
+
+            // Detect those SCCs that directly contain a placeholder
+            if let ty::RePlaceholder(placeholder) = region {
+                if self.universe_at_start_of_snapshot.cannot_name(placeholder.universe) {
+                    self.assign_scc_value(scc, *placeholder)?;
+                }
+            }
+        }
+
+        Ok(())
     }
 
-    fn fixed_point<'a>(
+    // assign_scc_value(S, P): Update `scc_values` to account for the fact that `P: S` must hold.
+    // This may create an error.
+    fn assign_scc_value(
         &mut self,
-        tcx: TyCtxt<'tcx>,
-        undo_log: impl IntoIterator<Item = &'a UndoLog<'tcx>> + Clone,
-        verifys: &[Verify<'tcx>],
-    ) where
-        'tcx: 'a,
-    {
-        let mut prev_len = 0;
-        while prev_len < self.len() {
-            debug!("tainted: prev_len = {:?} new_len = {:?}", prev_len, self.len());
-
-            prev_len = self.len();
-
-            for undo_entry in undo_log.clone() {
-                match undo_entry {
-                    &AddConstraint(Constraint::VarSubVar(a, b)) => {
-                        self.add_edge(tcx.mk_region(ReVar(a)), tcx.mk_region(ReVar(b)));
-                    }
-                    &AddConstraint(Constraint::RegSubVar(a, b)) => {
-                        self.add_edge(a, tcx.mk_region(ReVar(b)));
-                    }
-                    &AddConstraint(Constraint::VarSubReg(a, b)) => {
-                        self.add_edge(tcx.mk_region(ReVar(a)), b);
-                    }
-                    &AddConstraint(Constraint::RegSubReg(a, b)) => {
-                        self.add_edge(a, b);
-                    }
-                    &AddGiven(a, b) => {
-                        self.add_edge(a, tcx.mk_region(ReVar(b)));
-                    }
-                    &AddVerify(i) => span_bug!(
-                        verifys[i].origin.span(),
-                        "we never add verifications while doing higher-ranked things",
-                    ),
-                    &AddCombination(..) | &AddVar(..) => {}
+        scc: LeakCheckScc,
+        placeholder: ty::PlaceholderRegion,
+    ) -> RelateResult<'tcx, ()> {
+        match self.scc_placeholders[scc] {
+            Some(p) => {
+                assert_ne!(p, placeholder);
+                return Err(self.placeholder_error(p, placeholder));
+            }
+            None => {
+                self.scc_placeholders[scc] = Some(placeholder);
+            }
+        };
+
+        Ok(())
+    }
+
+    /// For each SCC S, iterate over each successor S1 where `S: S1`:
+    ///
+    /// * Compute
+    /// Iterate over each SCC `S` and ensure that, for each `S1` where `S1: S`,
+    /// `universe(S) <= universe(S1)`. This executes after
+    /// `assign_placeholder_values`, so `universe(S)` is already the minimum
+    /// universe of any of its direct constituents.
+    fn propagate_scc_value(&mut self) -> RelateResult<'tcx, ()> {
+        // Loop invariants:
+        //
+        // On start of the loop iteration for `scc1`:
+        //
+        // * `scc_universes[scc1]` contains the minimum universe of the
+        //   constituents of `scc1`
+        // * `scc_placeholder[scc1]` stores the placeholder that `scc1` must
+        //   be equal to (if any)
+        //
+        // For each succssor `scc2` where `scc1: scc2`:
+        //
+        // * `scc_placeholder[scc2]` stores some placeholder `P` where
+        //   `scc2: P` (if any)
+        // * `scc_universes[scc2]` contains the minimum universe of the
+        //   constituents of `scc2` and any of its successors
+        for scc1 in self.mini_graph.sccs.all_sccs() {
+            debug!(
+                "propagate_scc_value: scc={:?} with universe {:?}",
+                scc1, self.scc_universes[scc1]
+            );
+
+            // Walk over each `scc2` such that `scc1: scc2` and compute:
+            //
+            // * `scc1_universe`: the minimum universe of `scc2` and the constituents of `scc1`
+            // * `succ_bound`: placeholder `P` that the successors must outlive, if any (if there are multiple,
+            //   we pick one arbitrarily)
+            let mut scc1_universe = self.scc_universes[scc1];
+            let mut succ_bound = None;
+            for &scc2 in self.mini_graph.sccs.successors(scc1) {
+                let SccUniverse { universe: scc2_universe, region: scc2_region } =
+                    self.scc_universes[scc2];
+
+                scc1_universe.take_min(scc2_universe, scc2_region.unwrap());
+
+                if let Some(b) = self.scc_placeholders[scc2] {
+                    succ_bound = Some(b);
                 }
             }
+
+            // Update minimum universe of scc1.
+            self.scc_universes[scc1] = scc1_universe;
+
+            // At this point, `scc_placholder[scc1]` stores the placeholder that
+            // `scc1` must be equal to, if any.
+            if let Some(scc1_placeholder) = self.scc_placeholders[scc1] {
+                debug!(
+                    "propagate_scc_value: scc1={:?} placeholder={:?} scc1_universe={:?}",
+                    scc1, scc1_placeholder, scc1_universe
+                );
+
+                // Check if `P1: R` for some `R` in a universe that cannot name
+                // P1. That's an error.
+                if scc1_universe.universe.cannot_name(scc1_placeholder.universe) {
+                    return Err(self.error(scc1_placeholder, scc1_universe.region.unwrap()));
+                }
+
+                // Check if we have some placeholder where `S: P2`
+                // (transitively). In that case, since `S = P1`, that implies
+                // `P1: P2`, which is an error condition.
+                if let Some(scc2_placeholder) = succ_bound {
+                    assert_ne!(scc1_placeholder, scc2_placeholder);
+                    return Err(self.placeholder_error(scc1_placeholder, scc2_placeholder));
+                }
+            } else {
+                // Otherwise, we can reach a placeholder if some successor can.
+                self.scc_placeholders[scc1] = succ_bound;
+            }
+
+            // At this point, `scc_placeholder[scc1]` stores some placeholder that `scc1` must outlive (if any).
         }
+        Ok(())
     }
 
-    fn into_set(self) -> FxHashSet<ty::Region<'tcx>> {
-        self.regions
+    fn placeholder_error(
+        &self,
+        placeholder1: ty::PlaceholderRegion,
+        placeholder2: ty::PlaceholderRegion,
+    ) -> TypeError<'tcx> {
+        self.error(placeholder1, self.tcx.mk_region(ty::RePlaceholder(placeholder2)))
     }
 
-    fn len(&self) -> usize {
-        self.regions.len()
+    fn error(
+        &self,
+        placeholder: ty::PlaceholderRegion,
+        other_region: ty::Region<'tcx>,
+    ) -> TypeError<'tcx> {
+        debug!("error: placeholder={:?}, other_region={:?}", placeholder, other_region);
+        if self.overly_polymorphic {
+            return TypeError::RegionsOverlyPolymorphic(placeholder.name, other_region);
+        } else {
+            return TypeError::RegionsInsufficientlyPolymorphic(placeholder.name, other_region);
+        }
     }
+}
 
-    fn add_edge(&mut self, source: ty::Region<'tcx>, target: ty::Region<'tcx>) {
-        if self.directions.incoming {
-            if self.regions.contains(&target) {
-                self.regions.insert(source);
-            }
+// States we need to distinguish:
+//
+// * must be equal to a placeholder (i.e., a placeholder is in the SCC)
+//     * it could conflict with some other regions in the SCC in different universes
+//     * or a different placeholder
+// * `P1: S` and `S` must be equal to a placeholder
+// * `P1: S` and `S` is in an incompatible universe
+//
+// So if we
+//
+// (a) compute which placeholder (if any) each SCC must be equal to
+// (b) compute its minimum universe
+// (c) compute *some* placeholder where `S: P1` (any one will do)
+//
+// then we get an error if:
+//
+// - it must be equal to a placeholder `P1` and minimum universe cannot name `P1`
+// - `S: P1` and minimum universe cannot name `P1`
+// - `S: P1` and we must be equal to `P2`
+//
+// So we want to track:
+//
+// * Equal placeholder (if any)
+// * Some bounding placeholder (if any)
+// * Minimum universe
+//
+// * We compute equal placeholder + minimum universe of constituents in first pass
+// * Then we walk in order and compute from our dependencies `S1` where `S: S1` (`S -> S1`)
+//   * bounding placeholder (if any)
+//   * minimum universe
+// * And if we must be equal to a placeholder then we check it against
+//   * minimum universe
+//   * no bounding placeholder
+
+/// Tracks the "minimum universe" for each SCC, along with some region that
+/// caused it to change.
+#[derive(Copy, Clone, Debug)]
+struct SccUniverse<'tcx> {
+    /// For some SCC S, the minimum universe of:
+    ///
+    /// * each region R in S
+    /// * each SCC S1 such that S: S1
+    universe: ty::UniverseIndex,
+
+    /// Some region that caused `universe` to be what it is.
+    region: Option<ty::Region<'tcx>>,
+}
+
+impl<'tcx> SccUniverse<'tcx> {
+    /// If `universe` is less than our current universe, then update
+    /// `self.universe` and `self.region`.
+    fn take_min(&mut self, universe: ty::UniverseIndex, region: ty::Region<'tcx>) {
+        if universe < self.universe || self.region.is_none() {
+            self.universe = universe;
+            self.region = Some(region);
         }
+    }
+}
+
+rustc_index::newtype_index! {
+    struct LeakCheckNode {
+        DEBUG_FORMAT = "LeakCheckNode({})"
+    }
+}
 
-        if self.directions.outgoing {
-            if self.regions.contains(&source) {
-                self.regions.insert(target);
+rustc_index::newtype_index! {
+    struct LeakCheckScc {
+        DEBUG_FORMAT = "LeakCheckScc({})"
+    }
+}
+
+/// Represents the graph of constraints. For each `R1: R2` constraint we create
+/// an edge `R1 -> R2` in the graph.
+struct MiniGraph<'tcx> {
+    /// Map from a region to the index of the node in the graph.
+    nodes: FxHashMap<ty::Region<'tcx>, LeakCheckNode>,
+
+    /// Map from node index to SCC, and stores the successors of each SCC. All
+    /// the regions in the same SCC are equal to one another, and if `S1 -> S2`,
+    /// then `S1: S2`.
+    sccs: Sccs<LeakCheckNode, LeakCheckScc>,
+}
+
+impl<'tcx> MiniGraph<'tcx> {
+    fn new<'a>(
+        tcx: TyCtxt<'tcx>,
+        undo_log: impl Iterator<Item = &'a UndoLog<'tcx>>,
+        verifys: &[Verify<'tcx>],
+    ) -> Self
+    where
+        'tcx: 'a,
+    {
+        let mut nodes = FxHashMap::default();
+        let mut edges = Vec::new();
+
+        // Note that if `R2: R1`, we get a callback `r1, r2`, so `target` is first parameter.
+        Self::iterate_undo_log(tcx, undo_log, verifys, |target, source| {
+            let source_node = Self::add_node(&mut nodes, source);
+            let target_node = Self::add_node(&mut nodes, target);
+            edges.push((source_node, target_node));
+        });
+        let graph = VecGraph::new(nodes.len(), edges);
+        let sccs = Sccs::new(&graph);
+        Self { nodes, sccs }
+    }
+
+    /// Invokes `each_edge(R1, R2)` for each edge where `R2: R1`
+    fn iterate_undo_log<'a>(
+        tcx: TyCtxt<'tcx>,
+        undo_log: impl Iterator<Item = &'a UndoLog<'tcx>>,
+        verifys: &[Verify<'tcx>],
+        mut each_edge: impl FnMut(ty::Region<'tcx>, ty::Region<'tcx>),
+    ) where
+        'tcx: 'a,
+    {
+        for undo_entry in undo_log {
+            match undo_entry {
+                &AddConstraint(Constraint::VarSubVar(a, b)) => {
+                    each_edge(tcx.mk_region(ReVar(a)), tcx.mk_region(ReVar(b)));
+                }
+                &AddConstraint(Constraint::RegSubVar(a, b)) => {
+                    each_edge(a, tcx.mk_region(ReVar(b)));
+                }
+                &AddConstraint(Constraint::VarSubReg(a, b)) => {
+                    each_edge(tcx.mk_region(ReVar(a)), b);
+                }
+                &AddConstraint(Constraint::RegSubReg(a, b)) => {
+                    each_edge(a, b);
+                }
+                &AddGiven(a, b) => {
+                    each_edge(a, tcx.mk_region(ReVar(b)));
+                }
+                &AddVerify(i) => span_bug!(
+                    verifys[i].origin.span(),
+                    "we never add verifications while doing higher-ranked things",
+                ),
+                &AddCombination(..) | &AddVar(..) => {}
             }
         }
     }
+
+    fn add_node(
+        nodes: &mut FxHashMap<ty::Region<'tcx>, LeakCheckNode>,
+        r: ty::Region<'tcx>,
+    ) -> LeakCheckNode {
+        let l = nodes.len();
+        *nodes.entry(r).or_insert(LeakCheckNode::new(l))
+    }
 }
diff --git a/src/librustc_infer/lib.rs b/src/librustc_infer/lib.rs
index ed04ee02b72..0f3f3db8679 100644
--- a/src/librustc_infer/lib.rs
+++ b/src/librustc_infer/lib.rs
@@ -16,6 +16,9 @@
 #![feature(bool_to_option)]
 #![feature(box_patterns)]
 #![feature(box_syntax)]
+#![feature(const_fn)]
+#![feature(const_if_match)]
+#![feature(const_panic)]
 #![feature(extend_one)]
 #![feature(never_type)]
 #![feature(or_patterns)]
diff --git a/src/librustc_mir/borrow_check/type_check/relate_tys.rs b/src/librustc_mir/borrow_check/type_check/relate_tys.rs
index 7ff12820db8..285d9ed6469 100644
--- a/src/librustc_mir/borrow_check/type_check/relate_tys.rs
+++ b/src/librustc_mir/borrow_check/type_check/relate_tys.rs
@@ -25,7 +25,7 @@ pub(super) fn relate_types<'tcx>(
     category: ConstraintCategory,
     borrowck_context: Option<&mut BorrowCheckContext<'_, 'tcx>>,
 ) -> Fallible<()> {
-    debug!("eq_types(a={:?}, b={:?}, locations={:?})", a, b, locations);
+    debug!("relate_types(a={:?}, v={:?}, b={:?}, locations={:?})", a, v, b, locations);
     TypeRelating::new(
         infcx,
         NllTypeRelatingDelegate::new(infcx, borrowck_context, locations, category),
diff --git a/src/librustc_trait_selection/traits/coherence.rs b/src/librustc_trait_selection/traits/coherence.rs
index 706cbf058b7..3ec7fe2bf25 100644
--- a/src/librustc_trait_selection/traits/coherence.rs
+++ b/src/librustc_trait_selection/traits/coherence.rs
@@ -120,12 +120,13 @@ fn overlap<'cx, 'tcx>(
     debug!("overlap(a_def_id={:?}, b_def_id={:?})", a_def_id, b_def_id);
 
     selcx.infcx().probe_maybe_skip_leak_check(skip_leak_check.is_yes(), |snapshot| {
-        overlap_within_probe(selcx, a_def_id, b_def_id, snapshot)
+        overlap_within_probe(selcx, skip_leak_check, a_def_id, b_def_id, snapshot)
     })
 }
 
 fn overlap_within_probe(
     selcx: &mut SelectionContext<'cx, 'tcx>,
+    skip_leak_check: SkipLeakCheck,
     a_def_id: DefId,
     b_def_id: DefId,
     snapshot: &CombinedSnapshot<'_, 'tcx>,
@@ -180,6 +181,13 @@ fn overlap_within_probe(
         return None;
     }
 
+    if !skip_leak_check.is_yes() {
+        if let Err(_) = infcx.leak_check(true, snapshot) {
+            debug!("overlap: leak check failed");
+            return None;
+        }
+    }
+
     let impl_header = selcx.infcx().resolve_vars_if_possible(&a_impl_header);
     let intercrate_ambiguity_causes = selcx.take_intercrate_ambiguity_causes();
     debug!("overlap: intercrate_ambiguity_causes={:#?}", intercrate_ambiguity_causes);
diff --git a/src/librustc_trait_selection/traits/project.rs b/src/librustc_trait_selection/traits/project.rs
index 574d50a4fcc..bc696214cbc 100644
--- a/src/librustc_trait_selection/traits/project.rs
+++ b/src/librustc_trait_selection/traits/project.rs
@@ -149,15 +149,12 @@ pub fn poly_project_and_unify_type<'cx, 'tcx>(
     debug!("poly_project_and_unify_type(obligation={:?})", obligation);
 
     let infcx = selcx.infcx();
-    infcx.commit_if_ok(|snapshot| {
-        let (placeholder_predicate, placeholder_map) =
+    infcx.commit_if_ok(|_snapshot| {
+        let (placeholder_predicate, _) =
             infcx.replace_bound_vars_with_placeholders(&obligation.predicate);
 
         let placeholder_obligation = obligation.with(placeholder_predicate);
         let result = project_and_unify_type(selcx, &placeholder_obligation)?;
-        infcx
-            .leak_check(false, &placeholder_map, snapshot)
-            .map_err(|err| MismatchedProjectionTypes { err })?;
         Ok(result)
     })
 }
diff --git a/src/librustc_trait_selection/traits/select/candidate_assembly.rs b/src/librustc_trait_selection/traits/select/candidate_assembly.rs
index 9045451056b..4dab5814f7b 100644
--- a/src/librustc_trait_selection/traits/select/candidate_assembly.rs
+++ b/src/librustc_trait_selection/traits/select/candidate_assembly.rs
@@ -163,9 +163,9 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
             _ => return,
         }
 
-        let result = self.infcx.probe(|snapshot| {
-            self.match_projection_obligation_against_definition_bounds(obligation, snapshot)
-        });
+        let result = self
+            .infcx
+            .probe(|_| self.match_projection_obligation_against_definition_bounds(obligation));
 
         if result {
             candidates.vec.push(ProjectionCandidate);
@@ -345,8 +345,8 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
             obligation.predicate.def_id(),
             obligation.predicate.skip_binder().trait_ref.self_ty(),
             |impl_def_id| {
-                self.infcx.probe(|snapshot| {
-                    if let Ok(_substs) = self.match_impl(impl_def_id, obligation, snapshot) {
+                self.infcx.probe(|_| {
+                    if let Ok(_substs) = self.match_impl(impl_def_id, obligation) {
                         candidates.vec.push(ImplCandidate(impl_def_id));
                     }
                 });
diff --git a/src/librustc_trait_selection/traits/select/confirmation.rs b/src/librustc_trait_selection/traits/select/confirmation.rs
index 50c04e8fc34..834bf17227d 100644
--- a/src/librustc_trait_selection/traits/select/confirmation.rs
+++ b/src/librustc_trait_selection/traits/select/confirmation.rs
@@ -121,9 +121,8 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
     }
 
     fn confirm_projection_candidate(&mut self, obligation: &TraitObligation<'tcx>) {
-        self.infcx.commit_unconditionally(|snapshot| {
-            let result =
-                self.match_projection_obligation_against_definition_bounds(obligation, snapshot);
+        self.infcx.commit_unconditionally(|_| {
+            let result = self.match_projection_obligation_against_definition_bounds(obligation);
             assert!(result);
         })
     }
@@ -265,8 +264,8 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
 
         // First, create the substitutions by matching the impl again,
         // this time not in a probe.
-        self.infcx.commit_unconditionally(|snapshot| {
-            let substs = self.rematch_impl(impl_def_id, obligation, snapshot);
+        self.infcx.commit_unconditionally(|_| {
+            let substs = self.rematch_impl(impl_def_id, obligation);
             debug!("confirm_impl_candidate: substs={:?}", substs);
             let cause = obligation.derived_cause(ImplDerivedObligation);
             ensure_sufficient_stack(|| {
@@ -612,24 +611,10 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
 
                 // Require that the traits involved in this upcast are **equal**;
                 // only the **lifetime bound** is changed.
-                //
-                // FIXME: This condition is arguably too strong -- it would
-                // suffice for the source trait to be a *subtype* of the target
-                // trait. In particular, changing from something like
-                // `for<'a, 'b> Foo<'a, 'b>` to `for<'a> Foo<'a, 'a>` should be
-                // permitted. And, indeed, in the in commit
-                // 904a0bde93f0348f69914ee90b1f8b6e4e0d7cbc, this
-                // condition was loosened. However, when the leak check was
-                // added back, using subtype here actually guides the coercion
-                // code in such a way that it accepts `old-lub-glb-object.rs`.
-                // This is probably a good thing, but I've modified this to `.eq`
-                // because I want to continue rejecting that test (as we have
-                // done for quite some time) before we are firmly comfortable
-                // with what our behavior should be there. -nikomatsakis
                 let InferOk { obligations, .. } = self
                     .infcx
                     .at(&obligation.cause, obligation.param_env)
-                    .eq(target, source_trait) // FIXME -- see below
+                    .sup(target, source_trait)
                     .map_err(|_| Unimplemented)?;
                 nested.extend(obligations);
 
diff --git a/src/librustc_trait_selection/traits/select/mod.rs b/src/librustc_trait_selection/traits/select/mod.rs
index 076bdad423a..cff5efbfd0f 100644
--- a/src/librustc_trait_selection/traits/select/mod.rs
+++ b/src/librustc_trait_selection/traits/select/mod.rs
@@ -21,7 +21,7 @@ use super::{Normalized, ProjectionCacheKey};
 use super::{ObligationCause, PredicateObligation, TraitObligation};
 use super::{Overflow, SelectionError, Unimplemented};
 
-use crate::infer::{CombinedSnapshot, InferCtxt, InferOk, PlaceholderMap, TypeFreshener};
+use crate::infer::{InferCtxt, InferOk, TypeFreshener};
 use crate::traits::error_reporting::InferCtxtExt;
 use crate::traits::project::ProjectionCacheKeyExt;
 use rustc_ast::attr;
@@ -347,6 +347,12 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
     ) -> Result<EvaluationResult, OverflowError> {
         self.infcx.probe(|snapshot| -> Result<EvaluationResult, OverflowError> {
             let result = op(self)?;
+
+            match self.infcx.leak_check(true, snapshot) {
+                Ok(()) => {}
+                Err(_) => return Ok(EvaluatedToErr),
+            }
+
             match self.infcx.region_constraints_added_in_snapshot(snapshot) {
                 None => Ok(result),
                 Some(_) => Ok(result.max(EvaluatedToOkModuloRegions)),
@@ -1262,10 +1268,9 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
     fn match_projection_obligation_against_definition_bounds(
         &mut self,
         obligation: &TraitObligation<'tcx>,
-        snapshot: &CombinedSnapshot<'_, 'tcx>,
     ) -> bool {
         let poly_trait_predicate = self.infcx().resolve_vars_if_possible(&obligation.predicate);
-        let (placeholder_trait_predicate, placeholder_map) =
+        let (placeholder_trait_predicate, _) =
             self.infcx().replace_bound_vars_with_placeholders(&poly_trait_predicate);
         debug!(
             "match_projection_obligation_against_definition_bounds: \
@@ -1293,13 +1298,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
             if let ty::PredicateKind::Trait(bound, _) = bound.kind() {
                 let bound = bound.to_poly_trait_ref();
                 if self.infcx.probe(|_| {
-                    self.match_projection(
-                        obligation,
-                        bound,
-                        placeholder_trait_predicate.trait_ref,
-                        &placeholder_map,
-                        snapshot,
-                    )
+                    self.match_projection(obligation, bound, placeholder_trait_predicate.trait_ref)
                 }) {
                     return Some(bound);
                 }
@@ -1316,13 +1315,8 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
             None => false,
             Some(bound) => {
                 // Repeat the successful match, if any, this time outside of a probe.
-                let result = self.match_projection(
-                    obligation,
-                    bound,
-                    placeholder_trait_predicate.trait_ref,
-                    &placeholder_map,
-                    snapshot,
-                );
+                let result =
+                    self.match_projection(obligation, bound, placeholder_trait_predicate.trait_ref);
 
                 assert!(result);
                 true
@@ -1335,15 +1329,12 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
         obligation: &TraitObligation<'tcx>,
         trait_bound: ty::PolyTraitRef<'tcx>,
         placeholder_trait_ref: ty::TraitRef<'tcx>,
-        placeholder_map: &PlaceholderMap<'tcx>,
-        snapshot: &CombinedSnapshot<'_, 'tcx>,
     ) -> bool {
         debug_assert!(!placeholder_trait_ref.has_escaping_bound_vars());
         self.infcx
             .at(&obligation.cause, obligation.param_env)
             .sup(ty::Binder::dummy(placeholder_trait_ref), trait_bound)
             .is_ok()
-            && self.infcx.leak_check(false, placeholder_map, snapshot).is_ok()
     }
 
     fn evaluate_where_clause<'o>(
@@ -1808,9 +1799,8 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
         &mut self,
         impl_def_id: DefId,
         obligation: &TraitObligation<'tcx>,
-        snapshot: &CombinedSnapshot<'_, 'tcx>,
     ) -> Normalized<'tcx, SubstsRef<'tcx>> {
-        match self.match_impl(impl_def_id, obligation, snapshot) {
+        match self.match_impl(impl_def_id, obligation) {
             Ok(substs) => substs,
             Err(()) => {
                 bug!(
@@ -1826,7 +1816,6 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
         &mut self,
         impl_def_id: DefId,
         obligation: &TraitObligation<'tcx>,
-        snapshot: &CombinedSnapshot<'_, 'tcx>,
     ) -> Result<Normalized<'tcx, SubstsRef<'tcx>>, ()> {
         let impl_trait_ref = self.tcx().impl_trait_ref(impl_def_id).unwrap();
 
@@ -1837,7 +1826,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
             return Err(());
         }
 
-        let (placeholder_obligation, placeholder_map) =
+        let (placeholder_obligation, _) =
             self.infcx().replace_bound_vars_with_placeholders(&obligation.predicate);
         let placeholder_obligation_trait_ref = placeholder_obligation.trait_ref;
 
@@ -1869,11 +1858,6 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
             .map_err(|e| debug!("match_impl: failed eq_trait_refs due to `{}`", e))?;
         nested_obligations.extend(obligations);
 
-        if let Err(e) = self.infcx.leak_check(false, &placeholder_map, snapshot) {
-            debug!("match_impl: failed leak check due to `{}`", e);
-            return Err(());
-        }
-
         if !self.intercrate
             && self.tcx().impl_polarity(impl_def_id) == ty::ImplPolarity::Reservation
         {
diff --git a/src/librustc_typeck/check/coercion.rs b/src/librustc_typeck/check/coercion.rs
index dec53c369bb..b6cd8da2362 100644
--- a/src/librustc_typeck/check/coercion.rs
+++ b/src/librustc_typeck/check/coercion.rs
@@ -895,7 +895,12 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
     {
         let prev_ty = self.resolve_vars_with_obligations(prev_ty);
         let new_ty = self.resolve_vars_with_obligations(new_ty);
-        debug!("coercion::try_find_coercion_lub({:?}, {:?})", prev_ty, new_ty);
+        debug!(
+            "coercion::try_find_coercion_lub({:?}, {:?}, exprs={:?} exprs)",
+            prev_ty,
+            new_ty,
+            exprs.len()
+        );
 
         // Special-case that coercion alone cannot handle:
         // Function items or non-capturing closures of differing IDs or InternalSubsts.
@@ -1001,6 +1006,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                 Ok(ok) => {
                     let (adjustments, target) = self.register_infer_ok_obligations(ok);
                     self.apply_adjustments(new, adjustments);
+                    debug!(
+                        "coercion::try_find_coercion_lub: was able to coerce from previous type {:?} to new type {:?}",
+                        prev_ty, new_ty,
+                    );
                     return Ok(target);
                 }
                 Err(e) => first_error = Some(e),
@@ -1031,6 +1040,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
             };
 
             if !noop {
+                debug!(
+                    "coercion::try_find_coercion_lub: older expression {:?} had adjustments, requiring LUB",
+                    expr,
+                );
+
                 return self
                     .commit_if_ok(|_| self.at(cause, self.param_env).lub(prev_ty, new_ty))
                     .map(|ok| self.register_infer_ok_obligations(ok));
@@ -1048,6 +1062,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                 }
             }
             Ok(ok) => {
+                debug!(
+                    "coercion::try_find_coercion_lub: was able to coerce previous type {:?} to new type {:?}",
+                    prev_ty, new_ty,
+                );
                 let (adjustments, target) = self.register_infer_ok_obligations(ok);
                 for expr in exprs {
                     let expr = expr.as_coercion_site();
diff --git a/src/test/mir-opt/address-of/rustc.address_of_reborrow.SimplifyCfg-initial.after.mir b/src/test/mir-opt/address-of/rustc.address_of_reborrow.SimplifyCfg-initial.after.mir
index 9742530bd81..aeb38f3f910 100644
--- a/src/test/mir-opt/address-of/rustc.address_of_reborrow.SimplifyCfg-initial.after.mir
+++ b/src/test/mir-opt/address-of/rustc.address_of_reborrow.SimplifyCfg-initial.after.mir
@@ -12,7 +12,7 @@
 | 8: Canonical { max_universe: U0, variables: [], value: Ty(*const [i32]) } at $DIR/address-of.rs:16:12: 16:24
 | 9: Canonical { max_universe: U0, variables: [], value: Ty(*const [i32]) } at $DIR/address-of.rs:16:12: 16:24
 | 10: Canonical { max_universe: U0, variables: [CanonicalVarInfo { kind: Ty(General(U0)) }], value: Ty(*const ^0) } at $DIR/address-of.rs:18:5: 18:18
-| 11: Canonical { max_universe: U3, variables: [CanonicalVarInfo { kind: Region(U3) }], value: Ty(*const dyn std::marker::Send) } at $DIR/address-of.rs:20:5: 20:25
+| 11: Canonical { max_universe: U0, variables: [CanonicalVarInfo { kind: Region(U0) }], value: Ty(*const dyn std::marker::Send) } at $DIR/address-of.rs:20:5: 20:25
 | 12: Canonical { max_universe: U0, variables: [CanonicalVarInfo { kind: Ty(General(U0)) }], value: Ty(*const ^0) } at $DIR/address-of.rs:23:12: 23:20
 | 13: Canonical { max_universe: U0, variables: [CanonicalVarInfo { kind: Ty(General(U0)) }], value: Ty(*const ^0) } at $DIR/address-of.rs:23:12: 23:20
 | 14: Canonical { max_universe: U0, variables: [], value: Ty(*const [i32; 10]) } at $DIR/address-of.rs:24:12: 24:28
@@ -22,7 +22,7 @@
 | 18: Canonical { max_universe: U0, variables: [], value: Ty(*const [i32]) } at $DIR/address-of.rs:26:12: 26:24
 | 19: Canonical { max_universe: U0, variables: [], value: Ty(*const [i32]) } at $DIR/address-of.rs:26:12: 26:24
 | 20: Canonical { max_universe: U0, variables: [CanonicalVarInfo { kind: Ty(General(U0)) }], value: Ty(*mut ^0) } at $DIR/address-of.rs:28:5: 28:16
-| 21: Canonical { max_universe: U6, variables: [CanonicalVarInfo { kind: Region(U6) }], value: Ty(*mut dyn std::marker::Send) } at $DIR/address-of.rs:30:5: 30:23
+| 21: Canonical { max_universe: U0, variables: [CanonicalVarInfo { kind: Region(U0) }], value: Ty(*mut dyn std::marker::Send) } at $DIR/address-of.rs:30:5: 30:23
 | 22: Canonical { max_universe: U0, variables: [CanonicalVarInfo { kind: Ty(General(U0)) }], value: Ty(*mut ^0) } at $DIR/address-of.rs:33:12: 33:18
 | 23: Canonical { max_universe: U0, variables: [CanonicalVarInfo { kind: Ty(General(U0)) }], value: Ty(*mut ^0) } at $DIR/address-of.rs:33:12: 33:18
 | 24: Canonical { max_universe: U0, variables: [], value: Ty(*mut [i32; 10]) } at $DIR/address-of.rs:34:12: 34:26
diff --git a/src/test/ui/associated-types/associated-types-eq-hr.nll.stderr b/src/test/ui/associated-types/associated-types-eq-hr.nll.stderr
new file mode 100644
index 00000000000..25e9f726ba5
--- /dev/null
+++ b/src/test/ui/associated-types/associated-types-eq-hr.nll.stderr
@@ -0,0 +1,33 @@
+error[E0271]: type mismatch resolving `for<'x> <UintStruct as TheTrait<&'x isize>>::A == &'x isize`
+  --> $DIR/associated-types-eq-hr.rs:87:5
+   |
+LL | fn foo<T>()
+   |    --- required by a bound in this
+LL | where
+LL |     T: for<'x> TheTrait<&'x isize, A = &'x isize>,
+   |                                    ------------- required by this bound in `foo`
+...
+LL |     foo::<UintStruct>();
+   |     ^^^^^^^^^^^^^^^^^ expected `isize`, found `usize`
+   |
+   = note: expected reference `&isize`
+              found reference `&usize`
+
+error[E0271]: type mismatch resolving `for<'x> <IntStruct as TheTrait<&'x isize>>::A == &'x usize`
+  --> $DIR/associated-types-eq-hr.rs:91:5
+   |
+LL | fn bar<T>()
+   |    --- required by a bound in this
+LL | where
+LL |     T: for<'x> TheTrait<&'x isize, A = &'x usize>,
+   |                                    ------------- required by this bound in `bar`
+...
+LL |     bar::<IntStruct>();
+   |     ^^^^^^^^^^^^^^^^ expected `usize`, found `isize`
+   |
+   = note: expected reference `&usize`
+              found reference `&isize`
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0271`.
diff --git a/src/test/ui/associated-types/associated-types-eq-hr.rs b/src/test/ui/associated-types/associated-types-eq-hr.rs
index e6afa3f71c2..fb391913c32 100644
--- a/src/test/ui/associated-types/associated-types-eq-hr.rs
+++ b/src/test/ui/associated-types/associated-types-eq-hr.rs
@@ -7,7 +7,7 @@ pub trait TheTrait<T> {
 }
 
 struct IntStruct {
-    x: isize
+    x: isize,
 }
 
 impl<'a> TheTrait<&'a isize> for IntStruct {
@@ -19,7 +19,7 @@ impl<'a> TheTrait<&'a isize> for IntStruct {
 }
 
 struct UintStruct {
-    x: isize
+    x: isize,
 }
 
 impl<'a> TheTrait<&'a isize> for UintStruct {
@@ -30,8 +30,7 @@ impl<'a> TheTrait<&'a isize> for UintStruct {
     }
 }
 
-struct Tuple {
-}
+struct Tuple {}
 
 impl<'a> TheTrait<(&'a isize, &'a isize)> for Tuple {
     type A = &'a isize;
@@ -42,37 +41,43 @@ impl<'a> TheTrait<(&'a isize, &'a isize)> for Tuple {
 }
 
 fn foo<T>()
-    where T : for<'x> TheTrait<&'x isize, A = &'x isize>
+where
+    T: for<'x> TheTrait<&'x isize, A = &'x isize>,
 {
     // ok for IntStruct, but not UintStruct
 }
 
 fn bar<T>()
-    where T : for<'x> TheTrait<&'x isize, A = &'x usize>
+where
+    T: for<'x> TheTrait<&'x isize, A = &'x usize>,
 {
     // ok for UintStruct, but not IntStruct
 }
 
 fn tuple_one<T>()
-    where T : for<'x,'y> TheTrait<(&'x isize, &'y isize), A = &'x isize>
+where
+    T: for<'x, 'y> TheTrait<(&'x isize, &'y isize), A = &'x isize>,
 {
     // not ok for tuple, two lifetimes and we pick first
 }
 
 fn tuple_two<T>()
-    where T : for<'x,'y> TheTrait<(&'x isize, &'y isize), A = &'y isize>
+where
+    T: for<'x, 'y> TheTrait<(&'x isize, &'y isize), A = &'y isize>,
 {
     // not ok for tuple, two lifetimes and we pick second
 }
 
 fn tuple_three<T>()
-    where T : for<'x> TheTrait<(&'x isize, &'x isize), A = &'x isize>
+where
+    T: for<'x> TheTrait<(&'x isize, &'x isize), A = &'x isize>,
 {
     // ok for tuple
 }
 
 fn tuple_four<T>()
-    where T : for<'x,'y> TheTrait<(&'x isize, &'y isize)>
+where
+    T: for<'x, 'y> TheTrait<(&'x isize, &'y isize)>,
 {
     // not ok for tuple, two lifetimes, and lifetime matching is invariant
 }
@@ -89,14 +94,14 @@ pub fn call_bar() {
 
 pub fn call_tuple_one() {
     tuple_one::<Tuple>();
-    //~^ ERROR not satisfied
-    //~| ERROR type mismatch
+    //~^ ERROR implementation of `TheTrait` is not general enough
+    //~| ERROR implementation of `TheTrait` is not general enough
 }
 
 pub fn call_tuple_two() {
     tuple_two::<Tuple>();
-    //~^ ERROR not satisfied
-    //~| ERROR type mismatch
+    //~^ ERROR implementation of `TheTrait` is not general enough
+    //~| ERROR implementation of `TheTrait` is not general enough
 }
 
 pub fn call_tuple_three() {
@@ -105,7 +110,7 @@ pub fn call_tuple_three() {
 
 pub fn call_tuple_four() {
     tuple_four::<Tuple>();
-    //~^ ERROR not satisfied
+    //~^ ERROR implementation of `TheTrait` is not general enough
 }
 
-fn main() { }
+fn main() {}
diff --git a/src/test/ui/associated-types/associated-types-eq-hr.stderr b/src/test/ui/associated-types/associated-types-eq-hr.stderr
index 58d72746e76..127ab867355 100644
--- a/src/test/ui/associated-types/associated-types-eq-hr.stderr
+++ b/src/test/ui/associated-types/associated-types-eq-hr.stderr
@@ -1,10 +1,11 @@
 error[E0271]: type mismatch resolving `for<'x> <UintStruct as TheTrait<&'x isize>>::A == &'x isize`
-  --> $DIR/associated-types-eq-hr.rs:82:5
+  --> $DIR/associated-types-eq-hr.rs:87:5
    |
 LL | fn foo<T>()
    |    --- required by a bound in this
-LL |     where T : for<'x> TheTrait<&'x isize, A = &'x isize>
-   |                                           ------------- required by this bound in `foo`
+LL | where
+LL |     T: for<'x> TheTrait<&'x isize, A = &'x isize>,
+   |                                    ------------- required by this bound in `foo`
 ...
 LL |     foo::<UintStruct>();
    |     ^^^^^^^^^^^^^^^^^ expected `isize`, found `usize`
@@ -13,12 +14,13 @@ LL |     foo::<UintStruct>();
               found reference `&usize`
 
 error[E0271]: type mismatch resolving `for<'x> <IntStruct as TheTrait<&'x isize>>::A == &'x usize`
-  --> $DIR/associated-types-eq-hr.rs:86:5
+  --> $DIR/associated-types-eq-hr.rs:91:5
    |
 LL | fn bar<T>()
    |    --- required by a bound in this
-LL |     where T : for<'x> TheTrait<&'x isize, A = &'x usize>
-   |                                           ------------- required by this bound in `bar`
+LL | where
+LL |     T: for<'x> TheTrait<&'x isize, A = &'x usize>,
+   |                                    ------------- required by this bound in `bar`
 ...
 LL |     bar::<IntStruct>();
    |     ^^^^^^^^^^^^^^^^ expected `usize`, found `isize`
@@ -26,71 +28,86 @@ LL |     bar::<IntStruct>();
    = note: expected reference `&usize`
               found reference `&isize`
 
-error[E0277]: the trait bound `for<'x, 'y> Tuple: TheTrait<(&'x isize, &'y isize)>` is not satisfied
-  --> $DIR/associated-types-eq-hr.rs:91:17
+error: implementation of `TheTrait` is not general enough
+  --> $DIR/associated-types-eq-hr.rs:96:5
    |
-LL | fn tuple_one<T>()
-   |    --------- required by a bound in this
-LL |     where T : for<'x,'y> TheTrait<(&'x isize, &'y isize), A = &'x isize>
-   |               ---------------------------------------------------------- required by this bound in `tuple_one`
+LL | / pub trait TheTrait<T> {
+LL | |     type A;
+LL | |
+LL | |     fn get(&self, t: T) -> Self::A;
+LL | | }
+   | |_- trait `TheTrait` defined here
 ...
-LL |     tuple_one::<Tuple>();
-   |                 ^^^^^ the trait `for<'x, 'y> TheTrait<(&'x isize, &'y isize)>` is not implemented for `Tuple`
+LL |       tuple_one::<Tuple>();
+   |       ^^^^^^^^^^^^^^^^^^ implementation of `TheTrait` is not general enough
    |
-   = help: the following implementations were found:
-             <Tuple as TheTrait<(&'a isize, &'a isize)>>
+   = note: `Tuple` must implement `TheTrait<(&'0 isize, &'1 isize)>`, for any two lifetimes `'0` and `'1`...
+   = note: ...but `Tuple` actually implements `TheTrait<(&'2 isize, &'2 isize)>`, for some specific lifetime `'2`
 
-error[E0271]: type mismatch resolving `for<'x, 'y> <Tuple as TheTrait<(&'x isize, &'y isize)>>::A == &'x isize`
-  --> $DIR/associated-types-eq-hr.rs:91:5
+error: implementation of `TheTrait` is not general enough
+  --> $DIR/associated-types-eq-hr.rs:96:5
    |
-LL | fn tuple_one<T>()
-   |    --------- required by a bound in this
-LL |     where T : for<'x,'y> TheTrait<(&'x isize, &'y isize), A = &'x isize>
-   |                                                           ------------- required by this bound in `tuple_one`
+LL | / pub trait TheTrait<T> {
+LL | |     type A;
+LL | |
+LL | |     fn get(&self, t: T) -> Self::A;
+LL | | }
+   | |_- trait `TheTrait` defined here
 ...
-LL |     tuple_one::<Tuple>();
-   |     ^^^^^^^^^^^^^^^^^^ expected bound lifetime parameter 'x, found concrete lifetime
+LL |       tuple_one::<Tuple>();
+   |       ^^^^^^^^^^^^^^^^^^ implementation of `TheTrait` is not general enough
+   |
+   = note: `Tuple` must implement `TheTrait<(&'0 isize, &'1 isize)>`, for any two lifetimes `'0` and `'1`...
+   = note: ...but `Tuple` actually implements `TheTrait<(&'2 isize, &'2 isize)>`, for some specific lifetime `'2`
 
-error[E0277]: the trait bound `for<'x, 'y> Tuple: TheTrait<(&'x isize, &'y isize)>` is not satisfied
-  --> $DIR/associated-types-eq-hr.rs:97:17
+error: implementation of `TheTrait` is not general enough
+  --> $DIR/associated-types-eq-hr.rs:102:5
    |
-LL | fn tuple_two<T>()
-   |    --------- required by a bound in this
-LL |     where T : for<'x,'y> TheTrait<(&'x isize, &'y isize), A = &'y isize>
-   |               ---------------------------------------------------------- required by this bound in `tuple_two`
+LL | / pub trait TheTrait<T> {
+LL | |     type A;
+LL | |
+LL | |     fn get(&self, t: T) -> Self::A;
+LL | | }
+   | |_- trait `TheTrait` defined here
 ...
-LL |     tuple_two::<Tuple>();
-   |                 ^^^^^ the trait `for<'x, 'y> TheTrait<(&'x isize, &'y isize)>` is not implemented for `Tuple`
+LL |       tuple_two::<Tuple>();
+   |       ^^^^^^^^^^^^^^^^^^ implementation of `TheTrait` is not general enough
    |
-   = help: the following implementations were found:
-             <Tuple as TheTrait<(&'a isize, &'a isize)>>
+   = note: `Tuple` must implement `TheTrait<(&'0 isize, &'1 isize)>`, for any two lifetimes `'0` and `'1`...
+   = note: ...but `Tuple` actually implements `TheTrait<(&'2 isize, &'2 isize)>`, for some specific lifetime `'2`
 
-error[E0271]: type mismatch resolving `for<'x, 'y> <Tuple as TheTrait<(&'x isize, &'y isize)>>::A == &'y isize`
-  --> $DIR/associated-types-eq-hr.rs:97:5
+error: implementation of `TheTrait` is not general enough
+  --> $DIR/associated-types-eq-hr.rs:102:5
    |
-LL | fn tuple_two<T>()
-   |    --------- required by a bound in this
-LL |     where T : for<'x,'y> TheTrait<(&'x isize, &'y isize), A = &'y isize>
-   |                                                           ------------- required by this bound in `tuple_two`
+LL | / pub trait TheTrait<T> {
+LL | |     type A;
+LL | |
+LL | |     fn get(&self, t: T) -> Self::A;
+LL | | }
+   | |_- trait `TheTrait` defined here
 ...
-LL |     tuple_two::<Tuple>();
-   |     ^^^^^^^^^^^^^^^^^^ expected bound lifetime parameter 'x, found concrete lifetime
+LL |       tuple_two::<Tuple>();
+   |       ^^^^^^^^^^^^^^^^^^ implementation of `TheTrait` is not general enough
+   |
+   = note: `Tuple` must implement `TheTrait<(&'0 isize, &'1 isize)>`, for any two lifetimes `'0` and `'1`...
+   = note: ...but `Tuple` actually implements `TheTrait<(&'2 isize, &'2 isize)>`, for some specific lifetime `'2`
 
-error[E0277]: the trait bound `for<'x, 'y> Tuple: TheTrait<(&'x isize, &'y isize)>` is not satisfied
-  --> $DIR/associated-types-eq-hr.rs:107:18
+error: implementation of `TheTrait` is not general enough
+  --> $DIR/associated-types-eq-hr.rs:112:5
    |
-LL | fn tuple_four<T>()
-   |    ---------- required by a bound in this
-LL |     where T : for<'x,'y> TheTrait<(&'x isize, &'y isize)>
-   |               ------------------------------------------- required by this bound in `tuple_four`
+LL | / pub trait TheTrait<T> {
+LL | |     type A;
+LL | |
+LL | |     fn get(&self, t: T) -> Self::A;
+LL | | }
+   | |_- trait `TheTrait` defined here
 ...
-LL |     tuple_four::<Tuple>();
-   |                  ^^^^^ the trait `for<'x, 'y> TheTrait<(&'x isize, &'y isize)>` is not implemented for `Tuple`
+LL |       tuple_four::<Tuple>();
+   |       ^^^^^^^^^^^^^^^^^^^ implementation of `TheTrait` is not general enough
    |
-   = help: the following implementations were found:
-             <Tuple as TheTrait<(&'a isize, &'a isize)>>
+   = note: `Tuple` must implement `TheTrait<(&'0 isize, &'1 isize)>`, for any two lifetimes `'0` and `'1`...
+   = note: ...but `Tuple` actually implements `TheTrait<(&'2 isize, &'2 isize)>`, for some specific lifetime `'2`
 
 error: aborting due to 7 previous errors
 
-Some errors have detailed explanations: E0271, E0277.
-For more information about an error, try `rustc --explain E0271`.
+For more information about this error, try `rustc --explain E0271`.
diff --git a/src/test/ui/associated-types/cache/project-fn-ret-invariant.krisskross.nll.stderr b/src/test/ui/associated-types/cache/project-fn-ret-invariant.krisskross.nll.stderr
index 71a533a36f4..4fc336122fa 100644
--- a/src/test/ui/associated-types/cache/project-fn-ret-invariant.krisskross.nll.stderr
+++ b/src/test/ui/associated-types/cache/project-fn-ret-invariant.krisskross.nll.stderr
@@ -1,26 +1,26 @@
 error: lifetime may not live long enough
-  --> $DIR/project-fn-ret-invariant.rs:55:4
+  --> $DIR/project-fn-ret-invariant.rs:56:5
    |
-LL | fn transmute<'a,'b>(x: Type<'a>, y: Type<'b>) -> (Type<'a>, Type<'b>) {
-   |              -- -- lifetime `'b` defined here
+LL | fn transmute<'a, 'b>(x: Type<'a>, y: Type<'b>) -> (Type<'a>, Type<'b>) {
+   |              --  -- lifetime `'b` defined here
    |              |
    |              lifetime `'a` defined here
 ...
-LL |    (a, b)
-   |    ^^^^^^ function was supposed to return data with lifetime `'b` but it is returning data with lifetime `'a`
+LL |     (a, b)
+   |     ^^^^^^ function was supposed to return data with lifetime `'b` but it is returning data with lifetime `'a`
    |
    = help: consider adding the following bound: `'a: 'b`
 
 error: lifetime may not live long enough
-  --> $DIR/project-fn-ret-invariant.rs:55:4
+  --> $DIR/project-fn-ret-invariant.rs:56:5
    |
-LL | fn transmute<'a,'b>(x: Type<'a>, y: Type<'b>) -> (Type<'a>, Type<'b>) {
-   |              -- -- lifetime `'b` defined here
+LL | fn transmute<'a, 'b>(x: Type<'a>, y: Type<'b>) -> (Type<'a>, Type<'b>) {
+   |              --  -- lifetime `'b` defined here
    |              |
    |              lifetime `'a` defined here
 ...
-LL |    (a, b)
-   |    ^^^^^^ function was supposed to return data with lifetime `'a` but it is returning data with lifetime `'b`
+LL |     (a, b)
+   |     ^^^^^^ function was supposed to return data with lifetime `'a` but it is returning data with lifetime `'b`
    |
    = help: consider adding the following bound: `'b: 'a`
 
diff --git a/src/test/ui/associated-types/cache/project-fn-ret-invariant.krisskross.stderr b/src/test/ui/associated-types/cache/project-fn-ret-invariant.krisskross.stderr
index 5009e0868a7..9462121bdf2 100644
--- a/src/test/ui/associated-types/cache/project-fn-ret-invariant.krisskross.stderr
+++ b/src/test/ui/associated-types/cache/project-fn-ret-invariant.krisskross.stderr
@@ -1,23 +1,23 @@
 error[E0623]: lifetime mismatch
-  --> $DIR/project-fn-ret-invariant.rs:53:21
+  --> $DIR/project-fn-ret-invariant.rs:54:22
    |
-LL | fn transmute<'a,'b>(x: Type<'a>, y: Type<'b>) -> (Type<'a>, Type<'b>) {
-   |                                     --------     --------------------
-   |                                     |
-   |                                     this parameter and the return type are declared with different lifetimes...
-LL |    let a = bar(foo, y);
-   |                     ^ ...but data from `x` is returned here
+LL | fn transmute<'a, 'b>(x: Type<'a>, y: Type<'b>) -> (Type<'a>, Type<'b>) {
+   |                                      --------     --------------------
+   |                                      |
+   |                                      this parameter and the return type are declared with different lifetimes...
+LL |     let a = bar(foo, y);
+   |                      ^ ...but data from `x` is returned here
 
 error[E0623]: lifetime mismatch
-  --> $DIR/project-fn-ret-invariant.rs:54:21
+  --> $DIR/project-fn-ret-invariant.rs:56:9
    |
-LL | fn transmute<'a,'b>(x: Type<'a>, y: Type<'b>) -> (Type<'a>, Type<'b>) {
-   |                        --------                  --------------------
-   |                        |
-   |                        this parameter and the return type are declared with different lifetimes...
-LL |    let a = bar(foo, y);
-LL |    let b = bar(foo, x);
-   |                     ^ ...but data from `y` is returned here
+LL | fn transmute<'a, 'b>(x: Type<'a>, y: Type<'b>) -> (Type<'a>, Type<'b>) {
+   |                                      --------     --------------------
+   |                                      |
+   |                                      this parameter and the return type are declared with different lifetimes...
+...
+LL |     (a, b)
+   |         ^ ...but data from `x` is returned here
 
 error: aborting due to 2 previous errors
 
diff --git a/src/test/ui/associated-types/cache/project-fn-ret-invariant.ok.stderr b/src/test/ui/associated-types/cache/project-fn-ret-invariant.ok.stderr
index 8f445acf2b9..2156ecb1739 100644
--- a/src/test/ui/associated-types/cache/project-fn-ret-invariant.ok.stderr
+++ b/src/test/ui/associated-types/cache/project-fn-ret-invariant.ok.stderr
@@ -1,8 +1,8 @@
 error: fatal error triggered by #[rustc_error]
-  --> $DIR/project-fn-ret-invariant.rs:59:1
+  --> $DIR/project-fn-ret-invariant.rs:60:1
    |
-LL | fn main() { }
-   | ^^^^^^^^^^^^^
+LL | fn main() {}
+   | ^^^^^^^^^^^^
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/associated-types/cache/project-fn-ret-invariant.oneuse.nll.stderr b/src/test/ui/associated-types/cache/project-fn-ret-invariant.oneuse.nll.stderr
index c39030fbed1..44850df7b2f 100644
--- a/src/test/ui/associated-types/cache/project-fn-ret-invariant.oneuse.nll.stderr
+++ b/src/test/ui/associated-types/cache/project-fn-ret-invariant.oneuse.nll.stderr
@@ -1,26 +1,26 @@
 error: lifetime may not live long enough
-  --> $DIR/project-fn-ret-invariant.rs:38:12
+  --> $DIR/project-fn-ret-invariant.rs:39:13
    |
-LL | fn baz<'a,'b>(x: Type<'a>, y: Type<'b>) -> (Type<'a>, Type<'b>) {
-   |        -- -- lifetime `'b` defined here
+LL | fn baz<'a, 'b>(x: Type<'a>, y: Type<'b>) -> (Type<'a>, Type<'b>) {
+   |        --  -- lifetime `'b` defined here
    |        |
    |        lifetime `'a` defined here
-LL |    let f = foo; // <-- No consistent type can be inferred for `f` here.
-LL |    let a = bar(f, x);
-   |            ^^^^^^^^^ argument requires that `'a` must outlive `'b`
+LL |     let f = foo; // <-- No consistent type can be inferred for `f` here.
+LL |     let a = bar(f, x);
+   |             ^^^^^^^^^ argument requires that `'a` must outlive `'b`
    |
    = help: consider adding the following bound: `'a: 'b`
 
 error: lifetime may not live long enough
-  --> $DIR/project-fn-ret-invariant.rs:39:12
+  --> $DIR/project-fn-ret-invariant.rs:40:13
    |
-LL | fn baz<'a,'b>(x: Type<'a>, y: Type<'b>) -> (Type<'a>, Type<'b>) {
-   |        -- -- lifetime `'b` defined here
+LL | fn baz<'a, 'b>(x: Type<'a>, y: Type<'b>) -> (Type<'a>, Type<'b>) {
+   |        --  -- lifetime `'b` defined here
    |        |
    |        lifetime `'a` defined here
 ...
-LL |    let b = bar(f, y);
-   |            ^^^^^^^^^ argument requires that `'b` must outlive `'a`
+LL |     let b = bar(f, y);
+   |             ^^^^^^^^^ argument requires that `'b` must outlive `'a`
    |
    = help: consider adding the following bound: `'b: 'a`
 
diff --git a/src/test/ui/associated-types/cache/project-fn-ret-invariant.oneuse.stderr b/src/test/ui/associated-types/cache/project-fn-ret-invariant.oneuse.stderr
index 65d16440ac9..64b57223908 100644
--- a/src/test/ui/associated-types/cache/project-fn-ret-invariant.oneuse.stderr
+++ b/src/test/ui/associated-types/cache/project-fn-ret-invariant.oneuse.stderr
@@ -1,13 +1,13 @@
 error[E0623]: lifetime mismatch
-  --> $DIR/project-fn-ret-invariant.rs:39:19
+  --> $DIR/project-fn-ret-invariant.rs:40:20
    |
-LL | fn baz<'a,'b>(x: Type<'a>, y: Type<'b>) -> (Type<'a>, Type<'b>) {
-   |                               --------     --------------------
-   |                               |
-   |                               this parameter and the return type are declared with different lifetimes...
+LL | fn baz<'a, 'b>(x: Type<'a>, y: Type<'b>) -> (Type<'a>, Type<'b>) {
+   |                                --------     --------------------
+   |                                |
+   |                                this parameter and the return type are declared with different lifetimes...
 ...
-LL |    let b = bar(f, y);
-   |                   ^ ...but data from `x` is returned here
+LL |     let b = bar(f, y);
+   |                    ^ ...but data from `x` is returned here
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/associated-types/cache/project-fn-ret-invariant.rs b/src/test/ui/associated-types/cache/project-fn-ret-invariant.rs
index 23d873212ed..0034d796826 100644
--- a/src/test/ui/associated-types/cache/project-fn-ret-invariant.rs
+++ b/src/test/ui/associated-types/cache/project-fn-ret-invariant.rs
@@ -1,60 +1,61 @@
 #![feature(unboxed_closures)]
 #![feature(rustc_attrs)]
-
 // Test for projection cache. We should be able to project distinct
 // lifetimes from `foo` as we reinstantiate it multiple times, but not
 // if we do it just once. In this variant, the region `'a` is used in
 // an invariant position, which affects the results.
 
 // revisions: ok oneuse transmute krisskross
-
 #![allow(dead_code, unused_variables)]
 
 use std::marker::PhantomData;
 
 struct Type<'a> {
     // Invariant
-    data: PhantomData<fn(&'a u32) -> &'a u32>
+    data: PhantomData<fn(&'a u32) -> &'a u32>,
 }
 
-fn foo<'a>() -> Type<'a> { loop { } }
+fn foo<'a>() -> Type<'a> {
+    loop {}
+}
 
 fn bar<T>(t: T, x: T::Output) -> T::Output
-    where T: FnOnce<()>
+where
+    T: FnOnce<()>,
 {
     t()
 }
 
 #[cfg(ok)] // two instantiations: OK
-fn baz<'a,'b>(x: Type<'a>, y: Type<'b>) -> (Type<'a>, Type<'b>) {
+fn baz<'a, 'b>(x: Type<'a>, y: Type<'b>) -> (Type<'a>, Type<'b>) {
     let a = bar(foo, x);
     let b = bar(foo, y);
     (a, b)
 }
 
 #[cfg(oneuse)] // one instantiation: BAD
-fn baz<'a,'b>(x: Type<'a>, y: Type<'b>) -> (Type<'a>, Type<'b>) {
-   let f = foo; // <-- No consistent type can be inferred for `f` here.
-   let a = bar(f, x);
-   let b = bar(f, y); //[oneuse]~ ERROR lifetime mismatch [E0623]
-   (a, b)
+fn baz<'a, 'b>(x: Type<'a>, y: Type<'b>) -> (Type<'a>, Type<'b>) {
+    let f = foo; // <-- No consistent type can be inferred for `f` here.
+    let a = bar(f, x);
+    let b = bar(f, y); //[oneuse]~ ERROR lifetime mismatch [E0623]
+    (a, b)
 }
 
 #[cfg(transmute)] // one instantiations: BAD
-fn baz<'a,'b>(x: Type<'a>) -> Type<'static> {
-   // Cannot instantiate `foo` with any lifetime other than `'a`,
-   // since it is provided as input.
+fn baz<'a, 'b>(x: Type<'a>) -> Type<'static> {
+    // Cannot instantiate `foo` with any lifetime other than `'a`,
+    // since it is provided as input.
 
-   bar(foo, x) //[transmute]~ ERROR E0495
+    bar(foo, x) //[transmute]~ ERROR E0495
 }
 
 #[cfg(krisskross)] // two instantiations, mixing and matching: BAD
-fn transmute<'a,'b>(x: Type<'a>, y: Type<'b>) -> (Type<'a>, Type<'b>) {
-   let a = bar(foo, y); //[krisskross]~ ERROR E0623
-   let b = bar(foo, x); //[krisskross]~ ERROR E0623
-   (a, b)
+fn transmute<'a, 'b>(x: Type<'a>, y: Type<'b>) -> (Type<'a>, Type<'b>) {
+    let a = bar(foo, y); //[krisskross]~ ERROR E0623
+    let b = bar(foo, x);
+    (a, b) //[krisskross]~ ERROR E0623
 }
 
 #[rustc_error]
-fn main() { }
+fn main() {}
 //[ok]~^ ERROR fatal error triggered by #[rustc_error]
diff --git a/src/test/ui/associated-types/cache/project-fn-ret-invariant.transmute.nll.stderr b/src/test/ui/associated-types/cache/project-fn-ret-invariant.transmute.nll.stderr
index f74d4ba73bf..db82c9fd437 100644
--- a/src/test/ui/associated-types/cache/project-fn-ret-invariant.transmute.nll.stderr
+++ b/src/test/ui/associated-types/cache/project-fn-ret-invariant.transmute.nll.stderr
@@ -1,11 +1,11 @@
 error: lifetime may not live long enough
-  --> $DIR/project-fn-ret-invariant.rs:48:4
+  --> $DIR/project-fn-ret-invariant.rs:49:5
    |
-LL | fn baz<'a,'b>(x: Type<'a>) -> Type<'static> {
+LL | fn baz<'a, 'b>(x: Type<'a>) -> Type<'static> {
    |        -- lifetime `'a` defined here
 ...
-LL |    bar(foo, x)
-   |    ^^^^^^^^^^^ returning this value requires that `'a` must outlive `'static`
+LL |     bar(foo, x)
+   |     ^^^^^^^^^^^ returning this value requires that `'a` must outlive `'static`
    |
    = help: consider replacing `'a` with `'static`
 
diff --git a/src/test/ui/associated-types/cache/project-fn-ret-invariant.transmute.stderr b/src/test/ui/associated-types/cache/project-fn-ret-invariant.transmute.stderr
index 0a05fc6bb82..ef57f9e0bc4 100644
--- a/src/test/ui/associated-types/cache/project-fn-ret-invariant.transmute.stderr
+++ b/src/test/ui/associated-types/cache/project-fn-ret-invariant.transmute.stderr
@@ -1,27 +1,27 @@
-error[E0495]: cannot infer an appropriate lifetime due to conflicting requirements
-  --> $DIR/project-fn-ret-invariant.rs:48:4
+error[E0495]: cannot infer an appropriate lifetime for lifetime parameter `'a` due to conflicting requirements
+  --> $DIR/project-fn-ret-invariant.rs:49:9
    |
-LL |    bar(foo, x)
-   |    ^^^^^^^^^^^
+LL |     bar(foo, x)
+   |         ^^^
    |
-note: first, the lifetime cannot outlive the lifetime `'a` as defined on the function body at 44:8...
-  --> $DIR/project-fn-ret-invariant.rs:44:8
+note: first, the lifetime cannot outlive the lifetime `'a` as defined on the function body at 45:8...
+  --> $DIR/project-fn-ret-invariant.rs:45:8
    |
-LL | fn baz<'a,'b>(x: Type<'a>) -> Type<'static> {
+LL | fn baz<'a, 'b>(x: Type<'a>) -> Type<'static> {
    |        ^^
 note: ...so that the expression is assignable
-  --> $DIR/project-fn-ret-invariant.rs:48:13
+  --> $DIR/project-fn-ret-invariant.rs:49:14
    |
-LL |    bar(foo, x)
-   |             ^
+LL |     bar(foo, x)
+   |              ^
    = note: expected `Type<'_>`
               found `Type<'a>`
    = note: but, the lifetime must be valid for the static lifetime...
 note: ...so that the expression is assignable
-  --> $DIR/project-fn-ret-invariant.rs:48:4
+  --> $DIR/project-fn-ret-invariant.rs:49:5
    |
-LL |    bar(foo, x)
-   |    ^^^^^^^^^^^
+LL |     bar(foo, x)
+   |     ^^^^^^^^^^^
    = note: expected `Type<'static>`
               found `Type<'_>`
 
diff --git a/src/test/ui/associated-types/higher-ranked-projection.bad.nll.stderr b/src/test/ui/associated-types/higher-ranked-projection.bad.nll.stderr
new file mode 100644
index 00000000000..2e03986a9ed
--- /dev/null
+++ b/src/test/ui/associated-types/higher-ranked-projection.bad.nll.stderr
@@ -0,0 +1,8 @@
+error: higher-ranked subtype error
+  --> $DIR/higher-ranked-projection.rs:25:5
+   |
+LL |     foo(());
+   |     ^^^^^^^
+
+error: aborting due to previous error
+
diff --git a/src/test/ui/associated-types/higher-ranked-projection.bad.stderr b/src/test/ui/associated-types/higher-ranked-projection.bad.stderr
index 3b3e4c3ea11..811c9a8f5e1 100644
--- a/src/test/ui/associated-types/higher-ranked-projection.bad.stderr
+++ b/src/test/ui/associated-types/higher-ranked-projection.bad.stderr
@@ -1,14 +1,12 @@
-error[E0271]: type mismatch resolving `for<'a> <&'a _ as Mirror>::Image == _`
+error[E0308]: mismatched types
   --> $DIR/higher-ranked-projection.rs:25:5
    |
-LL | fn foo<U, T>(_t: T)
-   |    --- required by a bound in this
-LL |     where for<'a> &'a T: Mirror<Image=U>
-   |                                 ------- required by this bound in `foo`
-...
 LL |     foo(());
-   |     ^^^ expected bound lifetime parameter 'a, found concrete lifetime
+   |     ^^^ one type is more general than the other
+   |
+   = note: expected type `&'a ()`
+              found type `&()`
 
 error: aborting due to previous error
 
-For more information about this error, try `rustc --explain E0271`.
+For more information about this error, try `rustc --explain E0308`.
diff --git a/src/test/ui/associated-types/higher-ranked-projection.rs b/src/test/ui/associated-types/higher-ranked-projection.rs
index 5315e21b0f5..1b5476d4c36 100644
--- a/src/test/ui/associated-types/higher-ranked-projection.rs
+++ b/src/test/ui/associated-types/higher-ranked-projection.rs
@@ -23,5 +23,5 @@ fn foo<U, T>(_t: T)
 #[rustc_error]
 fn main() { //[good]~ ERROR fatal error triggered by #[rustc_error]
     foo(());
-    //[bad]~^ ERROR type mismatch
+    //[bad]~^ ERROR mismatched types
 }
diff --git a/src/test/ui/closure-expected-type/expect-fn-supply-fn.nll.stderr b/src/test/ui/closure-expected-type/expect-fn-supply-fn.nll.stderr
index 97fdb76dd11..64a0b52a1fa 100644
--- a/src/test/ui/closure-expected-type/expect-fn-supply-fn.nll.stderr
+++ b/src/test/ui/closure-expected-type/expect-fn-supply-fn.nll.stderr
@@ -1,42 +1,43 @@
-error[E0631]: type mismatch in closure arguments
-  --> $DIR/expect-fn-supply-fn.rs:30:5
+error: lifetime may not live long enough
+  --> $DIR/expect-fn-supply-fn.rs:16:49
    |
-LL | fn with_closure_expecting_fn_with_free_region<F>(_: F)
-   |    ------------------------------------------ required by a bound in this
-LL |     where F: for<'a> FnOnce(fn(&'a u32), &i32)
-   |                      ------------------------- required by this bound in `with_closure_expecting_fn_with_free_region`
+LL | fn expect_free_supply_free_from_fn<'x>(x: &'x u32) {
+   |                                    -- lifetime `'x` defined here
 ...
-LL |     with_closure_expecting_fn_with_free_region(|x: fn(&u32), y| {});
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ---------------- found signature of `fn(for<'r> fn(&'r u32), _) -> _`
-   |     |
-   |     expected signature of `fn(fn(&'a u32), &i32) -> _`
+LL |     with_closure_expecting_fn_with_free_region(|x: fn(&'x u32), y| {});
+   |                                                 ^
+   |                                                 |
+   |                                                 has type `fn(&'1 u32)`
+   |                                                 requires that `'1` must outlive `'x`
 
-error[E0631]: type mismatch in closure arguments
-  --> $DIR/expect-fn-supply-fn.rs:37:5
+error: lifetime may not live long enough
+  --> $DIR/expect-fn-supply-fn.rs:16:49
    |
-LL | fn with_closure_expecting_fn_with_bound_region<F>(_: F)
-   |    ------------------------------------------- required by a bound in this
-LL |     where F: FnOnce(fn(&u32), &i32)
-   |              ---------------------- required by this bound in `with_closure_expecting_fn_with_bound_region`
+LL | fn expect_free_supply_free_from_fn<'x>(x: &'x u32) {
+   |                                    -- lifetime `'x` defined here
 ...
+LL |     with_closure_expecting_fn_with_free_region(|x: fn(&'x u32), y| {});
+   |                                                 ^ requires that `'x` must outlive `'static`
+   |
+   = help: consider replacing `'x` with `'static`
+
+error: higher-ranked subtype error
+  --> $DIR/expect-fn-supply-fn.rs:32:49
+   |
+LL |     with_closure_expecting_fn_with_free_region(|x: fn(&u32), y| {});
+   |                                                 ^
+
+error: higher-ranked subtype error
+  --> $DIR/expect-fn-supply-fn.rs:39:50
+   |
 LL |     with_closure_expecting_fn_with_bound_region(|x: fn(&'x u32), y| {});
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ------------------- found signature of `fn(fn(&'x u32), _) -> _`
-   |     |
-   |     expected signature of `fn(for<'r> fn(&'r u32), &i32) -> _`
+   |                                                  ^
 
-error[E0631]: type mismatch in closure arguments
-  --> $DIR/expect-fn-supply-fn.rs:46:5
+error: higher-ranked subtype error
+  --> $DIR/expect-fn-supply-fn.rs:48:50
    |
-LL | fn with_closure_expecting_fn_with_bound_region<F>(_: F)
-   |    ------------------------------------------- required by a bound in this
-LL |     where F: FnOnce(fn(&u32), &i32)
-   |              ---------------------- required by this bound in `with_closure_expecting_fn_with_bound_region`
-...
 LL |     with_closure_expecting_fn_with_bound_region(|x: Foo<'_>, y| {
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ --------------- found signature of `for<'r> fn(fn(&'r u32), _) -> _`
-   |     |
-   |     expected signature of `fn(for<'r> fn(&'r u32), &i32) -> _`
+   |                                                  ^
 
-error: aborting due to 3 previous errors
+error: aborting due to 5 previous errors
 
-For more information about this error, try `rustc --explain E0631`.
diff --git a/src/test/ui/closure-expected-type/expect-fn-supply-fn.rs b/src/test/ui/closure-expected-type/expect-fn-supply-fn.rs
index a4e43da91ba..c81c40c18b4 100644
--- a/src/test/ui/closure-expected-type/expect-fn-supply-fn.rs
+++ b/src/test/ui/closure-expected-type/expect-fn-supply-fn.rs
@@ -1,10 +1,12 @@
 fn with_closure_expecting_fn_with_free_region<F>(_: F)
-    where F: for<'a> FnOnce(fn(&'a u32), &i32)
+where
+    F: for<'a> FnOnce(fn(&'a u32), &i32),
 {
 }
 
 fn with_closure_expecting_fn_with_bound_region<F>(_: F)
-    where F: FnOnce(fn(&u32), &i32)
+where
+    F: FnOnce(fn(&u32), &i32),
 {
 }
 
@@ -28,14 +30,14 @@ fn expect_free_supply_bound() {
     // Here, we are given a function whose region is bound at closure level,
     // but we expect one bound in the argument. Error results.
     with_closure_expecting_fn_with_free_region(|x: fn(&u32), y| {});
-    //~^ ERROR type mismatch
+    //~^ ERROR mismatched types
 }
 
 fn expect_bound_supply_free_from_fn<'x>(x: &'x u32) {
     // Here, we are given a `fn(&u32)` but we expect a `fn(&'x
     // u32)`. In principle, this could be ok, but we demand equality.
     with_closure_expecting_fn_with_bound_region(|x: fn(&'x u32), y| {});
-    //~^ ERROR type mismatch
+    //~^ ERROR mismatched types
 }
 
 fn expect_bound_supply_free_from_closure() {
@@ -44,7 +46,7 @@ fn expect_bound_supply_free_from_closure() {
     // the argument level.
     type Foo<'a> = fn(&'a u32);
     with_closure_expecting_fn_with_bound_region(|x: Foo<'_>, y| {
-    //~^ ERROR type mismatch
+        //~^ ERROR mismatched types
     });
 }
 
@@ -52,8 +54,7 @@ fn expect_bound_supply_bound<'x>(x: &'x u32) {
     // No error in this case. The supplied type supplies the bound
     // regions, and hence we are able to figure out the type of `y`
     // from the expected type
-    with_closure_expecting_fn_with_bound_region(|x: for<'z> fn(&'z u32), y| {
-    });
+    with_closure_expecting_fn_with_bound_region(|x: for<'z> fn(&'z u32), y| {});
 }
 
-fn main() { }
+fn main() {}
diff --git a/src/test/ui/closure-expected-type/expect-fn-supply-fn.stderr b/src/test/ui/closure-expected-type/expect-fn-supply-fn.stderr
index fae41c4114a..0de15dfa735 100644
--- a/src/test/ui/closure-expected-type/expect-fn-supply-fn.stderr
+++ b/src/test/ui/closure-expected-type/expect-fn-supply-fn.stderr
@@ -1,81 +1,68 @@
 error[E0308]: mismatched types
-  --> $DIR/expect-fn-supply-fn.rs:14:52
+  --> $DIR/expect-fn-supply-fn.rs:16:52
    |
 LL |     with_closure_expecting_fn_with_free_region(|x: fn(&'x u32), y| {});
    |                                                    ^^^^^^^^^^^ lifetime mismatch
    |
    = note: expected fn pointer `fn(&u32)`
               found fn pointer `fn(&'x u32)`
-note: the anonymous lifetime #2 defined on the body at 14:48...
-  --> $DIR/expect-fn-supply-fn.rs:14:48
+note: the anonymous lifetime #2 defined on the body at 16:48...
+  --> $DIR/expect-fn-supply-fn.rs:16:48
    |
 LL |     with_closure_expecting_fn_with_free_region(|x: fn(&'x u32), y| {});
    |                                                ^^^^^^^^^^^^^^^^^^^^^^
-note: ...does not necessarily outlive the lifetime `'x` as defined on the function body at 11:36
-  --> $DIR/expect-fn-supply-fn.rs:11:36
+note: ...does not necessarily outlive the lifetime `'x` as defined on the function body at 13:36
+  --> $DIR/expect-fn-supply-fn.rs:13:36
    |
 LL | fn expect_free_supply_free_from_fn<'x>(x: &'x u32) {
    |                                    ^^
 
 error[E0308]: mismatched types
-  --> $DIR/expect-fn-supply-fn.rs:14:52
+  --> $DIR/expect-fn-supply-fn.rs:16:52
    |
 LL |     with_closure_expecting_fn_with_free_region(|x: fn(&'x u32), y| {});
    |                                                    ^^^^^^^^^^^ lifetime mismatch
    |
    = note: expected fn pointer `fn(&u32)`
               found fn pointer `fn(&'x u32)`
-note: the lifetime `'x` as defined on the function body at 11:36...
-  --> $DIR/expect-fn-supply-fn.rs:11:36
+note: the lifetime `'x` as defined on the function body at 13:36...
+  --> $DIR/expect-fn-supply-fn.rs:13:36
    |
 LL | fn expect_free_supply_free_from_fn<'x>(x: &'x u32) {
    |                                    ^^
-note: ...does not necessarily outlive the anonymous lifetime #2 defined on the body at 14:48
-  --> $DIR/expect-fn-supply-fn.rs:14:48
+note: ...does not necessarily outlive the anonymous lifetime #2 defined on the body at 16:48
+  --> $DIR/expect-fn-supply-fn.rs:16:48
    |
 LL |     with_closure_expecting_fn_with_free_region(|x: fn(&'x u32), y| {});
    |                                                ^^^^^^^^^^^^^^^^^^^^^^
 
-error[E0631]: type mismatch in closure arguments
-  --> $DIR/expect-fn-supply-fn.rs:30:5
+error[E0308]: mismatched types
+  --> $DIR/expect-fn-supply-fn.rs:32:52
    |
-LL | fn with_closure_expecting_fn_with_free_region<F>(_: F)
-   |    ------------------------------------------ required by a bound in this
-LL |     where F: for<'a> FnOnce(fn(&'a u32), &i32)
-   |                      ------------------------- required by this bound in `with_closure_expecting_fn_with_free_region`
-...
 LL |     with_closure_expecting_fn_with_free_region(|x: fn(&u32), y| {});
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ---------------- found signature of `fn(for<'r> fn(&'r u32), _) -> _`
-   |     |
-   |     expected signature of `fn(fn(&'a u32), &i32) -> _`
+   |                                                    ^^^^^^^^ one type is more general than the other
+   |
+   = note: expected fn pointer `fn(&u32)`
+              found fn pointer `for<'r> fn(&'r u32)`
 
-error[E0631]: type mismatch in closure arguments
-  --> $DIR/expect-fn-supply-fn.rs:37:5
+error[E0308]: mismatched types
+  --> $DIR/expect-fn-supply-fn.rs:39:53
    |
-LL | fn with_closure_expecting_fn_with_bound_region<F>(_: F)
-   |    ------------------------------------------- required by a bound in this
-LL |     where F: FnOnce(fn(&u32), &i32)
-   |              ---------------------- required by this bound in `with_closure_expecting_fn_with_bound_region`
-...
 LL |     with_closure_expecting_fn_with_bound_region(|x: fn(&'x u32), y| {});
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ------------------- found signature of `fn(fn(&'x u32), _) -> _`
-   |     |
-   |     expected signature of `fn(for<'r> fn(&'r u32), &i32) -> _`
+   |                                                     ^^^^^^^^^^^ one type is more general than the other
+   |
+   = note: expected fn pointer `for<'r> fn(&'r u32)`
+              found fn pointer `fn(&'x u32)`
 
-error[E0631]: type mismatch in closure arguments
-  --> $DIR/expect-fn-supply-fn.rs:46:5
+error[E0308]: mismatched types
+  --> $DIR/expect-fn-supply-fn.rs:48:53
    |
-LL | fn with_closure_expecting_fn_with_bound_region<F>(_: F)
-   |    ------------------------------------------- required by a bound in this
-LL |     where F: FnOnce(fn(&u32), &i32)
-   |              ---------------------- required by this bound in `with_closure_expecting_fn_with_bound_region`
-...
 LL |     with_closure_expecting_fn_with_bound_region(|x: Foo<'_>, y| {
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ --------------- found signature of `for<'r> fn(fn(&'r u32), _) -> _`
-   |     |
-   |     expected signature of `fn(for<'r> fn(&'r u32), &i32) -> _`
+   |                                                     ^^^^^^^ one type is more general than the other
+   |
+   = note: expected fn pointer `for<'r> fn(&'r u32)`
+              found fn pointer `fn(&u32)`
 
 error: aborting due to 5 previous errors
 
-Some errors have detailed explanations: E0308, E0631.
-For more information about an error, try `rustc --explain E0308`.
+For more information about this error, try `rustc --explain E0308`.
diff --git a/src/test/ui/closures/issue-41366.rs b/src/test/ui/closures/issue-41366.rs
index 5cae0e76d1a..af1e37ba867 100644
--- a/src/test/ui/closures/issue-41366.rs
+++ b/src/test/ui/closures/issue-41366.rs
@@ -7,7 +7,6 @@ impl<'g> T<'g> for u32 {
 }
 
 fn main() {
-    (&|_|()) as &dyn for<'x> Fn(<u32 as T<'x>>::V);
+    (&|_| ()) as &dyn for<'x> Fn(<u32 as T<'x>>::V);
     //~^ ERROR: type mismatch in closure arguments
-    //~| ERROR: type mismatch resolving
 }
diff --git a/src/test/ui/closures/issue-41366.stderr b/src/test/ui/closures/issue-41366.stderr
index 2f2871e9f0e..9c4b7d529ef 100644
--- a/src/test/ui/closures/issue-41366.stderr
+++ b/src/test/ui/closures/issue-41366.stderr
@@ -1,23 +1,14 @@
 error[E0631]: type mismatch in closure arguments
   --> $DIR/issue-41366.rs:10:5
    |
-LL |     (&|_|()) as &dyn for<'x> Fn(<u32 as T<'x>>::V);
-   |     ^^-----^
+LL |     (&|_| ()) as &dyn for<'x> Fn(<u32 as T<'x>>::V);
+   |     ^^------^
    |     | |
-   |     | found signature of `fn(_) -> _`
-   |     expected signature of `for<'x> fn(<u32 as T<'x>>::V) -> _`
+   |     | found signature of `fn(u16) -> _`
+   |     expected signature of `fn(<u32 as T<'x>>::V) -> _`
    |
    = note: required for the cast to the object type `dyn for<'x> std::ops::Fn(<u32 as T<'x>>::V)`
 
-error[E0271]: type mismatch resolving `for<'x> <[closure@$DIR/issue-41366.rs:10:7: 10:12] as std::ops::FnOnce<(<u32 as T<'x>>::V,)>>::Output == ()`
-  --> $DIR/issue-41366.rs:10:5
-   |
-LL |     (&|_|()) as &dyn for<'x> Fn(<u32 as T<'x>>::V);
-   |     ^^^^^^^^ expected bound lifetime parameter 'x, found concrete lifetime
-   |
-   = note: required for the cast to the object type `dyn for<'x> std::ops::Fn(<u32 as T<'x>>::V)`
-
-error: aborting due to 2 previous errors
+error: aborting due to previous error
 
-Some errors have detailed explanations: E0271, E0631.
-For more information about an error, try `rustc --explain E0271`.
+For more information about this error, try `rustc --explain E0631`.
diff --git a/src/test/ui/coherence/coherence-fn-covariant-bound-vs-static.rs b/src/test/ui/coherence/coherence-fn-covariant-bound-vs-static.rs
new file mode 100644
index 00000000000..99f805f7f0f
--- /dev/null
+++ b/src/test/ui/coherence/coherence-fn-covariant-bound-vs-static.rs
@@ -0,0 +1,26 @@
+// Test that impls for these two types are considered ovelapping:
+//
+// * `for<'r> fn(fn(&'r u32))`
+// * `fn(fn(&'a u32)` where `'a` is free
+//
+// This is because, for `'a = 'static`, the two types overlap.
+// Effectively for them to be equal to you get:
+//
+// * `for<'r> fn(fn(&'r u32)) <: fn(fn(&'static u32))`
+//   * true if `exists<'r> { 'r: 'static }` (obviously true)
+// * `fn(fn(&'static u32)) <: for<'r> fn(fn(&'r u32))`
+//   * true if `forall<'r> { 'static: 'r }` (also true)
+
+trait Trait {}
+
+impl Trait for for<'r> fn(fn(&'r ())) {}
+impl<'a> Trait for fn(fn(&'a ())) {}
+//~^ ERROR conflicting implementations
+//
+// Note in particular that we do NOT get a future-compatibility warning
+// here. This is because the new leak-check proposed in [MCP 295] does not
+// "error" when these two types are equated.
+//
+// [MCP 295]: https://github.com/rust-lang/compiler-team/issues/295
+
+fn main() {}
diff --git a/src/test/ui/coherence/coherence-fn-covariant-bound-vs-static.stderr b/src/test/ui/coherence/coherence-fn-covariant-bound-vs-static.stderr
new file mode 100644
index 00000000000..49271edf8e5
--- /dev/null
+++ b/src/test/ui/coherence/coherence-fn-covariant-bound-vs-static.stderr
@@ -0,0 +1,13 @@
+error[E0119]: conflicting implementations of trait `Trait` for type `for<'r> fn(fn(&'r ()))`:
+  --> $DIR/coherence-fn-covariant-bound-vs-static.rs:17:1
+   |
+LL | impl Trait for for<'r> fn(fn(&'r ())) {}
+   | ------------------------------------- first implementation here
+LL | impl<'a> Trait for fn(fn(&'a ())) {}
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `for<'r> fn(fn(&'r ()))`
+   |
+   = note: this behavior recently changed as a result of a bug fix; see rust-lang/rust#56105 for details
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0119`.
diff --git a/src/test/ui/coherence/coherence-fn-implied-bounds.rs b/src/test/ui/coherence/coherence-fn-implied-bounds.rs
new file mode 100644
index 00000000000..4539af9a32e
--- /dev/null
+++ b/src/test/ui/coherence/coherence-fn-implied-bounds.rs
@@ -0,0 +1,26 @@
+// Test that our leak-check is not smart enough to take implied bounds
+// into account (yet). Here we have two types that look like they
+// should not be equivalent, but because of the rules on implied
+// bounds we ought to know that, in fact, `'a = 'b` must always hold,
+// and hence they are.
+//
+// Rustc can't figure this out and hence it accepts the impls but
+// gives a future-compatibility warning (because we'd like to make
+// this an error someday).
+//
+// Note that while we would like to make this a hard error, we also
+// give the same warning for `coherence-wasm-bindgen.rs`, which ought
+// to be accepted.
+
+#![deny(coherence_leak_check)]
+
+trait Trait {}
+
+impl Trait for for<'a, 'b> fn(&'a &'b u32, &'b &'a u32) -> &'b u32 {}
+
+impl Trait for for<'c> fn(&'c &'c u32, &'c &'c u32) -> &'c u32 {
+    //~^ ERROR conflicting implementations
+    //~| WARNING this was previously accepted by the compiler
+}
+
+fn main() {}
diff --git a/src/test/ui/coherence/coherence-fn-implied-bounds.stderr b/src/test/ui/coherence/coherence-fn-implied-bounds.stderr
new file mode 100644
index 00000000000..a3e7f0bcde3
--- /dev/null
+++ b/src/test/ui/coherence/coherence-fn-implied-bounds.stderr
@@ -0,0 +1,20 @@
+error: conflicting implementations of trait `Trait` for type `for<'a, 'b> fn(&'a &'b u32, &'b &'a u32) -> &'b u32`:
+  --> $DIR/coherence-fn-implied-bounds.rs:21:1
+   |
+LL | impl Trait for for<'a, 'b> fn(&'a &'b u32, &'b &'a u32) -> &'b u32 {}
+   | ------------------------------------------------------------------ first implementation here
+LL | 
+LL | impl Trait for for<'c> fn(&'c &'c u32, &'c &'c u32) -> &'c u32 {
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `for<'a, 'b> fn(&'a &'b u32, &'b &'a u32) -> &'b u32`
+   |
+note: the lint level is defined here
+  --> $DIR/coherence-fn-implied-bounds.rs:15:9
+   |
+LL | #![deny(coherence_leak_check)]
+   |         ^^^^^^^^^^^^^^^^^^^^
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+   = note: for more information, see issue #56105 <https://github.com/rust-lang/rust/issues/56105>
+   = note: this behavior recently changed as a result of a bug fix; see rust-lang/rust#56105 for details
+
+error: aborting due to previous error
+
diff --git a/src/test/ui/coherence/coherence-fn-inputs.rs b/src/test/ui/coherence/coherence-fn-inputs.rs
new file mode 100644
index 00000000000..3afec5c5459
--- /dev/null
+++ b/src/test/ui/coherence/coherence-fn-inputs.rs
@@ -0,0 +1,25 @@
+// Test that we consider these two types completely equal:
+//
+// * `for<'a, 'b> fn(&'a u32, &'b u32)`
+// * `for<'c> fn(&'c u32, &'c u32)`
+//
+// For a long time we considered these to be distinct types. But in fact they
+// are equivalent, if you work through the implications of subtyping -- this is
+// because:
+//
+// * `'c` can be the intersection of `'a` and `'b` (and there is always an intersection)
+// * `'a` and `'b` can both be equal to `'c`
+
+trait Trait {}
+impl Trait for for<'a, 'b> fn(&'a u32, &'b u32) {}
+impl Trait for for<'c> fn(&'c u32, &'c u32) {
+    //~^ ERROR conflicting implementations
+    //
+    // Note in particular that we do NOT get a future-compatibility warning
+    // here. This is because the new leak-check proposed in [MCP 295] does not
+    // "error" when these two types are equated.
+    //
+    // [MCP 295]: https://github.com/rust-lang/compiler-team/issues/295
+}
+
+fn main() {}
diff --git a/src/test/ui/coherence/coherence-fn-inputs.stderr b/src/test/ui/coherence/coherence-fn-inputs.stderr
new file mode 100644
index 00000000000..56ab873a393
--- /dev/null
+++ b/src/test/ui/coherence/coherence-fn-inputs.stderr
@@ -0,0 +1,13 @@
+error[E0119]: conflicting implementations of trait `Trait` for type `for<'a, 'b> fn(&'a u32, &'b u32)`:
+  --> $DIR/coherence-fn-inputs.rs:15:1
+   |
+LL | impl Trait for for<'a, 'b> fn(&'a u32, &'b u32) {}
+   | ----------------------------------------------- first implementation here
+LL | impl Trait for for<'c> fn(&'c u32, &'c u32) {
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `for<'a, 'b> fn(&'a u32, &'b u32)`
+   |
+   = note: this behavior recently changed as a result of a bug fix; see rust-lang/rust#56105 for details
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0119`.
diff --git a/src/test/ui/coherence/coherence-free-vs-bound-region.rs b/src/test/ui/coherence/coherence-free-vs-bound-region.rs
new file mode 100644
index 00000000000..2f5c49d293d
--- /dev/null
+++ b/src/test/ui/coherence/coherence-free-vs-bound-region.rs
@@ -0,0 +1,21 @@
+// Capture a coherence pattern from wasm-bindgen that we discovered as part of
+// future-compatibility warning #56105. This pattern currently receives a lint
+// warning but we probably want to support it long term.
+//
+// Key distinction: we are implementing once for `A` (take ownership) and one
+// for `&A` (borrow).
+//
+// c.f. #56105
+
+#![deny(coherence_leak_check)]
+
+trait TheTrait {}
+
+impl<'a> TheTrait for fn(&'a u8) {}
+
+impl TheTrait for fn(&u8) {
+    //~^ ERROR conflicting implementations of trait
+    //~| WARNING this was previously accepted by the compiler
+}
+
+fn main() {}
diff --git a/src/test/ui/coherence/coherence-free-vs-bound-region.stderr b/src/test/ui/coherence/coherence-free-vs-bound-region.stderr
new file mode 100644
index 00000000000..97aa4912721
--- /dev/null
+++ b/src/test/ui/coherence/coherence-free-vs-bound-region.stderr
@@ -0,0 +1,20 @@
+error: conflicting implementations of trait `TheTrait` for type `fn(&u8)`:
+  --> $DIR/coherence-free-vs-bound-region.rs:16:1
+   |
+LL | impl<'a> TheTrait for fn(&'a u8) {}
+   | -------------------------------- first implementation here
+LL | 
+LL | impl TheTrait for fn(&u8) {
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `fn(&u8)`
+   |
+note: the lint level is defined here
+  --> $DIR/coherence-free-vs-bound-region.rs:10:9
+   |
+LL | #![deny(coherence_leak_check)]
+   |         ^^^^^^^^^^^^^^^^^^^^
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+   = note: for more information, see issue #56105 <https://github.com/rust-lang/rust/issues/56105>
+   = note: this behavior recently changed as a result of a bug fix; see rust-lang/rust#56105 for details
+
+error: aborting due to previous error
+
diff --git a/src/test/ui/coherence/coherence-wasm-bindgen.rs b/src/test/ui/coherence/coherence-wasm-bindgen.rs
new file mode 100644
index 00000000000..ee09a72449b
--- /dev/null
+++ b/src/test/ui/coherence/coherence-wasm-bindgen.rs
@@ -0,0 +1,37 @@
+// Capture a coherence pattern from wasm-bindgen that we discovered as part of
+// future-compatibility warning #56105. This pattern currently receives a lint
+// warning but we probably want to support it long term.
+//
+// Key distinction: we are implementing once for `A` (take ownership) and one
+// for `&A` (borrow).
+//
+// c.f. #56105
+
+#![deny(coherence_leak_check)]
+
+trait IntoWasmAbi {
+    fn some_method(&self) {}
+}
+
+trait FromWasmAbi {}
+trait RefFromWasmAbi {}
+trait ReturnWasmAbi {}
+
+impl<'a, 'b, A, R> IntoWasmAbi for &'a (dyn Fn(A) -> R + 'b)
+where
+    A: FromWasmAbi,
+    R: ReturnWasmAbi,
+{
+}
+
+// Explicitly writing the bound lifetime.
+impl<'a, 'b, A, R> IntoWasmAbi for &'a (dyn for<'x> Fn(&'x A) -> R + 'b)
+where
+    A: RefFromWasmAbi,
+    R: ReturnWasmAbi,
+{
+    //~^^^^^ ERROR conflicting implementation
+    //~| WARNING this was previously accepted
+}
+
+fn main() {}
diff --git a/src/test/ui/coherence/coherence-wasm-bindgen.stderr b/src/test/ui/coherence/coherence-wasm-bindgen.stderr
new file mode 100644
index 00000000000..c77483bb847
--- /dev/null
+++ b/src/test/ui/coherence/coherence-wasm-bindgen.stderr
@@ -0,0 +1,32 @@
+error: conflicting implementations of trait `IntoWasmAbi` for type `&dyn std::ops::Fn(&_) -> _`:
+  --> $DIR/coherence-wasm-bindgen.rs:28:1
+   |
+LL | / impl<'a, 'b, A, R> IntoWasmAbi for &'a (dyn Fn(A) -> R + 'b)
+LL | | where
+LL | |     A: FromWasmAbi,
+LL | |     R: ReturnWasmAbi,
+LL | | {
+LL | | }
+   | |_- first implementation here
+...
+LL | / impl<'a, 'b, A, R> IntoWasmAbi for &'a (dyn for<'x> Fn(&'x A) -> R + 'b)
+LL | | where
+LL | |     A: RefFromWasmAbi,
+LL | |     R: ReturnWasmAbi,
+...  |
+LL | |
+LL | | }
+   | |_^ conflicting implementation for `&dyn std::ops::Fn(&_) -> _`
+   |
+note: the lint level is defined here
+  --> $DIR/coherence-wasm-bindgen.rs:10:9
+   |
+LL | #![deny(coherence_leak_check)]
+   |         ^^^^^^^^^^^^^^^^^^^^
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+   = note: for more information, see issue #56105 <https://github.com/rust-lang/rust/issues/56105>
+   = note: downstream crates may implement trait `FromWasmAbi` for type `&_`
+   = note: this behavior recently changed as a result of a bug fix; see rust-lang/rust#56105 for details
+
+error: aborting due to previous error
+
diff --git a/src/test/ui/generator/resume-arg-late-bound.nll.stderr b/src/test/ui/generator/resume-arg-late-bound.nll.stderr
new file mode 100644
index 00000000000..7d712191924
--- /dev/null
+++ b/src/test/ui/generator/resume-arg-late-bound.nll.stderr
@@ -0,0 +1,8 @@
+error: higher-ranked subtype error
+  --> $DIR/resume-arg-late-bound.rs:15:5
+   |
+LL |     test(gen);
+   |     ^^^^^^^^^
+
+error: aborting due to previous error
+
diff --git a/src/test/ui/generator/resume-arg-late-bound.rs b/src/test/ui/generator/resume-arg-late-bound.rs
index 87b1f1a065b..a8f657eaabe 100644
--- a/src/test/ui/generator/resume-arg-late-bound.rs
+++ b/src/test/ui/generator/resume-arg-late-bound.rs
@@ -13,5 +13,6 @@ fn main() {
         *arg = true;
     };
     test(gen);
-    //~^ ERROR type mismatch in function arguments
+    //~^ ERROR mismatched types
+    //~| ERROR mismatched types
 }
diff --git a/src/test/ui/generator/resume-arg-late-bound.stderr b/src/test/ui/generator/resume-arg-late-bound.stderr
index ffa440daed8..c379d9eae8e 100644
--- a/src/test/ui/generator/resume-arg-late-bound.stderr
+++ b/src/test/ui/generator/resume-arg-late-bound.stderr
@@ -1,15 +1,21 @@
-error[E0631]: type mismatch in function arguments
-  --> $DIR/resume-arg-late-bound.rs:15:10
+error[E0308]: mismatched types
+  --> $DIR/resume-arg-late-bound.rs:15:5
    |
-LL | fn test(a: impl for<'a> Generator<&'a mut bool>) {}
-   |                 ------------------------------- required by this bound in `test`
-...
 LL |     test(gen);
-   |          ^^^
-   |          |
-   |          expected signature of `for<'a> fn(&'a mut bool) -> _`
-   |          found signature of `fn(&mut bool) -> _`
+   |     ^^^^ one type is more general than the other
+   |
+   = note: expected type `for<'a> std::ops::Generator<&'a mut bool>`
+              found type `std::ops::Generator<&mut bool>`
+
+error[E0308]: mismatched types
+  --> $DIR/resume-arg-late-bound.rs:15:5
+   |
+LL |     test(gen);
+   |     ^^^^ one type is more general than the other
+   |
+   = note: expected type `for<'a> std::ops::Generator<&'a mut bool>`
+              found type `std::ops::Generator<&mut bool>`
 
-error: aborting due to previous error
+error: aborting due to 2 previous errors
 
-For more information about this error, try `rustc --explain E0631`.
+For more information about this error, try `rustc --explain E0308`.
diff --git a/src/test/ui/hr-subtype/hr-subtype.bound_a_b_ret_a_vs_bound_a_ret_a.nll.stderr b/src/test/ui/hr-subtype/hr-subtype.bound_a_b_ret_a_vs_bound_a_ret_a.nll.stderr
new file mode 100644
index 00000000000..d5343566633
--- /dev/null
+++ b/src/test/ui/hr-subtype/hr-subtype.bound_a_b_ret_a_vs_bound_a_ret_a.nll.stderr
@@ -0,0 +1,14 @@
+error: higher-ranked subtype error
+  --> $DIR/hr-subtype.rs:45:13
+   |
+LL |               gimme::<$t1>(None::<$t2>);
+   |               ^^^^^^^^^^^^^^^^^^^^^^^^^
+...
+LL | / check! { bound_a_b_ret_a_vs_bound_a_ret_a: (for<'a,'b> fn(&'a u32, &'b u32) -> &'a u32,
+LL | | for<'a>    fn(&'a u32, &'a u32) -> &'a u32) }
+   | |_____________________________________________- in this macro invocation
+   |
+   = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error: aborting due to previous error
+
diff --git a/src/test/ui/hr-subtype/hr-subtype.bound_a_b_ret_a_vs_bound_a_ret_a.stderr b/src/test/ui/hr-subtype/hr-subtype.bound_a_b_ret_a_vs_bound_a_ret_a.stderr
index b91798fa123..92a85825030 100644
--- a/src/test/ui/hr-subtype/hr-subtype.bound_a_b_ret_a_vs_bound_a_ret_a.stderr
+++ b/src/test/ui/hr-subtype/hr-subtype.bound_a_b_ret_a_vs_bound_a_ret_a.stderr
@@ -1,12 +1,12 @@
 error[E0308]: mismatched types
-  --> $DIR/hr-subtype.rs:39:26
+  --> $DIR/hr-subtype.rs:45:26
    |
 LL |               gimme::<$t1>(None::<$t2>);
-   |                            ^^^^^^^^^^^ expected concrete lifetime, found bound lifetime parameter 'a
+   |                            ^^^^^^^^^^^ one type is more general than the other
 ...
 LL | / check! { bound_a_b_ret_a_vs_bound_a_ret_a: (for<'a,'b> fn(&'a u32, &'b u32) -> &'a u32,
-LL | |                                             for<'a>    fn(&'a u32, &'a u32) -> &'a u32) }
-   | |_________________________________________________________________________________________- in this macro invocation
+LL | | for<'a>    fn(&'a u32, &'a u32) -> &'a u32) }
+   | |_____________________________________________- in this macro invocation
    |
    = note: expected enum `std::option::Option<for<'a, 'b> fn(&'a u32, &'b u32) -> &'a u32>`
               found enum `std::option::Option<for<'a> fn(&'a u32, &'a u32) -> &'a u32>`
diff --git a/src/test/ui/hr-subtype/hr-subtype.bound_a_b_vs_bound_a.stderr b/src/test/ui/hr-subtype/hr-subtype.bound_a_b_vs_bound_a.stderr
index 45f53d4fe99..94837556610 100644
--- a/src/test/ui/hr-subtype/hr-subtype.bound_a_b_vs_bound_a.stderr
+++ b/src/test/ui/hr-subtype/hr-subtype.bound_a_b_vs_bound_a.stderr
@@ -1,17 +1,14 @@
-error[E0308]: mismatched types
-  --> $DIR/hr-subtype.rs:39:26
+error: fatal error triggered by #[rustc_error]
+  --> $DIR/hr-subtype.rs:102:1
    |
-LL |               gimme::<$t1>(None::<$t2>);
-   |                            ^^^^^^^^^^^ expected concrete lifetime, found bound lifetime parameter 'a
-...
-LL | / check! { bound_a_b_vs_bound_a: (for<'a,'b> fn(&'a u32, &'b u32),
-LL | |                                 for<'a>    fn(&'a u32, &'a u32)) }
-   | |__________________________________________________________________- in this macro invocation
-   |
-   = note: expected enum `std::option::Option<for<'a, 'b> fn(&'a u32, &'b u32)>`
-              found enum `std::option::Option<for<'a> fn(&'a u32, &'a u32)>`
-   = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info)
+LL | / fn main() {
+LL | |
+LL | |
+LL | |
+...  |
+LL | |
+LL | | }
+   | |_^
 
 error: aborting due to previous error
 
-For more information about this error, try `rustc --explain E0308`.
diff --git a/src/test/ui/hr-subtype/hr-subtype.bound_a_vs_bound_a.stderr b/src/test/ui/hr-subtype/hr-subtype.bound_a_vs_bound_a.stderr
index 6aba6466fad..94837556610 100644
--- a/src/test/ui/hr-subtype/hr-subtype.bound_a_vs_bound_a.stderr
+++ b/src/test/ui/hr-subtype/hr-subtype.bound_a_vs_bound_a.stderr
@@ -1,11 +1,11 @@
 error: fatal error triggered by #[rustc_error]
-  --> $DIR/hr-subtype.rs:100:1
+  --> $DIR/hr-subtype.rs:102:1
    |
 LL | / fn main() {
 LL | |
 LL | |
 LL | |
-LL | |
+...  |
 LL | |
 LL | | }
    | |_^
diff --git a/src/test/ui/hr-subtype/hr-subtype.bound_a_vs_bound_b.stderr b/src/test/ui/hr-subtype/hr-subtype.bound_a_vs_bound_b.stderr
index 6aba6466fad..94837556610 100644
--- a/src/test/ui/hr-subtype/hr-subtype.bound_a_vs_bound_b.stderr
+++ b/src/test/ui/hr-subtype/hr-subtype.bound_a_vs_bound_b.stderr
@@ -1,11 +1,11 @@
 error: fatal error triggered by #[rustc_error]
-  --> $DIR/hr-subtype.rs:100:1
+  --> $DIR/hr-subtype.rs:102:1
    |
 LL | / fn main() {
 LL | |
 LL | |
 LL | |
-LL | |
+...  |
 LL | |
 LL | | }
    | |_^
diff --git a/src/test/ui/hr-subtype/hr-subtype.bound_a_vs_free_x.nll.stderr b/src/test/ui/hr-subtype/hr-subtype.bound_a_vs_free_x.nll.stderr
new file mode 100644
index 00000000000..f1156093967
--- /dev/null
+++ b/src/test/ui/hr-subtype/hr-subtype.bound_a_vs_free_x.nll.stderr
@@ -0,0 +1,14 @@
+error: higher-ranked subtype error
+  --> $DIR/hr-subtype.rs:45:13
+   |
+LL |               gimme::<$t1>(None::<$t2>);
+   |               ^^^^^^^^^^^^^^^^^^^^^^^^^
+...
+LL | / check! { bound_a_vs_free_x: (for<'a> fn(&'a u32),
+LL | | fn(&'x u32)) }
+   | |______________- in this macro invocation
+   |
+   = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error: aborting due to previous error
+
diff --git a/src/test/ui/hr-subtype/hr-subtype.bound_a_vs_free_x.stderr b/src/test/ui/hr-subtype/hr-subtype.bound_a_vs_free_x.stderr
index c3e4f6d2ed0..98f5bff7327 100644
--- a/src/test/ui/hr-subtype/hr-subtype.bound_a_vs_free_x.stderr
+++ b/src/test/ui/hr-subtype/hr-subtype.bound_a_vs_free_x.stderr
@@ -1,12 +1,12 @@
 error[E0308]: mismatched types
-  --> $DIR/hr-subtype.rs:39:26
+  --> $DIR/hr-subtype.rs:45:26
    |
 LL |               gimme::<$t1>(None::<$t2>);
-   |                            ^^^^^^^^^^^ expected concrete lifetime, found bound lifetime parameter 'a
+   |                            ^^^^^^^^^^^ one type is more general than the other
 ...
 LL | / check! { bound_a_vs_free_x: (for<'a> fn(&'a u32),
-LL | |                              fn(&'x u32)) }
-   | |___________________________________________- in this macro invocation
+LL | | fn(&'x u32)) }
+   | |______________- in this macro invocation
    |
    = note: expected enum `std::option::Option<for<'a> fn(&'a u32)>`
               found enum `std::option::Option<fn(&'x u32)>`
diff --git a/src/test/ui/hr-subtype/hr-subtype.bound_co_a_b_vs_bound_co_a.stderr b/src/test/ui/hr-subtype/hr-subtype.bound_co_a_b_vs_bound_co_a.stderr
index 4d7b86027f5..94837556610 100644
--- a/src/test/ui/hr-subtype/hr-subtype.bound_co_a_b_vs_bound_co_a.stderr
+++ b/src/test/ui/hr-subtype/hr-subtype.bound_co_a_b_vs_bound_co_a.stderr
@@ -1,17 +1,14 @@
-error[E0308]: mismatched types
-  --> $DIR/hr-subtype.rs:39:26
+error: fatal error triggered by #[rustc_error]
+  --> $DIR/hr-subtype.rs:102:1
    |
-LL |               gimme::<$t1>(None::<$t2>);
-   |                            ^^^^^^^^^^^ expected concrete lifetime, found bound lifetime parameter 'a
-...
-LL | / check! { bound_co_a_b_vs_bound_co_a: (for<'a,'b> fn(Co<'a>, Co<'b>),
-LL | |                                       for<'a>    fn(Co<'a>, Co<'a>)) }
-   | |______________________________________________________________________- in this macro invocation
-   |
-   = note: expected enum `std::option::Option<for<'a, 'b> fn(Co<'a>, Co<'b>)>`
-              found enum `std::option::Option<for<'a> fn(Co<'a>, Co<'a>)>`
-   = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info)
+LL | / fn main() {
+LL | |
+LL | |
+LL | |
+...  |
+LL | |
+LL | | }
+   | |_^
 
 error: aborting due to previous error
 
-For more information about this error, try `rustc --explain E0308`.
diff --git a/src/test/ui/hr-subtype/hr-subtype.bound_co_a_co_b_ret_contra_a.stderr b/src/test/ui/hr-subtype/hr-subtype.bound_co_a_co_b_ret_contra_a.stderr
index 7f0a4197dd7..94837556610 100644
--- a/src/test/ui/hr-subtype/hr-subtype.bound_co_a_co_b_ret_contra_a.stderr
+++ b/src/test/ui/hr-subtype/hr-subtype.bound_co_a_co_b_ret_contra_a.stderr
@@ -1,17 +1,14 @@
-error[E0308]: mismatched types
-  --> $DIR/hr-subtype.rs:39:26
+error: fatal error triggered by #[rustc_error]
+  --> $DIR/hr-subtype.rs:102:1
    |
-LL |               gimme::<$t1>(None::<$t2>);
-   |                            ^^^^^^^^^^^ expected concrete lifetime, found bound lifetime parameter 'a
-...
-LL | / check! { bound_co_a_co_b_ret_contra_a: (for<'a,'b> fn(Co<'a>, Co<'b>) -> Contra<'a>,
-LL | |                                         for<'a>    fn(Co<'a>, Co<'a>) -> Contra<'a>) }
-   | |______________________________________________________________________________________- in this macro invocation
-   |
-   = note: expected enum `std::option::Option<for<'a, 'b> fn(Co<'a>, Co<'b>) -> Contra<'a>>`
-              found enum `std::option::Option<for<'a> fn(Co<'a>, Co<'a>) -> Contra<'a>>`
-   = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info)
+LL | / fn main() {
+LL | |
+LL | |
+LL | |
+...  |
+LL | |
+LL | | }
+   | |_^
 
 error: aborting due to previous error
 
-For more information about this error, try `rustc --explain E0308`.
diff --git a/src/test/ui/hr-subtype/hr-subtype.bound_co_a_vs_bound_co_b.stderr b/src/test/ui/hr-subtype/hr-subtype.bound_co_a_vs_bound_co_b.stderr
index 6aba6466fad..94837556610 100644
--- a/src/test/ui/hr-subtype/hr-subtype.bound_co_a_vs_bound_co_b.stderr
+++ b/src/test/ui/hr-subtype/hr-subtype.bound_co_a_vs_bound_co_b.stderr
@@ -1,11 +1,11 @@
 error: fatal error triggered by #[rustc_error]
-  --> $DIR/hr-subtype.rs:100:1
+  --> $DIR/hr-subtype.rs:102:1
    |
 LL | / fn main() {
 LL | |
 LL | |
 LL | |
-LL | |
+...  |
 LL | |
 LL | | }
    | |_^
diff --git a/src/test/ui/hr-subtype/hr-subtype.bound_contra_a_contra_b_ret_co_a.stderr b/src/test/ui/hr-subtype/hr-subtype.bound_contra_a_contra_b_ret_co_a.stderr
index c12e543a44e..94837556610 100644
--- a/src/test/ui/hr-subtype/hr-subtype.bound_contra_a_contra_b_ret_co_a.stderr
+++ b/src/test/ui/hr-subtype/hr-subtype.bound_contra_a_contra_b_ret_co_a.stderr
@@ -1,17 +1,14 @@
-error[E0308]: mismatched types
-  --> $DIR/hr-subtype.rs:39:26
+error: fatal error triggered by #[rustc_error]
+  --> $DIR/hr-subtype.rs:102:1
    |
-LL |               gimme::<$t1>(None::<$t2>);
-   |                            ^^^^^^^^^^^ expected concrete lifetime, found bound lifetime parameter 'a
-...
-LL | / check! { bound_contra_a_contra_b_ret_co_a: (for<'a,'b> fn(Contra<'a>, Contra<'b>) -> Co<'a>,
-LL | |                                             for<'a>    fn(Contra<'a>, Contra<'a>) -> Co<'a>) }
-   | |______________________________________________________________________________________________- in this macro invocation
-   |
-   = note: expected enum `std::option::Option<for<'a, 'b> fn(Contra<'a>, Contra<'b>) -> Co<'a>>`
-              found enum `std::option::Option<for<'a> fn(Contra<'a>, Contra<'a>) -> Co<'a>>`
-   = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info)
+LL | / fn main() {
+LL | |
+LL | |
+LL | |
+...  |
+LL | |
+LL | | }
+   | |_^
 
 error: aborting due to previous error
 
-For more information about this error, try `rustc --explain E0308`.
diff --git a/src/test/ui/hr-subtype/hr-subtype.bound_inv_a_b_vs_bound_inv_a.nll.stderr b/src/test/ui/hr-subtype/hr-subtype.bound_inv_a_b_vs_bound_inv_a.nll.stderr
new file mode 100644
index 00000000000..4541c462ee0
--- /dev/null
+++ b/src/test/ui/hr-subtype/hr-subtype.bound_inv_a_b_vs_bound_inv_a.nll.stderr
@@ -0,0 +1,26 @@
+error: higher-ranked subtype error
+  --> $DIR/hr-subtype.rs:45:13
+   |
+LL |               gimme::<$t1>(None::<$t2>);
+   |               ^^^^^^^^^^^^^^^^^^^^^^^^^
+...
+LL | / check! { bound_inv_a_b_vs_bound_inv_a: (for<'a,'b> fn(Inv<'a>, Inv<'b>),
+LL | | for<'a>    fn(Inv<'a>, Inv<'a>)) }
+   | |__________________________________- in this macro invocation
+   |
+   = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error: higher-ranked subtype error
+  --> $DIR/hr-subtype.rs:45:13
+   |
+LL |               gimme::<$t1>(None::<$t2>);
+   |               ^^^^^^^^^^^^^^^^^^^^^^^^^
+...
+LL | / check! { bound_inv_a_b_vs_bound_inv_a: (for<'a,'b> fn(Inv<'a>, Inv<'b>),
+LL | | for<'a>    fn(Inv<'a>, Inv<'a>)) }
+   | |__________________________________- in this macro invocation
+   |
+   = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error: aborting due to 2 previous errors
+
diff --git a/src/test/ui/hr-subtype/hr-subtype.bound_inv_a_b_vs_bound_inv_a.stderr b/src/test/ui/hr-subtype/hr-subtype.bound_inv_a_b_vs_bound_inv_a.stderr
index 460356856bd..100ba6ac27e 100644
--- a/src/test/ui/hr-subtype/hr-subtype.bound_inv_a_b_vs_bound_inv_a.stderr
+++ b/src/test/ui/hr-subtype/hr-subtype.bound_inv_a_b_vs_bound_inv_a.stderr
@@ -1,12 +1,12 @@
 error[E0308]: mismatched types
-  --> $DIR/hr-subtype.rs:39:26
+  --> $DIR/hr-subtype.rs:45:26
    |
 LL |               gimme::<$t1>(None::<$t2>);
-   |                            ^^^^^^^^^^^ expected concrete lifetime, found bound lifetime parameter 'a
+   |                            ^^^^^^^^^^^ one type is more general than the other
 ...
 LL | / check! { bound_inv_a_b_vs_bound_inv_a: (for<'a,'b> fn(Inv<'a>, Inv<'b>),
-LL | |                                         for<'a>    fn(Inv<'a>, Inv<'a>)) }
-   | |__________________________________________________________________________- in this macro invocation
+LL | | for<'a>    fn(Inv<'a>, Inv<'a>)) }
+   | |__________________________________- in this macro invocation
    |
    = note: expected enum `std::option::Option<for<'a, 'b> fn(Inv<'a>, Inv<'b>)>`
               found enum `std::option::Option<for<'a> fn(Inv<'a>, Inv<'a>)>`
diff --git a/src/test/ui/hr-subtype/hr-subtype.bound_inv_a_vs_bound_inv_b.stderr b/src/test/ui/hr-subtype/hr-subtype.bound_inv_a_vs_bound_inv_b.stderr
index 6aba6466fad..94837556610 100644
--- a/src/test/ui/hr-subtype/hr-subtype.bound_inv_a_vs_bound_inv_b.stderr
+++ b/src/test/ui/hr-subtype/hr-subtype.bound_inv_a_vs_bound_inv_b.stderr
@@ -1,11 +1,11 @@
 error: fatal error triggered by #[rustc_error]
-  --> $DIR/hr-subtype.rs:100:1
+  --> $DIR/hr-subtype.rs:102:1
    |
 LL | / fn main() {
 LL | |
 LL | |
 LL | |
-LL | |
+...  |
 LL | |
 LL | | }
    | |_^
diff --git a/src/test/ui/hr-subtype/hr-subtype.free_inv_x_vs_free_inv_y.nll.stderr b/src/test/ui/hr-subtype/hr-subtype.free_inv_x_vs_free_inv_y.nll.stderr
index 6b5e7a5a634..af5cf41be0a 100644
--- a/src/test/ui/hr-subtype/hr-subtype.free_inv_x_vs_free_inv_y.nll.stderr
+++ b/src/test/ui/hr-subtype/hr-subtype.free_inv_x_vs_free_inv_y.nll.stderr
@@ -1,33 +1,33 @@
 error: lifetime may not live long enough
-  --> $DIR/hr-subtype.rs:33:13
+  --> $DIR/hr-subtype.rs:39:13
    |
-LL |           fn subtype<'x,'y:'x,'z:'y>() {
-   |                      -- -- lifetime `'y` defined here
+LL |           fn subtype<'x, 'y: 'x, 'z: 'y>() {
+   |                      --  -- lifetime `'y` defined here
    |                      |
    |                      lifetime `'x` defined here
 LL |               gimme::<$t2>(None::<$t1>);
    |               ^^^^^^^^^^^^^^^^^^^^^^^^^ argument requires that `'x` must outlive `'y`
 ...
 LL | / check! { free_inv_x_vs_free_inv_y: (fn(Inv<'x>),
-LL | |                                     fn(Inv<'y>)) }
-   | |__________________________________________________- in this macro invocation
+LL | | fn(Inv<'y>)) }
+   | |______________- in this macro invocation
    |
    = help: consider adding the following bound: `'x: 'y`
    = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info)
 
 error: lifetime may not live long enough
-  --> $DIR/hr-subtype.rs:39:13
+  --> $DIR/hr-subtype.rs:45:13
    |
-LL |           fn supertype<'x,'y:'x,'z:'y>() {
-   |                        -- -- lifetime `'y` defined here
+LL |           fn supertype<'x, 'y: 'x, 'z: 'y>() {
+   |                        --  -- lifetime `'y` defined here
    |                        |
    |                        lifetime `'x` defined here
 LL |               gimme::<$t1>(None::<$t2>);
    |               ^^^^^^^^^^^^^^^^^^^^^^^^^ argument requires that `'x` must outlive `'y`
 ...
 LL | / check! { free_inv_x_vs_free_inv_y: (fn(Inv<'x>),
-LL | |                                     fn(Inv<'y>)) }
-   | |__________________________________________________- in this macro invocation
+LL | | fn(Inv<'y>)) }
+   | |______________- in this macro invocation
    |
    = help: consider adding the following bound: `'x: 'y`
    = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info)
diff --git a/src/test/ui/hr-subtype/hr-subtype.free_inv_x_vs_free_inv_y.stderr b/src/test/ui/hr-subtype/hr-subtype.free_inv_x_vs_free_inv_y.stderr
index fc3643306e6..3c8af20e50c 100644
--- a/src/test/ui/hr-subtype/hr-subtype.free_inv_x_vs_free_inv_y.stderr
+++ b/src/test/ui/hr-subtype/hr-subtype.free_inv_x_vs_free_inv_y.stderr
@@ -1,65 +1,65 @@
 error[E0308]: mismatched types
-  --> $DIR/hr-subtype.rs:33:26
+  --> $DIR/hr-subtype.rs:39:26
    |
 LL |               gimme::<$t2>(None::<$t1>);
    |                            ^^^^^^^^^^^ lifetime mismatch
 ...
 LL | / check! { free_inv_x_vs_free_inv_y: (fn(Inv<'x>),
-LL | |                                     fn(Inv<'y>)) }
-   | |__________________________________________________- in this macro invocation
+LL | | fn(Inv<'y>)) }
+   | |______________- in this macro invocation
    |
    = note: expected enum `std::option::Option<fn(Inv<'y>)>`
               found enum `std::option::Option<fn(Inv<'x>)>`
-note: the lifetime `'x` as defined on the function body at 32:20...
-  --> $DIR/hr-subtype.rs:32:20
+note: the lifetime `'x` as defined on the function body at 38:20...
+  --> $DIR/hr-subtype.rs:38:20
    |
-LL |           fn subtype<'x,'y:'x,'z:'y>() {
+LL |           fn subtype<'x, 'y: 'x, 'z: 'y>() {
    |                      ^^
 ...
 LL | / check! { free_inv_x_vs_free_inv_y: (fn(Inv<'x>),
-LL | |                                     fn(Inv<'y>)) }
-   | |__________________________________________________- in this macro invocation
-note: ...does not necessarily outlive the lifetime `'y` as defined on the function body at 32:23
-  --> $DIR/hr-subtype.rs:32:23
+LL | | fn(Inv<'y>)) }
+   | |______________- in this macro invocation
+note: ...does not necessarily outlive the lifetime `'y` as defined on the function body at 38:24
+  --> $DIR/hr-subtype.rs:38:24
    |
-LL |           fn subtype<'x,'y:'x,'z:'y>() {
-   |                         ^^
+LL |           fn subtype<'x, 'y: 'x, 'z: 'y>() {
+   |                          ^^
 ...
 LL | / check! { free_inv_x_vs_free_inv_y: (fn(Inv<'x>),
-LL | |                                     fn(Inv<'y>)) }
-   | |__________________________________________________- in this macro invocation
+LL | | fn(Inv<'y>)) }
+   | |______________- in this macro invocation
    = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info)
 
 error[E0308]: mismatched types
-  --> $DIR/hr-subtype.rs:39:26
+  --> $DIR/hr-subtype.rs:45:26
    |
 LL |               gimme::<$t1>(None::<$t2>);
    |                            ^^^^^^^^^^^ lifetime mismatch
 ...
 LL | / check! { free_inv_x_vs_free_inv_y: (fn(Inv<'x>),
-LL | |                                     fn(Inv<'y>)) }
-   | |__________________________________________________- in this macro invocation
+LL | | fn(Inv<'y>)) }
+   | |______________- in this macro invocation
    |
    = note: expected enum `std::option::Option<fn(Inv<'x>)>`
               found enum `std::option::Option<fn(Inv<'y>)>`
-note: the lifetime `'x` as defined on the function body at 38:22...
-  --> $DIR/hr-subtype.rs:38:22
+note: the lifetime `'x` as defined on the function body at 44:22...
+  --> $DIR/hr-subtype.rs:44:22
    |
-LL |           fn supertype<'x,'y:'x,'z:'y>() {
+LL |           fn supertype<'x, 'y: 'x, 'z: 'y>() {
    |                        ^^
 ...
 LL | / check! { free_inv_x_vs_free_inv_y: (fn(Inv<'x>),
-LL | |                                     fn(Inv<'y>)) }
-   | |__________________________________________________- in this macro invocation
-note: ...does not necessarily outlive the lifetime `'y` as defined on the function body at 38:25
-  --> $DIR/hr-subtype.rs:38:25
+LL | | fn(Inv<'y>)) }
+   | |______________- in this macro invocation
+note: ...does not necessarily outlive the lifetime `'y` as defined on the function body at 44:26
+  --> $DIR/hr-subtype.rs:44:26
    |
-LL |           fn supertype<'x,'y:'x,'z:'y>() {
-   |                           ^^
+LL |           fn supertype<'x, 'y: 'x, 'z: 'y>() {
+   |                            ^^
 ...
 LL | / check! { free_inv_x_vs_free_inv_y: (fn(Inv<'x>),
-LL | |                                     fn(Inv<'y>)) }
-   | |__________________________________________________- in this macro invocation
+LL | | fn(Inv<'y>)) }
+   | |______________- in this macro invocation
    = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info)
 
 error: aborting due to 2 previous errors
diff --git a/src/test/ui/hr-subtype/hr-subtype.free_x_vs_free_x.stderr b/src/test/ui/hr-subtype/hr-subtype.free_x_vs_free_x.stderr
index 6aba6466fad..94837556610 100644
--- a/src/test/ui/hr-subtype/hr-subtype.free_x_vs_free_x.stderr
+++ b/src/test/ui/hr-subtype/hr-subtype.free_x_vs_free_x.stderr
@@ -1,11 +1,11 @@
 error: fatal error triggered by #[rustc_error]
-  --> $DIR/hr-subtype.rs:100:1
+  --> $DIR/hr-subtype.rs:102:1
    |
 LL | / fn main() {
 LL | |
 LL | |
 LL | |
-LL | |
+...  |
 LL | |
 LL | | }
    | |_^
diff --git a/src/test/ui/hr-subtype/hr-subtype.free_x_vs_free_y.nll.stderr b/src/test/ui/hr-subtype/hr-subtype.free_x_vs_free_y.nll.stderr
index 7c0770924da..75d7e0e46b7 100644
--- a/src/test/ui/hr-subtype/hr-subtype.free_x_vs_free_y.nll.stderr
+++ b/src/test/ui/hr-subtype/hr-subtype.free_x_vs_free_y.nll.stderr
@@ -1,16 +1,16 @@
 error: lifetime may not live long enough
-  --> $DIR/hr-subtype.rs:39:13
+  --> $DIR/hr-subtype.rs:45:13
    |
-LL |           fn supertype<'x,'y:'x,'z:'y>() {
-   |                        -- -- lifetime `'y` defined here
+LL |           fn supertype<'x, 'y: 'x, 'z: 'y>() {
+   |                        --  -- lifetime `'y` defined here
    |                        |
    |                        lifetime `'x` defined here
 LL |               gimme::<$t1>(None::<$t2>);
    |               ^^^^^^^^^^^^^^^^^^^^^^^^^ argument requires that `'x` must outlive `'y`
 ...
 LL | / check! { free_x_vs_free_y: (fn(&'x u32),
-LL | |                             fn(&'y u32)) }
-   | |__________________________________________- in this macro invocation
+LL | | fn(&'y u32)) }
+   | |______________- in this macro invocation
    |
    = help: consider adding the following bound: `'x: 'y`
    = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info)
diff --git a/src/test/ui/hr-subtype/hr-subtype.free_x_vs_free_y.stderr b/src/test/ui/hr-subtype/hr-subtype.free_x_vs_free_y.stderr
index 0dde27788f6..7b4cdd4a419 100644
--- a/src/test/ui/hr-subtype/hr-subtype.free_x_vs_free_y.stderr
+++ b/src/test/ui/hr-subtype/hr-subtype.free_x_vs_free_y.stderr
@@ -1,33 +1,33 @@
 error[E0308]: mismatched types
-  --> $DIR/hr-subtype.rs:39:26
+  --> $DIR/hr-subtype.rs:45:26
    |
 LL |               gimme::<$t1>(None::<$t2>);
    |                            ^^^^^^^^^^^ lifetime mismatch
 ...
 LL | / check! { free_x_vs_free_y: (fn(&'x u32),
-LL | |                             fn(&'y u32)) }
-   | |__________________________________________- in this macro invocation
+LL | | fn(&'y u32)) }
+   | |______________- in this macro invocation
    |
    = note: expected enum `std::option::Option<fn(&'x u32)>`
               found enum `std::option::Option<fn(&'y u32)>`
-note: the lifetime `'x` as defined on the function body at 38:22...
-  --> $DIR/hr-subtype.rs:38:22
+note: the lifetime `'x` as defined on the function body at 44:22...
+  --> $DIR/hr-subtype.rs:44:22
    |
-LL |           fn supertype<'x,'y:'x,'z:'y>() {
+LL |           fn supertype<'x, 'y: 'x, 'z: 'y>() {
    |                        ^^
 ...
 LL | / check! { free_x_vs_free_y: (fn(&'x u32),
-LL | |                             fn(&'y u32)) }
-   | |__________________________________________- in this macro invocation
-note: ...does not necessarily outlive the lifetime `'y` as defined on the function body at 38:25
-  --> $DIR/hr-subtype.rs:38:25
+LL | | fn(&'y u32)) }
+   | |______________- in this macro invocation
+note: ...does not necessarily outlive the lifetime `'y` as defined on the function body at 44:26
+  --> $DIR/hr-subtype.rs:44:26
    |
-LL |           fn supertype<'x,'y:'x,'z:'y>() {
-   |                           ^^
+LL |           fn supertype<'x, 'y: 'x, 'z: 'y>() {
+   |                            ^^
 ...
 LL | / check! { free_x_vs_free_y: (fn(&'x u32),
-LL | |                             fn(&'y u32)) }
-   | |__________________________________________- in this macro invocation
+LL | | fn(&'y u32)) }
+   | |______________- in this macro invocation
    = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info)
 
 error: aborting due to previous error
diff --git a/src/test/ui/hr-subtype/hr-subtype.rs b/src/test/ui/hr-subtype/hr-subtype.rs
index b31f198bd97..ad9500eedca 100644
--- a/src/test/ui/hr-subtype/hr-subtype.rs
+++ b/src/test/ui/hr-subtype/hr-subtype.rs
@@ -18,60 +18,62 @@
 // revisions: bound_inv_a_b_vs_bound_inv_a
 // revisions: bound_a_b_ret_a_vs_bound_a_ret_a
 
-fn gimme<T>(_: Option<T>) { }
+fn gimme<T>(_: Option<T>) {}
 
-struct Inv<'a> { x: *mut &'a u32 }
+struct Inv<'a> {
+    x: *mut &'a u32,
+}
 
-struct Co<'a> { x: fn(&'a u32) }
+struct Co<'a> {
+    x: fn(&'a u32),
+}
 
-struct Contra<'a> { x: &'a u32 }
+struct Contra<'a> {
+    x: &'a u32,
+}
 
 macro_rules! check {
     ($rev:ident: ($t1:ty, $t2:ty)) => {
         #[cfg($rev)]
-        fn subtype<'x,'y:'x,'z:'y>() {
+        fn subtype<'x, 'y: 'x, 'z: 'y>() {
             gimme::<$t2>(None::<$t1>);
             //[free_inv_x_vs_free_inv_y]~^ ERROR
         }
 
         #[cfg($rev)]
-        fn supertype<'x,'y:'x,'z:'y>() {
+        fn supertype<'x, 'y: 'x, 'z: 'y>() {
             gimme::<$t1>(None::<$t2>);
             //[bound_a_vs_free_x]~^ ERROR
             //[free_x_vs_free_y]~^^ ERROR
             //[bound_inv_a_b_vs_bound_inv_a]~^^^ ERROR
             //[bound_a_b_ret_a_vs_bound_a_ret_a]~^^^^ ERROR
             //[free_inv_x_vs_free_inv_y]~^^^^^ ERROR
-            //[bound_a_b_vs_bound_a]~^^^^^^ ERROR mismatched types
-            //[bound_co_a_co_b_ret_contra_a]~^^^^^^^ ERROR
-            //[bound_contra_a_contra_b_ret_co_a]~^^^^^^^^ ERROR
-            //[bound_co_a_b_vs_bound_co_a]~^^^^^^^^^ ERROR
         }
-    }
+    };
 }
 
 // If both have bound regions, they are equivalent, regardless of
 // variant.
 check! { bound_a_vs_bound_a: (for<'a> fn(&'a u32),
-                              for<'a> fn(&'a u32)) }
+for<'a> fn(&'a u32)) }
 check! { bound_a_vs_bound_b: (for<'a> fn(&'a u32),
-                              for<'b> fn(&'b u32)) }
+for<'b> fn(&'b u32)) }
 check! { bound_inv_a_vs_bound_inv_b: (for<'a> fn(Inv<'a>),
-                                      for<'b> fn(Inv<'b>)) }
+for<'b> fn(Inv<'b>)) }
 check! { bound_co_a_vs_bound_co_b: (for<'a> fn(Co<'a>),
-                                    for<'b> fn(Co<'b>)) }
+for<'b> fn(Co<'b>)) }
 
 // Bound is a subtype of free.
 check! { bound_a_vs_free_x: (for<'a> fn(&'a u32),
-                             fn(&'x u32)) }
+fn(&'x u32)) }
 
 // Two free regions are relatable if subtyping holds.
 check! { free_x_vs_free_x: (fn(&'x u32),
-                            fn(&'x u32)) }
+fn(&'x u32)) }
 check! { free_x_vs_free_y: (fn(&'x u32),
-                            fn(&'y u32)) }
+fn(&'y u32)) }
 check! { free_inv_x_vs_free_inv_y: (fn(Inv<'x>),
-                                    fn(Inv<'y>)) }
+fn(Inv<'y>)) }
 
 // Somewhat surprisingly, a fn taking two distinct bound lifetimes and
 // a fn taking one bound lifetime can be interchangeable, but only if
@@ -82,25 +84,29 @@ check! { free_inv_x_vs_free_inv_y: (fn(Inv<'x>),
 //   intersection;
 // - if we are contravariant, then 'a can be inferred to 'static.
 check! { bound_a_b_vs_bound_a: (for<'a,'b> fn(&'a u32, &'b u32),
-                                for<'a>    fn(&'a u32, &'a u32)) }
+for<'a>    fn(&'a u32, &'a u32)) }
 check! { bound_co_a_b_vs_bound_co_a: (for<'a,'b> fn(Co<'a>, Co<'b>),
-                                      for<'a>    fn(Co<'a>, Co<'a>)) }
+for<'a>    fn(Co<'a>, Co<'a>)) }
 check! { bound_contra_a_contra_b_ret_co_a: (for<'a,'b> fn(Contra<'a>, Contra<'b>) -> Co<'a>,
-                                            for<'a>    fn(Contra<'a>, Contra<'a>) -> Co<'a>) }
+for<'a>    fn(Contra<'a>, Contra<'a>) -> Co<'a>) }
 check! { bound_co_a_co_b_ret_contra_a: (for<'a,'b> fn(Co<'a>, Co<'b>) -> Contra<'a>,
-                                        for<'a>    fn(Co<'a>, Co<'a>) -> Contra<'a>) }
+for<'a>    fn(Co<'a>, Co<'a>) -> Contra<'a>) }
 
 // If we make those lifetimes invariant, then the two types are not interchangeable.
 check! { bound_inv_a_b_vs_bound_inv_a: (for<'a,'b> fn(Inv<'a>, Inv<'b>),
-                                        for<'a>    fn(Inv<'a>, Inv<'a>)) }
+for<'a>    fn(Inv<'a>, Inv<'a>)) }
 check! { bound_a_b_ret_a_vs_bound_a_ret_a: (for<'a,'b> fn(&'a u32, &'b u32) -> &'a u32,
-                                            for<'a>    fn(&'a u32, &'a u32) -> &'a u32) }
+for<'a>    fn(&'a u32, &'a u32) -> &'a u32) }
 
 #[rustc_error]
 fn main() {
-//[bound_a_vs_bound_a]~^ ERROR fatal error triggered by #[rustc_error]
-//[bound_a_vs_bound_b]~^^ ERROR fatal error triggered by #[rustc_error]
-//[bound_inv_a_vs_bound_inv_b]~^^^ ERROR fatal error triggered by #[rustc_error]
-//[bound_co_a_vs_bound_co_b]~^^^^ ERROR fatal error triggered by #[rustc_error]
-//[free_x_vs_free_x]~^^^^^ ERROR fatal error triggered by #[rustc_error]
+    //[bound_a_vs_bound_a]~^ ERROR fatal error triggered by #[rustc_error]
+    //[bound_a_vs_bound_b]~^^ ERROR fatal error triggered by #[rustc_error]
+    //[bound_inv_a_vs_bound_inv_b]~^^^ ERROR fatal error triggered by #[rustc_error]
+    //[bound_co_a_vs_bound_co_b]~^^^^ ERROR fatal error triggered by #[rustc_error]
+    //[free_x_vs_free_x]~^^^^^ ERROR fatal error triggered by #[rustc_error]
+    //[bound_co_a_b_vs_bound_co_a]~^^^^^^ ERROR
+    //[bound_co_a_co_b_ret_contra_a]~^^^^^^^ ERROR
+    //[bound_a_b_vs_bound_a]~^^^^^^^^ ERROR
+    //[bound_contra_a_contra_b_ret_co_a]~^^^^^^^^^ ERROR
 }
diff --git a/src/test/ui/hr-subtype/return-static.rs b/src/test/ui/hr-subtype/return-static.rs
new file mode 100644
index 00000000000..6455854f34d
--- /dev/null
+++ b/src/test/ui/hr-subtype/return-static.rs
@@ -0,0 +1,13 @@
+// check-pass
+
+fn make<T>() -> T {
+    panic!()
+}
+
+fn take<T>(x: T) {}
+
+fn main() {
+    let x: for<'a> fn(&'a u32) -> _ = make();
+    let y: &'static u32 = x(&22);
+    take::<for<'b> fn(&'b u32) -> &'b u32>(x);
+}
diff --git a/src/test/ui/hrtb/hrtb-conflate-regions.nll.stderr b/src/test/ui/hrtb/hrtb-conflate-regions.nll.stderr
new file mode 100644
index 00000000000..f290a93326f
--- /dev/null
+++ b/src/test/ui/hrtb/hrtb-conflate-regions.nll.stderr
@@ -0,0 +1,14 @@
+error: higher-ranked subtype error
+  --> $DIR/hrtb-conflate-regions.rs:27:10
+   |
+LL | fn b() { want_foo2::<SomeStruct>(); }
+   |          ^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: higher-ranked subtype error
+  --> $DIR/hrtb-conflate-regions.rs:27:10
+   |
+LL | fn b() { want_foo2::<SomeStruct>(); }
+   |          ^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to 2 previous errors
+
diff --git a/src/test/ui/hrtb/hrtb-conflate-regions.stderr b/src/test/ui/hrtb/hrtb-conflate-regions.stderr
index 7250935ea29..45573814d13 100644
--- a/src/test/ui/hrtb/hrtb-conflate-regions.stderr
+++ b/src/test/ui/hrtb/hrtb-conflate-regions.stderr
@@ -1,17 +1,16 @@
-error[E0277]: the trait bound `for<'a, 'b> SomeStruct: Foo<(&'a isize, &'b isize)>` is not satisfied
-  --> $DIR/hrtb-conflate-regions.rs:27:22
+error: implementation of `Foo` is not general enough
+  --> $DIR/hrtb-conflate-regions.rs:27:10
    |
-LL | fn want_foo2<T>()
-   |    --------- required by a bound in this
-LL |     where T : for<'a,'b> Foo<(&'a isize, &'b isize)>
-   |               -------------------------------------- required by this bound in `want_foo2`
+LL | / trait Foo<X> {
+LL | |     fn foo(&self, x: X) { }
+LL | | }
+   | |_- trait `Foo` defined here
 ...
-LL | fn b() { want_foo2::<SomeStruct>(); }
-   |                      ^^^^^^^^^^ the trait `for<'a, 'b> Foo<(&'a isize, &'b isize)>` is not implemented for `SomeStruct`
+LL |   fn b() { want_foo2::<SomeStruct>(); }
+   |            ^^^^^^^^^^^^^^^^^^^^^^^ implementation of `Foo` is not general enough
    |
-   = help: the following implementations were found:
-             <SomeStruct as Foo<(&'a isize, &'a isize)>>
+   = note: `SomeStruct` must implement `Foo<(&'0 isize, &'1 isize)>`, for any two lifetimes `'0` and `'1`...
+   = note: ...but `SomeStruct` actually implements `Foo<(&'2 isize, &'2 isize)>`, for some specific lifetime `'2`
 
 error: aborting due to previous error
 
-For more information about this error, try `rustc --explain E0277`.
diff --git a/src/test/ui/hrtb/hrtb-exists-forall-fn.nll.stderr b/src/test/ui/hrtb/hrtb-exists-forall-fn.nll.stderr
new file mode 100644
index 00000000000..11390d9e2d2
--- /dev/null
+++ b/src/test/ui/hrtb/hrtb-exists-forall-fn.nll.stderr
@@ -0,0 +1,8 @@
+error: higher-ranked subtype error
+  --> $DIR/hrtb-exists-forall-fn.rs:17:12
+   |
+LL |     let _: for<'b> fn(&'b u32) = foo();
+   |            ^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to previous error
+
diff --git a/src/test/ui/hrtb/hrtb-exists-forall-fn.stderr b/src/test/ui/hrtb/hrtb-exists-forall-fn.stderr
index 328e98657ef..9914783d976 100644
--- a/src/test/ui/hrtb/hrtb-exists-forall-fn.stderr
+++ b/src/test/ui/hrtb/hrtb-exists-forall-fn.stderr
@@ -2,9 +2,7 @@ error[E0308]: mismatched types
   --> $DIR/hrtb-exists-forall-fn.rs:17:34
    |
 LL |     let _: for<'b> fn(&'b u32) = foo();
-   |            -------------------   ^^^^^ expected concrete lifetime, found bound lifetime parameter 'b
-   |            |
-   |            expected due to this
+   |                                  ^^^^^ one type is more general than the other
    |
    = note: expected fn pointer `for<'b> fn(&'b u32)`
               found fn pointer `fn(&u32)`
diff --git a/src/test/ui/hrtb/hrtb-exists-forall-trait-contravariant.nll.stderr b/src/test/ui/hrtb/hrtb-exists-forall-trait-contravariant.nll.stderr
new file mode 100644
index 00000000000..a4c3ffd1f6c
--- /dev/null
+++ b/src/test/ui/hrtb/hrtb-exists-forall-trait-contravariant.nll.stderr
@@ -0,0 +1,8 @@
+error: higher-ranked subtype error
+  --> $DIR/hrtb-exists-forall-trait-contravariant.rs:34:5
+   |
+LL |     foo::<()>();
+   |     ^^^^^^^^^^^
+
+error: aborting due to previous error
+
diff --git a/src/test/ui/hrtb/hrtb-exists-forall-trait-contravariant.rs b/src/test/ui/hrtb/hrtb-exists-forall-trait-contravariant.rs
index 4c1d4d28a09..921061916fc 100644
--- a/src/test/ui/hrtb/hrtb-exists-forall-trait-contravariant.rs
+++ b/src/test/ui/hrtb/hrtb-exists-forall-trait-contravariant.rs
@@ -32,5 +32,5 @@ fn main() {
     // NB. *However*, the reinstated leak-check gives an error here.
 
     foo::<()>();
-    //~^ ERROR not satisfied
+    //~^ ERROR implementation of `Trait` is not general enough
 }
diff --git a/src/test/ui/hrtb/hrtb-exists-forall-trait-contravariant.stderr b/src/test/ui/hrtb/hrtb-exists-forall-trait-contravariant.stderr
index 7a7285d3d76..fe8209d054c 100644
--- a/src/test/ui/hrtb/hrtb-exists-forall-trait-contravariant.stderr
+++ b/src/test/ui/hrtb/hrtb-exists-forall-trait-contravariant.stderr
@@ -1,18 +1,14 @@
-error[E0277]: the trait bound `(): Trait<for<'b> fn(&'b u32)>` is not satisfied
-  --> $DIR/hrtb-exists-forall-trait-contravariant.rs:34:11
+error: implementation of `Trait` is not general enough
+  --> $DIR/hrtb-exists-forall-trait-contravariant.rs:34:5
    |
-LL | fn foo<T>()
-   |    --- required by a bound in this
-LL | where
-LL |     T: Trait<for<'b> fn(&'b u32)>,
-   |        -------------------------- required by this bound in `foo`
+LL | trait Trait<T> {}
+   | ----------------- trait `Trait` defined here
 ...
 LL |     foo::<()>();
-   |           ^^ the trait `Trait<for<'b> fn(&'b u32)>` is not implemented for `()`
+   |     ^^^^^^^^^ implementation of `Trait` is not general enough
    |
-   = help: the following implementations were found:
-             <() as Trait<fn(&'a u32)>>
+   = note: `()` must implement `Trait<for<'b> fn(&'b u32)>`
+   = note: ...but `()` actually implements `Trait<fn(&'0 u32)>`, for some specific lifetime `'0`
 
 error: aborting due to previous error
 
-For more information about this error, try `rustc --explain E0277`.
diff --git a/src/test/ui/hrtb/hrtb-exists-forall-trait-covariant.rs b/src/test/ui/hrtb/hrtb-exists-forall-trait-covariant.rs
index 95b57d6c5bb..f95496a6c3c 100644
--- a/src/test/ui/hrtb/hrtb-exists-forall-trait-covariant.rs
+++ b/src/test/ui/hrtb/hrtb-exists-forall-trait-covariant.rs
@@ -2,6 +2,8 @@
 //
 // In particular, we test this pattern in trait solving, where it is not connected
 // to any part of the source code.
+//
+// check-pass
 
 trait Trait<T> {}
 
@@ -30,9 +32,6 @@ fn main() {
     //         - `?b: ?a` -- solveable if `?b` is inferred to `'static`
     // - So the subtyping check succeeds, somewhat surprisingly.
     //   This is because we can use `'static`.
-    //
-    // NB. *However*, the reinstated leak-check gives an error here.
 
     foo::<()>();
-    //~^ ERROR not satisfied
 }
diff --git a/src/test/ui/hrtb/hrtb-exists-forall-trait-covariant.stderr b/src/test/ui/hrtb/hrtb-exists-forall-trait-covariant.stderr
deleted file mode 100644
index 1e335f9ee96..00000000000
--- a/src/test/ui/hrtb/hrtb-exists-forall-trait-covariant.stderr
+++ /dev/null
@@ -1,18 +0,0 @@
-error[E0277]: the trait bound `(): Trait<for<'b> fn(fn(&'b u32))>` is not satisfied
-  --> $DIR/hrtb-exists-forall-trait-covariant.rs:36:11
-   |
-LL | fn foo<T>()
-   |    --- required by a bound in this
-LL | where
-LL |     T: Trait<for<'b> fn(fn(&'b u32))>,
-   |        ------------------------------ required by this bound in `foo`
-...
-LL |     foo::<()>();
-   |           ^^ the trait `Trait<for<'b> fn(fn(&'b u32))>` is not implemented for `()`
-   |
-   = help: the following implementations were found:
-             <() as Trait<fn(fn(&'a u32))>>
-
-error: aborting due to previous error
-
-For more information about this error, try `rustc --explain E0277`.
diff --git a/src/test/ui/hrtb/hrtb-exists-forall-trait-invariant.nll.stderr b/src/test/ui/hrtb/hrtb-exists-forall-trait-invariant.nll.stderr
new file mode 100644
index 00000000000..e2a399b2faa
--- /dev/null
+++ b/src/test/ui/hrtb/hrtb-exists-forall-trait-invariant.nll.stderr
@@ -0,0 +1,8 @@
+error: higher-ranked subtype error
+  --> $DIR/hrtb-exists-forall-trait-invariant.rs:28:5
+   |
+LL |     foo::<()>();
+   |     ^^^^^^^^^^^
+
+error: aborting due to previous error
+
diff --git a/src/test/ui/hrtb/hrtb-exists-forall-trait-invariant.rs b/src/test/ui/hrtb/hrtb-exists-forall-trait-invariant.rs
index 827a68beee8..b1b7ec6bcf1 100644
--- a/src/test/ui/hrtb/hrtb-exists-forall-trait-invariant.rs
+++ b/src/test/ui/hrtb/hrtb-exists-forall-trait-invariant.rs
@@ -25,5 +25,5 @@ fn main() {
     //     yielding `fn(&!b u32)`, in a fresh universe U1
     //   - So we get `?a = !b` but the universe U0 assigned to `?a` cannot name `!b`.
 
-    foo::<()>(); //~ ERROR not satisfied
+    foo::<()>(); //~ ERROR implementation of `Trait` is not general enough
 }
diff --git a/src/test/ui/hrtb/hrtb-exists-forall-trait-invariant.stderr b/src/test/ui/hrtb/hrtb-exists-forall-trait-invariant.stderr
index 9174ea4d841..720e2276d53 100644
--- a/src/test/ui/hrtb/hrtb-exists-forall-trait-invariant.stderr
+++ b/src/test/ui/hrtb/hrtb-exists-forall-trait-invariant.stderr
@@ -1,18 +1,14 @@
-error[E0277]: the trait bound `(): Trait<for<'b> fn(std::cell::Cell<&'b u32>)>` is not satisfied
-  --> $DIR/hrtb-exists-forall-trait-invariant.rs:28:11
+error: implementation of `Trait` is not general enough
+  --> $DIR/hrtb-exists-forall-trait-invariant.rs:28:5
    |
-LL | fn foo<T>()
-   |    --- required by a bound in this
-LL | where
-LL |     T: Trait<for<'b> fn(Cell<&'b u32>)>,
-   |        -------------------------------- required by this bound in `foo`
+LL | trait Trait<T> {}
+   | ----------------- trait `Trait` defined here
 ...
 LL |     foo::<()>();
-   |           ^^ the trait `Trait<for<'b> fn(std::cell::Cell<&'b u32>)>` is not implemented for `()`
+   |     ^^^^^^^^^ implementation of `Trait` is not general enough
    |
-   = help: the following implementations were found:
-             <() as Trait<fn(std::cell::Cell<&'a u32>)>>
+   = note: `()` must implement `Trait<for<'b> fn(std::cell::Cell<&'b u32>)>`
+   = note: ...but `()` actually implements `Trait<fn(std::cell::Cell<&'0 u32>)>`, for some specific lifetime `'0`
 
 error: aborting due to previous error
 
-For more information about this error, try `rustc --explain E0277`.
diff --git a/src/test/ui/hrtb/hrtb-just-for-static.nll.stderr b/src/test/ui/hrtb/hrtb-just-for-static.nll.stderr
new file mode 100644
index 00000000000..8901a1b4681
--- /dev/null
+++ b/src/test/ui/hrtb/hrtb-just-for-static.nll.stderr
@@ -0,0 +1,24 @@
+error: higher-ranked subtype error
+  --> $DIR/hrtb-just-for-static.rs:24:5
+   |
+LL |     want_hrtb::<StaticInt>()
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: lifetime may not live long enough
+  --> $DIR/hrtb-just-for-static.rs:30:5
+   |
+LL | fn give_some<'a>() {
+   |              -- lifetime `'a` defined here
+LL |     want_hrtb::<&'a u32>()
+   |     ^^^^^^^^^^^^^^^^^^^^ requires that `'a` must outlive `'static`
+   |
+   = help: consider replacing `'a` with `'static`
+
+error: higher-ranked subtype error
+  --> $DIR/hrtb-just-for-static.rs:30:5
+   |
+LL |     want_hrtb::<&'a u32>()
+   |     ^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to 3 previous errors
+
diff --git a/src/test/ui/hrtb/hrtb-just-for-static.stderr b/src/test/ui/hrtb/hrtb-just-for-static.stderr
index 4fa40462477..5e3014317f5 100644
--- a/src/test/ui/hrtb/hrtb-just-for-static.stderr
+++ b/src/test/ui/hrtb/hrtb-just-for-static.stderr
@@ -1,31 +1,30 @@
-error[E0277]: the trait bound `for<'a> StaticInt: Foo<&'a isize>` is not satisfied
-  --> $DIR/hrtb-just-for-static.rs:24:17
+error: implementation of `Foo` is not general enough
+  --> $DIR/hrtb-just-for-static.rs:24:5
    |
-LL | fn want_hrtb<T>()
-   |    --------- required by a bound in this
-LL |     where T : for<'a> Foo<&'a isize>
-   |               ---------------------- required by this bound in `want_hrtb`
+LL | / trait Foo<X> {
+LL | |     fn foo(&self, x: X) { }
+LL | | }
+   | |_- trait `Foo` defined here
 ...
-LL |     want_hrtb::<StaticInt>()
-   |                 ^^^^^^^^^ the trait `for<'a> Foo<&'a isize>` is not implemented for `StaticInt`
+LL |       want_hrtb::<StaticInt>()
+   |       ^^^^^^^^^^^^^^^^^^^^^^ implementation of `Foo` is not general enough
    |
-   = help: the following implementations were found:
-             <StaticInt as Foo<&'static isize>>
+   = note: `StaticInt` must implement `Foo<&'0 isize>`, for any lifetime `'0`...
+   = note: ...but `StaticInt` actually implements `Foo<&'1 isize>`, for some specific lifetime `'1`
 
-error[E0277]: the trait bound `for<'a> &'a u32: Foo<&'a isize>` is not satisfied
-  --> $DIR/hrtb-just-for-static.rs:30:17
+error: implementation of `Foo` is not general enough
+  --> $DIR/hrtb-just-for-static.rs:30:5
    |
-LL | fn want_hrtb<T>()
-   |    --------- required by a bound in this
-LL |     where T : for<'a> Foo<&'a isize>
-   |               ---------------------- required by this bound in `want_hrtb`
+LL | / trait Foo<X> {
+LL | |     fn foo(&self, x: X) { }
+LL | | }
+   | |_- trait `Foo` defined here
 ...
-LL |     want_hrtb::<&'a u32>()
-   |                 ^^^^^^^ the trait `for<'a> Foo<&'a isize>` is not implemented for `&'a u32`
+LL |       want_hrtb::<&'a u32>()
+   |       ^^^^^^^^^^^^^^^^^^^^ implementation of `Foo` is not general enough
    |
-   = help: the following implementations were found:
-             <&'a u32 as Foo<&'a isize>>
+   = note: `Foo<&'0 isize>` would have to be implemented for the type `&'a u32`, for any lifetime `'0`...
+   = note: ...but `Foo<&'1 isize>` is actually implemented for the type `&'1 u32`, for some specific lifetime `'1`
 
 error: aborting due to 2 previous errors
 
-For more information about this error, try `rustc --explain E0277`.
diff --git a/src/test/ui/hrtb/issue-30786.migrate.stderr b/src/test/ui/hrtb/issue-30786.migrate.stderr
index c0e3fd3cf46..90a7cadca41 100644
--- a/src/test/ui/hrtb/issue-30786.migrate.stderr
+++ b/src/test/ui/hrtb/issue-30786.migrate.stderr
@@ -1,17 +1,43 @@
-error: implementation of `Stream` is not general enough
-  --> $DIR/issue-30786.rs:108:22
+error[E0599]: no method named `filterx` found for struct `Map<Repeat, [closure@$DIR/issue-30786.rs:127:27: 127:36]>` in the current scope
+  --> $DIR/issue-30786.rs:128:22
    |
-LL | / pub trait Stream {
-LL | |     type Item;
-LL | |     fn next(self) -> Option<Self::Item>;
-LL | | }
-   | |_- trait `Stream` defined here
+LL | pub struct Map<S, F> {
+   | --------------------
+   | |
+   | method `filterx` not found for this
+   | doesn't satisfy `_: StreamExt`
 ...
-LL |       let map = source.map(|x: &_| x);
-   |                        ^^^ implementation of `Stream` is not general enough
+LL |     let filter = map.filterx(|x: &_| true);
+   |                      ^^^^^^^ method not found in `Map<Repeat, [closure@$DIR/issue-30786.rs:127:27: 127:36]>`
    |
-   = note: `Stream` would have to be implemented for the type `&'0 mut Map<Repeat, [closure@$DIR/issue-30786.rs:108:26: 108:35]>`, for any lifetime `'0`...
-   = note: ...but `Stream` is actually implemented for the type `&'1 mut Map<Repeat, [closure@$DIR/issue-30786.rs:108:26: 108:35]>`, for some specific lifetime `'1`
+   = note: the method `filterx` exists but the following trait bounds were not satisfied:
+           `&'a mut Map<Repeat, [closure@$DIR/issue-30786.rs:127:27: 127:36]>: Stream`
+           which is required by `Map<Repeat, [closure@$DIR/issue-30786.rs:127:27: 127:36]>: StreamExt`
+           `&'a mut &Map<Repeat, [closure@$DIR/issue-30786.rs:127:27: 127:36]>: Stream`
+           which is required by `&Map<Repeat, [closure@$DIR/issue-30786.rs:127:27: 127:36]>: StreamExt`
+           `&'a mut &mut Map<Repeat, [closure@$DIR/issue-30786.rs:127:27: 127:36]>: Stream`
+           which is required by `&mut Map<Repeat, [closure@$DIR/issue-30786.rs:127:27: 127:36]>: StreamExt`
 
-error: aborting due to previous error
+error[E0599]: no method named `countx` found for struct `Filter<Map<Repeat, for<'r> fn(&'r u64) -> &'r u64 {identity::<u64>}>, [closure@$DIR/issue-30786.rs:140:30: 140:42]>` in the current scope
+  --> $DIR/issue-30786.rs:141:24
+   |
+LL | pub struct Filter<S, F> {
+   | -----------------------
+   | |
+   | method `countx` not found for this
+   | doesn't satisfy `_: StreamExt`
+...
+LL |     let count = filter.countx();
+   |                        ^^^^^^ method not found in `Filter<Map<Repeat, for<'r> fn(&'r u64) -> &'r u64 {identity::<u64>}>, [closure@$DIR/issue-30786.rs:140:30: 140:42]>`
+   |
+   = note: the method `countx` exists but the following trait bounds were not satisfied:
+           `&'a mut Filter<Map<Repeat, for<'r> fn(&'r u64) -> &'r u64 {identity::<u64>}>, [closure@$DIR/issue-30786.rs:140:30: 140:42]>: Stream`
+           which is required by `Filter<Map<Repeat, for<'r> fn(&'r u64) -> &'r u64 {identity::<u64>}>, [closure@$DIR/issue-30786.rs:140:30: 140:42]>: StreamExt`
+           `&'a mut &Filter<Map<Repeat, for<'r> fn(&'r u64) -> &'r u64 {identity::<u64>}>, [closure@$DIR/issue-30786.rs:140:30: 140:42]>: Stream`
+           which is required by `&Filter<Map<Repeat, for<'r> fn(&'r u64) -> &'r u64 {identity::<u64>}>, [closure@$DIR/issue-30786.rs:140:30: 140:42]>: StreamExt`
+           `&'a mut &mut Filter<Map<Repeat, for<'r> fn(&'r u64) -> &'r u64 {identity::<u64>}>, [closure@$DIR/issue-30786.rs:140:30: 140:42]>: Stream`
+           which is required by `&mut Filter<Map<Repeat, for<'r> fn(&'r u64) -> &'r u64 {identity::<u64>}>, [closure@$DIR/issue-30786.rs:140:30: 140:42]>: StreamExt`
+
+error: aborting due to 2 previous errors
 
+For more information about this error, try `rustc --explain E0599`.
diff --git a/src/test/ui/hrtb/issue-30786.nll.stderr b/src/test/ui/hrtb/issue-30786.nll.stderr
index c736c5479f8..90a7cadca41 100644
--- a/src/test/ui/hrtb/issue-30786.nll.stderr
+++ b/src/test/ui/hrtb/issue-30786.nll.stderr
@@ -1,56 +1,43 @@
-error: higher-ranked subtype error
-  --> $DIR/issue-30786.rs:108:15
-   |
-LL |     let map = source.map(|x: &_| x);
-   |               ^^^^^^^^^^^^^^^^^^^^^
-
-error: higher-ranked subtype error
-  --> $DIR/issue-30786.rs:114:18
-   |
-LL |     let filter = map.filter(|x: &_| true);
-   |                  ^^^^^^^^^^^^^^^^^^^^^^^^
-
-error: higher-ranked subtype error
-  --> $DIR/issue-30786.rs:114:18
-   |
-LL |     let filter = map.filter(|x: &_| true);
-   |                  ^^^^^^^^^^^^^^^^^^^^^^^^
-
-error: higher-ranked subtype error
-  --> $DIR/issue-30786.rs:114:18
-   |
-LL |     let filter = map.filter(|x: &_| true);
-   |                  ^^^^^^^^^^^^^^^^^^^^^^^^
-
-error: higher-ranked subtype error
-  --> $DIR/issue-30786.rs:114:18
-   |
-LL |     let filter = map.filter(|x: &_| true);
-   |                  ^^^^^^^^^^^^^^^^^^^^^^^^
-
-error: higher-ranked subtype error
-  --> $DIR/issue-30786.rs:119:17
-   |
-LL |     let count = filter.count(); // Assert that we still have a valid stream.
-   |                 ^^^^^^^^^^^^^^
-
-error: higher-ranked subtype error
-  --> $DIR/issue-30786.rs:119:17
-   |
-LL |     let count = filter.count(); // Assert that we still have a valid stream.
-   |                 ^^^^^^^^^^^^^^
-
-error: higher-ranked subtype error
-  --> $DIR/issue-30786.rs:119:17
-   |
-LL |     let count = filter.count(); // Assert that we still have a valid stream.
-   |                 ^^^^^^^^^^^^^^
-
-error: higher-ranked subtype error
-  --> $DIR/issue-30786.rs:119:17
-   |
-LL |     let count = filter.count(); // Assert that we still have a valid stream.
-   |                 ^^^^^^^^^^^^^^
-
-error: aborting due to 9 previous errors
-
+error[E0599]: no method named `filterx` found for struct `Map<Repeat, [closure@$DIR/issue-30786.rs:127:27: 127:36]>` in the current scope
+  --> $DIR/issue-30786.rs:128:22
+   |
+LL | pub struct Map<S, F> {
+   | --------------------
+   | |
+   | method `filterx` not found for this
+   | doesn't satisfy `_: StreamExt`
+...
+LL |     let filter = map.filterx(|x: &_| true);
+   |                      ^^^^^^^ method not found in `Map<Repeat, [closure@$DIR/issue-30786.rs:127:27: 127:36]>`
+   |
+   = note: the method `filterx` exists but the following trait bounds were not satisfied:
+           `&'a mut Map<Repeat, [closure@$DIR/issue-30786.rs:127:27: 127:36]>: Stream`
+           which is required by `Map<Repeat, [closure@$DIR/issue-30786.rs:127:27: 127:36]>: StreamExt`
+           `&'a mut &Map<Repeat, [closure@$DIR/issue-30786.rs:127:27: 127:36]>: Stream`
+           which is required by `&Map<Repeat, [closure@$DIR/issue-30786.rs:127:27: 127:36]>: StreamExt`
+           `&'a mut &mut Map<Repeat, [closure@$DIR/issue-30786.rs:127:27: 127:36]>: Stream`
+           which is required by `&mut Map<Repeat, [closure@$DIR/issue-30786.rs:127:27: 127:36]>: StreamExt`
+
+error[E0599]: no method named `countx` found for struct `Filter<Map<Repeat, for<'r> fn(&'r u64) -> &'r u64 {identity::<u64>}>, [closure@$DIR/issue-30786.rs:140:30: 140:42]>` in the current scope
+  --> $DIR/issue-30786.rs:141:24
+   |
+LL | pub struct Filter<S, F> {
+   | -----------------------
+   | |
+   | method `countx` not found for this
+   | doesn't satisfy `_: StreamExt`
+...
+LL |     let count = filter.countx();
+   |                        ^^^^^^ method not found in `Filter<Map<Repeat, for<'r> fn(&'r u64) -> &'r u64 {identity::<u64>}>, [closure@$DIR/issue-30786.rs:140:30: 140:42]>`
+   |
+   = note: the method `countx` exists but the following trait bounds were not satisfied:
+           `&'a mut Filter<Map<Repeat, for<'r> fn(&'r u64) -> &'r u64 {identity::<u64>}>, [closure@$DIR/issue-30786.rs:140:30: 140:42]>: Stream`
+           which is required by `Filter<Map<Repeat, for<'r> fn(&'r u64) -> &'r u64 {identity::<u64>}>, [closure@$DIR/issue-30786.rs:140:30: 140:42]>: StreamExt`
+           `&'a mut &Filter<Map<Repeat, for<'r> fn(&'r u64) -> &'r u64 {identity::<u64>}>, [closure@$DIR/issue-30786.rs:140:30: 140:42]>: Stream`
+           which is required by `&Filter<Map<Repeat, for<'r> fn(&'r u64) -> &'r u64 {identity::<u64>}>, [closure@$DIR/issue-30786.rs:140:30: 140:42]>: StreamExt`
+           `&'a mut &mut Filter<Map<Repeat, for<'r> fn(&'r u64) -> &'r u64 {identity::<u64>}>, [closure@$DIR/issue-30786.rs:140:30: 140:42]>: Stream`
+           which is required by `&mut Filter<Map<Repeat, for<'r> fn(&'r u64) -> &'r u64 {identity::<u64>}>, [closure@$DIR/issue-30786.rs:140:30: 140:42]>: StreamExt`
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0599`.
diff --git a/src/test/ui/hrtb/issue-30786.rs b/src/test/ui/hrtb/issue-30786.rs
index c656f843065..8ce5c090b54 100644
--- a/src/test/ui/hrtb/issue-30786.rs
+++ b/src/test/ui/hrtb/issue-30786.rs
@@ -16,7 +16,7 @@
 
 //[nll]compile-flags: -Z borrowck=mir
 
-pub trait Stream { //[migrate]~ NOTE trait `Stream` defined here
+pub trait Stream {
     type Item;
     fn next(self) -> Option<Self::Item>;
 }
@@ -37,8 +37,9 @@ pub struct Map<S, F> {
 }
 
 impl<'a, A, F, T> Stream for &'a mut Map<A, F>
-where &'a mut A: Stream,
-      F: FnMut(<&'a mut A as Stream>::Item) -> T,
+where
+    &'a mut A: Stream,
+    F: FnMut(<&'a mut A as Stream>::Item) -> T,
 {
     type Item = T;
     fn next(self) -> Option<T> {
@@ -55,8 +56,9 @@ pub struct Filter<S, F> {
 }
 
 impl<'a, A, F, T> Stream for &'a mut Filter<A, F>
-where for<'b> &'b mut A: Stream<Item=T>, // <---- BAD
-      F: FnMut(&T) -> bool,
+where
+    for<'b> &'b mut A: Stream<Item = T>, // <---- BAD
+    F: FnMut(&T) -> bool,
 {
     type Item = <&'a mut A as Stream>::Item;
     fn next(self) -> Option<Self::Item> {
@@ -69,29 +71,29 @@ where for<'b> &'b mut A: Stream<Item=T>, // <---- BAD
     }
 }
 
-pub trait StreamExt where for<'b> &'b mut Self: Stream {
-    fn map<F>(self, func: F) -> Map<Self, F>
-    where Self: Sized,
-    for<'a> &'a mut Map<Self, F>: Stream,
+pub trait StreamExt
+where
+    for<'b> &'b mut Self: Stream,
+{
+    fn mapx<F>(self, func: F) -> Map<Self, F>
+    where
+        Self: Sized,
+        for<'a> &'a mut Map<Self, F>: Stream,
     {
-        Map {
-            func: func,
-            stream: self,
-        }
+        Map { func: func, stream: self }
     }
 
-    fn filter<F>(self, func: F) -> Filter<Self, F>
-    where Self: Sized,
-    for<'a> &'a mut Filter<Self, F>: Stream,
+    fn filterx<F>(self, func: F) -> Filter<Self, F>
+    where
+        Self: Sized,
+        for<'a> &'a mut Filter<Self, F>: Stream,
     {
-        Filter {
-            func: func,
-            stream: self,
-        }
+        Filter { func: func, stream: self }
     }
 
-    fn count(mut self) -> usize
-    where Self: Sized,
+    fn countx(mut self) -> usize
+    where
+        Self: Sized,
     {
         let mut count = 0;
         while let Some(_) = self.next() {
@@ -101,24 +103,44 @@ pub trait StreamExt where for<'b> &'b mut Self: Stream {
     }
 }
 
-impl<T> StreamExt for T where for<'a> &'a mut T: Stream { }
+impl<T> StreamExt for T where for<'a> &'a mut T: Stream {}
 
-fn main() {
+fn identity<T>(x: &T) -> &T {
+    x
+}
+
+fn variant1() {
     let source = Repeat(10);
-    let map = source.map(|x: &_| x);
-    //[nll]~^ ERROR higher-ranked subtype error
-    //[migrate]~^^ ERROR implementation of `Stream` is not general enough
-    //[migrate]~| NOTE  `Stream` would have to be implemented for the type `&'0 mut Map
-    //[migrate]~| NOTE  but `Stream` is actually implemented for the type `&'1
-    //[migrate]~| NOTE  implementation of `Stream` is not general enough
-    let filter = map.filter(|x: &_| true);
-    //[nll]~^ ERROR higher-ranked subtype error
-    //[nll]~| ERROR higher-ranked subtype error
-    //[nll]~| ERROR higher-ranked subtype error
-    //[nll]~| ERROR higher-ranked subtype error
-    let count = filter.count(); // Assert that we still have a valid stream.
-    //[nll]~^ ERROR higher-ranked subtype error
-    //[nll]~| ERROR higher-ranked subtype error
-    //[nll]~| ERROR higher-ranked subtype error
-    //[nll]~| ERROR higher-ranked subtype error
+
+    // Here, the call to `mapx` returns a type `T` to which `StreamExt`
+    // is not applicable, because `for<'b> &'b mut T: Stream`) doesn't hold.
+    //
+    // More concretely, the type `T` is `Map<Repeat, Closure>`, and
+    // the where clause doesn't hold because the signature of the
+    // closure gets inferred to a signature like `|&'_ Stream| -> &'_`
+    // for some specific `'_`, rather than a more generic
+    // signature.
+    //
+    // Why *exactly* we opt for this signature is a bit unclear to me,
+    // we deduce it somehow from a reuqirement that `Map: Stream` I
+    // guess.
+    let map = source.mapx(|x: &_| x);
+    let filter = map.filterx(|x: &_| true);
+    //[migrate]~^ ERROR no method named `filterx`
+    //[nll]~^^ ERROR no method named `filterx`
 }
+
+fn variant2() {
+    let source = Repeat(10);
+
+    // Here, we use a function, which is not subject to the vagaries
+    // of closure signature inference. In this case, we get the error
+    // on `countx` as, I think, the test originally expected.
+    let map = source.mapx(identity);
+    let filter = map.filterx(|x: &_| true);
+    let count = filter.countx();
+    //[migrate]~^ ERROR no method named `countx`
+    //[nll]~^^ ERROR no method named `countx`
+}
+
+fn main() {}
diff --git a/src/test/ui/hrtb/issue-46989.nll.stderr b/src/test/ui/hrtb/issue-46989.nll.stderr
new file mode 100644
index 00000000000..6c127b92d97
--- /dev/null
+++ b/src/test/ui/hrtb/issue-46989.nll.stderr
@@ -0,0 +1,8 @@
+error: higher-ranked subtype error
+  --> $DIR/issue-46989.rs:38:5
+   |
+LL |     assert_foo::<fn(&i32)>();
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to previous error
+
diff --git a/src/test/ui/hrtb/issue-46989.rs b/src/test/ui/hrtb/issue-46989.rs
index 2c859055458..4a09f4be156 100644
--- a/src/test/ui/hrtb/issue-46989.rs
+++ b/src/test/ui/hrtb/issue-46989.rs
@@ -28,15 +28,13 @@
 //
 // holds because 'a can be instantiated to 'empty.
 
-trait Foo {
+trait Foo {}
 
-}
-
-impl<A> Foo for fn(A) { }
+impl<A> Foo for fn(A) {}
 
 fn assert_foo<T: Foo>() {}
 
 fn main() {
     assert_foo::<fn(&i32)>();
-    //~^ ERROR the trait bound `for<'r> fn(&'r i32): Foo` is not satisfied
+    //~^ ERROR implementation of `Foo` is not general enough
 }
diff --git a/src/test/ui/hrtb/issue-46989.stderr b/src/test/ui/hrtb/issue-46989.stderr
index 0a7382c4dd8..c85c37ff923 100644
--- a/src/test/ui/hrtb/issue-46989.stderr
+++ b/src/test/ui/hrtb/issue-46989.stderr
@@ -1,15 +1,14 @@
-error[E0277]: the trait bound `for<'r> fn(&'r i32): Foo` is not satisfied
-  --> $DIR/issue-46989.rs:40:18
+error: implementation of `Foo` is not general enough
+  --> $DIR/issue-46989.rs:38:5
    |
-LL | fn assert_foo<T: Foo>() {}
-   |                  --- required by this bound in `assert_foo`
+LL | trait Foo {}
+   | ------------ trait `Foo` defined here
 ...
 LL |     assert_foo::<fn(&i32)>();
-   |                  ^^^^^^^^ the trait `Foo` is not implemented for `for<'r> fn(&'r i32)`
+   |     ^^^^^^^^^^^^^^^^^^^^^^ implementation of `Foo` is not general enough
    |
-   = help: the following implementations were found:
-             <fn(A) as Foo>
+   = note: `Foo` would have to be implemented for the type `for<'r> fn(&'r i32)`
+   = note: ...but `Foo` is actually implemented for the type `fn(&'0 i32)`, for some specific lifetime `'0`
 
 error: aborting due to previous error
 
-For more information about this error, try `rustc --explain E0277`.
diff --git a/src/test/ui/issues/issue-40000.nll.stderr b/src/test/ui/issues/issue-40000.nll.stderr
new file mode 100644
index 00000000000..f673fbae8b7
--- /dev/null
+++ b/src/test/ui/issues/issue-40000.nll.stderr
@@ -0,0 +1,8 @@
+error: higher-ranked subtype error
+  --> $DIR/issue-40000.rs:6:9
+   |
+LL |     foo(bar);
+   |         ^^^
+
+error: aborting due to previous error
+
diff --git a/src/test/ui/issues/issue-40000.stderr b/src/test/ui/issues/issue-40000.stderr
index 983fdb13083..3eb3482ac91 100644
--- a/src/test/ui/issues/issue-40000.stderr
+++ b/src/test/ui/issues/issue-40000.stderr
@@ -2,10 +2,10 @@ error[E0308]: mismatched types
   --> $DIR/issue-40000.rs:6:9
    |
 LL |     foo(bar);
-   |         ^^^ expected concrete lifetime, found bound lifetime parameter
+   |         ^^^ one type is more general than the other
    |
-   = note: expected struct `std::boxed::Box<(dyn for<'r> std::ops::Fn(&'r i32) + 'static)>`
-              found struct `std::boxed::Box<dyn std::ops::Fn(_)>`
+   = note: expected trait object `dyn for<'r> std::ops::Fn(&'r i32)`
+              found trait object `dyn std::ops::Fn(&i32)`
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/issues/issue-43623.rs b/src/test/ui/issues/issue-43623.rs
index b259e9e269d..99cae46fd9c 100644
--- a/src/test/ui/issues/issue-43623.rs
+++ b/src/test/ui/issues/issue-43623.rs
@@ -9,11 +9,12 @@ impl<'a> Trait<'a> for Type {
 }
 
 pub fn break_me<T, F>(f: F)
-where T: for<'b> Trait<'b>,
-      F: for<'b> FnMut(<T as Trait<'b>>::Assoc) {
+where
+    T: for<'b> Trait<'b>,
+    F: for<'b> FnMut(<T as Trait<'b>>::Assoc),
+{
     break_me::<Type, fn(_)>;
     //~^ ERROR: type mismatch in function arguments
-    //~| ERROR: type mismatch resolving
 }
 
 fn main() {}
diff --git a/src/test/ui/issues/issue-43623.stderr b/src/test/ui/issues/issue-43623.stderr
index 99fb2a1f5d0..80aca482b3d 100644
--- a/src/test/ui/issues/issue-43623.stderr
+++ b/src/test/ui/issues/issue-43623.stderr
@@ -1,29 +1,18 @@
 error[E0631]: type mismatch in function arguments
-  --> $DIR/issue-43623.rs:14:5
+  --> $DIR/issue-43623.rs:16:5
    |
 LL | pub fn break_me<T, F>(f: F)
    |        -------- required by a bound in this
-LL | where T: for<'b> Trait<'b>,
-LL |       F: for<'b> FnMut(<T as Trait<'b>>::Assoc) {
-   |          -------------------------------------- required by this bound in `break_me`
+...
+LL |     F: for<'b> FnMut(<T as Trait<'b>>::Assoc),
+   |                ------------------------------ required by this bound in `break_me`
+LL | {
 LL |     break_me::<Type, fn(_)>;
    |     ^^^^^^^^^^^^^^^^^^^^^^^
    |     |
-   |     expected signature of `for<'b> fn(<Type as Trait<'b>>::Assoc) -> _`
-   |     found signature of `fn(_) -> _`
+   |     expected signature of `fn(<Type as Trait<'b>>::Assoc) -> _`
+   |     found signature of `fn(()) -> _`
 
-error[E0271]: type mismatch resolving `for<'b> <fn(_) as std::ops::FnOnce<(<Type as Trait<'b>>::Assoc,)>>::Output == ()`
-  --> $DIR/issue-43623.rs:14:5
-   |
-LL | pub fn break_me<T, F>(f: F)
-   |        -------- required by a bound in this
-LL | where T: for<'b> Trait<'b>,
-LL |       F: for<'b> FnMut(<T as Trait<'b>>::Assoc) {
-   |                  ------------------------------ required by this bound in `break_me`
-LL |     break_me::<Type, fn(_)>;
-   |     ^^^^^^^^^^^^^^^^^^^^^^^ expected bound lifetime parameter 'b, found concrete lifetime
-
-error: aborting due to 2 previous errors
+error: aborting due to previous error
 
-Some errors have detailed explanations: E0271, E0631.
-For more information about an error, try `rustc --explain E0271`.
+For more information about this error, try `rustc --explain E0631`.
diff --git a/src/test/ui/issues/issue-57362-2.stderr b/src/test/ui/issues/issue-57362-2.stderr
index 2edc0097464..47cc64ec470 100644
--- a/src/test/ui/issues/issue-57362-2.stderr
+++ b/src/test/ui/issues/issue-57362-2.stderr
@@ -4,6 +4,8 @@ error[E0599]: no function or associated item named `make_g` found for fn pointer
 LL |     let x = <fn (&())>::make_g();
    |                         ^^^^^^ function or associated item not found in `for<'r> fn(&'r ())`
    |
+   = note: the method `make_g` exists but the following trait bounds were not satisfied:
+           `for<'r> fn(&'r ()): X`
    = help: items from traits can only be used if the trait is implemented and in scope
 note: `X` defines an item `make_g`, perhaps you need to implement it
   --> $DIR/issue-57362-2.rs:8:1
diff --git a/src/test/ui/issues/issue-60283.rs b/src/test/ui/issues/issue-60283.rs
index e5a9caa32fa..9c2b2dc9f4d 100644
--- a/src/test/ui/issues/issue-60283.rs
+++ b/src/test/ui/issues/issue-60283.rs
@@ -7,11 +7,13 @@ impl<'a> Trait<'a> for () {
 }
 
 pub fn foo<T, F>(_: T, _: F)
-where T: for<'a> Trait<'a>,
-      F: for<'a> FnMut(<T as Trait<'a>>::Item) {}
+where
+    T: for<'a> Trait<'a>,
+    F: for<'a> FnMut(<T as Trait<'a>>::Item),
+{
+}
 
 fn main() {
     foo((), drop)
     //~^ ERROR type mismatch in function arguments
-    //~| ERROR type mismatch resolving
 }
diff --git a/src/test/ui/issues/issue-60283.stderr b/src/test/ui/issues/issue-60283.stderr
index e74a34e247a..ad679bfa220 100644
--- a/src/test/ui/issues/issue-60283.stderr
+++ b/src/test/ui/issues/issue-60283.stderr
@@ -1,31 +1,18 @@
 error[E0631]: type mismatch in function arguments
-  --> $DIR/issue-60283.rs:14:13
+  --> $DIR/issue-60283.rs:17:13
    |
 LL | pub fn foo<T, F>(_: T, _: F)
    |        --- required by a bound in this
-LL | where T: for<'a> Trait<'a>,
-LL |       F: for<'a> FnMut(<T as Trait<'a>>::Item) {}
-   |          ------------------------------------- required by this bound in `foo`
+...
+LL |     F: for<'a> FnMut(<T as Trait<'a>>::Item),
+   |                ----------------------------- required by this bound in `foo`
 ...
 LL |     foo((), drop)
    |             ^^^^
    |             |
-   |             expected signature of `for<'a> fn(<() as Trait<'a>>::Item) -> _`
-   |             found signature of `fn(_) -> _`
-
-error[E0271]: type mismatch resolving `for<'a> <fn(_) {std::mem::drop::<_>} as std::ops::FnOnce<(<() as Trait<'a>>::Item,)>>::Output == ()`
-  --> $DIR/issue-60283.rs:14:5
-   |
-LL | pub fn foo<T, F>(_: T, _: F)
-   |        --- required by a bound in this
-LL | where T: for<'a> Trait<'a>,
-LL |       F: for<'a> FnMut(<T as Trait<'a>>::Item) {}
-   |                  ----------------------------- required by this bound in `foo`
-...
-LL |     foo((), drop)
-   |     ^^^ expected bound lifetime parameter 'a, found concrete lifetime
+   |             expected signature of `fn(<() as Trait<'a>>::Item) -> _`
+   |             found signature of `fn(()) -> _`
 
-error: aborting due to 2 previous errors
+error: aborting due to previous error
 
-Some errors have detailed explanations: E0271, E0631.
-For more information about an error, try `rustc --explain E0271`.
+For more information about this error, try `rustc --explain E0631`.
diff --git a/src/test/ui/lub-glb/old-lub-glb-hr.rs b/src/test/ui/lub-glb/old-lub-glb-hr-eq.rs
index bc7b787cd65..fbf4aee0204 100644
--- a/src/test/ui/lub-glb/old-lub-glb-hr.rs
+++ b/src/test/ui/lub-glb/old-lub-glb-hr-eq.rs
@@ -4,23 +4,19 @@
 // longer get an error, because we recognize these two types as
 // equivalent!
 //
-// Whoops -- now that we reinstituted the leak-check, we get an error
-// again.
+// check-pass
 
-fn foo(
-    x: fn(&u8, &u8),
-    y: for<'a> fn(&'a u8, &'a u8),
-) {
+fn foo(x: fn(&u8, &u8), y: for<'a> fn(&'a u8, &'a u8)) {
+    // The two types above are actually equivalent. With the older
+    // leak check, though, we didn't consider them as equivalent, and
+    // hence we gave errors. But now we've fixed that.
     let z = match 22 {
         0 => x,
-        _ => y, //~ ERROR `match` arms have incompatible types
+        _ => y,
     };
 }
 
-fn bar(
-    x: fn(&u8, &u8),
-    y: for<'a> fn(&'a u8, &'a u8),
-) {
+fn foo_cast(x: fn(&u8, &u8), y: for<'a> fn(&'a u8, &'a u8)) {
     let z = match 22 {
         // No error with an explicit cast:
         0 => x as for<'a> fn(&'a u8, &'a u8),
@@ -28,5 +24,4 @@ fn bar(
     };
 }
 
-fn main() {
-}
+fn main() {}
diff --git a/src/test/ui/lub-glb/old-lub-glb-hr-noteq1.nll.stderr b/src/test/ui/lub-glb/old-lub-glb-hr-noteq1.nll.stderr
new file mode 100644
index 00000000000..b95e247d2a8
--- /dev/null
+++ b/src/test/ui/lub-glb/old-lub-glb-hr-noteq1.nll.stderr
@@ -0,0 +1,8 @@
+error: higher-ranked subtype error
+  --> $DIR/old-lub-glb-hr-noteq1.rs:11:14
+   |
+LL |         _ => y,
+   |              ^
+
+error: aborting due to previous error
+
diff --git a/src/test/ui/lub-glb/old-lub-glb-hr-noteq1.rs b/src/test/ui/lub-glb/old-lub-glb-hr-noteq1.rs
new file mode 100644
index 00000000000..918542d471b
--- /dev/null
+++ b/src/test/ui/lub-glb/old-lub-glb-hr-noteq1.rs
@@ -0,0 +1,24 @@
+// Test taking the LUB of two function types that are not equatable but where one is more
+// general than the other. Test the case where the more general type (`x`) is the first
+// match arm specifically.
+
+fn foo(x: for<'a, 'b> fn(&'a u8, &'b u8) -> &'a u8, y: for<'a> fn(&'a u8, &'a u8) -> &'a u8) {
+    // The two types above are not equivalent. With the older LUB/GLB
+    // algorithm, this may have worked (I don't remember), but now it
+    // doesn't because we require equality.
+    let z = match 22 {
+        0 => x,
+        _ => y, //~ ERROR `match` arms have incompatible types
+    };
+}
+
+fn foo_cast(x: for<'a, 'b> fn(&'a u8, &'b u8) -> &'a u8, y: for<'a> fn(&'a u8, &'a u8) -> &'a u8) {
+    // But we can *upcast* explicitly the type of `x` and figure
+    // things out:
+    let z = match 22 {
+        0 => x as for<'a> fn(&'a u8, &'a u8) -> &'a u8,
+        _ => y,
+    };
+}
+
+fn main() {}
diff --git a/src/test/ui/lub-glb/old-lub-glb-hr-noteq1.stderr b/src/test/ui/lub-glb/old-lub-glb-hr-noteq1.stderr
new file mode 100644
index 00000000000..305e952d604
--- /dev/null
+++ b/src/test/ui/lub-glb/old-lub-glb-hr-noteq1.stderr
@@ -0,0 +1,18 @@
+error[E0308]: `match` arms have incompatible types
+  --> $DIR/old-lub-glb-hr-noteq1.rs:11:14
+   |
+LL |       let z = match 22 {
+   |  _____________-
+LL | |         0 => x,
+   | |              - this is found to be of type `for<'a, 'b> fn(&'a u8, &'b u8) -> &'a u8`
+LL | |         _ => y,
+   | |              ^ one type is more general than the other
+LL | |     };
+   | |_____- `match` arms have incompatible types
+   |
+   = note: expected fn pointer `for<'a, 'b> fn(&'a u8, &'b u8) -> &'a u8`
+              found fn pointer `for<'a> fn(&'a u8, &'a u8) -> &'a u8`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0308`.
diff --git a/src/test/ui/lub-glb/old-lub-glb-hr-noteq2.rs b/src/test/ui/lub-glb/old-lub-glb-hr-noteq2.rs
new file mode 100644
index 00000000000..4bdd05b4f92
--- /dev/null
+++ b/src/test/ui/lub-glb/old-lub-glb-hr-noteq2.rs
@@ -0,0 +1,33 @@
+// Test taking the LUB of two function types that are not equatable but where
+// one is more general than the other. Test the case where the more general type
+// (`x`) is the second match arm specifically.
+//
+// FIXME(#73154) Skip for compare-mode because the pure NLL checker accepts this
+// test. (Note that it still errors in old-lub-glb-hr-noteq1.rs). What happens
+// is that, due to the ordering of the match arms, we pick the correct "more
+// general" fn type, and we ignore the errors from the non-NLL type checker that
+// requires equality. The NLL type checker only requires a subtyping
+// relationship, and that holds.
+//
+// ignore-compare-mode-nll
+
+fn foo(x: for<'a, 'b> fn(&'a u8, &'b u8) -> &'a u8, y: for<'a> fn(&'a u8, &'a u8) -> &'a u8) {
+    // The two types above are not equivalent. With the older LUB/GLB
+    // algorithm, this may have worked (I don't remember), but now it
+    // doesn't because we require equality.
+    let z = match 22 {
+        0 => y,
+        _ => x, //~ ERROR `match` arms have incompatible types
+    };
+}
+
+fn foo_cast(x: for<'a, 'b> fn(&'a u8, &'b u8) -> &'a u8, y: for<'a> fn(&'a u8, &'a u8) -> &'a u8) {
+    // But we can *upcast* explicitly the type of `x` and figure
+    // things out:
+    let z = match 22 {
+        0 => x as for<'a> fn(&'a u8, &'a u8) -> &'a u8,
+        _ => y,
+    };
+}
+
+fn main() {}
diff --git a/src/test/ui/lub-glb/old-lub-glb-hr-noteq2.stderr b/src/test/ui/lub-glb/old-lub-glb-hr-noteq2.stderr
new file mode 100644
index 00000000000..252e13aada0
--- /dev/null
+++ b/src/test/ui/lub-glb/old-lub-glb-hr-noteq2.stderr
@@ -0,0 +1,18 @@
+error[E0308]: `match` arms have incompatible types
+  --> $DIR/old-lub-glb-hr-noteq2.rs:20:14
+   |
+LL |       let z = match 22 {
+   |  _____________-
+LL | |         0 => y,
+   | |              - this is found to be of type `for<'a> fn(&'a u8, &'a u8) -> &'a u8`
+LL | |         _ => x,
+   | |              ^ one type is more general than the other
+LL | |     };
+   | |_____- `match` arms have incompatible types
+   |
+   = note: expected fn pointer `for<'a> fn(&'a u8, &'a u8) -> &'a u8`
+              found fn pointer `for<'a, 'b> fn(&'a u8, &'b u8) -> &'a u8`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0308`.
diff --git a/src/test/ui/lub-glb/old-lub-glb-hr.stderr b/src/test/ui/lub-glb/old-lub-glb-hr.stderr
deleted file mode 100644
index 6d5d5117469..00000000000
--- a/src/test/ui/lub-glb/old-lub-glb-hr.stderr
+++ /dev/null
@@ -1,18 +0,0 @@
-error[E0308]: `match` arms have incompatible types
-  --> $DIR/old-lub-glb-hr.rs:16:14
-   |
-LL |       let z = match 22 {
-   |  _____________-
-LL | |         0 => x,
-   | |              - this is found to be of type `for<'r, 's> fn(&'r u8, &'s u8)`
-LL | |         _ => y,
-   | |              ^ expected bound lifetime parameter, found concrete lifetime
-LL | |     };
-   | |_____- `match` arms have incompatible types
-   |
-   = note:    expected type `for<'r, 's> fn(&'r u8, &'s u8)`
-           found fn pointer `for<'a> fn(&'a u8, &'a u8)`
-
-error: aborting due to previous error
-
-For more information about this error, try `rustc --explain E0308`.
diff --git a/src/test/ui/lub-glb/old-lub-glb-object.nll.stderr b/src/test/ui/lub-glb/old-lub-glb-object.nll.stderr
new file mode 100644
index 00000000000..51bf96f3233
--- /dev/null
+++ b/src/test/ui/lub-glb/old-lub-glb-object.nll.stderr
@@ -0,0 +1,14 @@
+error: higher-ranked subtype error
+  --> $DIR/old-lub-glb-object.rs:10:14
+   |
+LL |         _ => y,
+   |              ^
+
+error: higher-ranked subtype error
+  --> $DIR/old-lub-glb-object.rs:10:14
+   |
+LL |         _ => y,
+   |              ^
+
+error: aborting due to 2 previous errors
+
diff --git a/src/test/ui/lub-glb/old-lub-glb-object.rs b/src/test/ui/lub-glb/old-lub-glb-object.rs
index 63bbae59991..39d351c2355 100644
--- a/src/test/ui/lub-glb/old-lub-glb-object.rs
+++ b/src/test/ui/lub-glb/old-lub-glb-object.rs
@@ -1,22 +1,17 @@
 // Test that we give a note when the old LUB/GLB algorithm would have
 // succeeded but the new code (which is stricter) gives an error.
 
-trait Foo<T, U> { }
+trait Foo<T, U> {}
 
-fn foo(
-    x: &dyn for<'a, 'b> Foo<&'a u8, &'b u8>,
-    y: &dyn for<'a> Foo<&'a u8, &'a u8>,
-) {
+fn foo(x: &dyn for<'a, 'b> Foo<&'a u8, &'b u8>, y: &dyn for<'a> Foo<&'a u8, &'a u8>) {
     let z = match 22 {
+        //~^ ERROR mismatched types
         0 => x,
-        _ => y, //~ ERROR `match` arms have incompatible types
+        _ => y,
     };
 }
 
-fn bar(
-    x: &dyn for<'a, 'b> Foo<&'a u8, &'b u8>,
-    y: &dyn for<'a> Foo<&'a u8, &'a u8>,
-) {
+fn bar(x: &dyn for<'a, 'b> Foo<&'a u8, &'b u8>, y: &dyn for<'a> Foo<&'a u8, &'a u8>) {
     // Accepted with explicit case:
     let z = match 22 {
         0 => x as &dyn for<'a> Foo<&'a u8, &'a u8>,
@@ -24,5 +19,4 @@ fn bar(
     };
 }
 
-fn main() {
-}
+fn main() {}
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 65c797f6b19..6eabe5eaeee 100644
--- a/src/test/ui/lub-glb/old-lub-glb-object.stderr
+++ b/src/test/ui/lub-glb/old-lub-glb-object.stderr
@@ -1,17 +1,16 @@
-error[E0308]: `match` arms have incompatible types
-  --> $DIR/old-lub-glb-object.rs:12:14
+error[E0308]: mismatched types
+  --> $DIR/old-lub-glb-object.rs:7:13
    |
 LL |       let z = match 22 {
-   |  _____________-
+   |  _____________^
+LL | |
 LL | |         0 => x,
-   | |              - this is found to be of type `&dyn for<'a, 'b> Foo<&'a u8, &'b u8>`
 LL | |         _ => y,
-   | |              ^ expected bound lifetime parameter 'a, found concrete lifetime
 LL | |     };
-   | |_____- `match` arms have incompatible types
+   | |_____^ one type is more general than the other
    |
-   = note:   expected type `&dyn for<'a, 'b> Foo<&'a u8, &'b u8>`
-           found reference `&dyn for<'a> Foo<&'a u8, &'a u8>`
+   = note: expected trait object `dyn for<'a, 'b> Foo<&'a u8, &'b u8>`
+              found trait object `dyn for<'a> Foo<&'a u8, &'a u8>`
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/mismatched_types/closure-arg-type-mismatch.nll.stderr b/src/test/ui/mismatched_types/closure-arg-type-mismatch.nll.stderr
new file mode 100644
index 00000000000..6ed91b20ab8
--- /dev/null
+++ b/src/test/ui/mismatched_types/closure-arg-type-mismatch.nll.stderr
@@ -0,0 +1,27 @@
+error[E0631]: type mismatch in closure arguments
+  --> $DIR/closure-arg-type-mismatch.rs:3:14
+   |
+LL |     a.iter().map(|_: (u32, u32)| 45);
+   |              ^^^ ------------------ found signature of `fn((u32, u32)) -> _`
+   |              |
+   |              expected signature of `fn(&(u32, u32)) -> _`
+
+error[E0631]: type mismatch in closure arguments
+  --> $DIR/closure-arg-type-mismatch.rs:4:14
+   |
+LL |     a.iter().map(|_: &(u16, u16)| 45);
+   |              ^^^ ------------------- found signature of `for<'r> fn(&'r (u16, u16)) -> _`
+   |              |
+   |              expected signature of `fn(&(u32, u32)) -> _`
+
+error[E0631]: type mismatch in closure arguments
+  --> $DIR/closure-arg-type-mismatch.rs:5:14
+   |
+LL |     a.iter().map(|_: (u16, u16)| 45);
+   |              ^^^ ------------------ found signature of `fn((u16, u16)) -> _`
+   |              |
+   |              expected signature of `fn(&(u32, u32)) -> _`
+
+error: aborting due to 3 previous errors
+
+For more information about this error, try `rustc --explain E0631`.
diff --git a/src/test/ui/mismatched_types/closure-arg-type-mismatch.rs b/src/test/ui/mismatched_types/closure-arg-type-mismatch.rs
index 521bd3695df..e278049c8cc 100644
--- a/src/test/ui/mismatched_types/closure-arg-type-mismatch.rs
+++ b/src/test/ui/mismatched_types/closure-arg-type-mismatch.rs
@@ -7,6 +7,9 @@ fn main() {
 
 fn baz<F: Fn(*mut &u32)>(_: F) {}
 fn _test<'a>(f: fn(*mut &'a u32)) {
-    baz(f); //~ ERROR type mismatch
-     //~| ERROR type mismatch
+    baz(f);
+    //~^ ERROR mismatched types
+    //~| ERROR mismatched types
+    //~| ERROR mismatched types
+    //~| ERROR mismatched types
 }
diff --git a/src/test/ui/mismatched_types/closure-arg-type-mismatch.stderr b/src/test/ui/mismatched_types/closure-arg-type-mismatch.stderr
index 69a4b458ebf..664fa4bcaf3 100644
--- a/src/test/ui/mismatched_types/closure-arg-type-mismatch.stderr
+++ b/src/test/ui/mismatched_types/closure-arg-type-mismatch.stderr
@@ -22,28 +22,43 @@ LL |     a.iter().map(|_: (u16, u16)| 45);
    |              |
    |              expected signature of `fn(&(u32, u32)) -> _`
 
-error[E0631]: type mismatch in function arguments
-  --> $DIR/closure-arg-type-mismatch.rs:10:9
+error[E0308]: mismatched types
+  --> $DIR/closure-arg-type-mismatch.rs:10:5
    |
-LL | fn baz<F: Fn(*mut &u32)>(_: F) {}
-   |           ------------- required by this bound in `baz`
-LL | fn _test<'a>(f: fn(*mut &'a u32)) {
 LL |     baz(f);
-   |         ^
-   |         |
-   |         expected signature of `for<'r> fn(*mut &'r u32) -> _`
-   |         found signature of `fn(*mut &'a u32) -> _`
+   |     ^^^ one type is more general than the other
+   |
+   = note: expected type `for<'r> std::ops::Fn<(*mut &'r u32,)>`
+              found type `std::ops::Fn<(*mut &'a u32,)>`
+
+error[E0308]: mismatched types
+  --> $DIR/closure-arg-type-mismatch.rs:10:5
+   |
+LL |     baz(f);
+   |     ^^^ one type is more general than the other
+   |
+   = note: expected type `std::ops::FnOnce<(*mut &u32,)>`
+              found type `std::ops::FnOnce<(*mut &'a u32,)>`
 
-error[E0271]: type mismatch resolving `for<'r> <fn(*mut &'a u32) as std::ops::FnOnce<(*mut &'r u32,)>>::Output == ()`
+error[E0308]: mismatched types
   --> $DIR/closure-arg-type-mismatch.rs:10:5
    |
-LL | fn baz<F: Fn(*mut &u32)>(_: F) {}
-   |           ------------- required by this bound in `baz`
-LL | fn _test<'a>(f: fn(*mut &'a u32)) {
 LL |     baz(f);
-   |     ^^^ expected bound lifetime parameter, found concrete lifetime
+   |     ^^^ one type is more general than the other
+   |
+   = note: expected type `for<'r> std::ops::Fn<(*mut &'r u32,)>`
+              found type `std::ops::Fn<(*mut &'a u32,)>`
+
+error[E0308]: mismatched types
+  --> $DIR/closure-arg-type-mismatch.rs:10:5
+   |
+LL |     baz(f);
+   |     ^^^ one type is more general than the other
+   |
+   = note: expected type `std::ops::FnOnce<(*mut &u32,)>`
+              found type `std::ops::FnOnce<(*mut &'a u32,)>`
 
-error: aborting due to 5 previous errors
+error: aborting due to 7 previous errors
 
-Some errors have detailed explanations: E0271, E0631.
-For more information about an error, try `rustc --explain E0271`.
+Some errors have detailed explanations: E0308, E0631.
+For more information about an error, try `rustc --explain E0308`.
diff --git a/src/test/ui/mismatched_types/closure-mismatch.nll.stderr b/src/test/ui/mismatched_types/closure-mismatch.nll.stderr
new file mode 100644
index 00000000000..745a61b866e
--- /dev/null
+++ b/src/test/ui/mismatched_types/closure-mismatch.nll.stderr
@@ -0,0 +1,14 @@
+error: higher-ranked subtype error
+  --> $DIR/closure-mismatch.rs:8:5
+   |
+LL |     baz(|_| ());
+   |     ^^^^^^^^^^^
+
+error: higher-ranked subtype error
+  --> $DIR/closure-mismatch.rs:8:5
+   |
+LL |     baz(|_| ());
+   |     ^^^^^^^^^^^
+
+error: aborting due to 2 previous errors
+
diff --git a/src/test/ui/mismatched_types/closure-mismatch.rs b/src/test/ui/mismatched_types/closure-mismatch.rs
index 40a4641fe71..d2b78b4b7db 100644
--- a/src/test/ui/mismatched_types/closure-mismatch.rs
+++ b/src/test/ui/mismatched_types/closure-mismatch.rs
@@ -5,6 +5,5 @@ impl<T: Fn(&())> Foo for T {}
 fn baz<T: Foo>(_: T) {}
 
 fn main() {
-    baz(|_| ()); //~ ERROR type mismatch
-    //~^ ERROR type mismatch
+    baz(|_| ()); //~ ERROR mismatched types
 }
diff --git a/src/test/ui/mismatched_types/closure-mismatch.stderr b/src/test/ui/mismatched_types/closure-mismatch.stderr
index 389b2157446..d6c17d125cf 100644
--- a/src/test/ui/mismatched_types/closure-mismatch.stderr
+++ b/src/test/ui/mismatched_types/closure-mismatch.stderr
@@ -1,28 +1,12 @@
-error[E0271]: type mismatch resolving `for<'r> <[closure@$DIR/closure-mismatch.rs:8:9: 8:15] as std::ops::FnOnce<(&'r (),)>>::Output == ()`
+error[E0308]: mismatched types
   --> $DIR/closure-mismatch.rs:8:5
    |
-LL | fn baz<T: Foo>(_: T) {}
-   |           --- required by this bound in `baz`
-...
 LL |     baz(|_| ());
-   |     ^^^ expected bound lifetime parameter, found concrete lifetime
+   |     ^^^ one type is more general than the other
    |
-   = note: required because of the requirements on the impl of `Foo` for `[closure@$DIR/closure-mismatch.rs:8:9: 8:15]`
+   = note: expected type `for<'r> std::ops::Fn<(&'r (),)>`
+              found type `std::ops::Fn<(&(),)>`
 
-error[E0631]: type mismatch in closure arguments
-  --> $DIR/closure-mismatch.rs:8:5
-   |
-LL | fn baz<T: Foo>(_: T) {}
-   |           --- required by this bound in `baz`
-...
-LL |     baz(|_| ());
-   |     ^^^ ------ found signature of `fn(_) -> _`
-   |     |
-   |     expected signature of `for<'r> fn(&'r ()) -> _`
-   |
-   = note: required because of the requirements on the impl of `Foo` for `[closure@$DIR/closure-mismatch.rs:8:9: 8:15]`
-
-error: aborting due to 2 previous errors
+error: aborting due to previous error
 
-Some errors have detailed explanations: E0271, E0631.
-For more information about an error, try `rustc --explain E0271`.
+For more information about this error, try `rustc --explain E0308`.
diff --git a/src/test/ui/regions-fn-subtyping-return-static-fail.nll.stderr b/src/test/ui/regions-fn-subtyping-return-static-fail.nll.stderr
new file mode 100644
index 00000000000..d762f55f9d5
--- /dev/null
+++ b/src/test/ui/regions-fn-subtyping-return-static-fail.nll.stderr
@@ -0,0 +1,8 @@
+error: higher-ranked subtype error
+  --> $DIR/regions-fn-subtyping-return-static-fail.rs:48:5
+   |
+LL |     want_G(baz);
+   |     ^^^^^^^^^^^
+
+error: aborting due to previous error
+
diff --git a/src/test/ui/regions-fn-subtyping-return-static-fail.rs b/src/test/ui/regions-fn-subtyping-return-static-fail.rs
index 2dd0c9796e2..539221b5a04 100644
--- a/src/test/ui/regions-fn-subtyping-return-static-fail.rs
+++ b/src/test/ui/regions-fn-subtyping-return-static-fail.rs
@@ -13,11 +13,11 @@ struct S;
 
 // Given 'cx, return 'cx
 type F = for<'cx> fn(&'cx S) -> &'cx S;
-fn want_F(f: F) { }
+fn want_F(f: F) {}
 
 // Given anything, return 'static
 type G = for<'cx> fn(&'cx S) -> &'static S;
-fn want_G(f: G) { }
+fn want_G(f: G) {}
 
 // Should meet both.
 fn foo(x: &S) -> &'static S {
@@ -25,7 +25,7 @@ fn foo(x: &S) -> &'static S {
 }
 
 // Should meet both.
-fn bar<'a,'b>(x: &'a S) -> &'b S {
+fn bar<'a, 'b>(x: &'a S) -> &'b S {
     panic!()
 }
 
@@ -37,7 +37,7 @@ fn baz(x: &S) -> &S {
 fn supply_F() {
     want_F(foo);
 
-    want_F(bar); //~ ERROR mismatched types
+    want_F(bar);
 
     want_F(baz);
 }
@@ -48,5 +48,4 @@ fn supply_G() {
     want_G(baz); //~ ERROR mismatched types
 }
 
-pub fn main() {
-}
+pub fn main() {}
diff --git a/src/test/ui/regions-fn-subtyping-return-static-fail.stderr b/src/test/ui/regions-fn-subtyping-return-static-fail.stderr
index 27704b3e0a8..c9ce936c7d4 100644
--- a/src/test/ui/regions-fn-subtyping-return-static-fail.stderr
+++ b/src/test/ui/regions-fn-subtyping-return-static-fail.stderr
@@ -1,21 +1,12 @@
 error[E0308]: mismatched types
-  --> $DIR/regions-fn-subtyping-return-static-fail.rs:40:12
-   |
-LL |     want_F(bar);
-   |            ^^^ expected concrete lifetime, found bound lifetime parameter 'cx
-   |
-   = note: expected fn pointer `for<'cx> fn(&'cx S) -> &'cx S`
-                 found fn item `for<'a> fn(&'a S) -> &S {bar::<'_>}`
-
-error[E0308]: mismatched types
   --> $DIR/regions-fn-subtyping-return-static-fail.rs:48:12
    |
 LL |     want_G(baz);
-   |            ^^^ expected concrete lifetime, found bound lifetime parameter 'cx
+   |            ^^^ one type is more general than the other
    |
    = note: expected fn pointer `for<'cx> fn(&'cx S) -> &'static S`
-                 found fn item `for<'r> fn(&'r S) -> &'r S {baz}`
+              found fn pointer `for<'r> fn(&'r S) -> &'r S`
 
-error: aborting due to 2 previous errors
+error: aborting due to previous error
 
 For more information about this error, try `rustc --explain E0308`.
diff --git a/src/test/ui/regions/region-lifetime-bounds-on-fns-where-clause.nll.stderr b/src/test/ui/regions/region-lifetime-bounds-on-fns-where-clause.nll.stderr
index c3e8789a903..695f5506d5e 100644
--- a/src/test/ui/regions/region-lifetime-bounds-on-fns-where-clause.nll.stderr
+++ b/src/test/ui/regions/region-lifetime-bounds-on-fns-where-clause.nll.stderr
@@ -1,14 +1,40 @@
-error[E0308]: mismatched types
-  --> $DIR/region-lifetime-bounds-on-fns-where-clause.rs:20:43
+error: lifetime may not live long enough
+  --> $DIR/region-lifetime-bounds-on-fns-where-clause.rs:8:5
+   |
+LL | fn b<'a, 'b>(x: &mut &'a isize, y: &mut &'b isize) {
+   |      --  -- lifetime `'b` defined here
+   |      |
+   |      lifetime `'a` defined here
+LL |     // Illegal now because there is no `'b:'a` declaration.
+LL |     *x = *y;
+   |     ^^^^^^^ assignment requires that `'b` must outlive `'a`
+   |
+   = help: consider adding the following bound: `'b: 'a`
+
+error: lifetime may not live long enough
+  --> $DIR/region-lifetime-bounds-on-fns-where-clause.rs:14:5
+   |
+LL | fn c<'a,'b>(x: &mut &'a isize, y: &mut &'b isize) {
+   |      -- -- lifetime `'b` defined here
+   |      |
+   |      lifetime `'a` defined here
+...
+LL |     a(x, y);
+   |     ^^^^^^^ argument requires that `'b` must outlive `'a`
+   |
+   = help: consider adding the following bound: `'b: 'a`
+
+error: higher-ranked subtype error
+  --> $DIR/region-lifetime-bounds-on-fns-where-clause.rs:20:12
    |
 LL |     let _: fn(&mut &isize, &mut &isize) = a;
-   |            ----------------------------   ^ expected concrete lifetime, found bound lifetime parameter
-   |            |
-   |            expected due to this
+   |            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: higher-ranked subtype error
+  --> $DIR/region-lifetime-bounds-on-fns-where-clause.rs:20:12
    |
-   = note: expected fn pointer `for<'r, 's, 't0, 't1> fn(&'r mut &'s isize, &'t0 mut &'t1 isize)`
-                 found fn item `for<'r, 's> fn(&'r mut &isize, &'s mut &isize) {a::<'_, '_>}`
+LL |     let _: fn(&mut &isize, &mut &isize) = a;
+   |            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
-error: aborting due to previous error
+error: aborting due to 4 previous errors
 
-For more information about this error, try `rustc --explain E0308`.
diff --git a/src/test/ui/regions/region-lifetime-bounds-on-fns-where-clause.stderr b/src/test/ui/regions/region-lifetime-bounds-on-fns-where-clause.stderr
index 159d32b50b0..b83e07663fa 100644
--- a/src/test/ui/regions/region-lifetime-bounds-on-fns-where-clause.stderr
+++ b/src/test/ui/regions/region-lifetime-bounds-on-fns-where-clause.stderr
@@ -20,12 +20,10 @@ error[E0308]: mismatched types
   --> $DIR/region-lifetime-bounds-on-fns-where-clause.rs:20:43
    |
 LL |     let _: fn(&mut &isize, &mut &isize) = a;
-   |            ----------------------------   ^ expected concrete lifetime, found bound lifetime parameter
-   |            |
-   |            expected due to this
+   |                                           ^ one type is more general than the other
    |
    = note: expected fn pointer `for<'r, 's, 't0, 't1> fn(&'r mut &'s isize, &'t0 mut &'t1 isize)`
-                 found fn item `for<'r, 's> fn(&'r mut &isize, &'s mut &isize) {a::<'_, '_>}`
+              found fn pointer `for<'r, 's> fn(&'r mut &isize, &'s mut &isize)`
 
 error: aborting due to 3 previous errors
 
diff --git a/src/test/ui/regions/region-multiple-lifetime-bounds-on-fns-where-clause.nll.stderr b/src/test/ui/regions/region-multiple-lifetime-bounds-on-fns-where-clause.nll.stderr
index 2aadd8f4f8c..a28f7aa3e08 100644
--- a/src/test/ui/regions/region-multiple-lifetime-bounds-on-fns-where-clause.nll.stderr
+++ b/src/test/ui/regions/region-multiple-lifetime-bounds-on-fns-where-clause.nll.stderr
@@ -1,14 +1,46 @@
-error[E0308]: mismatched types
-  --> $DIR/region-multiple-lifetime-bounds-on-fns-where-clause.rs:22:56
+error: lifetime may not live long enough
+  --> $DIR/region-multiple-lifetime-bounds-on-fns-where-clause.rs:9:5
+   |
+LL | fn b<'a, 'b, 'c>(x: &mut &'a isize, y: &mut &'b isize, z: &mut &'c isize) {
+   |      --  -- lifetime `'b` defined here
+   |      |
+   |      lifetime `'a` defined here
+LL |     // Illegal now because there is no `'b:'a` declaration.
+LL |     *x = *y;
+   |     ^^^^^^^ assignment requires that `'b` must outlive `'a`
+   |
+   = help: consider adding the following bound: `'b: 'a`
+
+error: lifetime may not live long enough
+  --> $DIR/region-multiple-lifetime-bounds-on-fns-where-clause.rs:16:5
+   |
+LL | fn c<'a,'b, 'c>(x: &mut &'a isize, y: &mut &'b isize, z: &mut &'c isize) {
+   |      -- -- lifetime `'b` defined here
+   |      |
+   |      lifetime `'a` defined here
+...
+LL |     a(x, y, z);
+   |     ^^^^^^^^^^ argument requires that `'b` must outlive `'a`
+   |
+   = help: consider adding the following bound: `'b: 'a`
+
+error: higher-ranked subtype error
+  --> $DIR/region-multiple-lifetime-bounds-on-fns-where-clause.rs:22:12
    |
 LL |     let _: fn(&mut &isize, &mut &isize, &mut &isize) = a;
-   |            -----------------------------------------   ^ expected concrete lifetime, found bound lifetime parameter
-   |            |
-   |            expected due to this
+   |            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: higher-ranked subtype error
+  --> $DIR/region-multiple-lifetime-bounds-on-fns-where-clause.rs:22:12
    |
-   = note: expected fn pointer `for<'r, 's, 't0, 't1, 't2, 't3> fn(&'r mut &'s isize, &'t0 mut &'t1 isize, &'t2 mut &'t3 isize)`
-                 found fn item `for<'r, 's, 't0> fn(&'r mut &isize, &'s mut &isize, &'t0 mut &isize) {a::<'_, '_, '_>}`
+LL |     let _: fn(&mut &isize, &mut &isize, &mut &isize) = a;
+   |            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: higher-ranked subtype error
+  --> $DIR/region-multiple-lifetime-bounds-on-fns-where-clause.rs:22:12
+   |
+LL |     let _: fn(&mut &isize, &mut &isize, &mut &isize) = a;
+   |            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
-error: aborting due to previous error
+error: aborting due to 5 previous errors
 
-For more information about this error, try `rustc --explain E0308`.
diff --git a/src/test/ui/regions/region-multiple-lifetime-bounds-on-fns-where-clause.stderr b/src/test/ui/regions/region-multiple-lifetime-bounds-on-fns-where-clause.stderr
index dda6129e195..c93f2890f11 100644
--- a/src/test/ui/regions/region-multiple-lifetime-bounds-on-fns-where-clause.stderr
+++ b/src/test/ui/regions/region-multiple-lifetime-bounds-on-fns-where-clause.stderr
@@ -31,12 +31,10 @@ error[E0308]: mismatched types
   --> $DIR/region-multiple-lifetime-bounds-on-fns-where-clause.rs:22:56
    |
 LL |     let _: fn(&mut &isize, &mut &isize, &mut &isize) = a;
-   |            -----------------------------------------   ^ expected concrete lifetime, found bound lifetime parameter
-   |            |
-   |            expected due to this
+   |                                                        ^ one type is more general than the other
    |
    = note: expected fn pointer `for<'r, 's, 't0, 't1, 't2, 't3> fn(&'r mut &'s isize, &'t0 mut &'t1 isize, &'t2 mut &'t3 isize)`
-                 found fn item `for<'r, 's, 't0> fn(&'r mut &isize, &'s mut &isize, &'t0 mut &isize) {a::<'_, '_, '_>}`
+              found fn pointer `for<'r, 's, 't0> fn(&'r mut &isize, &'s mut &isize, &'t0 mut &isize)`
 
 error: aborting due to 4 previous errors
 
diff --git a/src/test/ui/regions/regions-fn-subtyping-return-static.rs b/src/test/ui/regions/regions-fn-subtyping-return-static.rs
index fa2cc37d05b..de14d5ba82a 100644
--- a/src/test/ui/regions/regions-fn-subtyping-return-static.rs
+++ b/src/test/ui/regions/regions-fn-subtyping-return-static.rs
@@ -5,6 +5,8 @@
 // *ANY* lifetime and returns a reference with the 'static lifetime.
 // This can safely be considered to be an instance of `F` because all
 // lifetimes are sublifetimes of 'static.
+//
+// check-pass
 
 #![allow(dead_code)]
 #![allow(unused_variables)]
@@ -14,11 +16,11 @@ struct S;
 
 // Given 'cx, return 'cx
 type F = for<'cx> fn(&'cx S) -> &'cx S;
-fn want_F(f: F) { }
+fn want_F(f: F) {}
 
 // Given anything, return 'static
 type G = for<'cx> fn(&'cx S) -> &'static S;
-fn want_G(f: G) { }
+fn want_G(f: G) {}
 
 // Should meet both.
 fn foo(x: &S) -> &'static S {
@@ -26,7 +28,7 @@ fn foo(x: &S) -> &'static S {
 }
 
 // Should meet both.
-fn bar<'a,'b>(x: &'a S) -> &'b S {
+fn bar<'a, 'b>(x: &'a S) -> &'b S {
     panic!()
 }
 
@@ -38,10 +40,9 @@ fn baz(x: &S) -> &S {
 fn supply_F() {
     want_F(foo);
 
-    want_F(bar); //~ ERROR mismatched types
+    want_F(bar);
 
     want_F(baz);
 }
 
-pub fn main() {
-}
+pub fn main() {}
diff --git a/src/test/ui/regions/regions-fn-subtyping-return-static.stderr b/src/test/ui/regions/regions-fn-subtyping-return-static.stderr
deleted file mode 100644
index a8a7e97e6ac..00000000000
--- a/src/test/ui/regions/regions-fn-subtyping-return-static.stderr
+++ /dev/null
@@ -1,12 +0,0 @@
-error[E0308]: mismatched types
-  --> $DIR/regions-fn-subtyping-return-static.rs:41:12
-   |
-LL |     want_F(bar);
-   |            ^^^ expected concrete lifetime, found bound lifetime parameter 'cx
-   |
-   = note: expected fn pointer `for<'cx> fn(&'cx S) -> &'cx S`
-                 found fn item `for<'a> fn(&'a S) -> &S {bar::<'_>}`
-
-error: aborting due to previous error
-
-For more information about this error, try `rustc --explain E0308`.
diff --git a/src/test/ui/regions/regions-lifetime-bounds-on-fns.nll.stderr b/src/test/ui/regions/regions-lifetime-bounds-on-fns.nll.stderr
index 434a3e47b49..37f7fcf2e33 100644
--- a/src/test/ui/regions/regions-lifetime-bounds-on-fns.nll.stderr
+++ b/src/test/ui/regions/regions-lifetime-bounds-on-fns.nll.stderr
@@ -1,14 +1,40 @@
-error[E0308]: mismatched types
-  --> $DIR/regions-lifetime-bounds-on-fns.rs:20:43
+error: lifetime may not live long enough
+  --> $DIR/regions-lifetime-bounds-on-fns.rs:8:5
+   |
+LL | fn b<'a, 'b>(x: &mut &'a isize, y: &mut &'b isize) {
+   |      --  -- lifetime `'b` defined here
+   |      |
+   |      lifetime `'a` defined here
+LL |     // Illegal now because there is no `'b:'a` declaration.
+LL |     *x = *y;
+   |     ^^^^^^^ assignment requires that `'b` must outlive `'a`
+   |
+   = help: consider adding the following bound: `'b: 'a`
+
+error: lifetime may not live long enough
+  --> $DIR/regions-lifetime-bounds-on-fns.rs:14:5
+   |
+LL | fn c<'a,'b>(x: &mut &'a isize, y: &mut &'b isize) {
+   |      -- -- lifetime `'b` defined here
+   |      |
+   |      lifetime `'a` defined here
+...
+LL |     a(x, y);
+   |     ^^^^^^^ argument requires that `'b` must outlive `'a`
+   |
+   = help: consider adding the following bound: `'b: 'a`
+
+error: higher-ranked subtype error
+  --> $DIR/regions-lifetime-bounds-on-fns.rs:20:12
    |
 LL |     let _: fn(&mut &isize, &mut &isize) = a;
-   |            ----------------------------   ^ expected concrete lifetime, found bound lifetime parameter
-   |            |
-   |            expected due to this
+   |            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: higher-ranked subtype error
+  --> $DIR/regions-lifetime-bounds-on-fns.rs:20:12
    |
-   = note: expected fn pointer `for<'r, 's, 't0, 't1> fn(&'r mut &'s isize, &'t0 mut &'t1 isize)`
-                 found fn item `for<'r, 's> fn(&'r mut &isize, &'s mut &isize) {a::<'_, '_>}`
+LL |     let _: fn(&mut &isize, &mut &isize) = a;
+   |            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
-error: aborting due to previous error
+error: aborting due to 4 previous errors
 
-For more information about this error, try `rustc --explain E0308`.
diff --git a/src/test/ui/regions/regions-lifetime-bounds-on-fns.stderr b/src/test/ui/regions/regions-lifetime-bounds-on-fns.stderr
index 01f43aeebaf..2b2dd0dbbf2 100644
--- a/src/test/ui/regions/regions-lifetime-bounds-on-fns.stderr
+++ b/src/test/ui/regions/regions-lifetime-bounds-on-fns.stderr
@@ -20,12 +20,10 @@ error[E0308]: mismatched types
   --> $DIR/regions-lifetime-bounds-on-fns.rs:20:43
    |
 LL |     let _: fn(&mut &isize, &mut &isize) = a;
-   |            ----------------------------   ^ expected concrete lifetime, found bound lifetime parameter
-   |            |
-   |            expected due to this
+   |                                           ^ one type is more general than the other
    |
    = note: expected fn pointer `for<'r, 's, 't0, 't1> fn(&'r mut &'s isize, &'t0 mut &'t1 isize)`
-                 found fn item `for<'r, 's> fn(&'r mut &isize, &'s mut &isize) {a::<'_, '_>}`
+              found fn pointer `for<'r, 's> fn(&'r mut &isize, &'s mut &isize)`
 
 error: aborting due to 3 previous errors
 
diff --git a/src/test/ui/rfc1623.nll.stderr b/src/test/ui/rfc1623.nll.stderr
new file mode 100644
index 00000000000..848d4fef1ab
--- /dev/null
+++ b/src/test/ui/rfc1623.nll.stderr
@@ -0,0 +1,68 @@
+error[E0277]: `dyn for<'a, 'b> std::ops::Fn(&'a Foo<'b>) -> &'a Foo<'b>` cannot be shared between threads safely
+  --> $DIR/rfc1623.rs:21:1
+   |
+LL | / static SOME_STRUCT: &SomeStruct = &SomeStruct {
+LL | |     foo: &Foo { bools: &[false, true] },
+LL | |     bar: &Bar { bools: &[true, true] },
+LL | |     f: &id,
+LL | |
+LL | | };
+   | |__^ `dyn for<'a, 'b> std::ops::Fn(&'a Foo<'b>) -> &'a Foo<'b>` cannot be shared between threads safely
+   |
+   = help: within `&SomeStruct`, the trait `std::marker::Sync` is not implemented for `dyn for<'a, 'b> std::ops::Fn(&'a Foo<'b>) -> &'a Foo<'b>`
+   = note: required because it appears within the type `&dyn for<'a, 'b> std::ops::Fn(&'a Foo<'b>) -> &'a Foo<'b>`
+   = note: required because it appears within the type `SomeStruct`
+   = note: required because it appears within the type `&SomeStruct`
+   = note: shared static variables must have a type that implements `Sync`
+
+error: higher-ranked subtype error
+  --> $DIR/rfc1623.rs:21:35
+   |
+LL |   static SOME_STRUCT: &SomeStruct = &SomeStruct {
+   |  ___________________________________^
+LL | |     foo: &Foo { bools: &[false, true] },
+LL | |     bar: &Bar { bools: &[true, true] },
+LL | |     f: &id,
+LL | |
+LL | | };
+   | |_^
+
+error: higher-ranked subtype error
+  --> $DIR/rfc1623.rs:21:35
+   |
+LL |   static SOME_STRUCT: &SomeStruct = &SomeStruct {
+   |  ___________________________________^
+LL | |     foo: &Foo { bools: &[false, true] },
+LL | |     bar: &Bar { bools: &[true, true] },
+LL | |     f: &id,
+LL | |
+LL | | };
+   | |_^
+
+error: higher-ranked subtype error
+  --> $DIR/rfc1623.rs:21:35
+   |
+LL |   static SOME_STRUCT: &SomeStruct = &SomeStruct {
+   |  ___________________________________^
+LL | |     foo: &Foo { bools: &[false, true] },
+LL | |     bar: &Bar { bools: &[true, true] },
+LL | |     f: &id,
+LL | |
+LL | | };
+   | |_^
+
+error: higher-ranked subtype error
+  --> $DIR/rfc1623.rs:21:35
+   |
+LL |   static SOME_STRUCT: &SomeStruct = &SomeStruct {
+   |  ___________________________________^
+LL | |     foo: &Foo { bools: &[false, true] },
+LL | |     bar: &Bar { bools: &[true, true] },
+LL | |     f: &id,
+LL | |
+LL | | };
+   | |_^
+
+error: aborting due to 5 previous errors
+
+For more information about this error, try `rustc --explain E0277`.
diff --git a/src/test/ui/rfc1623.rs b/src/test/ui/rfc1623.rs
index 55f5d0b94dc..aa6b1c0012c 100644
--- a/src/test/ui/rfc1623.rs
+++ b/src/test/ui/rfc1623.rs
@@ -8,23 +8,21 @@ fn non_elidable<'a, 'b>(a: &'a u8, b: &'b u8) -> &'a u8 {
 static NON_ELIDABLE_FN: &for<'a> fn(&'a u8, &'a u8) -> &'a u8 =
     &(non_elidable as for<'a> fn(&'a u8, &'a u8) -> &'a u8);
 
-
 struct SomeStruct<'x, 'y, 'z: 'x> {
     foo: &'x Foo<'z>,
     bar: &'x Bar<'z>,
-    f: &'y dyn for<'a, 'b> Fn(&'a Foo<'b>) -> &'a Bar<'b>,
+    f: &'y dyn for<'a, 'b> Fn(&'a Foo<'b>) -> &'a Foo<'b>,
 }
 
 fn id<T>(t: T) -> T {
     t
 }
 
-static SOME_STRUCT: &SomeStruct = SomeStruct { //~ ERROR mismatched types
+static SOME_STRUCT: &SomeStruct = &SomeStruct {
     foo: &Foo { bools: &[false, true] },
     bar: &Bar { bools: &[true, true] },
     f: &id,
-    //~^ ERROR type mismatch in function arguments
-    //~| ERROR type mismatch resolving
+    //~^ ERROR mismatched types
 };
 
 // very simple test for a 'static static with default lifetime
diff --git a/src/test/ui/rfc1623.stderr b/src/test/ui/rfc1623.stderr
index ca956004ef7..2efc58ac381 100644
--- a/src/test/ui/rfc1623.stderr
+++ b/src/test/ui/rfc1623.stderr
@@ -1,46 +1,12 @@
 error[E0308]: mismatched types
-  --> $DIR/rfc1623.rs:22:35
-   |
-LL |   static SOME_STRUCT: &SomeStruct = SomeStruct {
-   |  ___________________________________^
-LL | |     foo: &Foo { bools: &[false, true] },
-LL | |     bar: &Bar { bools: &[true, true] },
-LL | |     f: &id,
-LL | |
-LL | |
-LL | | };
-   | |_^ expected `&SomeStruct<'static, 'static, 'static>`, found struct `SomeStruct`
-   |
-help: consider borrowing here
-   |
-LL | static SOME_STRUCT: &SomeStruct = &SomeStruct {
-LL |     foo: &Foo { bools: &[false, true] },
-LL |     bar: &Bar { bools: &[true, true] },
-LL |     f: &id,
-LL |
-LL |
- ...
-
-error[E0631]: type mismatch in function arguments
-  --> $DIR/rfc1623.rs:25:8
-   |
-LL | fn id<T>(t: T) -> T {
-   | ------------------- found signature of `fn(_) -> _`
-...
-LL |     f: &id,
-   |        ^^^ expected signature of `for<'a, 'b> fn(&'a Foo<'b>) -> _`
-   |
-   = note: required for the cast to the object type `dyn for<'a, 'b> std::ops::Fn(&'a Foo<'b>) -> &'a Foo<'b>`
-
-error[E0271]: type mismatch resolving `for<'a, 'b> <fn(_) -> _ {id::<_>} as std::ops::FnOnce<(&'a Foo<'b>,)>>::Output == &'a Foo<'b>`
-  --> $DIR/rfc1623.rs:25:8
+  --> $DIR/rfc1623.rs:24:8
    |
 LL |     f: &id,
-   |        ^^^ expected bound lifetime parameter 'a, found concrete lifetime
+   |        ^^^ one type is more general than the other
    |
-   = note: required for the cast to the object type `dyn for<'a, 'b> std::ops::Fn(&'a Foo<'b>) -> &'a Foo<'b>`
+   = note: expected type `std::ops::FnOnce<(&'a Foo<'b>,)>`
+              found type `std::ops::FnOnce<(&Foo<'_>,)>`
 
-error: aborting due to 3 previous errors
+error: aborting due to previous error
 
-Some errors have detailed explanations: E0271, E0308, E0631.
-For more information about an error, try `rustc --explain E0271`.
+For more information about this error, try `rustc --explain E0308`.
diff --git a/src/test/ui/type-alias-impl-trait/issue-57611-trait-alias.nll.stderr b/src/test/ui/type-alias-impl-trait/issue-57611-trait-alias.nll.stderr
new file mode 100644
index 00000000000..8c9cb742fac
--- /dev/null
+++ b/src/test/ui/type-alias-impl-trait/issue-57611-trait-alias.nll.stderr
@@ -0,0 +1,14 @@
+error: higher-ranked subtype error
+  --> $DIR/issue-57611-trait-alias.rs:21:9
+   |
+LL |         |x| x
+   |         ^^^^^
+
+error: higher-ranked subtype error
+  --> $DIR/issue-57611-trait-alias.rs:21:9
+   |
+LL |         |x| x
+   |         ^^^^^
+
+error: aborting due to 2 previous errors
+
diff --git a/src/test/ui/type-alias-impl-trait/issue-57611-trait-alias.rs b/src/test/ui/type-alias-impl-trait/issue-57611-trait-alias.rs
index 1c2051e7eae..41e019247c9 100644
--- a/src/test/ui/type-alias-impl-trait/issue-57611-trait-alias.rs
+++ b/src/test/ui/type-alias-impl-trait/issue-57611-trait-alias.rs
@@ -14,8 +14,8 @@ trait Foo {
 struct X;
 
 impl Foo for X {
-    type Bar = impl Baz<Self, Self>; //~ ERROR type mismatch in closure arguments
-    //~^ ERROR type mismatch resolving
+    type Bar = impl Baz<Self, Self>;
+    //~^ ERROR mismatched types
 
     fn bar(&self) -> Self::Bar {
         |x| x
diff --git a/src/test/ui/type-alias-impl-trait/issue-57611-trait-alias.stderr b/src/test/ui/type-alias-impl-trait/issue-57611-trait-alias.stderr
index cc121ac89fb..cd637056c94 100644
--- a/src/test/ui/type-alias-impl-trait/issue-57611-trait-alias.stderr
+++ b/src/test/ui/type-alias-impl-trait/issue-57611-trait-alias.stderr
@@ -1,23 +1,12 @@
-error[E0631]: type mismatch in closure arguments
+error[E0308]: mismatched types
   --> $DIR/issue-57611-trait-alias.rs:17:16
    |
 LL |     type Bar = impl Baz<Self, Self>;
-   |                ^^^^^^^^^^^^^^^^^^^^ expected signature of `for<'r> fn(&'r X) -> _`
-...
-LL |         |x| x
-   |         ----- found signature of `fn(_) -> _`
+   |                ^^^^^^^^^^^^^^^^^^^^ one type is more general than the other
    |
-   = note: the return type of a function must have a statically known size
+   = note: expected type `std::ops::FnOnce<(&X,)>`
+              found type `std::ops::FnOnce<(&X,)>`
 
-error[E0271]: type mismatch resolving `for<'r> <[closure@$DIR/issue-57611-trait-alias.rs:21:9: 21:14] as std::ops::FnOnce<(&'r X,)>>::Output == &'r X`
-  --> $DIR/issue-57611-trait-alias.rs:17:16
-   |
-LL |     type Bar = impl Baz<Self, Self>;
-   |                ^^^^^^^^^^^^^^^^^^^^ expected bound lifetime parameter, found concrete lifetime
-   |
-   = note: the return type of a function must have a statically known size
-
-error: aborting due to 2 previous errors
+error: aborting due to previous error
 
-Some errors have detailed explanations: E0271, E0631.
-For more information about an error, try `rustc --explain E0271`.
+For more information about this error, try `rustc --explain E0308`.
diff --git a/src/test/ui/unboxed-closures/unboxed-closures-unsafe-extern-fn.rs b/src/test/ui/unboxed-closures/unboxed-closures-unsafe-extern-fn.rs
index a6e26614a6a..e2082d4f78e 100644
--- a/src/test/ui/unboxed-closures/unboxed-closures-unsafe-extern-fn.rs
+++ b/src/test/ui/unboxed-closures/unboxed-closures-unsafe-extern-fn.rs
@@ -1,23 +1,29 @@
 // Tests that unsafe extern fn pointers do not implement any Fn traits.
 
-use std::ops::{Fn,FnMut,FnOnce};
+use std::ops::{Fn, FnMut, FnOnce};
 
-unsafe fn square(x: &isize) -> isize { (*x) * (*x) }
+unsafe fn square(x: &isize) -> isize {
+    (*x) * (*x)
+}
 
-fn call_it<F:Fn(&isize)->isize>(_: &F, _: isize) -> isize { 0 }
-fn call_it_mut<F:FnMut(&isize)->isize>(_: &mut F, _: isize) -> isize { 0 }
-fn call_it_once<F:FnOnce(&isize)->isize>(_: F, _: isize) -> isize { 0 }
+fn call_it<F: Fn(&isize) -> isize>(_: &F, _: isize) -> isize {
+    0
+}
+fn call_it_mut<F: FnMut(&isize) -> isize>(_: &mut F, _: isize) -> isize {
+    0
+}
+fn call_it_once<F: FnOnce(&isize) -> isize>(_: F, _: isize) -> isize {
+    0
+}
 
 fn a() {
     let x = call_it(&square, 22);
     //~^ ERROR E0277
-    //~| ERROR expected
 }
 
 fn b() {
     let y = call_it_mut(&mut square, 22);
     //~^ ERROR E0277
-    //~| ERROR expected
 }
 
 fn c() {
@@ -25,4 +31,4 @@ fn c() {
     //~^ ERROR E0277
 }
 
-fn main() { }
+fn main() {}
diff --git a/src/test/ui/unboxed-closures/unboxed-closures-unsafe-extern-fn.stderr b/src/test/ui/unboxed-closures/unboxed-closures-unsafe-extern-fn.stderr
index b9ee9e46020..b06f745e7c1 100644
--- a/src/test/ui/unboxed-closures/unboxed-closures-unsafe-extern-fn.stderr
+++ b/src/test/ui/unboxed-closures/unboxed-closures-unsafe-extern-fn.stderr
@@ -1,30 +1,19 @@
 error[E0277]: expected a `std::ops::Fn<(&isize,)>` closure, found `for<'r> unsafe fn(&'r isize) -> isize {square}`
-  --> $DIR/unboxed-closures-unsafe-extern-fn.rs:12:21
+  --> $DIR/unboxed-closures-unsafe-extern-fn.rs:20:21
    |
-LL | fn call_it<F:Fn(&isize)->isize>(_: &F, _: isize) -> isize { 0 }
-   |              ----------------- required by this bound in `call_it`
+LL | fn call_it<F: Fn(&isize) -> isize>(_: &F, _: isize) -> isize {
+   |               ------------------- required by this bound in `call_it`
 ...
 LL |     let x = call_it(&square, 22);
    |                     ^^^^^^^ expected an `Fn<(&isize,)>` closure, found `for<'r> unsafe fn(&'r isize) -> isize {square}`
    |
    = help: the trait `for<'r> std::ops::Fn<(&'r isize,)>` is not implemented for `for<'r> unsafe fn(&'r isize) -> isize {square}`
 
-error[E0277]: expected a `std::ops::FnOnce<(&isize,)>` closure, found `for<'r> unsafe fn(&'r isize) -> isize {square}`
-  --> $DIR/unboxed-closures-unsafe-extern-fn.rs:12:21
-   |
-LL | fn call_it<F:Fn(&isize)->isize>(_: &F, _: isize) -> isize { 0 }
-   |                          ----- required by this bound in `call_it`
-...
-LL |     let x = call_it(&square, 22);
-   |                     ^^^^^^^ expected an `FnOnce<(&isize,)>` closure, found `for<'r> unsafe fn(&'r isize) -> isize {square}`
-   |
-   = help: the trait `std::ops::FnOnce<(&isize,)>` is not implemented for `for<'r> unsafe fn(&'r isize) -> isize {square}`
-
 error[E0277]: expected a `std::ops::FnMut<(&isize,)>` closure, found `for<'r> unsafe fn(&'r isize) -> isize {square}`
-  --> $DIR/unboxed-closures-unsafe-extern-fn.rs:18:25
+  --> $DIR/unboxed-closures-unsafe-extern-fn.rs:25:25
    |
-LL | fn call_it_mut<F:FnMut(&isize)->isize>(_: &mut F, _: isize) -> isize { 0 }
-   |                  -------------------- required by this bound in `call_it_mut`
+LL | fn call_it_mut<F: FnMut(&isize) -> isize>(_: &mut F, _: isize) -> isize {
+   |                   ---------------------- required by this bound in `call_it_mut`
 ...
 LL |     let y = call_it_mut(&mut square, 22);
    |                         ^^^^^^^^^^^ expected an `FnMut<(&isize,)>` closure, found `for<'r> unsafe fn(&'r isize) -> isize {square}`
@@ -32,27 +21,16 @@ LL |     let y = call_it_mut(&mut square, 22);
    = help: the trait `for<'r> std::ops::FnMut<(&'r isize,)>` is not implemented for `for<'r> unsafe fn(&'r isize) -> isize {square}`
 
 error[E0277]: expected a `std::ops::FnOnce<(&isize,)>` closure, found `for<'r> unsafe fn(&'r isize) -> isize {square}`
-  --> $DIR/unboxed-closures-unsafe-extern-fn.rs:18:25
-   |
-LL | fn call_it_mut<F:FnMut(&isize)->isize>(_: &mut F, _: isize) -> isize { 0 }
-   |                                 ----- required by this bound in `call_it_mut`
-...
-LL |     let y = call_it_mut(&mut square, 22);
-   |                         ^^^^^^^^^^^ expected an `FnOnce<(&isize,)>` closure, found `for<'r> unsafe fn(&'r isize) -> isize {square}`
-   |
-   = help: the trait `std::ops::FnOnce<(&isize,)>` is not implemented for `for<'r> unsafe fn(&'r isize) -> isize {square}`
-
-error[E0277]: expected a `std::ops::FnOnce<(&isize,)>` closure, found `for<'r> unsafe fn(&'r isize) -> isize {square}`
-  --> $DIR/unboxed-closures-unsafe-extern-fn.rs:24:26
+  --> $DIR/unboxed-closures-unsafe-extern-fn.rs:30:26
    |
-LL | fn call_it_once<F:FnOnce(&isize)->isize>(_: F, _: isize) -> isize { 0 }
-   |                                   ----- required by this bound in `call_it_once`
+LL | fn call_it_once<F: FnOnce(&isize) -> isize>(_: F, _: isize) -> isize {
+   |                    ----------------------- required by this bound in `call_it_once`
 ...
 LL |     let z = call_it_once(square, 22);
    |                          ^^^^^^ expected an `FnOnce<(&isize,)>` closure, found `for<'r> unsafe fn(&'r isize) -> isize {square}`
    |
-   = help: the trait `std::ops::FnOnce<(&isize,)>` is not implemented for `for<'r> unsafe fn(&'r isize) -> isize {square}`
+   = help: the trait `for<'r> std::ops::FnOnce<(&'r isize,)>` is not implemented for `for<'r> unsafe fn(&'r isize) -> isize {square}`
 
-error: aborting due to 5 previous errors
+error: aborting due to 3 previous errors
 
 For more information about this error, try `rustc --explain E0277`.
diff --git a/src/test/ui/unboxed-closures/unboxed-closures-wrong-abi.rs b/src/test/ui/unboxed-closures/unboxed-closures-wrong-abi.rs
index dd3b1afc39f..dd76c597d28 100644
--- a/src/test/ui/unboxed-closures/unboxed-closures-wrong-abi.rs
+++ b/src/test/ui/unboxed-closures/unboxed-closures-wrong-abi.rs
@@ -1,23 +1,29 @@
 // Tests that unsafe extern fn pointers do not implement any Fn traits.
 
-use std::ops::{Fn,FnMut,FnOnce};
+use std::ops::{Fn, FnMut, FnOnce};
 
-extern "C" fn square(x: &isize) -> isize { (*x) * (*x) }
+extern "C" fn square(x: &isize) -> isize {
+    (*x) * (*x)
+}
 
-fn call_it<F:Fn(&isize)->isize>(_: &F, _: isize) -> isize { 0 }
-fn call_it_mut<F:FnMut(&isize)->isize>(_: &mut F, _: isize) -> isize { 0 }
-fn call_it_once<F:FnOnce(&isize)->isize>(_: F, _: isize) -> isize { 0 }
+fn call_it<F: Fn(&isize) -> isize>(_: &F, _: isize) -> isize {
+    0
+}
+fn call_it_mut<F: FnMut(&isize) -> isize>(_: &mut F, _: isize) -> isize {
+    0
+}
+fn call_it_once<F: FnOnce(&isize) -> isize>(_: F, _: isize) -> isize {
+    0
+}
 
 fn a() {
     let x = call_it(&square, 22);
     //~^ ERROR E0277
-    //~| ERROR expected
 }
 
 fn b() {
     let y = call_it_mut(&mut square, 22);
     //~^ ERROR E0277
-    //~| ERROR expected
 }
 
 fn c() {
@@ -25,4 +31,4 @@ fn c() {
     //~^ ERROR E0277
 }
 
-fn main() { }
+fn main() {}
diff --git a/src/test/ui/unboxed-closures/unboxed-closures-wrong-abi.stderr b/src/test/ui/unboxed-closures/unboxed-closures-wrong-abi.stderr
index 654b626cf65..8f6945cda80 100644
--- a/src/test/ui/unboxed-closures/unboxed-closures-wrong-abi.stderr
+++ b/src/test/ui/unboxed-closures/unboxed-closures-wrong-abi.stderr
@@ -1,30 +1,19 @@
 error[E0277]: expected a `std::ops::Fn<(&isize,)>` closure, found `for<'r> extern "C" fn(&'r isize) -> isize {square}`
-  --> $DIR/unboxed-closures-wrong-abi.rs:12:21
+  --> $DIR/unboxed-closures-wrong-abi.rs:20:21
    |
-LL | fn call_it<F:Fn(&isize)->isize>(_: &F, _: isize) -> isize { 0 }
-   |              ----------------- required by this bound in `call_it`
+LL | fn call_it<F: Fn(&isize) -> isize>(_: &F, _: isize) -> isize {
+   |               ------------------- required by this bound in `call_it`
 ...
 LL |     let x = call_it(&square, 22);
    |                     ^^^^^^^ expected an `Fn<(&isize,)>` closure, found `for<'r> extern "C" fn(&'r isize) -> isize {square}`
    |
    = help: the trait `for<'r> std::ops::Fn<(&'r isize,)>` is not implemented for `for<'r> extern "C" fn(&'r isize) -> isize {square}`
 
-error[E0277]: expected a `std::ops::FnOnce<(&isize,)>` closure, found `for<'r> extern "C" fn(&'r isize) -> isize {square}`
-  --> $DIR/unboxed-closures-wrong-abi.rs:12:21
-   |
-LL | fn call_it<F:Fn(&isize)->isize>(_: &F, _: isize) -> isize { 0 }
-   |                          ----- required by this bound in `call_it`
-...
-LL |     let x = call_it(&square, 22);
-   |                     ^^^^^^^ expected an `FnOnce<(&isize,)>` closure, found `for<'r> extern "C" fn(&'r isize) -> isize {square}`
-   |
-   = help: the trait `std::ops::FnOnce<(&isize,)>` is not implemented for `for<'r> extern "C" fn(&'r isize) -> isize {square}`
-
 error[E0277]: expected a `std::ops::FnMut<(&isize,)>` closure, found `for<'r> extern "C" fn(&'r isize) -> isize {square}`
-  --> $DIR/unboxed-closures-wrong-abi.rs:18:25
+  --> $DIR/unboxed-closures-wrong-abi.rs:25:25
    |
-LL | fn call_it_mut<F:FnMut(&isize)->isize>(_: &mut F, _: isize) -> isize { 0 }
-   |                  -------------------- required by this bound in `call_it_mut`
+LL | fn call_it_mut<F: FnMut(&isize) -> isize>(_: &mut F, _: isize) -> isize {
+   |                   ---------------------- required by this bound in `call_it_mut`
 ...
 LL |     let y = call_it_mut(&mut square, 22);
    |                         ^^^^^^^^^^^ expected an `FnMut<(&isize,)>` closure, found `for<'r> extern "C" fn(&'r isize) -> isize {square}`
@@ -32,27 +21,16 @@ LL |     let y = call_it_mut(&mut square, 22);
    = help: the trait `for<'r> std::ops::FnMut<(&'r isize,)>` is not implemented for `for<'r> extern "C" fn(&'r isize) -> isize {square}`
 
 error[E0277]: expected a `std::ops::FnOnce<(&isize,)>` closure, found `for<'r> extern "C" fn(&'r isize) -> isize {square}`
-  --> $DIR/unboxed-closures-wrong-abi.rs:18:25
-   |
-LL | fn call_it_mut<F:FnMut(&isize)->isize>(_: &mut F, _: isize) -> isize { 0 }
-   |                                 ----- required by this bound in `call_it_mut`
-...
-LL |     let y = call_it_mut(&mut square, 22);
-   |                         ^^^^^^^^^^^ expected an `FnOnce<(&isize,)>` closure, found `for<'r> extern "C" fn(&'r isize) -> isize {square}`
-   |
-   = help: the trait `std::ops::FnOnce<(&isize,)>` is not implemented for `for<'r> extern "C" fn(&'r isize) -> isize {square}`
-
-error[E0277]: expected a `std::ops::FnOnce<(&isize,)>` closure, found `for<'r> extern "C" fn(&'r isize) -> isize {square}`
-  --> $DIR/unboxed-closures-wrong-abi.rs:24:26
+  --> $DIR/unboxed-closures-wrong-abi.rs:30:26
    |
-LL | fn call_it_once<F:FnOnce(&isize)->isize>(_: F, _: isize) -> isize { 0 }
-   |                                   ----- required by this bound in `call_it_once`
+LL | fn call_it_once<F: FnOnce(&isize) -> isize>(_: F, _: isize) -> isize {
+   |                    ----------------------- required by this bound in `call_it_once`
 ...
 LL |     let z = call_it_once(square, 22);
    |                          ^^^^^^ expected an `FnOnce<(&isize,)>` closure, found `for<'r> extern "C" fn(&'r isize) -> isize {square}`
    |
-   = help: the trait `std::ops::FnOnce<(&isize,)>` is not implemented for `for<'r> extern "C" fn(&'r isize) -> isize {square}`
+   = help: the trait `for<'r> std::ops::FnOnce<(&'r isize,)>` is not implemented for `for<'r> extern "C" fn(&'r isize) -> isize {square}`
 
-error: aborting due to 5 previous errors
+error: aborting due to 3 previous errors
 
 For more information about this error, try `rustc --explain E0277`.
diff --git a/src/test/ui/unboxed-closures/unboxed-closures-wrong-arg-type-extern-fn.rs b/src/test/ui/unboxed-closures/unboxed-closures-wrong-arg-type-extern-fn.rs
index c689d792661..02e8b7b47ae 100644
--- a/src/test/ui/unboxed-closures/unboxed-closures-wrong-arg-type-extern-fn.rs
+++ b/src/test/ui/unboxed-closures/unboxed-closures-wrong-arg-type-extern-fn.rs
@@ -1,24 +1,30 @@
 // Tests that unsafe extern fn pointers do not implement any Fn traits.
 
-use std::ops::{Fn,FnMut,FnOnce};
+use std::ops::{Fn, FnMut, FnOnce};
 
-unsafe fn square(x: isize) -> isize { x * x }
+unsafe fn square(x: isize) -> isize {
+    x * x
+}
 // note: argument type here is `isize`, not `&isize`
 
-fn call_it<F:Fn(&isize)->isize>(_: &F, _: isize) -> isize { 0 }
-fn call_it_mut<F:FnMut(&isize)->isize>(_: &mut F, _: isize) -> isize { 0 }
-fn call_it_once<F:FnOnce(&isize)->isize>(_: F, _: isize) -> isize { 0 }
+fn call_it<F: Fn(&isize) -> isize>(_: &F, _: isize) -> isize {
+    0
+}
+fn call_it_mut<F: FnMut(&isize) -> isize>(_: &mut F, _: isize) -> isize {
+    0
+}
+fn call_it_once<F: FnOnce(&isize) -> isize>(_: F, _: isize) -> isize {
+    0
+}
 
 fn a() {
     let x = call_it(&square, 22);
     //~^ ERROR E0277
-    //~| ERROR expected
 }
 
 fn b() {
     let y = call_it_mut(&mut square, 22);
     //~^ ERROR E0277
-    //~| ERROR expected
 }
 
 fn c() {
@@ -26,4 +32,4 @@ fn c() {
     //~^ ERROR E0277
 }
 
-fn main() { }
+fn main() {}
diff --git a/src/test/ui/unboxed-closures/unboxed-closures-wrong-arg-type-extern-fn.stderr b/src/test/ui/unboxed-closures/unboxed-closures-wrong-arg-type-extern-fn.stderr
index 434c8a579f6..93a645b485e 100644
--- a/src/test/ui/unboxed-closures/unboxed-closures-wrong-arg-type-extern-fn.stderr
+++ b/src/test/ui/unboxed-closures/unboxed-closures-wrong-arg-type-extern-fn.stderr
@@ -1,30 +1,19 @@
 error[E0277]: expected a `std::ops::Fn<(&isize,)>` closure, found `unsafe fn(isize) -> isize {square}`
-  --> $DIR/unboxed-closures-wrong-arg-type-extern-fn.rs:13:21
+  --> $DIR/unboxed-closures-wrong-arg-type-extern-fn.rs:21:21
    |
-LL | fn call_it<F:Fn(&isize)->isize>(_: &F, _: isize) -> isize { 0 }
-   |              ----------------- required by this bound in `call_it`
+LL | fn call_it<F: Fn(&isize) -> isize>(_: &F, _: isize) -> isize {
+   |               ------------------- required by this bound in `call_it`
 ...
 LL |     let x = call_it(&square, 22);
    |                     ^^^^^^^ expected an `Fn<(&isize,)>` closure, found `unsafe fn(isize) -> isize {square}`
    |
    = help: the trait `for<'r> std::ops::Fn<(&'r isize,)>` is not implemented for `unsafe fn(isize) -> isize {square}`
 
-error[E0277]: expected a `std::ops::FnOnce<(&isize,)>` closure, found `unsafe fn(isize) -> isize {square}`
-  --> $DIR/unboxed-closures-wrong-arg-type-extern-fn.rs:13:21
-   |
-LL | fn call_it<F:Fn(&isize)->isize>(_: &F, _: isize) -> isize { 0 }
-   |                          ----- required by this bound in `call_it`
-...
-LL |     let x = call_it(&square, 22);
-   |                     ^^^^^^^ expected an `FnOnce<(&isize,)>` closure, found `unsafe fn(isize) -> isize {square}`
-   |
-   = help: the trait `std::ops::FnOnce<(&isize,)>` is not implemented for `unsafe fn(isize) -> isize {square}`
-
 error[E0277]: expected a `std::ops::FnMut<(&isize,)>` closure, found `unsafe fn(isize) -> isize {square}`
-  --> $DIR/unboxed-closures-wrong-arg-type-extern-fn.rs:19:25
+  --> $DIR/unboxed-closures-wrong-arg-type-extern-fn.rs:26:25
    |
-LL | fn call_it_mut<F:FnMut(&isize)->isize>(_: &mut F, _: isize) -> isize { 0 }
-   |                  -------------------- required by this bound in `call_it_mut`
+LL | fn call_it_mut<F: FnMut(&isize) -> isize>(_: &mut F, _: isize) -> isize {
+   |                   ---------------------- required by this bound in `call_it_mut`
 ...
 LL |     let y = call_it_mut(&mut square, 22);
    |                         ^^^^^^^^^^^ expected an `FnMut<(&isize,)>` closure, found `unsafe fn(isize) -> isize {square}`
@@ -32,27 +21,16 @@ LL |     let y = call_it_mut(&mut square, 22);
    = help: the trait `for<'r> std::ops::FnMut<(&'r isize,)>` is not implemented for `unsafe fn(isize) -> isize {square}`
 
 error[E0277]: expected a `std::ops::FnOnce<(&isize,)>` closure, found `unsafe fn(isize) -> isize {square}`
-  --> $DIR/unboxed-closures-wrong-arg-type-extern-fn.rs:19:25
-   |
-LL | fn call_it_mut<F:FnMut(&isize)->isize>(_: &mut F, _: isize) -> isize { 0 }
-   |                                 ----- required by this bound in `call_it_mut`
-...
-LL |     let y = call_it_mut(&mut square, 22);
-   |                         ^^^^^^^^^^^ expected an `FnOnce<(&isize,)>` closure, found `unsafe fn(isize) -> isize {square}`
-   |
-   = help: the trait `std::ops::FnOnce<(&isize,)>` is not implemented for `unsafe fn(isize) -> isize {square}`
-
-error[E0277]: expected a `std::ops::FnOnce<(&isize,)>` closure, found `unsafe fn(isize) -> isize {square}`
-  --> $DIR/unboxed-closures-wrong-arg-type-extern-fn.rs:25:26
+  --> $DIR/unboxed-closures-wrong-arg-type-extern-fn.rs:31:26
    |
-LL | fn call_it_once<F:FnOnce(&isize)->isize>(_: F, _: isize) -> isize { 0 }
-   |                                   ----- required by this bound in `call_it_once`
+LL | fn call_it_once<F: FnOnce(&isize) -> isize>(_: F, _: isize) -> isize {
+   |                    ----------------------- required by this bound in `call_it_once`
 ...
 LL |     let z = call_it_once(square, 22);
    |                          ^^^^^^ expected an `FnOnce<(&isize,)>` closure, found `unsafe fn(isize) -> isize {square}`
    |
-   = help: the trait `std::ops::FnOnce<(&isize,)>` is not implemented for `unsafe fn(isize) -> isize {square}`
+   = help: the trait `for<'r> std::ops::FnOnce<(&'r isize,)>` is not implemented for `unsafe fn(isize) -> isize {square}`
 
-error: aborting due to 5 previous errors
+error: aborting due to 3 previous errors
 
 For more information about this error, try `rustc --explain E0277`.
diff --git a/src/test/ui/where-clauses/where-for-self-2.nll.stderr b/src/test/ui/where-clauses/where-for-self-2.nll.stderr
new file mode 100644
index 00000000000..d0c476dc6ec
--- /dev/null
+++ b/src/test/ui/where-clauses/where-for-self-2.nll.stderr
@@ -0,0 +1,8 @@
+error: higher-ranked subtype error
+  --> $DIR/where-for-self-2.rs:23:5
+   |
+LL |     foo(&X);
+   |     ^^^^^^^
+
+error: aborting due to previous error
+
diff --git a/src/test/ui/where-clauses/where-for-self-2.rs b/src/test/ui/where-clauses/where-for-self-2.rs
index 31174fd4cf1..37c6954fd52 100644
--- a/src/test/ui/where-clauses/where-for-self-2.rs
+++ b/src/test/ui/where-clauses/where-for-self-2.rs
@@ -14,9 +14,11 @@ impl Bar for &'static u32 {
 }
 
 fn foo<T>(x: &T)
-    where for<'a> &'a T: Bar
-{}
+where
+    for<'a> &'a T: Bar,
+{
+}
 
 fn main() {
-    foo(&X); //~ ERROR trait bound
+    foo(&X); //~ ERROR implementation of `Bar` is not general enough
 }
diff --git a/src/test/ui/where-clauses/where-for-self-2.stderr b/src/test/ui/where-clauses/where-for-self-2.stderr
index 9976243b200..30eb78b2da4 100644
--- a/src/test/ui/where-clauses/where-for-self-2.stderr
+++ b/src/test/ui/where-clauses/where-for-self-2.stderr
@@ -1,17 +1,16 @@
-error[E0277]: the trait bound `for<'a> &'a _: Bar` is not satisfied
-  --> $DIR/where-for-self-2.rs:21:5
+error: implementation of `Bar` is not general enough
+  --> $DIR/where-for-self-2.rs:23:5
    |
-LL | fn foo<T>(x: &T)
-   |    --- required by a bound in this
-LL |     where for<'a> &'a T: Bar
-   |                          --- required by this bound in `foo`
+LL | / trait Bar {
+LL | |     fn bar(&self);
+LL | | }
+   | |_- trait `Bar` defined here
 ...
-LL |     foo(&X);
-   |     ^^^ the trait `for<'a> Bar` is not implemented for `&'a _`
+LL |       foo(&X);
+   |       ^^^ implementation of `Bar` is not general enough
    |
-   = help: the following implementations were found:
-             <&'static u32 as Bar>
+   = note: `Bar` would have to be implemented for the type `&'0 u32`, for any lifetime `'0`...
+   = note: ...but `Bar` is actually implemented for the type `&'1 u32`, for some specific lifetime `'1`
 
 error: aborting due to previous error
 
-For more information about this error, try `rustc --explain E0277`.