about summary refs log tree commit diff
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2019-02-21 21:35:21 +0000
committerbors <bors@rust-lang.org>2019-02-21 21:35:21 +0000
commit8a1d0defdf34f017ca5aeebfe85924c1ac028c81 (patch)
tree112aee9acee8d1d2efe74ae96e5a811075958d96
parent633d75ac17fa1a1bdaf5923895e6d5b7f3040c92 (diff)
parent33d3598e3b57c0fcfd36f34c346847bcc4edd3d2 (diff)
downloadrust-8a1d0defdf34f017ca5aeebfe85924c1ac028c81.tar.gz
rust-8a1d0defdf34f017ca5aeebfe85924c1ac028c81.zip
Auto merge of #58592 - nikomatsakis:universe-leak-check, r=aturon
Re-implement leak check in terms of universes

This PR temporarily restores the leak-check, but implemented in terms of universes. This is not because the leak check behavior was necessarily **correct**, but because (a) we may want to have a transition period and because (b) we want to have more breathing room to work through the full implications of handling higher-ranked types correctly. Note that this PR builds atop https://github.com/rust-lang/rust/pull/58056.

Fixes #58451
Fixes #46989
Fixes #57639

r? @aturon
cc @arielb1, @lqd

~~Temporary note: I've not finished running `./x.py test` locally -- I'm confident a lot of error messages in tests will need updating. I sort of expect them to revert to the older, (imo) less good error messages, which is mildly unfortunate. There might be a way to preserve the new error messages, not sure.~~
-rw-r--r--src/librustc/infer/higher_ranked/mod.rs66
-rw-r--r--src/librustc/infer/mod.rs47
-rw-r--r--src/librustc/infer/region_constraints/leak_check.rs174
-rw-r--r--src/librustc/infer/region_constraints/mod.rs2
-rw-r--r--src/librustc/traits/auto_trait.rs8
-rw-r--r--src/librustc/traits/error_reporting.rs11
-rw-r--r--src/librustc/traits/fulfill.rs6
-rw-r--r--src/librustc/traits/project.rs14
-rw-r--r--src/librustc/traits/select.rs84
-rw-r--r--src/librustc/ty/error.rs16
-rw-r--r--src/librustc/ty/structural_impls.rs8
-rw-r--r--src/test/ui/anonymous-higher-ranked-lifetime.rs11
-rw-r--r--src/test/ui/anonymous-higher-ranked-lifetime.stderr196
-rw-r--r--src/test/ui/associated-types/associated-types-eq-hr.rs8
-rw-r--r--src/test/ui/associated-types/associated-types-eq-hr.stderr95
-rw-r--r--src/test/ui/associated-types/higher-ranked-projection.bad.stderr15
-rw-r--r--src/test/ui/associated-types/higher-ranked-projection.good.stderr2
-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.rs6
-rw-r--r--src/test/ui/closure-expected-type/expect-fn-supply-fn.stderr57
-rw-r--r--src/test/ui/coherence/coherence-subtyping.old.stderr14
-rw-r--r--src/test/ui/coherence/coherence-subtyping.re.stderr14
-rw-r--r--src/test/ui/coherence/coherence-subtyping.rs6
-rw-r--r--src/test/ui/hr-subtype/hr-subtype.bound_a_b_ret_a_vs_bound_a_ret_a.stderr2
-rw-r--r--src/test/ui/hr-subtype/hr-subtype.bound_a_b_vs_bound_a.stderr22
-rw-r--r--src/test/ui/hr-subtype/hr-subtype.bound_a_vs_bound_a.stderr6
-rw-r--r--src/test/ui/hr-subtype/hr-subtype.bound_a_vs_bound_b.stderr6
-rw-r--r--src/test/ui/hr-subtype/hr-subtype.bound_a_vs_free_x.stderr2
-rw-r--r--src/test/ui/hr-subtype/hr-subtype.bound_co_a_b_vs_bound_co_a.stderr22
-rw-r--r--src/test/ui/hr-subtype/hr-subtype.bound_co_a_co_b_ret_contra_a.stderr22
-rw-r--r--src/test/ui/hr-subtype/hr-subtype.bound_co_a_vs_bound_co_b.stderr6
-rw-r--r--src/test/ui/hr-subtype/hr-subtype.bound_contra_a_contra_b_ret_co_a.stderr22
-rw-r--r--src/test/ui/hr-subtype/hr-subtype.bound_inv_a_b_vs_bound_inv_a.stderr2
-rw-r--r--src/test/ui/hr-subtype/hr-subtype.bound_inv_a_vs_bound_inv_b.stderr6
-rw-r--r--src/test/ui/hr-subtype/hr-subtype.free_x_vs_free_x.stderr6
-rw-r--r--src/test/ui/hr-subtype/hr-subtype.rs8
-rw-r--r--src/test/ui/hrtb/hrtb-conflate-regions.stderr18
-rw-r--r--src/test/ui/hrtb/hrtb-exists-forall-fn.stderr2
-rw-r--r--src/test/ui/hrtb/hrtb-exists-forall-trait-contravariant.rs7
-rw-r--r--src/test/ui/hrtb/hrtb-exists-forall-trait-contravariant.stderr21
-rw-r--r--src/test/ui/hrtb/hrtb-exists-forall-trait-covariant.rs7
-rw-r--r--src/test/ui/hrtb/hrtb-exists-forall-trait-covariant.stderr21
-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.stderr21
-rw-r--r--src/test/ui/hrtb/hrtb-higher-ranker-supertraits-transitive.stderr17
-rw-r--r--src/test/ui/hrtb/hrtb-higher-ranker-supertraits.rs4
-rw-r--r--src/test/ui/hrtb/hrtb-higher-ranker-supertraits.stderr41
-rw-r--r--src/test/ui/hrtb/hrtb-just-for-static.stderr35
-rw-r--r--src/test/ui/hrtb/issue-46989.rs42
-rw-r--r--src/test/ui/hrtb/issue-46989.stderr17
-rw-r--r--src/test/ui/hrtb/issue-57639.rs29
-rw-r--r--src/test/ui/hrtb/issue-58451.rs13
-rw-r--r--src/test/ui/hrtb/issue-58451.stderr16
-rw-r--r--src/test/ui/issues/issue-40000.stderr6
-rw-r--r--src/test/ui/issues/issue-57362-1.rs2
-rw-r--r--src/test/ui/issues/issue-57362-1.stderr11
-rw-r--r--src/test/ui/issues/issue-57362-2.rs2
-rw-r--r--src/test/ui/issues/issue-57362-2.stderr16
-rw-r--r--src/test/ui/lub-glb/old-lub-glb-hr.rs5
-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.rs4
-rw-r--r--src/test/ui/lub-glb/old-lub-glb-object.stderr18
-rw-r--r--src/test/ui/mismatched_types/closure-arg-type-mismatch.rs4
-rw-r--r--src/test/ui/mismatched_types/closure-arg-type-mismatch.stderr33
-rw-r--r--src/test/ui/mismatched_types/closure-mismatch.rs3
-rw-r--r--src/test/ui/mismatched_types/closure-mismatch.stderr34
-rw-r--r--src/test/ui/mismatched_types/issue-36053-2.rs1
-rw-r--r--src/test/ui/mismatched_types/issue-36053-2.stderr10
-rw-r--r--src/test/ui/regions-fn-subtyping-return-static-fail.rs4
-rw-r--r--src/test/ui/regions-fn-subtyping-return-static-fail.stderr17
-rw-r--r--src/test/ui/regions/region-lifetime-bounds-on-fns-where-clause.stderr4
-rw-r--r--src/test/ui/regions/region-multiple-lifetime-bounds-on-fns-where-clause.stderr4
-rw-r--r--src/test/ui/regions/regions-fn-subtyping-return-static.rs4
-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.stderr4
-rw-r--r--src/test/ui/unboxed-closures/unboxed-closures-unsafe-extern-fn.rs2
-rw-r--r--src/test/ui/unboxed-closures/unboxed-closures-unsafe-extern-fn.stderr34
-rw-r--r--src/test/ui/unboxed-closures/unboxed-closures-wrong-abi.rs2
-rw-r--r--src/test/ui/unboxed-closures/unboxed-closures-wrong-abi.stderr34
-rw-r--r--src/test/ui/unboxed-closures/unboxed-closures-wrong-arg-type-extern-fn.rs2
-rw-r--r--src/test/ui/unboxed-closures/unboxed-closures-wrong-arg-type-extern-fn.stderr34
-rw-r--r--src/test/ui/where-clauses/where-for-self-2.rs2
-rw-r--r--src/test/ui/where-clauses/where-for-self-2.stderr19
83 files changed, 1280 insertions, 372 deletions
diff --git a/src/librustc/infer/higher_ranked/mod.rs b/src/librustc/infer/higher_ranked/mod.rs
index c864349019b..7c83fe7fd69 100644
--- a/src/librustc/infer/higher_ranked/mod.rs
+++ b/src/librustc/infer/higher_ranked/mod.rs
@@ -4,6 +4,7 @@
 use super::combine::CombineFields;
 use super::{HigherRankedType, InferCtxt, PlaceholderMap};
 
+use crate::infer::CombinedSnapshot;
 use crate::ty::relate::{Relate, RelateResult, TypeRelation};
 use crate::ty::{self, Binder, TypeFoldable};
 
@@ -29,27 +30,32 @@ impl<'a, 'gcx, 'tcx> CombineFields<'a, 'gcx, 'tcx> {
 
         let span = self.trace.cause.span;
 
-        // First, we instantiate each bound region in the supertype with a
-        // fresh placeholder region.
-        let (b_prime, _) = self.infcx.replace_bound_vars_with_placeholders(b);
+        return self.infcx.commit_if_ok(|snapshot| {
+            // 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);
 
-        // Next, we instantiate each bound region in the subtype
-        // with a fresh region variable. These region variables --
-        // but no other pre-existing region variables -- can name
-        // the placeholders.
-        let (a_prime, _) =
-            self.infcx
-                .replace_bound_vars_with_fresh_vars(span, HigherRankedType, a);
+            // Next, we instantiate each bound region in the subtype
+            // with a fresh region variable. These region variables --
+            // but no other pre-existing region variables -- can name
+            // the placeholders.
+            let (a_prime, _) =
+                self.infcx
+                    .replace_bound_vars_with_fresh_vars(span, HigherRankedType, a);
+
+            debug!("a_prime={:?}", a_prime);
+            debug!("b_prime={:?}", b_prime);
 
-        debug!("a_prime={:?}", a_prime);
-        debug!("b_prime={:?}", b_prime);
+            // Compare types now that bound regions have been replaced.
+            let result = self.sub(a_is_expected).relate(&a_prime, &b_prime)?;
 
-        // 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);
+            debug!("higher_ranked_sub: OK result={:?}", result);
 
-        Ok(ty::Binder::bind(result))
+            Ok(ty::Binder::bind(result))
+        });
     }
 }
 
@@ -72,10 +78,10 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
     /// [rustc guide]: https://rust-lang.github.io/rustc-guide/traits/hrtb.html
     pub fn replace_bound_vars_with_placeholders<T>(
         &self,
-        binder: &ty::Binder<T>
+        binder: &ty::Binder<T>,
     ) -> (T, PlaceholderMap<'tcx>)
     where
-        T: TypeFoldable<'tcx>
+        T: TypeFoldable<'tcx>,
     {
         let next_universe = self.create_next_universe();
 
@@ -97,16 +103,24 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
 
         debug!(
             "replace_bound_vars_with_placeholders(\
-                next_universe={:?}, \
-                binder={:?}, \
-                result={:?}, \
-                map={:?})",
-            next_universe,
-            binder,
-            result,
-            map,
+             next_universe={:?}, \
+             binder={:?}, \
+             result={:?}, \
+             map={:?})",
+            next_universe, binder, result, map,
         );
 
         (result, map)
     }
+
+    /// See `infer::region_constraints::RegionConstraintCollector::leak_check`.
+    pub fn leak_check(
+        &self,
+        overly_polymorphic: bool,
+        placeholder_map: &PlaceholderMap<'tcx>,
+        snapshot: &CombinedSnapshot<'_, 'tcx>,
+    ) -> RelateResult<'tcx, ()> {
+        self.borrow_region_constraints()
+            .leak_check(self.tcx, overly_polymorphic, placeholder_map, snapshot)
+    }
 }
diff --git a/src/librustc/infer/mod.rs b/src/librustc/infer/mod.rs
index 04d08c19980..ac2ebece442 100644
--- a/src/librustc/infer/mod.rs
+++ b/src/librustc/infer/mod.rs
@@ -937,32 +937,41 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
             return None;
         }
 
-        let (
-            ty::SubtypePredicate {
-                a_is_expected,
-                a,
-                b,
-            },
-            _,
-        ) = self.replace_bound_vars_with_placeholders(predicate);
+        Some(self.commit_if_ok(|snapshot| {
+            let (
+                ty::SubtypePredicate {
+                    a_is_expected,
+                    a,
+                    b,
+                },
+                placeholder_map,
+            ) = self.replace_bound_vars_with_placeholders(predicate);
 
-        Some(
-            self.at(cause, param_env)
-                .sub_exp(a_is_expected, a, b)
-                .map(|ok| ok.unit()),
-        )
+            let ok = self.at(cause, param_env)
+                .sub_exp(a_is_expected, a, b)?;
+
+            self.leak_check(false, &placeholder_map, snapshot)?;
+
+            Ok(ok.unit())
+        }))
     }
 
     pub fn region_outlives_predicate(
         &self,
         cause: &traits::ObligationCause<'tcx>,
         predicate: &ty::PolyRegionOutlivesPredicate<'tcx>,
-    ) {
-        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`
+    ) -> UnitResult<'tcx> {
+        self.commit_if_ok(|snapshot| {
+            let (ty::OutlivesPredicate(r_a, r_b), placeholder_map) =
+                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(())
+        })
     }
 
     pub fn next_ty_var_id(&self, diverging: bool, origin: TypeVariableOrigin) -> TyVid {
diff --git a/src/librustc/infer/region_constraints/leak_check.rs b/src/librustc/infer/region_constraints/leak_check.rs
new file mode 100644
index 00000000000..8085258610d
--- /dev/null
+++ b/src/librustc/infer/region_constraints/leak_check.rs
@@ -0,0 +1,174 @@
+use super::*;
+use crate::infer::{CombinedSnapshot, PlaceholderMap};
+use crate::ty::error::TypeError;
+use crate::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.
+    ///
+    /// This is a temporary backwards compatibility measure to try and
+    /// retain the older (arguably incorrect) behavior of the
+    /// compiler.
+    ///
+    /// NB. The use of snapshot here 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.
+    pub fn leak_check(
+        &mut self,
+        tcx: TyCtxt<'_, '_, 'tcx>,
+        overly_polymorphic: bool,
+        placeholder_map: &PlaceholderMap<'tcx>,
+        _snapshot: &CombinedSnapshot<'_, 'tcx>,
+    ) -> RelateResult<'tcx, ()> {
+        debug!("leak_check(placeholders={:?})", placeholder_map);
+
+        assert!(self.in_snapshot());
+
+        // If the user gave `-Zno-leak-check`, then skip the leak
+        // check completely. This is wildly unsound and also not
+        // unlikely to cause an ICE or two. It is intended for use
+        // only during a transition period, in which the MIR typeck
+        // uses the "universe-style" check, and the rest of typeck
+        // uses the more conservative leak check.  Since the leak
+        // check is more conservative, we can't test the
+        // universe-style check without disabling it.
+        if tcx.sess.opts.debugging_opts.no_leak_check {
+            return Ok(());
+        }
+
+        // Go through each placeholder that we created.
+        for (_, &placeholder_region) in placeholder_map {
+            // 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, &self.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)
+                });
+            }
+        }
+
+        Ok(())
+    }
+}
+
+#[derive(Debug)]
+struct TaintSet<'tcx> {
+    directions: TaintDirections,
+    regions: FxHashSet<ty::Region<'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: directions,
+            regions: regions,
+        }
+    }
+
+    fn fixed_point(
+        &mut self,
+        tcx: TyCtxt<'_, '_, 'tcx>,
+        undo_log: &[UndoLog<'tcx>],
+        verifys: &[Verify<'tcx>],
+    ) {
+        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 {
+                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",
+                    ),
+                    &Purged | &AddCombination(..) | &AddVar(..) => {}
+                }
+            }
+        }
+    }
+
+    fn into_set(self) -> FxHashSet<ty::Region<'tcx>> {
+        self.regions
+    }
+
+    fn len(&self) -> usize {
+        self.regions.len()
+    }
+
+    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);
+            }
+        }
+
+        if self.directions.outgoing {
+            if self.regions.contains(&source) {
+                self.regions.insert(target);
+            }
+        }
+    }
+}
diff --git a/src/librustc/infer/region_constraints/mod.rs b/src/librustc/infer/region_constraints/mod.rs
index 45d614167ea..8389f0ab1aa 100644
--- a/src/librustc/infer/region_constraints/mod.rs
+++ b/src/librustc/infer/region_constraints/mod.rs
@@ -17,6 +17,8 @@ use crate::ty::{Region, RegionVid};
 use std::collections::BTreeMap;
 use std::{cmp, fmt, mem, u32};
 
+mod leak_check;
+
 #[derive(Default)]
 pub struct RegionConstraintCollector<'tcx> {
     /// For each `RegionVid`, the corresponding `RegionVariableOrigin`.
diff --git a/src/librustc/traits/auto_trait.rs b/src/librustc/traits/auto_trait.rs
index 8957bbaa4ad..60a3777abf8 100644
--- a/src/librustc/traits/auto_trait.rs
+++ b/src/librustc/traits/auto_trait.rs
@@ -771,7 +771,13 @@ impl<'a, 'tcx> AutoTraitFinder<'a, 'tcx> {
                     }
                 }
                 &ty::Predicate::RegionOutlives(ref binder) => {
-                    let () = select.infcx().region_outlives_predicate(&dummy_cause, binder);
+                    if select
+                        .infcx()
+                        .region_outlives_predicate(&dummy_cause, binder)
+                        .is_err()
+                    {
+                        return false;
+                    }
                 }
                 &ty::Predicate::TypeOutlives(ref binder) => {
                     match (
diff --git a/src/librustc/traits/error_reporting.rs b/src/librustc/traits/error_reporting.rs
index eb284645d36..3eb49092fed 100644
--- a/src/librustc/traits/error_reporting.rs
+++ b/src/librustc/traits/error_reporting.rs
@@ -730,9 +730,14 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
                     }
 
                     ty::Predicate::RegionOutlives(ref predicate) => {
-                        // These errors should show up as region
-                        // inference failures.
-                        panic!("region outlives {:?} failed", predicate);
+                        let predicate = self.resolve_type_vars_if_possible(predicate);
+                        let err = self.region_outlives_predicate(&obligation.cause,
+                                                                 &predicate).err().unwrap();
+                        struct_span_err!(
+                            self.tcx.sess, span, E0279,
+                            "the requirement `{}` is not satisfied (`{}`)",
+                            predicate, err,
+                        )
                     }
 
                     ty::Predicate::Projection(..) | ty::Predicate::TypeOutlives(..) => {
diff --git a/src/librustc/traits/fulfill.rs b/src/librustc/traits/fulfill.rs
index 587f57bb09d..7648bde1d3c 100644
--- a/src/librustc/traits/fulfill.rs
+++ b/src/librustc/traits/fulfill.rs
@@ -331,8 +331,10 @@ impl<'a, 'b, 'gcx, 'tcx> ObligationProcessor for FulfillProcessor<'a, 'b, 'gcx,
             }
 
             ty::Predicate::RegionOutlives(ref binder) => {
-                let () = self.selcx.infcx().region_outlives_predicate(&obligation.cause, binder);
-                ProcessResult::Changed(vec![])
+                match self.selcx.infcx().region_outlives_predicate(&obligation.cause, binder) {
+                    Ok(()) => ProcessResult::Changed(vec![]),
+                    Err(_) => ProcessResult::Error(CodeSelectionError(Unimplemented)),
+                }
             }
 
             ty::Predicate::TypeOutlives(ref binder) => {
diff --git a/src/librustc/traits/project.rs b/src/librustc/traits/project.rs
index 5a44d886e3c..05141c9daf1 100644
--- a/src/librustc/traits/project.rs
+++ b/src/librustc/traits/project.rs
@@ -191,12 +191,15 @@ pub fn poly_project_and_unify_type<'cx, 'gcx, 'tcx>(
            obligation);
 
     let infcx = selcx.infcx();
-    infcx.commit_if_ok(|_| {
-        let (placeholder_predicate, _) =
+    infcx.commit_if_ok(|snapshot| {
+        let (placeholder_predicate, placeholder_map) =
             infcx.replace_bound_vars_with_placeholders(&obligation.predicate);
 
         let placeholder_obligation = obligation.with(placeholder_predicate);
-        project_and_unify_type(selcx, &placeholder_obligation)
+        let result = project_and_unify_type(selcx, &placeholder_obligation)?;
+        infcx.leak_check(false, &placeholder_map, snapshot)
+            .map_err(|err| MismatchedProjectionTypes { err })?;
+        Ok(result)
     })
 }
 
@@ -1427,9 +1430,8 @@ fn confirm_callable_candidate<'cx, 'gcx, 'tcx>(
 fn confirm_param_env_candidate<'cx, 'gcx, 'tcx>(
     selcx: &mut SelectionContext<'cx, 'gcx, 'tcx>,
     obligation: &ProjectionTyObligation<'tcx>,
-    poly_cache_entry: ty::PolyProjectionPredicate<'tcx>)
-    -> Progress<'tcx>
-{
+    poly_cache_entry: ty::PolyProjectionPredicate<'tcx>,
+) -> Progress<'tcx> {
     let infcx = selcx.infcx();
     let cause = &obligation.cause;
     let param_env = obligation.param_env;
diff --git a/src/librustc/traits/select.rs b/src/librustc/traits/select.rs
index c2c05ce7af5..05fb40ac10a 100644
--- a/src/librustc/traits/select.rs
+++ b/src/librustc/traits/select.rs
@@ -29,7 +29,7 @@ use super::{
 
 use crate::dep_graph::{DepKind, DepNodeIndex};
 use crate::hir::def_id::DefId;
-use crate::infer::{InferCtxt, InferOk, TypeFreshener};
+use crate::infer::{CombinedSnapshot, InferCtxt, InferOk, PlaceholderMap, TypeFreshener};
 use crate::middle::lang_items;
 use crate::mir::interpret::GlobalId;
 use crate::ty::fast_reject;
@@ -1667,8 +1667,11 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
             _ => return,
         }
 
-        let result = self.infcx.probe(|_| {
-            self.match_projection_obligation_against_definition_bounds(obligation)
+        let result = self.infcx.probe(|snapshot| {
+            self.match_projection_obligation_against_definition_bounds(
+                obligation,
+                snapshot,
+            )
         });
 
         if result {
@@ -1679,18 +1682,19 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
     fn match_projection_obligation_against_definition_bounds(
         &mut self,
         obligation: &TraitObligation<'tcx>,
+        snapshot: &CombinedSnapshot<'_, 'tcx>,
     ) -> bool {
         let poly_trait_predicate = self.infcx()
             .resolve_type_vars_if_possible(&obligation.predicate);
-        let (skol_trait_predicate, _) = self.infcx()
+        let (placeholder_trait_predicate, placeholder_map) = self.infcx()
             .replace_bound_vars_with_placeholders(&poly_trait_predicate);
         debug!(
             "match_projection_obligation_against_definition_bounds: \
-             skol_trait_predicate={:?}",
-            skol_trait_predicate,
+             placeholder_trait_predicate={:?}",
+            placeholder_trait_predicate,
         );
 
-        let (def_id, substs) = match skol_trait_predicate.trait_ref.self_ty().sty {
+        let (def_id, substs) = match placeholder_trait_predicate.trait_ref.self_ty().sty {
             ty::Projection(ref data) => (data.trait_ref(self.tcx()).def_id, data.substs),
             ty::Opaque(def_id, substs) => (def_id, substs),
             _ => {
@@ -1698,7 +1702,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
                     obligation.cause.span,
                     "match_projection_obligation_against_definition_bounds() called \
                      but self-ty is not a projection: {:?}",
-                    skol_trait_predicate.trait_ref.self_ty()
+                    placeholder_trait_predicate.trait_ref.self_ty()
                 );
             }
         };
@@ -1723,7 +1727,9 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
                     self.match_projection(
                         obligation,
                         bound.clone(),
-                        skol_trait_predicate.trait_ref.clone(),
+                        placeholder_trait_predicate.trait_ref.clone(),
+                        &placeholder_map,
+                        snapshot,
                     )
                 })
             });
@@ -1740,7 +1746,9 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
                 let result = self.match_projection(
                     obligation,
                     bound,
-                    skol_trait_predicate.trait_ref.clone(),
+                    placeholder_trait_predicate.trait_ref.clone(),
+                    &placeholder_map,
+                    snapshot,
                 );
 
                 assert!(result);
@@ -1753,13 +1761,17 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
         &mut self,
         obligation: &TraitObligation<'tcx>,
         trait_bound: ty::PolyTraitRef<'tcx>,
-        skol_trait_ref: ty::TraitRef<'tcx>,
+        placeholder_trait_ref: ty::TraitRef<'tcx>,
+        placeholder_map: &PlaceholderMap<'tcx>,
+        snapshot: &CombinedSnapshot<'_, 'tcx>,
     ) -> bool {
-        debug_assert!(!skol_trait_ref.has_escaping_bound_vars());
+        debug_assert!(!placeholder_trait_ref.has_escaping_bound_vars());
         self.infcx
             .at(&obligation.cause, obligation.param_env)
-            .sup(ty::Binder::dummy(skol_trait_ref), trait_bound)
+            .sup(ty::Binder::dummy(placeholder_trait_ref), trait_bound)
             .is_ok()
+            &&
+            self.infcx.leak_check(false, placeholder_map, snapshot).is_ok()
     }
 
     /// Given an obligation like `<SomeTrait for T>`, search the obligations that the caller
@@ -1960,8 +1972,8 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
             obligation.predicate.def_id(),
             obligation.predicate.skip_binder().trait_ref.self_ty(),
             |impl_def_id| {
-                self.infcx.probe(|_| {
-                    if let Ok(_substs) = self.match_impl(impl_def_id, obligation)
+                self.infcx.probe(|snapshot| {
+                    if let Ok(_substs) = self.match_impl(impl_def_id, obligation, snapshot)
                     {
                         candidates.vec.push(ImplCandidate(impl_def_id));
                     }
@@ -2758,9 +2770,12 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
     }
 
     fn confirm_projection_candidate(&mut self, obligation: &TraitObligation<'tcx>) {
-        self.infcx.in_snapshot(|_| {
+        self.infcx.in_snapshot(|snapshot| {
             let result =
-                self.match_projection_obligation_against_definition_bounds(obligation);
+                self.match_projection_obligation_against_definition_bounds(
+                    obligation,
+                    snapshot,
+                );
             assert!(result);
         })
     }
@@ -2912,8 +2927,8 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
 
         // First, create the substitutions by matching the impl again,
         // this time not in a probe.
-        self.infcx.in_snapshot(|_| {
-            let substs = self.rematch_impl(impl_def_id, obligation);
+        self.infcx.in_snapshot(|snapshot| {
+            let substs = self.rematch_impl(impl_def_id, obligation, snapshot);
             debug!("confirm_impl_candidate: substs={:?}", substs);
             let cause = obligation.derived_cause(ImplDerivedObligation);
             self.vtable_impl(
@@ -3300,9 +3315,27 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
                     tcx.mk_existential_predicates(iter)
                 });
                 let source_trait = tcx.mk_dynamic(existential_predicates, r_b);
+
+                // 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 guies 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)
-                    .sup(target, source_trait)
+                    .eq(target, source_trait) // FIXME -- see below
                     .map_err(|_| Unimplemented)?;
                 nested.extend(obligations);
 
@@ -3504,8 +3537,9 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
         &mut self,
         impl_def_id: DefId,
         obligation: &TraitObligation<'tcx>,
+        snapshot: &CombinedSnapshot<'_, 'tcx>,
     ) -> Normalized<'tcx, &'tcx Substs<'tcx>> {
-        match self.match_impl(impl_def_id, obligation) {
+        match self.match_impl(impl_def_id, obligation, snapshot) {
             Ok(substs) => substs,
             Err(()) => {
                 bug!(
@@ -3521,6 +3555,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
         &mut self,
         impl_def_id: DefId,
         obligation: &TraitObligation<'tcx>,
+        snapshot: &CombinedSnapshot<'_, 'tcx>,
     ) -> Result<Normalized<'tcx, &'tcx Substs<'tcx>>, ()> {
         let impl_trait_ref = self.tcx().impl_trait_ref(impl_def_id).unwrap();
 
@@ -3531,7 +3566,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
             return Err(());
         }
 
-        let (skol_obligation, _) = self.infcx()
+        let (skol_obligation, placeholder_map) = self.infcx()
             .replace_bound_vars_with_placeholders(&obligation.predicate);
         let skol_obligation_trait_ref = skol_obligation.trait_ref;
 
@@ -3563,6 +3598,11 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, '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(());
+        }
+
         debug!("match_impl: success impl_substs={:?}", impl_substs);
         Ok(Normalized {
             value: impl_substs,
diff --git a/src/librustc/ty/error.rs b/src/librustc/ty/error.rs
index e3e0ce14774..f58e5e4fb69 100644
--- a/src/librustc/ty/error.rs
+++ b/src/librustc/ty/error.rs
@@ -1,5 +1,5 @@
 use crate::hir::def_id::DefId;
-use crate::ty::{self, Region, Ty, TyCtxt};
+use crate::ty::{self, BoundRegion, Region, Ty, TyCtxt};
 use std::borrow::Cow;
 use std::fmt;
 use rustc_target::spec::abi;
@@ -27,6 +27,8 @@ pub enum TypeError<'tcx> {
     ArgCount,
 
     RegionsDoesNotOutlive(Region<'tcx>, Region<'tcx>),
+    RegionsInsufficientlyPolymorphic(BoundRegion, Region<'tcx>),
+    RegionsOverlyPolymorphic(BoundRegion, Region<'tcx>),
     RegionsPlaceholderMismatch,
 
     Sorts(ExpectedFound<Ty<'tcx>>),
@@ -101,6 +103,18 @@ impl<'tcx> fmt::Display for TypeError<'tcx> {
             RegionsDoesNotOutlive(..) => {
                 write!(f, "lifetime mismatch")
             }
+            RegionsInsufficientlyPolymorphic(br, _) => {
+                write!(f,
+                       "expected bound lifetime parameter{}{}, found concrete lifetime",
+                       if br.is_named() { " " } else { "" },
+                       br)
+            }
+            RegionsOverlyPolymorphic(br, _) => {
+                write!(f,
+                       "expected concrete lifetime, found bound lifetime parameter{}{}",
+                       if br.is_named() { " " } else { "" },
+                       br)
+            }
             RegionsPlaceholderMismatch => {
                 write!(f, "one type is more general than the other")
             }
diff --git a/src/librustc/ty/structural_impls.rs b/src/librustc/ty/structural_impls.rs
index d09cfa84a16..f9173836cc6 100644
--- a/src/librustc/ty/structural_impls.rs
+++ b/src/librustc/ty/structural_impls.rs
@@ -434,6 +434,12 @@ impl<'a, 'tcx> Lift<'tcx> for ty::error::TypeError<'a> {
             RegionsDoesNotOutlive(a, b) => {
                 return tcx.lift(&(a, b)).map(|(a, b)| RegionsDoesNotOutlive(a, b))
             }
+            RegionsInsufficientlyPolymorphic(a, b) => {
+                return tcx.lift(&b).map(|b| RegionsInsufficientlyPolymorphic(a, b))
+            }
+            RegionsOverlyPolymorphic(a, b) => {
+                return tcx.lift(&b).map(|b| RegionsOverlyPolymorphic(a, b))
+            }
             RegionsPlaceholderMismatch => RegionsPlaceholderMismatch,
             IntMismatch(x) => IntMismatch(x),
             FloatMismatch(x) => FloatMismatch(x),
@@ -1021,6 +1027,8 @@ EnumTypeFoldableImpl! {
         (ty::error::TypeError::FixedArraySize)(x),
         (ty::error::TypeError::ArgCount),
         (ty::error::TypeError::RegionsDoesNotOutlive)(a, b),
+        (ty::error::TypeError::RegionsInsufficientlyPolymorphic)(a, b),
+        (ty::error::TypeError::RegionsOverlyPolymorphic)(a, b),
         (ty::error::TypeError::RegionsPlaceholderMismatch),
         (ty::error::TypeError::IntMismatch)(x),
         (ty::error::TypeError::FloatMismatch)(x),
diff --git a/src/test/ui/anonymous-higher-ranked-lifetime.rs b/src/test/ui/anonymous-higher-ranked-lifetime.rs
index 55b1667da50..2e2a124db9a 100644
--- a/src/test/ui/anonymous-higher-ranked-lifetime.rs
+++ b/src/test/ui/anonymous-higher-ranked-lifetime.rs
@@ -1,15 +1,26 @@
 fn main() {
     f1(|_: (), _: ()| {}); //~ ERROR type mismatch
+    //~^ ERROR type mismatch
     f2(|_: (), _: ()| {}); //~ ERROR type mismatch
+    //~^ ERROR type mismatch
     f3(|_: (), _: ()| {}); //~ ERROR type mismatch
+    //~^ ERROR type mismatch
     f4(|_: (), _: ()| {}); //~ ERROR type mismatch
+    //~^ ERROR type mismatch
     f5(|_: (), _: ()| {}); //~ ERROR type mismatch
+    //~^ ERROR type mismatch
     g1(|_: (), _: ()| {}); //~ ERROR type mismatch
+    //~^ ERROR type mismatch
     g2(|_: (), _: ()| {}); //~ ERROR type mismatch
+    //~^ ERROR type mismatch
     g3(|_: (), _: ()| {}); //~ ERROR type mismatch
+    //~^ ERROR type mismatch
     g4(|_: (), _: ()| {}); //~ ERROR type mismatch
+    //~^ ERROR type mismatch
     h1(|_: (), _: (), _: (), _: ()| {}); //~ ERROR type mismatch
+    //~^ ERROR type mismatch
     h2(|_: (), _: (), _: (), _: ()| {}); //~ ERROR type mismatch
+    //~^ ERROR type mismatch
 }
 
 // Basic
diff --git a/src/test/ui/anonymous-higher-ranked-lifetime.stderr b/src/test/ui/anonymous-higher-ranked-lifetime.stderr
index d2c722e32b2..378f352cb92 100644
--- a/src/test/ui/anonymous-higher-ranked-lifetime.stderr
+++ b/src/test/ui/anonymous-higher-ranked-lifetime.stderr
@@ -7,13 +7,27 @@ LL |     f1(|_: (), _: ()| {}); //~ ERROR type mismatch
    |     expected signature of `for<'r, 's> fn(&'r (), &'s ()) -> _`
    |
 note: required by `f1`
-  --> $DIR/anonymous-higher-ranked-lifetime.rs:16:1
+  --> $DIR/anonymous-higher-ranked-lifetime.rs:27:1
    |
 LL | fn f1<F>(_: F) where F: Fn(&(), &()) {}
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error[E0631]: type mismatch in closure arguments
-  --> $DIR/anonymous-higher-ranked-lifetime.rs:3:5
+  --> $DIR/anonymous-higher-ranked-lifetime.rs:2:5
+   |
+LL |     f1(|_: (), _: ()| {}); //~ ERROR type mismatch
+   |     ^^ -------------- found signature of `fn((), ()) -> _`
+   |     |
+   |     expected signature of `fn(&(), &()) -> _`
+   |
+note: required by `f1`
+  --> $DIR/anonymous-higher-ranked-lifetime.rs:27:1
+   |
+LL | fn f1<F>(_: F) where F: Fn(&(), &()) {}
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error[E0631]: type mismatch in closure arguments
+  --> $DIR/anonymous-higher-ranked-lifetime.rs:4:5
    |
 LL |     f2(|_: (), _: ()| {}); //~ ERROR type mismatch
    |     ^^ -------------- found signature of `fn((), ()) -> _`
@@ -21,7 +35,7 @@ LL |     f2(|_: (), _: ()| {}); //~ ERROR type mismatch
    |     expected signature of `for<'a, 'r> fn(&'a (), &'r ()) -> _`
    |
 note: required by `f2`
-  --> $DIR/anonymous-higher-ranked-lifetime.rs:17:1
+  --> $DIR/anonymous-higher-ranked-lifetime.rs:28:1
    |
 LL | fn f2<F>(_: F) where F: for<'a> Fn(&'a (), &()) {}
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -29,19 +43,47 @@ LL | fn f2<F>(_: F) where F: for<'a> Fn(&'a (), &()) {}
 error[E0631]: type mismatch in closure arguments
   --> $DIR/anonymous-higher-ranked-lifetime.rs:4:5
    |
+LL |     f2(|_: (), _: ()| {}); //~ ERROR type mismatch
+   |     ^^ -------------- found signature of `fn((), ()) -> _`
+   |     |
+   |     expected signature of `fn(&'a (), &()) -> _`
+   |
+note: required by `f2`
+  --> $DIR/anonymous-higher-ranked-lifetime.rs:28:1
+   |
+LL | fn f2<F>(_: F) where F: for<'a> Fn(&'a (), &()) {}
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error[E0631]: type mismatch in closure arguments
+  --> $DIR/anonymous-higher-ranked-lifetime.rs:6:5
+   |
 LL |     f3(|_: (), _: ()| {}); //~ ERROR type mismatch
    |     ^^ -------------- found signature of `fn((), ()) -> _`
    |     |
    |     expected signature of `for<'r> fn(&(), &'r ()) -> _`
    |
 note: required by `f3`
-  --> $DIR/anonymous-higher-ranked-lifetime.rs:18:1
+  --> $DIR/anonymous-higher-ranked-lifetime.rs:29:1
    |
 LL | fn f3<'a, F>(_: F) where F: Fn(&'a (), &()) {}
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error[E0631]: type mismatch in closure arguments
-  --> $DIR/anonymous-higher-ranked-lifetime.rs:5:5
+  --> $DIR/anonymous-higher-ranked-lifetime.rs:6:5
+   |
+LL |     f3(|_: (), _: ()| {}); //~ ERROR type mismatch
+   |     ^^ -------------- found signature of `fn((), ()) -> _`
+   |     |
+   |     expected signature of `fn(&(), &()) -> _`
+   |
+note: required by `f3`
+  --> $DIR/anonymous-higher-ranked-lifetime.rs:29:1
+   |
+LL | fn f3<'a, F>(_: F) where F: Fn(&'a (), &()) {}
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error[E0631]: type mismatch in closure arguments
+  --> $DIR/anonymous-higher-ranked-lifetime.rs:8:5
    |
 LL |     f4(|_: (), _: ()| {}); //~ ERROR type mismatch
    |     ^^ -------------- found signature of `fn((), ()) -> _`
@@ -49,13 +91,27 @@ LL |     f4(|_: (), _: ()| {}); //~ ERROR type mismatch
    |     expected signature of `for<'s, 'r> fn(&'s (), &'r ()) -> _`
    |
 note: required by `f4`
-  --> $DIR/anonymous-higher-ranked-lifetime.rs:19:1
+  --> $DIR/anonymous-higher-ranked-lifetime.rs:30:1
    |
 LL | fn f4<F>(_: F) where F: for<'r> Fn(&(), &'r ()) {}
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error[E0631]: type mismatch in closure arguments
-  --> $DIR/anonymous-higher-ranked-lifetime.rs:6:5
+  --> $DIR/anonymous-higher-ranked-lifetime.rs:8:5
+   |
+LL |     f4(|_: (), _: ()| {}); //~ ERROR type mismatch
+   |     ^^ -------------- found signature of `fn((), ()) -> _`
+   |     |
+   |     expected signature of `fn(&(), &'r ()) -> _`
+   |
+note: required by `f4`
+  --> $DIR/anonymous-higher-ranked-lifetime.rs:30:1
+   |
+LL | fn f4<F>(_: F) where F: for<'r> Fn(&(), &'r ()) {}
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error[E0631]: type mismatch in closure arguments
+  --> $DIR/anonymous-higher-ranked-lifetime.rs:10:5
    |
 LL |     f5(|_: (), _: ()| {}); //~ ERROR type mismatch
    |     ^^ -------------- found signature of `fn((), ()) -> _`
@@ -63,13 +119,27 @@ LL |     f5(|_: (), _: ()| {}); //~ ERROR type mismatch
    |     expected signature of `for<'r> fn(&'r (), &'r ()) -> _`
    |
 note: required by `f5`
-  --> $DIR/anonymous-higher-ranked-lifetime.rs:20:1
+  --> $DIR/anonymous-higher-ranked-lifetime.rs:31:1
    |
 LL | fn f5<F>(_: F) where F: for<'r> Fn(&'r (), &'r ()) {}
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error[E0631]: type mismatch in closure arguments
-  --> $DIR/anonymous-higher-ranked-lifetime.rs:7:5
+  --> $DIR/anonymous-higher-ranked-lifetime.rs:10:5
+   |
+LL |     f5(|_: (), _: ()| {}); //~ ERROR type mismatch
+   |     ^^ -------------- found signature of `fn((), ()) -> _`
+   |     |
+   |     expected signature of `fn(&'r (), &'r ()) -> _`
+   |
+note: required by `f5`
+  --> $DIR/anonymous-higher-ranked-lifetime.rs:31:1
+   |
+LL | fn f5<F>(_: F) where F: for<'r> Fn(&'r (), &'r ()) {}
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error[E0631]: type mismatch in closure arguments
+  --> $DIR/anonymous-higher-ranked-lifetime.rs:12:5
    |
 LL |     g1(|_: (), _: ()| {}); //~ ERROR type mismatch
    |     ^^ -------------- found signature of `fn((), ()) -> _`
@@ -77,13 +147,27 @@ LL |     g1(|_: (), _: ()| {}); //~ ERROR type mismatch
    |     expected signature of `for<'r> fn(&'r (), std::boxed::Box<(dyn for<'s> std::ops::Fn(&'s ()) + 'static)>) -> _`
    |
 note: required by `g1`
-  --> $DIR/anonymous-higher-ranked-lifetime.rs:23:1
+  --> $DIR/anonymous-higher-ranked-lifetime.rs:34:1
    |
 LL | fn g1<F>(_: F) where F: Fn(&(), Box<Fn(&())>) {}
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error[E0631]: type mismatch in closure arguments
-  --> $DIR/anonymous-higher-ranked-lifetime.rs:8:5
+  --> $DIR/anonymous-higher-ranked-lifetime.rs:12:5
+   |
+LL |     g1(|_: (), _: ()| {}); //~ ERROR type mismatch
+   |     ^^ -------------- found signature of `fn((), ()) -> _`
+   |     |
+   |     expected signature of `fn(&(), std::boxed::Box<(dyn for<'r> std::ops::Fn(&'r ()) + 'static)>) -> _`
+   |
+note: required by `g1`
+  --> $DIR/anonymous-higher-ranked-lifetime.rs:34:1
+   |
+LL | fn g1<F>(_: F) where F: Fn(&(), Box<Fn(&())>) {}
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error[E0631]: type mismatch in closure arguments
+  --> $DIR/anonymous-higher-ranked-lifetime.rs:14:5
    |
 LL |     g2(|_: (), _: ()| {}); //~ ERROR type mismatch
    |     ^^ -------------- found signature of `fn((), ()) -> _`
@@ -91,13 +175,27 @@ LL |     g2(|_: (), _: ()| {}); //~ ERROR type mismatch
    |     expected signature of `for<'r> fn(&'r (), for<'s> fn(&'s ())) -> _`
    |
 note: required by `g2`
-  --> $DIR/anonymous-higher-ranked-lifetime.rs:24:1
+  --> $DIR/anonymous-higher-ranked-lifetime.rs:35:1
    |
 LL | fn g2<F>(_: F) where F: Fn(&(), fn(&())) {}
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error[E0631]: type mismatch in closure arguments
-  --> $DIR/anonymous-higher-ranked-lifetime.rs:9:5
+  --> $DIR/anonymous-higher-ranked-lifetime.rs:14:5
+   |
+LL |     g2(|_: (), _: ()| {}); //~ ERROR type mismatch
+   |     ^^ -------------- found signature of `fn((), ()) -> _`
+   |     |
+   |     expected signature of `fn(&(), for<'r> fn(&'r ())) -> _`
+   |
+note: required by `g2`
+  --> $DIR/anonymous-higher-ranked-lifetime.rs:35:1
+   |
+LL | fn g2<F>(_: F) where F: Fn(&(), fn(&())) {}
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error[E0631]: type mismatch in closure arguments
+  --> $DIR/anonymous-higher-ranked-lifetime.rs:16:5
    |
 LL |     g3(|_: (), _: ()| {}); //~ ERROR type mismatch
    |     ^^ -------------- found signature of `fn((), ()) -> _`
@@ -105,13 +203,27 @@ LL |     g3(|_: (), _: ()| {}); //~ ERROR type mismatch
    |     expected signature of `for<'s> fn(&'s (), std::boxed::Box<(dyn for<'r> std::ops::Fn(&'r ()) + 'static)>) -> _`
    |
 note: required by `g3`
-  --> $DIR/anonymous-higher-ranked-lifetime.rs:25:1
+  --> $DIR/anonymous-higher-ranked-lifetime.rs:36:1
    |
 LL | fn g3<F>(_: F) where F: for<'s> Fn(&'s (), Box<Fn(&())>) {}
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error[E0631]: type mismatch in closure arguments
-  --> $DIR/anonymous-higher-ranked-lifetime.rs:10:5
+  --> $DIR/anonymous-higher-ranked-lifetime.rs:16:5
+   |
+LL |     g3(|_: (), _: ()| {}); //~ ERROR type mismatch
+   |     ^^ -------------- found signature of `fn((), ()) -> _`
+   |     |
+   |     expected signature of `fn(&'s (), std::boxed::Box<(dyn for<'r> std::ops::Fn(&'r ()) + 'static)>) -> _`
+   |
+note: required by `g3`
+  --> $DIR/anonymous-higher-ranked-lifetime.rs:36:1
+   |
+LL | fn g3<F>(_: F) where F: for<'s> Fn(&'s (), Box<Fn(&())>) {}
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error[E0631]: type mismatch in closure arguments
+  --> $DIR/anonymous-higher-ranked-lifetime.rs:18:5
    |
 LL |     g4(|_: (), _: ()| {}); //~ ERROR type mismatch
    |     ^^ -------------- found signature of `fn((), ()) -> _`
@@ -119,13 +231,27 @@ LL |     g4(|_: (), _: ()| {}); //~ ERROR type mismatch
    |     expected signature of `for<'s> fn(&'s (), for<'r> fn(&'r ())) -> _`
    |
 note: required by `g4`
-  --> $DIR/anonymous-higher-ranked-lifetime.rs:26:1
+  --> $DIR/anonymous-higher-ranked-lifetime.rs:37:1
+   |
+LL | fn g4<F>(_: F) where F: Fn(&(), for<'r> fn(&'r ())) {}
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error[E0631]: type mismatch in closure arguments
+  --> $DIR/anonymous-higher-ranked-lifetime.rs:18:5
+   |
+LL |     g4(|_: (), _: ()| {}); //~ ERROR type mismatch
+   |     ^^ -------------- found signature of `fn((), ()) -> _`
+   |     |
+   |     expected signature of `fn(&(), for<'r> fn(&'r ())) -> _`
+   |
+note: required by `g4`
+  --> $DIR/anonymous-higher-ranked-lifetime.rs:37:1
    |
 LL | fn g4<F>(_: F) where F: Fn(&(), for<'r> fn(&'r ())) {}
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error[E0631]: type mismatch in closure arguments
-  --> $DIR/anonymous-higher-ranked-lifetime.rs:11:5
+  --> $DIR/anonymous-higher-ranked-lifetime.rs:20:5
    |
 LL |     h1(|_: (), _: (), _: (), _: ()| {}); //~ ERROR type mismatch
    |     ^^ ---------------------------- found signature of `fn((), (), (), ()) -> _`
@@ -133,13 +259,27 @@ LL |     h1(|_: (), _: (), _: (), _: ()| {}); //~ ERROR type mismatch
    |     expected signature of `for<'r, 's> fn(&'r (), std::boxed::Box<(dyn for<'t0> std::ops::Fn(&'t0 ()) + 'static)>, &'s (), for<'t0, 't1> fn(&'t0 (), &'t1 ())) -> _`
    |
 note: required by `h1`
-  --> $DIR/anonymous-higher-ranked-lifetime.rs:29:1
+  --> $DIR/anonymous-higher-ranked-lifetime.rs:40:1
    |
 LL | fn h1<F>(_: F) where F: Fn(&(), Box<Fn(&())>, &(), fn(&(), &())) {}
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error[E0631]: type mismatch in closure arguments
-  --> $DIR/anonymous-higher-ranked-lifetime.rs:12:5
+  --> $DIR/anonymous-higher-ranked-lifetime.rs:20:5
+   |
+LL |     h1(|_: (), _: (), _: (), _: ()| {}); //~ ERROR type mismatch
+   |     ^^ ---------------------------- found signature of `fn((), (), (), ()) -> _`
+   |     |
+   |     expected signature of `fn(&(), std::boxed::Box<(dyn for<'r> std::ops::Fn(&'r ()) + 'static)>, &(), for<'r, 's> fn(&'r (), &'s ())) -> _`
+   |
+note: required by `h1`
+  --> $DIR/anonymous-higher-ranked-lifetime.rs:40:1
+   |
+LL | fn h1<F>(_: F) where F: Fn(&(), Box<Fn(&())>, &(), fn(&(), &())) {}
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error[E0631]: type mismatch in closure arguments
+  --> $DIR/anonymous-higher-ranked-lifetime.rs:22:5
    |
 LL |     h2(|_: (), _: (), _: (), _: ()| {}); //~ ERROR type mismatch
    |     ^^ ---------------------------- found signature of `fn((), (), (), ()) -> _`
@@ -147,11 +287,25 @@ LL |     h2(|_: (), _: (), _: (), _: ()| {}); //~ ERROR type mismatch
    |     expected signature of `for<'r, 't0> fn(&'r (), std::boxed::Box<(dyn for<'s> std::ops::Fn(&'s ()) + 'static)>, &'t0 (), for<'s, 't1> fn(&'s (), &'t1 ())) -> _`
    |
 note: required by `h2`
-  --> $DIR/anonymous-higher-ranked-lifetime.rs:30:1
+  --> $DIR/anonymous-higher-ranked-lifetime.rs:41:1
+   |
+LL | fn h2<F>(_: F) where F: for<'t0> Fn(&(), Box<Fn(&())>, &'t0 (), fn(&(), &())) {}
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error[E0631]: type mismatch in closure arguments
+  --> $DIR/anonymous-higher-ranked-lifetime.rs:22:5
+   |
+LL |     h2(|_: (), _: (), _: (), _: ()| {}); //~ ERROR type mismatch
+   |     ^^ ---------------------------- found signature of `fn((), (), (), ()) -> _`
+   |     |
+   |     expected signature of `fn(&(), std::boxed::Box<(dyn for<'r> std::ops::Fn(&'r ()) + 'static)>, &'t0 (), for<'r, 's> fn(&'r (), &'s ())) -> _`
+   |
+note: required by `h2`
+  --> $DIR/anonymous-higher-ranked-lifetime.rs:41:1
    |
 LL | fn h2<F>(_: F) where F: for<'t0> Fn(&(), Box<Fn(&())>, &'t0 (), fn(&(), &())) {}
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
-error: aborting due to 11 previous errors
+error: aborting due to 22 previous errors
 
 For more information about this error, try `rustc --explain E0631`.
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 20fa1e7a48d..e6afa3f71c2 100644
--- a/src/test/ui/associated-types/associated-types-eq-hr.rs
+++ b/src/test/ui/associated-types/associated-types-eq-hr.rs
@@ -89,12 +89,14 @@ pub fn call_bar() {
 
 pub fn call_tuple_one() {
     tuple_one::<Tuple>();
-    //~^ ERROR not general enough
+    //~^ ERROR not satisfied
+    //~| ERROR type mismatch
 }
 
 pub fn call_tuple_two() {
     tuple_two::<Tuple>();
-    //~^ ERROR not general enough
+    //~^ ERROR not satisfied
+    //~| ERROR type mismatch
 }
 
 pub fn call_tuple_three() {
@@ -103,7 +105,7 @@ pub fn call_tuple_three() {
 
 pub fn call_tuple_four() {
     tuple_four::<Tuple>();
-    //~^ ERROR not general enough
+    //~^ ERROR not satisfied
 }
 
 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 5299ebbb1ba..3721b698988 100644
--- a/src/test/ui/associated-types/associated-types-eq-hr.stderr
+++ b/src/test/ui/associated-types/associated-types-eq-hr.stderr
@@ -34,36 +34,93 @@ LL | |     // ok for UintStruct, but not IntStruct
 LL | | }
    | |_^
 
-error: implementation of `TheTrait` is not general enough
+error[E0277]: the trait bound `for<'x, 'y> Tuple: TheTrait<(&'x isize, &'y isize)>` is not satisfied
   --> $DIR/associated-types-eq-hr.rs:91:5
    |
 LL |     tuple_one::<Tuple>();
-   |     ^^^^^^^^^^^^^^^^^^
+   |     ^^^^^^^^^^^^^^^^^^ the trait `for<'x, 'y> TheTrait<(&'x isize, &'y isize)>` is not implemented for `Tuple`
    |
-   = note: Due to a where-clause on `tuple_one`,
-   = 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`
+   = help: the following implementations were found:
+             <Tuple as TheTrait<(&'a isize, &'a isize)>>
+note: required by `tuple_one`
+  --> $DIR/associated-types-eq-hr.rs:56:1
+   |
+LL | / fn tuple_one<T>()
+LL | |     where T : for<'x,'y> TheTrait<(&'x isize, &'y isize), A = &'x isize>
+LL | | {
+LL | |     // not ok for tuple, two lifetimes and we pick first
+LL | | }
+   | |_^
 
-error: implementation of `TheTrait` is not general enough
-  --> $DIR/associated-types-eq-hr.rs:96:5
+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
+   |
+LL |     tuple_one::<Tuple>();
+   |     ^^^^^^^^^^^^^^^^^^ expected bound lifetime parameter 'x, found concrete lifetime
+   |
+note: required by `tuple_one`
+  --> $DIR/associated-types-eq-hr.rs:56:1
+   |
+LL | / fn tuple_one<T>()
+LL | |     where T : for<'x,'y> TheTrait<(&'x isize, &'y isize), A = &'x isize>
+LL | | {
+LL | |     // not ok for tuple, two lifetimes and we pick first
+LL | | }
+   | |_^
+
+error[E0277]: the trait bound `for<'x, 'y> Tuple: TheTrait<(&'x isize, &'y isize)>` is not satisfied
+  --> $DIR/associated-types-eq-hr.rs:97:5
    |
 LL |     tuple_two::<Tuple>();
-   |     ^^^^^^^^^^^^^^^^^^
+   |     ^^^^^^^^^^^^^^^^^^ the trait `for<'x, 'y> TheTrait<(&'x isize, &'y isize)>` is not implemented for `Tuple`
+   |
+   = help: the following implementations were found:
+             <Tuple as TheTrait<(&'a isize, &'a isize)>>
+note: required by `tuple_two`
+  --> $DIR/associated-types-eq-hr.rs:62:1
    |
-   = note: Due to a where-clause on `tuple_two`,
-   = 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`
+LL | / fn tuple_two<T>()
+LL | |     where T : for<'x,'y> TheTrait<(&'x isize, &'y isize), A = &'y isize>
+LL | | {
+LL | |     // not ok for tuple, two lifetimes and we pick second
+LL | | }
+   | |_^
+
+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
+   |
+LL |     tuple_two::<Tuple>();
+   |     ^^^^^^^^^^^^^^^^^^ expected bound lifetime parameter 'x, found concrete lifetime
+   |
+note: required by `tuple_two`
+  --> $DIR/associated-types-eq-hr.rs:62:1
+   |
+LL | / fn tuple_two<T>()
+LL | |     where T : for<'x,'y> TheTrait<(&'x isize, &'y isize), A = &'y isize>
+LL | | {
+LL | |     // not ok for tuple, two lifetimes and we pick second
+LL | | }
+   | |_^
 
-error: implementation of `TheTrait` is not general enough
-  --> $DIR/associated-types-eq-hr.rs:105:5
+error[E0277]: the trait bound `for<'x, 'y> Tuple: TheTrait<(&'x isize, &'y isize)>` is not satisfied
+  --> $DIR/associated-types-eq-hr.rs:107:5
    |
 LL |     tuple_four::<Tuple>();
-   |     ^^^^^^^^^^^^^^^^^^^
+   |     ^^^^^^^^^^^^^^^^^^^ the trait `for<'x, 'y> TheTrait<(&'x isize, &'y isize)>` is not implemented for `Tuple`
+   |
+   = help: the following implementations were found:
+             <Tuple as TheTrait<(&'a isize, &'a isize)>>
+note: required by `tuple_four`
+  --> $DIR/associated-types-eq-hr.rs:74:1
    |
-   = note: Due to a where-clause on `tuple_four`,
-   = 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`
+LL | / fn tuple_four<T>()
+LL | |     where T : for<'x,'y> TheTrait<(&'x isize, &'y isize)>
+LL | | {
+LL | |     // not ok for tuple, two lifetimes, and lifetime matching is invariant
+LL | | }
+   | |_^
 
-error: aborting due to 5 previous errors
+error: aborting due to 7 previous errors
 
-For more information about this error, try `rustc --explain E0271`.
+Some errors occurred: E0271, E0277.
+For more information about an error, try `rustc --explain E0271`.
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 811c9a8f5e1..cc69e849fe1 100644
--- a/src/test/ui/associated-types/higher-ranked-projection.bad.stderr
+++ b/src/test/ui/associated-types/higher-ranked-projection.bad.stderr
@@ -1,12 +1,17 @@
-error[E0308]: mismatched types
+error[E0271]: type mismatch resolving `for<'a> <&'a _ as Mirror>::Image == _`
   --> $DIR/higher-ranked-projection.rs:25:5
    |
 LL |     foo(());
-   |     ^^^ one type is more general than the other
+   |     ^^^ expected bound lifetime parameter 'a, found concrete lifetime
    |
-   = note: expected type `&'a ()`
-              found type `&()`
+note: required by `foo`
+  --> $DIR/higher-ranked-projection.rs:14:1
+   |
+LL | / fn foo<U, T>(_t: T)
+LL | |     where for<'a> &'a T: Mirror<Image=U>
+LL | | {}
+   | |__^
 
 error: aborting due to previous error
 
-For more information about this error, try `rustc --explain E0308`.
+For more information about this error, try `rustc --explain E0271`.
diff --git a/src/test/ui/associated-types/higher-ranked-projection.good.stderr b/src/test/ui/associated-types/higher-ranked-projection.good.stderr
index 92fd2562858..165e5213e0d 100644
--- a/src/test/ui/associated-types/higher-ranked-projection.good.stderr
+++ b/src/test/ui/associated-types/higher-ranked-projection.good.stderr
@@ -3,7 +3,7 @@ error: compilation successful
    |
 LL | / fn main() { //[good]~ ERROR compilation successful
 LL | |     foo(());
-LL | |     //[bad]~^ ERROR mismatched types
+LL | |     //[bad]~^ ERROR type mismatch
 LL | | }
    | |_^
 
diff --git a/src/test/ui/associated-types/higher-ranked-projection.rs b/src/test/ui/associated-types/higher-ranked-projection.rs
index fd7252f9e22..a2ea6d8f206 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 compilation successful
     foo(());
-    //[bad]~^ ERROR mismatched types
+    //[bad]~^ ERROR type mismatch
 }
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 6977fd47a2e..a4e43da91ba 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
@@ -28,14 +28,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 mismatched types
+    //~^ ERROR type mismatch
 }
 
 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 mismatched types
+    //~^ ERROR type mismatch
 }
 
 fn expect_bound_supply_free_from_closure() {
@@ -44,7 +44,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 mismatched types
+    //~^ ERROR type mismatch
     });
 }
 
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 b1cfd6cef10..ab35aeff697 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
@@ -36,33 +36,58 @@ note: ...does not necessarily outlive the anonymous lifetime #2 defined on the b
 LL |     with_closure_expecting_fn_with_free_region(|x: fn(&'x u32), y| {});
    |                                                ^^^^^^^^^^^^^^^^^^^^^^
 
-error[E0308]: mismatched types
-  --> $DIR/expect-fn-supply-fn.rs:30:52
+error[E0631]: type mismatch in closure arguments
+  --> $DIR/expect-fn-supply-fn.rs:30:5
    |
 LL |     with_closure_expecting_fn_with_free_region(|x: fn(&u32), y| {});
-   |                                                    ^^^^^^^^ one type is more general than the other
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ---------------- found signature of `fn(for<'r> fn(&'r u32), _) -> _`
+   |     |
+   |     expected signature of `fn(fn(&'a u32), &i32) -> _`
    |
-   = note: expected type `fn(&u32)`
-              found type `for<'r> fn(&'r u32)`
+note: required by `with_closure_expecting_fn_with_free_region`
+  --> $DIR/expect-fn-supply-fn.rs:1:1
+   |
+LL | / fn with_closure_expecting_fn_with_free_region<F>(_: F)
+LL | |     where F: for<'a> FnOnce(fn(&'a u32), &i32)
+LL | | {
+LL | | }
+   | |_^
 
-error[E0308]: mismatched types
-  --> $DIR/expect-fn-supply-fn.rs:37:53
+error[E0631]: type mismatch in closure arguments
+  --> $DIR/expect-fn-supply-fn.rs:37:5
    |
 LL |     with_closure_expecting_fn_with_bound_region(|x: fn(&'x u32), y| {});
-   |                                                     ^^^^^^^^^^^ one type is more general than the other
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ------------------- found signature of `fn(fn(&'x u32), _) -> _`
+   |     |
+   |     expected signature of `fn(for<'r> fn(&'r u32), &i32) -> _`
    |
-   = note: expected type `for<'r> fn(&'r u32)`
-              found type `fn(&'x u32)`
+note: required by `with_closure_expecting_fn_with_bound_region`
+  --> $DIR/expect-fn-supply-fn.rs:6:1
+   |
+LL | / fn with_closure_expecting_fn_with_bound_region<F>(_: F)
+LL | |     where F: FnOnce(fn(&u32), &i32)
+LL | | {
+LL | | }
+   | |_^
 
-error[E0308]: mismatched types
-  --> $DIR/expect-fn-supply-fn.rs:46:53
+error[E0631]: type mismatch in closure arguments
+  --> $DIR/expect-fn-supply-fn.rs:46:5
    |
 LL |     with_closure_expecting_fn_with_bound_region(|x: Foo<'_>, y| {
-   |                                                     ^^^^^^^ one type is more general than the other
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ --------------- found signature of `for<'r> fn(fn(&'r u32), _) -> _`
+   |     |
+   |     expected signature of `fn(for<'r> fn(&'r u32), &i32) -> _`
+   |
+note: required by `with_closure_expecting_fn_with_bound_region`
+  --> $DIR/expect-fn-supply-fn.rs:6:1
    |
-   = note: expected type `for<'r> fn(&'r u32)`
-              found type `fn(&u32)`
+LL | / fn with_closure_expecting_fn_with_bound_region<F>(_: F)
+LL | |     where F: FnOnce(fn(&u32), &i32)
+LL | | {
+LL | | }
+   | |_^
 
 error: aborting due to 5 previous errors
 
-For more information about this error, try `rustc --explain E0308`.
+Some errors occurred: E0308, E0631.
+For more information about an error, try `rustc --explain E0308`.
diff --git a/src/test/ui/coherence/coherence-subtyping.old.stderr b/src/test/ui/coherence/coherence-subtyping.old.stderr
deleted file mode 100644
index db9f9f76653..00000000000
--- a/src/test/ui/coherence/coherence-subtyping.old.stderr
+++ /dev/null
@@ -1,14 +0,0 @@
-error[E0119]: conflicting implementations of trait `TheTrait` for type `for<'a, 'b> fn(&'a u8, &'b u8) -> &'a u8`:
-  --> $DIR/coherence-subtyping.rs:15:1
-   |
-LL | impl TheTrait for for<'a,'b> fn(&'a u8, &'b u8) -> &'a u8 {
-   | --------------------------------------------------------- first implementation here
-...
-LL | impl TheTrait for for<'a> fn(&'a u8, &'a u8) -> &'a u8 {
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `for<'a, 'b> fn(&'a u8, &'b u8) -> &'a u8`
-   |
-   = 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-subtyping.re.stderr b/src/test/ui/coherence/coherence-subtyping.re.stderr
deleted file mode 100644
index db9f9f76653..00000000000
--- a/src/test/ui/coherence/coherence-subtyping.re.stderr
+++ /dev/null
@@ -1,14 +0,0 @@
-error[E0119]: conflicting implementations of trait `TheTrait` for type `for<'a, 'b> fn(&'a u8, &'b u8) -> &'a u8`:
-  --> $DIR/coherence-subtyping.rs:15:1
-   |
-LL | impl TheTrait for for<'a,'b> fn(&'a u8, &'b u8) -> &'a u8 {
-   | --------------------------------------------------------- first implementation here
-...
-LL | impl TheTrait for for<'a> fn(&'a u8, &'a u8) -> &'a u8 {
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `for<'a, 'b> fn(&'a u8, &'b u8) -> &'a u8`
-   |
-   = 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-subtyping.rs b/src/test/ui/coherence/coherence-subtyping.rs
index f27e14eab63..e7406757806 100644
--- a/src/test/ui/coherence/coherence-subtyping.rs
+++ b/src/test/ui/coherence/coherence-subtyping.rs
@@ -1,7 +1,11 @@
 // Test that two distinct impls which match subtypes of one another
 // yield coherence errors (or not) depending on the variance.
+//
+// Note: This scenario is currently accepted, but as part of the
+// universe transition (#56105) may eventually become an error.
 
 // revisions: old re
+// compile-pass
 
 #![cfg_attr(re, feature(re_rebalance_coherence))]
 
@@ -13,8 +17,6 @@ impl TheTrait for for<'a,'b> fn(&'a u8, &'b u8) -> &'a u8 {
 }
 
 impl TheTrait for for<'a> fn(&'a u8, &'a u8) -> &'a u8 {
-    //[old]~^ ERROR
-    //[re]~^^ ERROR
 }
 
 fn main() { }
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 bdfabdabbeb..8e2b0b8c600 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
@@ -2,7 +2,7 @@ error[E0308]: mismatched types
   --> $DIR/hr-subtype.rs:39:26
    |
 LL |               gimme::<$t1>(None::<$t2>);
-   |                            ^^^^^^^^^^^ one type is more general than the other
+   |                            ^^^^^^^^^^^ expected concrete lifetime, found bound lifetime parameter 'a
 ...
 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) }
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 25b74d855bb..dbb50181390 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,14 +1,16 @@
-error: compilation successful
-  --> $DIR/hr-subtype.rs:96:1
+error[E0308]: mismatched types
+  --> $DIR/hr-subtype.rs:39:26
    |
-LL | / fn main() {
-LL | | //[bound_a_vs_bound_a]~^ ERROR compilation successful
-LL | | //[bound_a_vs_bound_b]~^^ ERROR compilation successful
-LL | | //[bound_inv_a_vs_bound_inv_b]~^^^ ERROR compilation successful
-...  |
-LL | | //[bound_contra_a_contra_b_ret_co_a]~^^^^^^^^^ ERROR compilation successful
-LL | | }
-   | |_^
+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 type `std::option::Option<for<'a, 'b> fn(&'a u32, &'b u32)>`
+              found type `std::option::Option<for<'a> fn(&'a u32, &'a u32)>`
 
 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 25b74d855bb..5fcb63e17bf 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,12 +1,12 @@
 error: compilation successful
-  --> $DIR/hr-subtype.rs:96:1
+  --> $DIR/hr-subtype.rs:100:1
    |
 LL | / fn main() {
 LL | | //[bound_a_vs_bound_a]~^ ERROR compilation successful
 LL | | //[bound_a_vs_bound_b]~^^ ERROR compilation successful
 LL | | //[bound_inv_a_vs_bound_inv_b]~^^^ ERROR compilation successful
-...  |
-LL | | //[bound_contra_a_contra_b_ret_co_a]~^^^^^^^^^ ERROR compilation successful
+LL | | //[bound_co_a_vs_bound_co_b]~^^^^ ERROR compilation successful
+LL | | //[free_x_vs_free_x]~^^^^^ ERROR compilation successful
 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 25b74d855bb..5fcb63e17bf 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,12 +1,12 @@
 error: compilation successful
-  --> $DIR/hr-subtype.rs:96:1
+  --> $DIR/hr-subtype.rs:100:1
    |
 LL | / fn main() {
 LL | | //[bound_a_vs_bound_a]~^ ERROR compilation successful
 LL | | //[bound_a_vs_bound_b]~^^ ERROR compilation successful
 LL | | //[bound_inv_a_vs_bound_inv_b]~^^^ ERROR compilation successful
-...  |
-LL | | //[bound_contra_a_contra_b_ret_co_a]~^^^^^^^^^ ERROR compilation successful
+LL | | //[bound_co_a_vs_bound_co_b]~^^^^ ERROR compilation successful
+LL | | //[free_x_vs_free_x]~^^^^^ ERROR compilation successful
 LL | | }
    | |_^
 
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 74b8c89b6e8..db9892b48a6 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
@@ -2,7 +2,7 @@ error[E0308]: mismatched types
   --> $DIR/hr-subtype.rs:39:26
    |
 LL |               gimme::<$t1>(None::<$t2>);
-   |                            ^^^^^^^^^^^ one type is more general than the other
+   |                            ^^^^^^^^^^^ expected concrete lifetime, found bound lifetime parameter 'a
 ...
 LL | / check! { bound_a_vs_free_x: (for<'a> fn(&'a u32),
 LL | |                              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 25b74d855bb..e9fb73411bd 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,14 +1,16 @@
-error: compilation successful
-  --> $DIR/hr-subtype.rs:96:1
+error[E0308]: mismatched types
+  --> $DIR/hr-subtype.rs:39:26
    |
-LL | / fn main() {
-LL | | //[bound_a_vs_bound_a]~^ ERROR compilation successful
-LL | | //[bound_a_vs_bound_b]~^^ ERROR compilation successful
-LL | | //[bound_inv_a_vs_bound_inv_b]~^^^ ERROR compilation successful
-...  |
-LL | | //[bound_contra_a_contra_b_ret_co_a]~^^^^^^^^^ ERROR compilation successful
-LL | | }
-   | |_^
+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 type `std::option::Option<for<'a, 'b> fn(Co<'a>, Co<'b>)>`
+              found type `std::option::Option<for<'a> fn(Co<'a>, Co<'a>)>`
 
 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 25b74d855bb..d0e80faa68e 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,14 +1,16 @@
-error: compilation successful
-  --> $DIR/hr-subtype.rs:96:1
+error[E0308]: mismatched types
+  --> $DIR/hr-subtype.rs:39:26
    |
-LL | / fn main() {
-LL | | //[bound_a_vs_bound_a]~^ ERROR compilation successful
-LL | | //[bound_a_vs_bound_b]~^^ ERROR compilation successful
-LL | | //[bound_inv_a_vs_bound_inv_b]~^^^ ERROR compilation successful
-...  |
-LL | | //[bound_contra_a_contra_b_ret_co_a]~^^^^^^^^^ ERROR compilation successful
-LL | | }
-   | |_^
+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 type `std::option::Option<for<'a, 'b> fn(Co<'a>, Co<'b>) -> Contra<'a>>`
+              found type `std::option::Option<for<'a> fn(Co<'a>, Co<'a>) -> Contra<'a>>`
 
 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 25b74d855bb..5fcb63e17bf 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,12 +1,12 @@
 error: compilation successful
-  --> $DIR/hr-subtype.rs:96:1
+  --> $DIR/hr-subtype.rs:100:1
    |
 LL | / fn main() {
 LL | | //[bound_a_vs_bound_a]~^ ERROR compilation successful
 LL | | //[bound_a_vs_bound_b]~^^ ERROR compilation successful
 LL | | //[bound_inv_a_vs_bound_inv_b]~^^^ ERROR compilation successful
-...  |
-LL | | //[bound_contra_a_contra_b_ret_co_a]~^^^^^^^^^ ERROR compilation successful
+LL | | //[bound_co_a_vs_bound_co_b]~^^^^ ERROR compilation successful
+LL | | //[free_x_vs_free_x]~^^^^^ ERROR compilation successful
 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 25b74d855bb..3605ecf4f86 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,14 +1,16 @@
-error: compilation successful
-  --> $DIR/hr-subtype.rs:96:1
+error[E0308]: mismatched types
+  --> $DIR/hr-subtype.rs:39:26
    |
-LL | / fn main() {
-LL | | //[bound_a_vs_bound_a]~^ ERROR compilation successful
-LL | | //[bound_a_vs_bound_b]~^^ ERROR compilation successful
-LL | | //[bound_inv_a_vs_bound_inv_b]~^^^ ERROR compilation successful
-...  |
-LL | | //[bound_contra_a_contra_b_ret_co_a]~^^^^^^^^^ ERROR compilation successful
-LL | | }
-   | |_^
+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 type `std::option::Option<for<'a, 'b> fn(Contra<'a>, Contra<'b>) -> Co<'a>>`
+              found type `std::option::Option<for<'a> fn(Contra<'a>, Contra<'a>) -> Co<'a>>`
 
 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.stderr b/src/test/ui/hr-subtype/hr-subtype.bound_inv_a_b_vs_bound_inv_a.stderr
index 8168941e277..fae6e9b5c89 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
@@ -2,7 +2,7 @@ error[E0308]: mismatched types
   --> $DIR/hr-subtype.rs:39:26
    |
 LL |               gimme::<$t1>(None::<$t2>);
-   |                            ^^^^^^^^^^^ one type is more general than the other
+   |                            ^^^^^^^^^^^ expected concrete lifetime, found bound lifetime parameter 'a
 ...
 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>)) }
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 25b74d855bb..5fcb63e17bf 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,12 +1,12 @@
 error: compilation successful
-  --> $DIR/hr-subtype.rs:96:1
+  --> $DIR/hr-subtype.rs:100:1
    |
 LL | / fn main() {
 LL | | //[bound_a_vs_bound_a]~^ ERROR compilation successful
 LL | | //[bound_a_vs_bound_b]~^^ ERROR compilation successful
 LL | | //[bound_inv_a_vs_bound_inv_b]~^^^ ERROR compilation successful
-...  |
-LL | | //[bound_contra_a_contra_b_ret_co_a]~^^^^^^^^^ ERROR compilation successful
+LL | | //[bound_co_a_vs_bound_co_b]~^^^^ ERROR compilation successful
+LL | | //[free_x_vs_free_x]~^^^^^ ERROR compilation successful
 LL | | }
    | |_^
 
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 25b74d855bb..5fcb63e17bf 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,12 +1,12 @@
 error: compilation successful
-  --> $DIR/hr-subtype.rs:96:1
+  --> $DIR/hr-subtype.rs:100:1
    |
 LL | / fn main() {
 LL | | //[bound_a_vs_bound_a]~^ ERROR compilation successful
 LL | | //[bound_a_vs_bound_b]~^^ ERROR compilation successful
 LL | | //[bound_inv_a_vs_bound_inv_b]~^^^ ERROR compilation successful
-...  |
-LL | | //[bound_contra_a_contra_b_ret_co_a]~^^^^^^^^^ ERROR compilation successful
+LL | | //[bound_co_a_vs_bound_co_b]~^^^^ ERROR compilation successful
+LL | | //[free_x_vs_free_x]~^^^^^ ERROR compilation successful
 LL | | }
    | |_^
 
diff --git a/src/test/ui/hr-subtype/hr-subtype.rs b/src/test/ui/hr-subtype/hr-subtype.rs
index ad4f39f8405..2f7c1e6fd8c 100644
--- a/src/test/ui/hr-subtype/hr-subtype.rs
+++ b/src/test/ui/hr-subtype/hr-subtype.rs
@@ -42,6 +42,10 @@ macro_rules! check {
             //[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
         }
     }
 }
@@ -99,8 +103,4 @@ fn main() {
 //[bound_inv_a_vs_bound_inv_b]~^^^ ERROR compilation successful
 //[bound_co_a_vs_bound_co_b]~^^^^ ERROR compilation successful
 //[free_x_vs_free_x]~^^^^^ ERROR compilation successful
-//[bound_a_b_vs_bound_a]~^^^^^^ ERROR compilation successful
-//[bound_co_a_co_b_ret_contra_a]~^^^^^^^ ERROR compilation successful
-//[bound_co_a_b_vs_bound_co_a]~^^^^^^^^ ERROR compilation successful
-//[bound_contra_a_contra_b_ret_co_a]~^^^^^^^^^ ERROR compilation successful
 }
diff --git a/src/test/ui/hrtb/hrtb-conflate-regions.stderr b/src/test/ui/hrtb/hrtb-conflate-regions.stderr
index 630dda2694f..50e1af8f142 100644
--- a/src/test/ui/hrtb/hrtb-conflate-regions.stderr
+++ b/src/test/ui/hrtb/hrtb-conflate-regions.stderr
@@ -1,12 +1,20 @@
-error: implementation of `Foo` is not general enough
+error[E0277]: the trait bound `for<'a, 'b> SomeStruct: Foo<(&'a isize, &'b isize)>` is not satisfied
   --> $DIR/hrtb-conflate-regions.rs:28:10
    |
 LL | fn b() { want_foo2::<SomeStruct>(); } //~ ERROR
-   |          ^^^^^^^^^^^^^^^^^^^^^^^
+   |          ^^^^^^^^^^^^^^^^^^^^^^^ the trait `for<'a, 'b> Foo<(&'a isize, &'b isize)>` is not implemented for `SomeStruct`
    |
-   = note: Due to a where-clause on `want_foo2`,
-   = 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`
+   = help: the following implementations were found:
+             <SomeStruct as Foo<(&'a isize, &'a isize)>>
+note: required by `want_foo2`
+  --> $DIR/hrtb-conflate-regions.rs:8:1
+   |
+LL | / fn want_foo2<T>()
+LL | |     where T : for<'a,'b> Foo<(&'a isize, &'b isize)>
+LL | | {
+LL | | }
+   | |_^
 
 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.stderr b/src/test/ui/hrtb/hrtb-exists-forall-fn.stderr
index 6301ed45ac2..8e8892552b7 100644
--- a/src/test/ui/hrtb/hrtb-exists-forall-fn.stderr
+++ b/src/test/ui/hrtb/hrtb-exists-forall-fn.stderr
@@ -2,7 +2,7 @@ error[E0308]: mismatched types
   --> $DIR/hrtb-exists-forall-fn.rs:17:34
    |
 LL |     let _: for<'b> fn(&'b u32) = foo(); //~ ERROR mismatched types
-   |                                  ^^^^^ one type is more general than the other
+   |                                  ^^^^^ expected concrete lifetime, found bound lifetime parameter 'b
    |
    = note: expected type `for<'b> fn(&'b u32)`
               found type `fn(&u32)`
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 8801760056e..4c1d4d28a09 100644
--- a/src/test/ui/hrtb/hrtb-exists-forall-trait-contravariant.rs
+++ b/src/test/ui/hrtb/hrtb-exists-forall-trait-contravariant.rs
@@ -1,9 +1,7 @@
-// Test a `exists<'a> { forall<'b> { 'a = 'b } }` pattern -- which should not compile!
+// Test a case where variance and higher-ranked types interact in surprising ways.
 //
 // In particular, we test this pattern in trait solving, where it is not connected
 // to any part of the source code.
-//
-// compile-pass
 
 trait Trait<T> {}
 
@@ -30,6 +28,9 @@ fn main() {
     //     - `?a: ?b` -- solveable if `?b` is also inferred to `'empty`
     // - So the subtyping check succeeds, somewhat surprisingly.
     //   This is because we can use `'empty`.
+    //
+    // 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-contravariant.stderr b/src/test/ui/hrtb/hrtb-exists-forall-trait-contravariant.stderr
new file mode 100644
index 00000000000..7f2ca037f0f
--- /dev/null
+++ b/src/test/ui/hrtb/hrtb-exists-forall-trait-contravariant.stderr
@@ -0,0 +1,21 @@
+error[E0277]: the trait bound `(): Trait<for<'b> fn(&'b u32)>` is not satisfied
+  --> $DIR/hrtb-exists-forall-trait-contravariant.rs:34:5
+   |
+LL |     foo::<()>();
+   |     ^^^^^^^^^ the trait `Trait<for<'b> fn(&'b u32)>` is not implemented for `()`
+   |
+   = help: the following implementations were found:
+             <() as Trait<fn(&'a u32)>>
+note: required by `foo`
+  --> $DIR/hrtb-exists-forall-trait-contravariant.rs:8:1
+   |
+LL | / fn foo<T>()
+LL | | where
+LL | |     T: Trait<for<'b> fn(&'b u32)>,
+LL | | {
+LL | | }
+   | |_^
+
+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 da1bb7cd5fd..95b57d6c5bb 100644
--- a/src/test/ui/hrtb/hrtb-exists-forall-trait-covariant.rs
+++ b/src/test/ui/hrtb/hrtb-exists-forall-trait-covariant.rs
@@ -1,9 +1,7 @@
-// Test a `exists<'a> { forall<'b> { 'a = 'b } }` pattern -- which should not compile!
+// Test a case where variance and higher-ranked types interact in surprising ways.
 //
 // In particular, we test this pattern in trait solving, where it is not connected
 // to any part of the source code.
-//
-// compile-pass
 
 trait Trait<T> {}
 
@@ -32,6 +30,9 @@ 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
new file mode 100644
index 00000000000..cd5982e7588
--- /dev/null
+++ b/src/test/ui/hrtb/hrtb-exists-forall-trait-covariant.stderr
@@ -0,0 +1,21 @@
+error[E0277]: the trait bound `(): Trait<for<'b> fn(fn(&'b u32))>` is not satisfied
+  --> $DIR/hrtb-exists-forall-trait-covariant.rs:36:5
+   |
+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))>>
+note: required by `foo`
+  --> $DIR/hrtb-exists-forall-trait-covariant.rs:8:1
+   |
+LL | / fn foo<T>()
+LL | | where
+LL | |     T: Trait<for<'b> fn(fn(&'b u32))>,
+LL | | {
+LL | | }
+   | |_^
+
+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.rs b/src/test/ui/hrtb/hrtb-exists-forall-trait-invariant.rs
index da3f8ad1b89..827a68beee8 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 general enough
+    foo::<()>(); //~ ERROR not satisfied
 }
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 a44837a1e26..f56b81759fe 100644
--- a/src/test/ui/hrtb/hrtb-exists-forall-trait-invariant.stderr
+++ b/src/test/ui/hrtb/hrtb-exists-forall-trait-invariant.stderr
@@ -1,12 +1,21 @@
-error: implementation of `Trait` is not general enough
+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:5
    |
-LL |     foo::<()>(); //~ ERROR not general enough
-   |     ^^^^^^^^^
+LL |     foo::<()>(); //~ ERROR not satisfied
+   |     ^^^^^^^^^ the trait `Trait<for<'b> fn(std::cell::Cell<&'b u32>)>` is not implemented for `()`
    |
-   = note: Due to a where-clause on `foo`,
-   = 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`
+   = help: the following implementations were found:
+             <() as Trait<fn(std::cell::Cell<&'a u32>)>>
+note: required by `foo`
+  --> $DIR/hrtb-exists-forall-trait-invariant.rs:10:1
+   |
+LL | / fn foo<T>()
+LL | | where
+LL | |     T: Trait<for<'b> fn(Cell<&'b u32>)>,
+LL | | {
+LL | | }
+   | |_^
 
 error: aborting due to previous error
 
+For more information about this error, try `rustc --explain E0277`.
diff --git a/src/test/ui/hrtb/hrtb-higher-ranker-supertraits-transitive.stderr b/src/test/ui/hrtb/hrtb-higher-ranker-supertraits-transitive.stderr
index 0d7b5cbf823..77c1789852e 100644
--- a/src/test/ui/hrtb/hrtb-higher-ranker-supertraits-transitive.stderr
+++ b/src/test/ui/hrtb/hrtb-higher-ranker-supertraits-transitive.stderr
@@ -1,12 +1,19 @@
-error[E0308]: mismatched types
+error[E0277]: the trait bound `for<'ccx> B: Bar<'ccx>` is not satisfied
   --> $DIR/hrtb-higher-ranker-supertraits-transitive.rs:47:5
    |
 LL |     want_bar_for_any_ccx(b); //~ ERROR
-   |     ^^^^^^^^^^^^^^^^^^^^ one type is more general than the other
+   |     ^^^^^^^^^^^^^^^^^^^^ the trait `for<'ccx> Bar<'ccx>` is not implemented for `B`
    |
-   = note: expected type `for<'ccx> Bar<'ccx>`
-              found type `Bar<'static>`
+   = help: consider adding a `where for<'ccx> B: Bar<'ccx>` bound
+note: required by `want_bar_for_any_ccx`
+  --> $DIR/hrtb-higher-ranker-supertraits-transitive.rs:31:1
+   |
+LL | / fn want_bar_for_any_ccx<B>(b: &B)
+LL | |     where B : for<'ccx> Bar<'ccx>
+LL | | {
+LL | | }
+   | |_^
 
 error: aborting due to previous error
 
-For more information about this error, try `rustc --explain E0308`.
+For more information about this error, try `rustc --explain E0277`.
diff --git a/src/test/ui/hrtb/hrtb-higher-ranker-supertraits.rs b/src/test/ui/hrtb/hrtb-higher-ranker-supertraits.rs
index 3d2d403462d..48ebe5017aa 100644
--- a/src/test/ui/hrtb/hrtb-higher-ranker-supertraits.rs
+++ b/src/test/ui/hrtb/hrtb-higher-ranker-supertraits.rs
@@ -15,7 +15,7 @@ fn want_foo_for_some_tcx<'x,F>(f: &'x F)
     where F : Foo<'x>
 {
     want_foo_for_some_tcx(f);
-    want_foo_for_any_tcx(f); //~ ERROR E0308
+    want_foo_for_any_tcx(f); //~ ERROR not satisfied
 }
 
 fn want_foo_for_any_tcx<F>(f: &F)
@@ -32,7 +32,7 @@ fn want_bar_for_some_ccx<'x,B>(b: &B)
     want_foo_for_any_tcx(b);
 
     want_bar_for_some_ccx(b);
-    want_bar_for_any_ccx(b); //~ ERROR E0308
+    want_bar_for_any_ccx(b); //~ ERROR not satisfied
 }
 
 fn want_bar_for_any_ccx<B>(b: &B)
diff --git a/src/test/ui/hrtb/hrtb-higher-ranker-supertraits.stderr b/src/test/ui/hrtb/hrtb-higher-ranker-supertraits.stderr
index 31dbeec2a55..5914cb3eaa4 100644
--- a/src/test/ui/hrtb/hrtb-higher-ranker-supertraits.stderr
+++ b/src/test/ui/hrtb/hrtb-higher-ranker-supertraits.stderr
@@ -1,21 +1,40 @@
-error[E0308]: mismatched types
+error[E0277]: the trait bound `for<'tcx> F: Foo<'tcx>` is not satisfied
   --> $DIR/hrtb-higher-ranker-supertraits.rs:18:5
    |
-LL |     want_foo_for_any_tcx(f); //~ ERROR E0308
-   |     ^^^^^^^^^^^^^^^^^^^^ one type is more general than the other
+LL |     want_foo_for_any_tcx(f); //~ ERROR not satisfied
+   |     ^^^^^^^^^^^^^^^^^^^^ the trait `for<'tcx> Foo<'tcx>` is not implemented for `F`
    |
-   = note: expected type `for<'tcx> Foo<'tcx>`
-              found type `Foo<'x>`
+   = help: consider adding a `where for<'tcx> F: Foo<'tcx>` bound
+note: required by `want_foo_for_any_tcx`
+  --> $DIR/hrtb-higher-ranker-supertraits.rs:21:1
+   |
+LL | / fn want_foo_for_any_tcx<F>(f: &F)
+LL | |     where F : for<'tcx> Foo<'tcx>
+LL | | {
+LL | |     want_foo_for_some_tcx(f);
+LL | |     want_foo_for_any_tcx(f);
+LL | | }
+   | |_^
 
-error[E0308]: mismatched types
+error[E0277]: the trait bound `for<'ccx> B: Bar<'ccx>` is not satisfied
   --> $DIR/hrtb-higher-ranker-supertraits.rs:35:5
    |
-LL |     want_bar_for_any_ccx(b); //~ ERROR E0308
-   |     ^^^^^^^^^^^^^^^^^^^^ one type is more general than the other
+LL |     want_bar_for_any_ccx(b); //~ ERROR not satisfied
+   |     ^^^^^^^^^^^^^^^^^^^^ the trait `for<'ccx> Bar<'ccx>` is not implemented for `B`
+   |
+   = help: consider adding a `where for<'ccx> B: Bar<'ccx>` bound
+note: required by `want_bar_for_any_ccx`
+  --> $DIR/hrtb-higher-ranker-supertraits.rs:38:1
    |
-   = note: expected type `for<'ccx> Bar<'ccx>`
-              found type `Bar<'x>`
+LL | / fn want_bar_for_any_ccx<B>(b: &B)
+LL | |     where B : for<'ccx> Bar<'ccx>
+LL | | {
+LL | |     want_foo_for_some_tcx(b);
+...  |
+LL | |     want_bar_for_any_ccx(b);
+LL | | }
+   | |_^
 
 error: aborting due to 2 previous errors
 
-For more information about this error, try `rustc --explain E0308`.
+For more information about this error, try `rustc --explain E0277`.
diff --git a/src/test/ui/hrtb/hrtb-just-for-static.stderr b/src/test/ui/hrtb/hrtb-just-for-static.stderr
index 99c87f13672..fe2bc1f2225 100644
--- a/src/test/ui/hrtb/hrtb-just-for-static.stderr
+++ b/src/test/ui/hrtb/hrtb-just-for-static.stderr
@@ -1,22 +1,37 @@
-error: implementation of `Foo` is not general enough
+error[E0277]: the trait bound `for<'a> StaticInt: Foo<&'a isize>` is not satisfied
   --> $DIR/hrtb-just-for-static.rs:24:5
    |
 LL |     want_hrtb::<StaticInt>() //~ ERROR
-   |     ^^^^^^^^^^^^^^^^^^^^^^
+   |     ^^^^^^^^^^^^^^^^^^^^^^ the trait `for<'a> Foo<&'a isize>` is not implemented for `StaticInt`
    |
-   = note: Due to a where-clause on `want_hrtb`,
-   = note: `StaticInt` must implement `Foo<&'0 isize>`, for any lifetime `'0`
-   = note: but `StaticInt` actually implements `Foo<&'1 isize>`, for some specific lifetime `'1`
+   = help: the following implementations were found:
+             <StaticInt as Foo<&'static isize>>
+note: required by `want_hrtb`
+  --> $DIR/hrtb-just-for-static.rs:8:1
+   |
+LL | / fn want_hrtb<T>()
+LL | |     where T : for<'a> Foo<&'a isize>
+LL | | {
+LL | | }
+   | |_^
 
-error: implementation of `Foo` is not general enough
+error[E0277]: the trait bound `for<'a> &'a u32: Foo<&'a isize>` is not satisfied
   --> $DIR/hrtb-just-for-static.rs:30:5
    |
 LL |     want_hrtb::<&'a u32>() //~ ERROR
-   |     ^^^^^^^^^^^^^^^^^^^^
+   |     ^^^^^^^^^^^^^^^^^^^^ the trait `for<'a> Foo<&'a isize>` is not implemented for `&'a u32`
+   |
+   = help: the following implementations were found:
+             <&'a u32 as Foo<&'a isize>>
+note: required by `want_hrtb`
+  --> $DIR/hrtb-just-for-static.rs:8:1
    |
-   = note: Due to a where-clause on `want_hrtb`,
-   = 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`
+LL | / fn want_hrtb<T>()
+LL | |     where T : for<'a> Foo<&'a isize>
+LL | | {
+LL | | }
+   | |_^
 
 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-46989.rs b/src/test/ui/hrtb/issue-46989.rs
new file mode 100644
index 00000000000..2c859055458
--- /dev/null
+++ b/src/test/ui/hrtb/issue-46989.rs
@@ -0,0 +1,42 @@
+// Regression test for #46989:
+//
+// In the move to universes, this test started passing.
+// It is not necessarily WRONG to do so, but it was a bit
+// surprising. The reason that it passed is that when we were
+// asked to prove that
+//
+//     for<'a> fn(&'a i32): Foo
+//
+// we were able to use the impl below to prove
+//
+//     fn(&'empty i32): Foo
+//
+// and then we were able to prove that
+//
+//     fn(&'empty i32) = for<'a> fn(&'a i32)
+//
+// This last fact is somewhat surprising, but essentially "falls out"
+// from handling variance correctly. In particular, consider the subtyping
+// relations. First:
+//
+//     fn(&'empty i32) <: for<'a> fn(&'a i32)
+//
+// This holds because -- intuitively -- a fn that takes a reference but doesn't use
+// it can be given a reference with any lifetime. Similarly, the opposite direction:
+//
+//     for<'a> fn(&'a i32) <: fn(&'empty i32)
+//
+// holds because 'a can be instantiated to 'empty.
+
+trait Foo {
+
+}
+
+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
+}
diff --git a/src/test/ui/hrtb/issue-46989.stderr b/src/test/ui/hrtb/issue-46989.stderr
new file mode 100644
index 00000000000..b308291d5c0
--- /dev/null
+++ b/src/test/ui/hrtb/issue-46989.stderr
@@ -0,0 +1,17 @@
+error[E0277]: the trait bound `for<'r> fn(&'r i32): Foo` is not satisfied
+  --> $DIR/issue-46989.rs:40:5
+   |
+LL |     assert_foo::<fn(&i32)>();
+   |     ^^^^^^^^^^^^^^^^^^^^^^ the trait `Foo` is not implemented for `for<'r> fn(&'r i32)`
+   |
+   = help: the following implementations were found:
+             <fn(A) as Foo>
+note: required by `assert_foo`
+  --> $DIR/issue-46989.rs:37:1
+   |
+LL | fn assert_foo<T: Foo>() {}
+   | ^^^^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0277`.
diff --git a/src/test/ui/hrtb/issue-57639.rs b/src/test/ui/hrtb/issue-57639.rs
new file mode 100644
index 00000000000..4bcaef3616b
--- /dev/null
+++ b/src/test/ui/hrtb/issue-57639.rs
@@ -0,0 +1,29 @@
+// Regression test for #57639:
+//
+// In the move to universes, this test stopped working. The problem
+// was that when the trait solver was asked to prove `for<'a> T::Item:
+// Foo<'a>` as part of WF checking, it wound up "eagerly committing"
+// to the where clause, which says that `T::Item: Foo<'a>`, but it
+// should instead have been using the bound found in the trait
+// declaration. Pre-universe, this used to work out ok because we got
+// "eager errors" due to the leak check.
+//
+// See [this comment on GitHub][c] for more details.
+//
+// run-pass
+//
+// [c]: https://github.com/rust-lang/rust/issues/57639#issuecomment-455685861
+
+trait Foo<'a> {}
+
+trait Bar {
+    type Item: for<'a> Foo<'a>;
+}
+
+fn foo<'a, T>(_: T)
+where
+    T: Bar,
+    T::Item: Foo<'a>,
+{}
+
+fn main() { }
diff --git a/src/test/ui/hrtb/issue-58451.rs b/src/test/ui/hrtb/issue-58451.rs
new file mode 100644
index 00000000000..229e5057678
--- /dev/null
+++ b/src/test/ui/hrtb/issue-58451.rs
@@ -0,0 +1,13 @@
+// Regression test for #58451:
+//
+// Error reporting here encountered an ICE in the shift to universes.
+
+fn f<I>(i: I)
+where
+    I: IntoIterator,
+    I::Item: for<'a> Into<&'a ()>,
+{}
+
+fn main() {
+    f(&[f()]); //~ ERROR this function takes 1 parameter
+}
diff --git a/src/test/ui/hrtb/issue-58451.stderr b/src/test/ui/hrtb/issue-58451.stderr
new file mode 100644
index 00000000000..79c24855dc9
--- /dev/null
+++ b/src/test/ui/hrtb/issue-58451.stderr
@@ -0,0 +1,16 @@
+error[E0061]: this function takes 1 parameter but 0 parameters were supplied
+  --> $DIR/issue-58451.rs:12:9
+   |
+LL | / fn f<I>(i: I)
+LL | | where
+LL | |     I: IntoIterator,
+LL | |     I::Item: for<'a> Into<&'a ()>,
+LL | | {}
+   | |__- defined here
+...
+LL |       f(&[f()]); //~ ERROR this function takes 1 parameter
+   |           ^^^ expected 1 parameter
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0061`.
diff --git a/src/test/ui/issues/issue-40000.stderr b/src/test/ui/issues/issue-40000.stderr
index d7966cea52b..ce0c44c1475 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); //~ ERROR E0308
-   |         ^^^ one type is more general than the other
+   |         ^^^ expected concrete lifetime, found bound lifetime parameter
    |
-   = note: expected type `dyn for<'r> std::ops::Fn(&'r i32)`
-              found type `dyn std::ops::Fn(&i32)`
+   = note: expected type `std::boxed::Box<(dyn for<'r> std::ops::Fn(&'r i32) + 'static)>`
+              found type `std::boxed::Box<dyn std::ops::Fn(_)>`
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/issues/issue-57362-1.rs b/src/test/ui/issues/issue-57362-1.rs
index fe6b69f0097..1fa417fe98a 100644
--- a/src/test/ui/issues/issue-57362-1.rs
+++ b/src/test/ui/issues/issue-57362-1.rs
@@ -17,7 +17,7 @@ impl<T> Trait for fn(&T) {
 
 fn f() {
     let a: fn(_) = |_: &u8| {};
-    a.f(); //~ ERROR not general enough
+    a.f(); //~ ERROR no method named `f`
 }
 
 fn main() {}
diff --git a/src/test/ui/issues/issue-57362-1.stderr b/src/test/ui/issues/issue-57362-1.stderr
index 06946bcf744..b21b35849b1 100644
--- a/src/test/ui/issues/issue-57362-1.stderr
+++ b/src/test/ui/issues/issue-57362-1.stderr
@@ -1,11 +1,14 @@
-error: implementation of `Trait` is not general enough
+error[E0599]: no method named `f` found for type `fn(&u8)` in the current scope
   --> $DIR/issue-57362-1.rs:20:7
    |
-LL |     a.f(); //~ ERROR not general enough
+LL |     a.f(); //~ ERROR no method named `f`
    |       ^
    |
-   = note: `Trait` would have to be implemented for the type `fn(&'0 u8)`, for some specific lifetime `'0`
-   = note: but `Trait` is actually implemented for the type `for<'r> fn(&'r u8)`
+   = note: a is a function, perhaps you wish to call it
+   = help: items from traits can only be used if the trait is implemented and in scope
+   = note: the following trait defines an item `f`, perhaps you need to implement it:
+           candidate #1: `Trait`
 
 error: aborting due to previous error
 
+For more information about this error, try `rustc --explain E0599`.
diff --git a/src/test/ui/issues/issue-57362-2.rs b/src/test/ui/issues/issue-57362-2.rs
index 436a4a90457..870d7f28ba9 100644
--- a/src/test/ui/issues/issue-57362-2.rs
+++ b/src/test/ui/issues/issue-57362-2.rs
@@ -19,7 +19,7 @@ impl<'a> X for fn(&'a ()) {
 }
 
 fn g() {
-    let x = <fn (&())>::make_g(); //~ ERROR not general enough
+    let x = <fn (&())>::make_g(); //~ ERROR no function or associated item
 }
 
 fn main() {}
diff --git a/src/test/ui/issues/issue-57362-2.stderr b/src/test/ui/issues/issue-57362-2.stderr
index 14b7f52bb87..b8211691f7b 100644
--- a/src/test/ui/issues/issue-57362-2.stderr
+++ b/src/test/ui/issues/issue-57362-2.stderr
@@ -1,11 +1,15 @@
-error: implementation of `X` is not general enough
-  --> $DIR/issue-57362-2.rs:22:13
+error[E0599]: no function or associated item named `make_g` found for type `for<'r> fn(&'r ())` in the current scope
+  --> $DIR/issue-57362-2.rs:22:25
    |
-LL |     let x = <fn (&())>::make_g(); //~ ERROR not general enough
-   |             ^^^^^^^^^^^^^^^^^^
+LL |     let x = <fn (&())>::make_g(); //~ ERROR no function or associated item
+   |             ------------^^^^^^
+   |             |
+   |             function or associated item not found in `for<'r> fn(&'r ())`
    |
-   = note: `X` would have to be implemented for the type `for<'r> fn(&'r ())`
-   = note: but `X` is actually implemented for the type `fn(&'0 ())`, for some specific lifetime `'0`
+   = help: items from traits can only be used if the trait is implemented and in scope
+   = note: the following trait defines an item `make_g`, perhaps you need to implement it:
+           candidate #1: `X`
 
 error: aborting due to previous error
 
+For more information about this error, try `rustc --explain E0599`.
diff --git a/src/test/ui/lub-glb/old-lub-glb-hr.rs b/src/test/ui/lub-glb/old-lub-glb-hr.rs
index 324dc86bd92..6bf1fd41d77 100644
--- a/src/test/ui/lub-glb/old-lub-glb-hr.rs
+++ b/src/test/ui/lub-glb/old-lub-glb-hr.rs
@@ -4,7 +4,8 @@
 // longer get an error, because we recognize these two types as
 // equivalent!
 //
-// compile-pass
+// Whoops -- now that we reinstituted the leak-check, we get an error
+// again.
 
 fn foo(
     x: fn(&u8, &u8),
@@ -12,7 +13,7 @@ fn foo(
 ) {
     let z = match 22 {
         0 => x,
-        _ => y,
+        _ => y, //~ ERROR match arms have incompatible types
     };
 }
 
diff --git a/src/test/ui/lub-glb/old-lub-glb-hr.stderr b/src/test/ui/lub-glb/old-lub-glb-hr.stderr
new file mode 100644
index 00000000000..8f228ea4cad
--- /dev/null
+++ b/src/test/ui/lub-glb/old-lub-glb-hr.stderr
@@ -0,0 +1,18 @@
+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, //~ ERROR match arms have incompatible types
+   | |              ^ 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 type `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.rs b/src/test/ui/lub-glb/old-lub-glb-object.rs
index 9be7a813603..dcd604a5157 100644
--- a/src/test/ui/lub-glb/old-lub-glb-object.rs
+++ b/src/test/ui/lub-glb/old-lub-glb-object.rs
@@ -7,9 +7,9 @@ fn foo(
     x: &for<'a, 'b> Foo<&'a u8, &'b u8>,
     y: &for<'a> Foo<&'a u8, &'a u8>,
 ) {
-    let z = match 22 { //~ ERROR E0308
+    let z = match 22 {
         0 => x,
-        _ => y,
+        _ => y, //~ ERROR match arms have incompatible types
     };
 }
 
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 17d3648156b..056f9131dd2 100644
--- a/src/test/ui/lub-glb/old-lub-glb-object.stderr
+++ b/src/test/ui/lub-glb/old-lub-glb-object.stderr
@@ -1,15 +1,17 @@
-error[E0308]: mismatched types
-  --> $DIR/old-lub-glb-object.rs:10:13
+error[E0308]: match arms have incompatible types
+  --> $DIR/old-lub-glb-object.rs:12:14
    |
-LL |       let z = match 22 { //~ ERROR E0308
-   |  _____________^
+LL |       let z = match 22 {
+   |  _____________-
 LL | |         0 => x,
-LL | |         _ => y,
+   | |              - this is found to be of type `&dyn for<'a, 'b> Foo<&'a u8, &'b u8>`
+LL | |         _ => y, //~ ERROR match arms have incompatible types
+   | |              ^ expected bound lifetime parameter 'a, found concrete lifetime
 LL | |     };
-   | |_____^ one type is more general than the other
+   | |_____- `match` arms have incompatible types
    |
-   = note: expected type `dyn for<'a, 'b> Foo<&'a u8, &'b u8>`
-              found type `dyn for<'a> Foo<&'a u8, &'a u8>`
+   = note: expected type `&dyn for<'a, 'b> Foo<&'a u8, &'b u8>`
+              found type `&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.rs b/src/test/ui/mismatched_types/closure-arg-type-mismatch.rs
index 437150666be..521bd3695df 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,6 @@ fn main() {
 
 fn baz<F: Fn(*mut &u32)>(_: F) {}
 fn _test<'a>(f: fn(*mut &'a u32)) {
-    baz(f); //~ ERROR mismatched types
-     //~| ERROR mismatched types
+    baz(f); //~ ERROR type mismatch
+     //~| ERROR type mismatch
 }
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 a6628006587..5dd6887005e 100644
--- a/src/test/ui/mismatched_types/closure-arg-type-mismatch.stderr
+++ b/src/test/ui/mismatched_types/closure-arg-type-mismatch.stderr
@@ -22,25 +22,34 @@ LL |     a.iter().map(|_: (u16, u16)| 45); //~ ERROR type mismatch
    |              |
    |              expected signature of `fn(&(u32, u32)) -> _`
 
-error[E0308]: mismatched types
+error[E0631]: type mismatch in function arguments
   --> $DIR/closure-arg-type-mismatch.rs:10:5
    |
-LL |     baz(f); //~ ERROR mismatched types
-   |     ^^^ one type is more general than the other
+LL |     baz(f); //~ ERROR type mismatch
+   |     ^^^
+   |     |
+   |     expected signature of `for<'r> fn(*mut &'r u32) -> _`
+   |     found signature of `fn(*mut &'a u32) -> _`
    |
-   = note: expected type `for<'r> std::ops::Fn<(*mut &'r u32,)>`
-              found type `std::ops::Fn<(*mut &'a u32,)>`
+note: required by `baz`
+  --> $DIR/closure-arg-type-mismatch.rs:8:1
+   |
+LL | fn baz<F: Fn(*mut &u32)>(_: F) {}
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
-error[E0308]: mismatched types
+error[E0271]: type mismatch resolving `for<'r> <fn(*mut &'a u32) as std::ops::FnOnce<(*mut &'r u32,)>>::Output == ()`
   --> $DIR/closure-arg-type-mismatch.rs:10:5
    |
-LL |     baz(f); //~ ERROR mismatched types
-   |     ^^^ one type is more general than the other
+LL |     baz(f); //~ ERROR type mismatch
+   |     ^^^ expected bound lifetime parameter, found concrete lifetime
+   |
+note: required by `baz`
+  --> $DIR/closure-arg-type-mismatch.rs:8:1
    |
-   = note: expected type `std::ops::FnOnce<(*mut &u32,)>`
-              found type `std::ops::FnOnce<(*mut &'a u32,)>`
+LL | fn baz<F: Fn(*mut &u32)>(_: F) {}
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: aborting due to 5 previous errors
 
-Some errors occurred: E0308, E0631.
-For more information about an error, try `rustc --explain E0308`.
+Some errors occurred: E0271, E0631.
+For more information about an error, try `rustc --explain E0271`.
diff --git a/src/test/ui/mismatched_types/closure-mismatch.rs b/src/test/ui/mismatched_types/closure-mismatch.rs
index 152a5254937..40a4641fe71 100644
--- a/src/test/ui/mismatched_types/closure-mismatch.rs
+++ b/src/test/ui/mismatched_types/closure-mismatch.rs
@@ -5,5 +5,6 @@ impl<T: Fn(&())> Foo for T {}
 fn baz<T: Foo>(_: T) {}
 
 fn main() {
-    baz(|_| ()); //~ ERROR E0308
+    baz(|_| ()); //~ ERROR type mismatch
+    //~^ ERROR type mismatch
 }
diff --git a/src/test/ui/mismatched_types/closure-mismatch.stderr b/src/test/ui/mismatched_types/closure-mismatch.stderr
index 0d87bc22875..e55047e96c2 100644
--- a/src/test/ui/mismatched_types/closure-mismatch.stderr
+++ b/src/test/ui/mismatched_types/closure-mismatch.stderr
@@ -1,12 +1,32 @@
-error[E0308]: mismatched types
+error[E0271]: type mismatch resolving `for<'r> <[closure@$DIR/closure-mismatch.rs:8:9: 8:15] as std::ops::FnOnce<(&'r (),)>>::Output == ()`
   --> $DIR/closure-mismatch.rs:8:5
    |
-LL |     baz(|_| ()); //~ ERROR E0308
-   |     ^^^ one type is more general than the other
+LL |     baz(|_| ()); //~ ERROR type mismatch
+   |     ^^^ expected bound lifetime parameter, found concrete lifetime
    |
-   = note: expected type `for<'r> std::ops::Fn<(&'r (),)>`
-              found type `std::ops::Fn<(&(),)>`
+   = note: required because of the requirements on the impl of `Foo` for `[closure@$DIR/closure-mismatch.rs:8:9: 8:15]`
+note: required by `baz`
+  --> $DIR/closure-mismatch.rs:5:1
+   |
+LL | fn baz<T: Foo>(_: T) {}
+   | ^^^^^^^^^^^^^^^^^^^^
+
+error[E0631]: type mismatch in closure arguments
+  --> $DIR/closure-mismatch.rs:8:5
+   |
+LL |     baz(|_| ()); //~ ERROR type mismatch
+   |     ^^^ ------ 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]`
+note: required by `baz`
+  --> $DIR/closure-mismatch.rs:5:1
+   |
+LL | fn baz<T: Foo>(_: T) {}
+   | ^^^^^^^^^^^^^^^^^^^^
 
-error: aborting due to previous error
+error: aborting due to 2 previous errors
 
-For more information about this error, try `rustc --explain E0308`.
+Some errors occurred: E0271, E0631.
+For more information about an error, try `rustc --explain E0271`.
diff --git a/src/test/ui/mismatched_types/issue-36053-2.rs b/src/test/ui/mismatched_types/issue-36053-2.rs
index 9035e3380b0..9edfebcd494 100644
--- a/src/test/ui/mismatched_types/issue-36053-2.rs
+++ b/src/test/ui/mismatched_types/issue-36053-2.rs
@@ -7,4 +7,5 @@ fn main() {
     once::<&str>("str").fuse().filter(|a: &str| true).count();
     //~^ ERROR no method named `count`
     //~| ERROR type mismatch in closure arguments
+    //~| ERROR type mismatch in closure arguments
 }
diff --git a/src/test/ui/mismatched_types/issue-36053-2.stderr b/src/test/ui/mismatched_types/issue-36053-2.stderr
index e53e8c520e0..c5c67e6bd9b 100644
--- a/src/test/ui/mismatched_types/issue-36053-2.stderr
+++ b/src/test/ui/mismatched_types/issue-36053-2.stderr
@@ -16,7 +16,15 @@ LL |     once::<&str>("str").fuse().filter(|a: &str| true).count();
    |                                |
    |                                expected signature of `for<'r> fn(&'r &str) -> _`
 
-error: aborting due to 2 previous errors
+error[E0631]: type mismatch in closure arguments
+  --> $DIR/issue-36053-2.rs:7:32
+   |
+LL |     once::<&str>("str").fuse().filter(|a: &str| true).count();
+   |                                ^^^^^^ -------------- found signature of `for<'r> fn(&'r str) -> _`
+   |                                |
+   |                                expected signature of `fn(&&str) -> _`
+
+error: aborting due to 3 previous errors
 
 Some errors occurred: E0599, E0631.
 For more information about an error, try `rustc --explain E0599`.
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 242119cc201..2dd0c9796e2 100644
--- a/src/test/ui/regions-fn-subtyping-return-static-fail.rs
+++ b/src/test/ui/regions-fn-subtyping-return-static-fail.rs
@@ -37,7 +37,7 @@ fn baz(x: &S) -> &S {
 fn supply_F() {
     want_F(foo);
 
-    want_F(bar);
+    want_F(bar); //~ ERROR mismatched types
 
     want_F(baz);
 }
@@ -45,7 +45,7 @@ fn supply_F() {
 fn supply_G() {
     want_G(foo);
     want_G(bar);
-    want_G(baz); //~ ERROR
+    want_G(baz); //~ ERROR mismatched types
 }
 
 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 a9234e43191..66e6a615b33 100644
--- a/src/test/ui/regions-fn-subtyping-return-static-fail.stderr
+++ b/src/test/ui/regions-fn-subtyping-return-static-fail.stderr
@@ -1,12 +1,21 @@
 error[E0308]: mismatched types
+  --> $DIR/regions-fn-subtyping-return-static-fail.rs:40:12
+   |
+LL |     want_F(bar); //~ ERROR mismatched types
+   |            ^^^ expected concrete lifetime, found bound lifetime parameter 'cx
+   |
+   = note: expected type `for<'cx> fn(&'cx S) -> &'cx S`
+              found type `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); //~ ERROR
-   |            ^^^ one type is more general than the other
+LL |     want_G(baz); //~ ERROR mismatched types
+   |            ^^^ expected concrete lifetime, found bound lifetime parameter 'cx
    |
    = note: expected type `for<'cx> fn(&'cx S) -> &'static S`
-              found type `for<'r> fn(&'r S) -> &'r S`
+              found type `for<'r> fn(&'r S) -> &'r S {baz}`
 
-error: aborting due to previous error
+error: aborting due to 2 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 47e1d0efdc7..5c8b3d3ba69 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,10 +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; //~ ERROR mismatched types
-   |                                           ^ one type is more general than the other
+   |                                           ^ expected concrete lifetime, found bound lifetime parameter
    |
    = note: expected type `for<'r, 's, 't0, 't1> fn(&'r mut &'s isize, &'t0 mut &'t1 isize)`
-              found type `for<'r, 's> fn(&'r mut &isize, &'s mut &isize)`
+              found type `for<'r, 's> fn(&'r mut &isize, &'s mut &isize) {a::<'_, '_>}`
 
 error: aborting due to 3 previous errors
 
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 1e7b99053f7..f36885f7aeb 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,10 +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; //~ ERROR E0308
-   |                                                        ^ one type is more general than the other
+   |                                                        ^ expected concrete lifetime, found bound lifetime parameter
    |
    = note: expected type `for<'r, 's, 't0, 't1, 't2, 't3> fn(&'r mut &'s isize, &'t0 mut &'t1 isize, &'t2 mut &'t3 isize)`
-              found type `for<'r, 's, 't0> fn(&'r mut &isize, &'s mut &isize, &'t0 mut &isize)`
+              found type `for<'r, 's, 't0> fn(&'r mut &isize, &'s mut &isize, &'t0 mut &isize) {a::<'_, '_, '_>}`
 
 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 9010770f1dc..fa2cc37d05b 100644
--- a/src/test/ui/regions/regions-fn-subtyping-return-static.rs
+++ b/src/test/ui/regions/regions-fn-subtyping-return-static.rs
@@ -5,8 +5,6 @@
 // *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.
-//
-// compile-pass
 
 #![allow(dead_code)]
 #![allow(unused_variables)]
@@ -40,7 +38,7 @@ fn baz(x: &S) -> &S {
 fn supply_F() {
     want_F(foo);
 
-    want_F(bar);
+    want_F(bar); //~ ERROR mismatched types
 
     want_F(baz);
 }
diff --git a/src/test/ui/regions/regions-fn-subtyping-return-static.stderr b/src/test/ui/regions/regions-fn-subtyping-return-static.stderr
new file mode 100644
index 00000000000..42a5a7c806e
--- /dev/null
+++ b/src/test/ui/regions/regions-fn-subtyping-return-static.stderr
@@ -0,0 +1,12 @@
+error[E0308]: mismatched types
+  --> $DIR/regions-fn-subtyping-return-static.rs:41:12
+   |
+LL |     want_F(bar); //~ ERROR mismatched types
+   |            ^^^ expected concrete lifetime, found bound lifetime parameter 'cx
+   |
+   = note: expected type `for<'cx> fn(&'cx S) -> &'cx S`
+              found type `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.stderr b/src/test/ui/regions/regions-lifetime-bounds-on-fns.stderr
index a43ee7ec3ac..99d85e9e4b5 100644
--- a/src/test/ui/regions/regions-lifetime-bounds-on-fns.stderr
+++ b/src/test/ui/regions/regions-lifetime-bounds-on-fns.stderr
@@ -20,10 +20,10 @@ error[E0308]: mismatched types
   --> $DIR/regions-lifetime-bounds-on-fns.rs:20:43
    |
 LL |     let _: fn(&mut &isize, &mut &isize) = a; //~ ERROR E0308
-   |                                           ^ one type is more general than the other
+   |                                           ^ expected concrete lifetime, found bound lifetime parameter
    |
    = note: expected type `for<'r, 's, 't0, 't1> fn(&'r mut &'s isize, &'t0 mut &'t1 isize)`
-              found type `for<'r, 's> fn(&'r mut &isize, &'s mut &isize)`
+              found type `for<'r, 's> fn(&'r mut &isize, &'s mut &isize) {a::<'_, '_>}`
 
 error: aborting due to 3 previous errors
 
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 12626fe69cb..a6e26614a6a 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
@@ -11,11 +11,13 @@ 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() {
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 29f276711c7..ca029828366 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
@@ -11,8 +11,21 @@ note: required by `call_it`
 LL | fn call_it<F:Fn(&isize)->isize>(_: &F, _: isize) -> isize { 0 }
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
+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:13
+   |
+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}`
+note: required by `call_it`
+  --> $DIR/unboxed-closures-unsafe-extern-fn.rs:7:1
+   |
+LL | fn call_it<F:Fn(&isize)->isize>(_: &F, _: isize) -> isize { 0 }
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
 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:17:13
+  --> $DIR/unboxed-closures-unsafe-extern-fn.rs:18:13
    |
 LL |     let y = call_it_mut(&mut square, 22);
    |             ^^^^^^^^^^^ expected an `FnMut<(&isize,)>` closure, found `for<'r> unsafe fn(&'r isize) -> isize {square}`
@@ -25,18 +38,31 @@ LL | fn call_it_mut<F:FnMut(&isize)->isize>(_: &mut F, _: isize) -> isize { 0 }
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 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:22:13
+  --> $DIR/unboxed-closures-unsafe-extern-fn.rs:18:13
+   |
+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}`
+note: required by `call_it_mut`
+  --> $DIR/unboxed-closures-unsafe-extern-fn.rs:8:1
+   |
+LL | fn call_it_mut<F:FnMut(&isize)->isize>(_: &mut F, _: isize) -> isize { 0 }
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+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:13
    |
 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 `for<'r> std::ops::FnOnce<(&'r isize,)>` is not implemented for `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}`
 note: required by `call_it_once`
   --> $DIR/unboxed-closures-unsafe-extern-fn.rs:9:1
    |
 LL | fn call_it_once<F:FnOnce(&isize)->isize>(_: F, _: isize) -> isize { 0 }
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
-error: aborting due to 3 previous errors
+error: aborting due to 5 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 7c3152c87c4..dd3b1afc39f 100644
--- a/src/test/ui/unboxed-closures/unboxed-closures-wrong-abi.rs
+++ b/src/test/ui/unboxed-closures/unboxed-closures-wrong-abi.rs
@@ -11,11 +11,13 @@ 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() {
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 e3824578605..0abc58aeebf 100644
--- a/src/test/ui/unboxed-closures/unboxed-closures-wrong-abi.stderr
+++ b/src/test/ui/unboxed-closures/unboxed-closures-wrong-abi.stderr
@@ -11,8 +11,21 @@ note: required by `call_it`
 LL | fn call_it<F:Fn(&isize)->isize>(_: &F, _: isize) -> isize { 0 }
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
+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:13
+   |
+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}`
+note: required by `call_it`
+  --> $DIR/unboxed-closures-wrong-abi.rs:7:1
+   |
+LL | fn call_it<F:Fn(&isize)->isize>(_: &F, _: isize) -> isize { 0 }
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
 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:17:13
+  --> $DIR/unboxed-closures-wrong-abi.rs:18:13
    |
 LL |     let y = call_it_mut(&mut square, 22);
    |             ^^^^^^^^^^^ expected an `FnMut<(&isize,)>` closure, found `for<'r> extern "C" fn(&'r isize) -> isize {square}`
@@ -25,18 +38,31 @@ LL | fn call_it_mut<F:FnMut(&isize)->isize>(_: &mut F, _: isize) -> isize { 0 }
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 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:22:13
+  --> $DIR/unboxed-closures-wrong-abi.rs:18:13
+   |
+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}`
+note: required by `call_it_mut`
+  --> $DIR/unboxed-closures-wrong-abi.rs:8:1
+   |
+LL | fn call_it_mut<F:FnMut(&isize)->isize>(_: &mut F, _: isize) -> isize { 0 }
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+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:13
    |
 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 `for<'r> std::ops::FnOnce<(&'r isize,)>` is not implemented for `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}`
 note: required by `call_it_once`
   --> $DIR/unboxed-closures-wrong-abi.rs:9:1
    |
 LL | fn call_it_once<F:FnOnce(&isize)->isize>(_: F, _: isize) -> isize { 0 }
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
-error: aborting due to 3 previous errors
+error: aborting due to 5 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 61d46869cbb..c689d792661 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
@@ -12,11 +12,13 @@ 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() {
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 da511f091bf..19b87ad171a 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
@@ -11,8 +11,21 @@ note: required by `call_it`
 LL | fn call_it<F:Fn(&isize)->isize>(_: &F, _: isize) -> isize { 0 }
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
+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:13
+   |
+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}`
+note: required by `call_it`
+  --> $DIR/unboxed-closures-wrong-arg-type-extern-fn.rs:8:1
+   |
+LL | fn call_it<F:Fn(&isize)->isize>(_: &F, _: isize) -> isize { 0 }
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
 error[E0277]: expected a `std::ops::FnMut<(&isize,)>` closure, found `unsafe fn(isize) -> isize {square}`
-  --> $DIR/unboxed-closures-wrong-arg-type-extern-fn.rs:18:13
+  --> $DIR/unboxed-closures-wrong-arg-type-extern-fn.rs:19:13
    |
 LL |     let y = call_it_mut(&mut square, 22);
    |             ^^^^^^^^^^^ expected an `FnMut<(&isize,)>` closure, found `unsafe fn(isize) -> isize {square}`
@@ -25,18 +38,31 @@ LL | fn call_it_mut<F:FnMut(&isize)->isize>(_: &mut F, _: isize) -> isize { 0 }
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error[E0277]: expected a `std::ops::FnOnce<(&isize,)>` closure, found `unsafe fn(isize) -> isize {square}`
-  --> $DIR/unboxed-closures-wrong-arg-type-extern-fn.rs:23:13
+  --> $DIR/unboxed-closures-wrong-arg-type-extern-fn.rs:19:13
+   |
+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}`
+note: required by `call_it_mut`
+  --> $DIR/unboxed-closures-wrong-arg-type-extern-fn.rs:9:1
+   |
+LL | fn call_it_mut<F:FnMut(&isize)->isize>(_: &mut F, _: isize) -> isize { 0 }
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+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:13
    |
 LL |     let z = call_it_once(square, 22);
    |             ^^^^^^^^^^^^ expected an `FnOnce<(&isize,)>` closure, found `unsafe fn(isize) -> isize {square}`
    |
-   = help: the trait `for<'r> std::ops::FnOnce<(&'r isize,)>` is not implemented for `unsafe fn(isize) -> isize {square}`
+   = help: the trait `std::ops::FnOnce<(&isize,)>` is not implemented for `unsafe fn(isize) -> isize {square}`
 note: required by `call_it_once`
   --> $DIR/unboxed-closures-wrong-arg-type-extern-fn.rs:10:1
    |
 LL | fn call_it_once<F:FnOnce(&isize)->isize>(_: F, _: isize) -> isize { 0 }
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
-error: aborting due to 3 previous errors
+error: aborting due to 5 previous errors
 
 For more information about this error, try `rustc --explain E0277`.
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 0ce38e69f6b..31174fd4cf1 100644
--- a/src/test/ui/where-clauses/where-for-self-2.rs
+++ b/src/test/ui/where-clauses/where-for-self-2.rs
@@ -18,5 +18,5 @@ fn foo<T>(x: &T)
 {}
 
 fn main() {
-    foo(&X); //~ ERROR implementation of `Bar` is not general enough
+    foo(&X); //~ ERROR trait bound
 }
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 342cabfd6bf..bbcb61a856d 100644
--- a/src/test/ui/where-clauses/where-for-self-2.stderr
+++ b/src/test/ui/where-clauses/where-for-self-2.stderr
@@ -1,12 +1,19 @@
-error: implementation of `Bar` is not general enough
+error[E0277]: the trait bound `for<'a> &'a _: Bar` is not satisfied
   --> $DIR/where-for-self-2.rs:21:5
    |
-LL |     foo(&X); //~ ERROR implementation of `Bar` is not general enough
-   |     ^^^
+LL |     foo(&X); //~ ERROR trait bound
+   |     ^^^ the trait `for<'a> Bar` is not implemented for `&'a _`
    |
-   = note: Due to a where-clause on `foo`,
-   = 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`
+   = help: the following implementations were found:
+             <&'static u32 as Bar>
+note: required by `foo`
+  --> $DIR/where-for-self-2.rs:16:1
+   |
+LL | / fn foo<T>(x: &T)
+LL | |     where for<'a> &'a T: Bar
+LL | | {}
+   | |__^
 
 error: aborting due to previous error
 
+For more information about this error, try `rustc --explain E0277`.