about summary refs log tree commit diff
path: root/src
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2017-11-17 22:16:11 +0000
committerbors <bors@rust-lang.org>2017-11-17 22:16:11 +0000
commit18d8acf41d21c19eedcb732d161ae943c438fd57 (patch)
treed0ea741999f6186f0926448d7a6812a58c8cd38c /src
parentaabfed5e0c84211005c1cb2ecec2206a574a5146 (diff)
parent9877fa048d66e7181a87de889768a67ea5ea3cd4 (diff)
downloadrust-18d8acf41d21c19eedcb732d161ae943c438fd57.tar.gz
rust-18d8acf41d21c19eedcb732d161ae943c438fd57.zip
Auto merge of #45853 - nikomatsakis:chalk-simplify-hr-lub-glb, r=arielb1
Simplify higher-ranked LUB/GLB

This is a better version of https://github.com/rust-lang/rust/pull/44211. It still makes higher-ranked LUB/GLB into a hard equality test, however, it does try to identify that something changed and issue a notice to the user. I wroteup https://github.com/rust-lang/rust/issues/45852 as a tracking issue for this change.

Currently, this moves straight to a hard-error, on the basis that the crater run in #44211 saw no impact. It might be good to retest -- or perhaps to try for a warning period. Trying to do the latter in a precise way would be somewhat painful, but an imprecise way might suffice -- that is, we could issue warning *whenever* a LUB/GLB operation succeeds that will later fail, even if it doesn't ultimately impact the type check. I could experiment with this.

~~I am *mildly* wary about landing this independently of other code that moves to a universe-based system. In particular, I was nervous that this change would make coherence accepts new pairs of impls that will later be errors. I have the code for the universe-based approach available, I hope to open an PR and run some tests on its impact very shortly.~~ @arielb1 points out that I was being silly.

r? @arielb1
Diffstat (limited to 'src')
-rw-r--r--src/librustc/infer/error_reporting/mod.rs9
-rw-r--r--src/librustc/infer/glb.rs28
-rw-r--r--src/librustc/infer/higher_ranked/mod.rs9
-rw-r--r--src/librustc/infer/lub.rs28
-rw-r--r--src/librustc/infer/mod.rs5
-rw-r--r--src/librustc/ty/error.rs11
-rw-r--r--src/librustc/ty/fold.rs9
-rw-r--r--src/librustc/ty/structural_impls.rs5
-rw-r--r--src/librustc_driver/test.rs212
-rw-r--r--src/test/run-pass/lub-glb-with-unbound-infer-var.rs24
-rw-r--r--src/test/ui/lub-glb/old-lub-glb-hr.rs36
-rw-r--r--src/test/ui/lub-glb/old-lub-glb-hr.stderr22
-rw-r--r--src/test/ui/lub-glb/old-lub-glb-object.rs38
-rw-r--r--src/test/ui/lub-glb/old-lub-glb-object.stderr22
14 files changed, 232 insertions, 226 deletions
diff --git a/src/librustc/infer/error_reporting/mod.rs b/src/librustc/infer/error_reporting/mod.rs
index d22eb20e70a..4f36193e197 100644
--- a/src/librustc/infer/error_reporting/mod.rs
+++ b/src/librustc/infer/error_reporting/mod.rs
@@ -762,9 +762,12 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
             }
         }
 
-        self.note_error_origin(diag, &cause);
         self.check_and_note_conflicting_crates(diag, terr, span);
         self.tcx.note_and_explain_type_err(diag, terr, span);
+
+        // It reads better to have the error origin as the final
+        // thing.
+        self.note_error_origin(diag, &cause);
     }
 
     pub fn report_and_explain_type_error(&self,
@@ -772,6 +775,10 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
                                          terr: &TypeError<'tcx>)
                                          -> DiagnosticBuilder<'tcx>
     {
+        debug!("report_and_explain_type_error(trace={:?}, terr={:?})",
+               trace,
+               terr);
+
         let span = trace.cause.span;
         let failure_str = trace.cause.as_failure_str();
         let mut diag = match trace.cause.code {
diff --git a/src/librustc/infer/glb.rs b/src/librustc/infer/glb.rs
index 8b42314ed97..fd14e0e40e2 100644
--- a/src/librustc/infer/glb.rs
+++ b/src/librustc/infer/glb.rs
@@ -15,6 +15,7 @@ use super::Subtype;
 
 use traits::ObligationCause;
 use ty::{self, Ty, TyCtxt};
+use ty::error::TypeError;
 use ty::relate::{Relate, RelateResult, TypeRelation};
 
 /// "Greatest lower bound" (common subtype)
@@ -74,7 +75,32 @@ impl<'combine, 'infcx, 'gcx, 'tcx> TypeRelation<'infcx, 'gcx, 'tcx>
                   -> RelateResult<'tcx, ty::Binder<T>>
         where T: Relate<'tcx>
     {
-        self.fields.higher_ranked_glb(a, b, self.a_is_expected)
+        debug!("binders(a={:?}, b={:?})", a, b);
+        let was_error = self.infcx().probe(|_snapshot| {
+            // Subtle: use a fresh combine-fields here because we recover
+            // from Err. Doing otherwise could propagate obligations out
+            // through our `self.obligations` field.
+            self.infcx()
+                .combine_fields(self.fields.trace.clone(), self.fields.param_env)
+                .higher_ranked_glb(a, b, self.a_is_expected)
+                .is_err()
+        });
+        debug!("binders: was_error={:?}", was_error);
+
+        // When higher-ranked types are involved, computing the LUB is
+        // very challenging, switch to invariance. This is obviously
+        // overly conservative but works ok in practice.
+        match self.relate_with_variance(ty::Variance::Invariant, a, b) {
+            Ok(_) => Ok(a.clone()),
+            Err(err) => {
+                debug!("binders: error occurred, was_error={:?}", was_error);
+                if !was_error {
+                    Err(TypeError::OldStyleLUB(Box::new(err)))
+                } else {
+                    Err(err)
+                }
+            }
+        }
     }
 }
 
diff --git a/src/librustc/infer/higher_ranked/mod.rs b/src/librustc/infer/higher_ranked/mod.rs
index c49b3b4b9c8..57e237fb913 100644
--- a/src/librustc/infer/higher_ranked/mod.rs
+++ b/src/librustc/infer/higher_ranked/mod.rs
@@ -19,6 +19,7 @@ use super::{CombinedSnapshot,
 use super::combine::CombineFields;
 use super::region_constraints::{TaintDirections};
 
+use std::collections::BTreeMap;
 use ty::{self, TyCtxt, Binder, TypeFoldable};
 use ty::error::TypeError;
 use ty::relate::{Relate, RelateResult, TypeRelation};
@@ -246,7 +247,7 @@ impl<'a, 'gcx, 'tcx> CombineFields<'a, 'gcx, 'tcx> {
                                              snapshot: &CombinedSnapshot,
                                              debruijn: ty::DebruijnIndex,
                                              new_vars: &[ty::RegionVid],
-                                             a_map: &FxHashMap<ty::BoundRegion, ty::Region<'tcx>>,
+                                             a_map: &BTreeMap<ty::BoundRegion, ty::Region<'tcx>>,
                                              r0: ty::Region<'tcx>)
                                              -> ty::Region<'tcx> {
             // Regions that pre-dated the LUB computation stay as they are.
@@ -342,7 +343,7 @@ impl<'a, 'gcx, 'tcx> CombineFields<'a, 'gcx, 'tcx> {
                                              snapshot: &CombinedSnapshot,
                                              debruijn: ty::DebruijnIndex,
                                              new_vars: &[ty::RegionVid],
-                                             a_map: &FxHashMap<ty::BoundRegion, ty::Region<'tcx>>,
+                                             a_map: &BTreeMap<ty::BoundRegion, ty::Region<'tcx>>,
                                              a_vars: &[ty::RegionVid],
                                              b_vars: &[ty::RegionVid],
                                              r0: ty::Region<'tcx>)
@@ -411,7 +412,7 @@ impl<'a, 'gcx, 'tcx> CombineFields<'a, 'gcx, 'tcx> {
 
         fn rev_lookup<'a, 'gcx, 'tcx>(infcx: &InferCtxt<'a, 'gcx, 'tcx>,
                                       span: Span,
-                                      a_map: &FxHashMap<ty::BoundRegion, ty::Region<'tcx>>,
+                                      a_map: &BTreeMap<ty::BoundRegion, ty::Region<'tcx>>,
                                       r: ty::Region<'tcx>) -> ty::Region<'tcx>
         {
             for (a_br, a_r) in a_map {
@@ -434,7 +435,7 @@ impl<'a, 'gcx, 'tcx> CombineFields<'a, 'gcx, 'tcx> {
 }
 
 fn var_ids<'a, 'gcx, 'tcx>(fields: &CombineFields<'a, 'gcx, 'tcx>,
-                           map: &FxHashMap<ty::BoundRegion, ty::Region<'tcx>>)
+                           map: &BTreeMap<ty::BoundRegion, ty::Region<'tcx>>)
                            -> Vec<ty::RegionVid> {
     map.iter()
        .map(|(_, &r)| match *r {
diff --git a/src/librustc/infer/lub.rs b/src/librustc/infer/lub.rs
index 4a2a7a6bdfe..55c7eef607b 100644
--- a/src/librustc/infer/lub.rs
+++ b/src/librustc/infer/lub.rs
@@ -15,6 +15,7 @@ use super::Subtype;
 
 use traits::ObligationCause;
 use ty::{self, Ty, TyCtxt};
+use ty::error::TypeError;
 use ty::relate::{Relate, RelateResult, TypeRelation};
 
 /// "Least upper bound" (common supertype)
@@ -74,7 +75,32 @@ impl<'combine, 'infcx, 'gcx, 'tcx> TypeRelation<'infcx, 'gcx, 'tcx>
                   -> RelateResult<'tcx, ty::Binder<T>>
         where T: Relate<'tcx>
     {
-        self.fields.higher_ranked_lub(a, b, self.a_is_expected)
+        debug!("binders(a={:?}, b={:?})", a, b);
+        let was_error = self.infcx().probe(|_snapshot| {
+            // Subtle: use a fresh combine-fields here because we recover
+            // from Err. Doing otherwise could propagate obligations out
+            // through our `self.obligations` field.
+            self.infcx()
+                .combine_fields(self.fields.trace.clone(), self.fields.param_env)
+                .higher_ranked_lub(a, b, self.a_is_expected)
+                .is_err()
+        });
+        debug!("binders: was_error={:?}", was_error);
+
+        // When higher-ranked types are involved, computing the LUB is
+        // very challenging, switch to invariance. This is obviously
+        // overly conservative but works ok in practice.
+        match self.relate_with_variance(ty::Variance::Invariant, a, b) {
+            Ok(_) => Ok(a.clone()),
+            Err(err) => {
+                debug!("binders: error occurred, was_error={:?}", was_error);
+                if !was_error {
+                    Err(TypeError::OldStyleLUB(Box::new(err)))
+                } else {
+                    Err(err)
+                }
+            }
+        }
     }
 }
 
diff --git a/src/librustc/infer/mod.rs b/src/librustc/infer/mod.rs
index f734ff84f63..4f923f0b249 100644
--- a/src/librustc/infer/mod.rs
+++ b/src/librustc/infer/mod.rs
@@ -31,6 +31,7 @@ use ty::relate::RelateResult;
 use traits::{self, ObligationCause, PredicateObligations, Reveal};
 use rustc_data_structures::unify::{self, UnificationTable};
 use std::cell::{Cell, RefCell, Ref, RefMut};
+use std::collections::BTreeMap;
 use std::fmt;
 use syntax::ast;
 use errors::DiagnosticBuilder;
@@ -184,7 +185,7 @@ pub struct InferCtxt<'a, 'gcx: 'a+'tcx, 'tcx: 'a> {
 
 /// A map returned by `skolemize_late_bound_regions()` indicating the skolemized
 /// region that each late-bound region was replaced with.
-pub type SkolemizationMap<'tcx> = FxHashMap<ty::BoundRegion, ty::Region<'tcx>>;
+pub type SkolemizationMap<'tcx> = BTreeMap<ty::BoundRegion, ty::Region<'tcx>>;
 
 /// See `error_reporting` module for more details
 #[derive(Clone, Debug)]
@@ -1384,7 +1385,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
         span: Span,
         lbrct: LateBoundRegionConversionTime,
         value: &ty::Binder<T>)
-        -> (T, FxHashMap<ty::BoundRegion, ty::Region<'tcx>>)
+        -> (T, BTreeMap<ty::BoundRegion, ty::Region<'tcx>>)
         where T : TypeFoldable<'tcx>
     {
         self.tcx.replace_late_bound_regions(
diff --git a/src/librustc/ty/error.rs b/src/librustc/ty/error.rs
index 5cfa72c0712..228ca76ed9a 100644
--- a/src/librustc/ty/error.rs
+++ b/src/librustc/ty/error.rs
@@ -54,6 +54,8 @@ pub enum TypeError<'tcx> {
     ProjectionBoundsLength(ExpectedFound<usize>),
     TyParamDefaultMismatch(ExpectedFound<type_variable::Default<'tcx>>),
     ExistentialMismatch(ExpectedFound<&'tcx ty::Slice<ty::ExistentialPredicate<'tcx>>>),
+
+    OldStyleLUB(Box<TypeError<'tcx>>),
 }
 
 #[derive(Clone, RustcEncodable, RustcDecodable, PartialEq, Eq, Hash, Debug, Copy)]
@@ -170,6 +172,9 @@ impl<'tcx> fmt::Display for TypeError<'tcx> {
                 report_maybe_different(f, format!("trait `{}`", values.expected),
                                        format!("trait `{}`", values.found))
             }
+            OldStyleLUB(ref err) => {
+                write!(f, "{}", err)
+            }
         }
     }
 }
@@ -293,6 +298,12 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
                 db.span_note(found.origin_span,
                              "...that also applies to the same type variable here");
             }
+            OldStyleLUB(err) => {
+                db.note("this was previously accepted by the compiler but has been phased out");
+                db.note("for more information, see https://github.com/rust-lang/rust/issues/45852");
+
+                self.note_and_explain_type_err(db, &err, sp);
+            }
             _ => {}
         }
     }
diff --git a/src/librustc/ty/fold.rs b/src/librustc/ty/fold.rs
index 149999e0eee..bee11999223 100644
--- a/src/librustc/ty/fold.rs
+++ b/src/librustc/ty/fold.rs
@@ -43,7 +43,8 @@ use middle::const_val::ConstVal;
 use ty::{self, Binder, Ty, TyCtxt, TypeFlags};
 
 use std::fmt;
-use util::nodemap::{FxHashMap, FxHashSet};
+use std::collections::BTreeMap;
+use util::nodemap::FxHashSet;
 
 /// The TypeFoldable trait is implemented for every type that can be folded.
 /// Basically, every type that has a corresponding method in TypeFolder.
@@ -324,14 +325,14 @@ struct RegionReplacer<'a, 'gcx: 'a+'tcx, 'tcx: 'a> {
     tcx: TyCtxt<'a, 'gcx, 'tcx>,
     current_depth: u32,
     fld_r: &'a mut (FnMut(ty::BoundRegion) -> ty::Region<'tcx> + 'a),
-    map: FxHashMap<ty::BoundRegion, ty::Region<'tcx>>
+    map: BTreeMap<ty::BoundRegion, ty::Region<'tcx>>
 }
 
 impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
     pub fn replace_late_bound_regions<T,F>(self,
         value: &Binder<T>,
         mut f: F)
-        -> (T, FxHashMap<ty::BoundRegion, ty::Region<'tcx>>)
+        -> (T, BTreeMap<ty::BoundRegion, ty::Region<'tcx>>)
         where F : FnMut(ty::BoundRegion) -> ty::Region<'tcx>,
               T : TypeFoldable<'tcx>,
     {
@@ -438,7 +439,7 @@ impl<'a, 'gcx, 'tcx> RegionReplacer<'a, 'gcx, 'tcx> {
             tcx,
             current_depth: 1,
             fld_r,
-            map: FxHashMap()
+            map: BTreeMap::default()
         }
     }
 }
diff --git a/src/librustc/ty/structural_impls.rs b/src/librustc/ty/structural_impls.rs
index 5f1448cd1f1..e5c24b4fcf9 100644
--- a/src/librustc/ty/structural_impls.rs
+++ b/src/librustc/ty/structural_impls.rs
@@ -428,7 +428,8 @@ impl<'a, 'tcx> Lift<'tcx> for ty::error::TypeError<'a> {
             TyParamDefaultMismatch(ref x) => {
                 return tcx.lift(x).map(TyParamDefaultMismatch)
             }
-            ExistentialMismatch(ref x) => return tcx.lift(x).map(ExistentialMismatch)
+            ExistentialMismatch(ref x) => return tcx.lift(x).map(ExistentialMismatch),
+            OldStyleLUB(ref x) => return tcx.lift(x).map(OldStyleLUB),
         })
     }
 }
@@ -1174,6 +1175,7 @@ impl<'tcx> TypeFoldable<'tcx> for ty::error::TypeError<'tcx> {
             Sorts(x) => Sorts(x.fold_with(folder)),
             TyParamDefaultMismatch(ref x) => TyParamDefaultMismatch(x.fold_with(folder)),
             ExistentialMismatch(x) => ExistentialMismatch(x.fold_with(folder)),
+            OldStyleLUB(ref x) => OldStyleLUB(x.fold_with(folder)),
         }
     }
 
@@ -1191,6 +1193,7 @@ impl<'tcx> TypeFoldable<'tcx> for ty::error::TypeError<'tcx> {
                 b.visit_with(visitor)
             },
             Sorts(x) => x.visit_with(visitor),
+            OldStyleLUB(ref x) => x.visit_with(visitor),
             TyParamDefaultMismatch(ref x) => x.visit_with(visitor),
             ExistentialMismatch(x) => x.visit_with(visitor),
             Mismatch |
diff --git a/src/librustc_driver/test.rs b/src/librustc_driver/test.rs
index 9e02065145d..78ce959e5c9 100644
--- a/src/librustc_driver/test.rs
+++ b/src/librustc_driver/test.rs
@@ -353,28 +353,10 @@ impl<'a, 'gcx, 'tcx> Env<'a, 'gcx, 'tcx> {
         self.infcx.tcx.mk_imm_ref(r, self.tcx().types.isize)
     }
 
-    pub fn t_rptr_static(&self) -> Ty<'tcx> {
-        self.infcx.tcx.mk_imm_ref(self.infcx.tcx.types.re_static,
-                                  self.tcx().types.isize)
-    }
-
-    pub fn t_rptr_empty(&self) -> Ty<'tcx> {
-        self.infcx.tcx.mk_imm_ref(self.infcx.tcx.types.re_empty,
-                                  self.tcx().types.isize)
-    }
-
     pub fn sub(&self, t1: Ty<'tcx>, t2: Ty<'tcx>) -> InferResult<'tcx, ()> {
         self.infcx.at(&ObligationCause::dummy(), self.param_env).sub(t1, t2)
     }
 
-    pub fn lub(&self, t1: Ty<'tcx>, t2: Ty<'tcx>) -> InferResult<'tcx, Ty<'tcx>> {
-        self.infcx.at(&ObligationCause::dummy(), self.param_env).lub(t1, t2)
-    }
-
-    pub fn glb(&self, t1: Ty<'tcx>, t2: Ty<'tcx>) -> InferResult<'tcx, Ty<'tcx>> {
-        self.infcx.at(&ObligationCause::dummy(), self.param_env).glb(t1, t2)
-    }
-
     /// Checks that `t1 <: t2` is true (this may register additional
     /// region checks).
     pub fn check_sub(&self, t1: Ty<'tcx>, t2: Ty<'tcx>) {
@@ -399,37 +381,6 @@ impl<'a, 'gcx, 'tcx> Env<'a, 'gcx, 'tcx> {
             }
         }
     }
-
-    /// Checks that `LUB(t1,t2) == t_lub`
-    pub fn check_lub(&self, t1: Ty<'tcx>, t2: Ty<'tcx>, t_lub: Ty<'tcx>) {
-        match self.lub(t1, t2) {
-            Ok(InferOk { obligations, value: t }) => {
-                // None of these tests should require nested obligations:
-                assert!(obligations.is_empty());
-
-                self.assert_eq(t, t_lub);
-            }
-            Err(ref e) => panic!("unexpected error in LUB: {}", e),
-        }
-    }
-
-    /// Checks that `GLB(t1,t2) == t_glb`
-    pub fn check_glb(&self, t1: Ty<'tcx>, t2: Ty<'tcx>, t_glb: Ty<'tcx>) {
-        debug!("check_glb(t1={}, t2={}, t_glb={})", t1, t2, t_glb);
-        match self.glb(t1, t2) {
-            Err(e) => panic!("unexpected error computing LUB: {:?}", e),
-            Ok(InferOk { obligations, value: t }) => {
-                // None of these tests should require nested obligations:
-                assert!(obligations.is_empty());
-
-                self.assert_eq(t, t_glb);
-
-                // sanity check for good measure:
-                self.assert_subtype(t, t1);
-                self.assert_subtype(t, t2);
-            }
-        }
-    }
 }
 
 #[test]
@@ -508,169 +459,6 @@ fn sub_free_bound_false_infer() {
     })
 }
 
-#[test]
-fn lub_free_bound_infer() {
-    //! Test result of:
-    //!
-    //!     LUB(fn(_#1), for<'b> fn(&'b isize))
-    //!
-    //! This should yield `fn(&'_ isize)`. We check
-    //! that it yields `fn(&'x isize)` for some free `'x`,
-    //! anyhow.
-
-    test_env(EMPTY_SOURCE_STR, errors(&[]), |mut env| {
-        env.create_simple_region_hierarchy();
-        let t_infer1 = env.infcx.next_ty_var(TypeVariableOrigin::MiscVariable(DUMMY_SP));
-        let t_rptr_bound1 = env.t_rptr_late_bound(1);
-        let t_rptr_free1 = env.t_rptr_free(1);
-        env.check_lub(env.t_fn(&[t_infer1], env.tcx().types.isize),
-                      env.t_fn(&[t_rptr_bound1], env.tcx().types.isize),
-                      env.t_fn(&[t_rptr_free1], env.tcx().types.isize));
-    });
-}
-
-#[test]
-fn lub_bound_bound() {
-    test_env(EMPTY_SOURCE_STR, errors(&[]), |env| {
-        let t_rptr_bound1 = env.t_rptr_late_bound(1);
-        let t_rptr_bound2 = env.t_rptr_late_bound(2);
-        env.check_lub(env.t_fn(&[t_rptr_bound1], env.tcx().types.isize),
-                      env.t_fn(&[t_rptr_bound2], env.tcx().types.isize),
-                      env.t_fn(&[t_rptr_bound1], env.tcx().types.isize));
-    })
-}
-
-#[test]
-fn lub_bound_free() {
-    test_env(EMPTY_SOURCE_STR, errors(&[]), |mut env| {
-        env.create_simple_region_hierarchy();
-        let t_rptr_bound1 = env.t_rptr_late_bound(1);
-        let t_rptr_free1 = env.t_rptr_free(1);
-        env.check_lub(env.t_fn(&[t_rptr_bound1], env.tcx().types.isize),
-                      env.t_fn(&[t_rptr_free1], env.tcx().types.isize),
-                      env.t_fn(&[t_rptr_free1], env.tcx().types.isize));
-    })
-}
-
-#[test]
-fn lub_bound_static() {
-    test_env(EMPTY_SOURCE_STR, errors(&[]), |env| {
-        let t_rptr_bound1 = env.t_rptr_late_bound(1);
-        let t_rptr_static = env.t_rptr_static();
-        env.check_lub(env.t_fn(&[t_rptr_bound1], env.tcx().types.isize),
-                      env.t_fn(&[t_rptr_static], env.tcx().types.isize),
-                      env.t_fn(&[t_rptr_static], env.tcx().types.isize));
-    })
-}
-
-#[test]
-fn lub_bound_bound_inverse_order() {
-    test_env(EMPTY_SOURCE_STR, errors(&[]), |env| {
-        let t_rptr_bound1 = env.t_rptr_late_bound(1);
-        let t_rptr_bound2 = env.t_rptr_late_bound(2);
-        env.check_lub(env.t_fn(&[t_rptr_bound1, t_rptr_bound2], t_rptr_bound1),
-                      env.t_fn(&[t_rptr_bound2, t_rptr_bound1], t_rptr_bound1),
-                      env.t_fn(&[t_rptr_bound1, t_rptr_bound1], t_rptr_bound1));
-    })
-}
-
-#[test]
-fn lub_free_free() {
-    test_env(EMPTY_SOURCE_STR, errors(&[]), |mut env| {
-        env.create_simple_region_hierarchy();
-        let t_rptr_free1 = env.t_rptr_free(1);
-        let t_rptr_free2 = env.t_rptr_free(2);
-        let t_rptr_static = env.t_rptr_static();
-        env.check_lub(env.t_fn(&[t_rptr_free1], env.tcx().types.isize),
-                      env.t_fn(&[t_rptr_free2], env.tcx().types.isize),
-                      env.t_fn(&[t_rptr_static], env.tcx().types.isize));
-    })
-}
-
-#[test]
-fn lub_returning_scope() {
-    test_env(EMPTY_SOURCE_STR, errors(&[]), |mut env| {
-        env.create_simple_region_hierarchy();
-        let t_rptr_scope10 = env.t_rptr_scope(10);
-        let t_rptr_scope11 = env.t_rptr_scope(11);
-        let t_rptr_empty = env.t_rptr_empty();
-        env.check_lub(env.t_fn(&[t_rptr_scope10], env.tcx().types.isize),
-                      env.t_fn(&[t_rptr_scope11], env.tcx().types.isize),
-                      env.t_fn(&[t_rptr_empty], env.tcx().types.isize));
-    });
-}
-
-#[test]
-fn glb_free_free_with_common_scope() {
-    test_env(EMPTY_SOURCE_STR, errors(&[]), |mut env| {
-        env.create_simple_region_hierarchy();
-        let t_rptr_free1 = env.t_rptr_free(1);
-        let t_rptr_free2 = env.t_rptr_free(2);
-        let t_rptr_scope = env.t_rptr_scope(1);
-        env.check_glb(env.t_fn(&[t_rptr_free1], env.tcx().types.isize),
-                      env.t_fn(&[t_rptr_free2], env.tcx().types.isize),
-                      env.t_fn(&[t_rptr_scope], env.tcx().types.isize));
-    })
-}
-
-#[test]
-fn glb_bound_bound() {
-    test_env(EMPTY_SOURCE_STR, errors(&[]), |env| {
-        let t_rptr_bound1 = env.t_rptr_late_bound(1);
-        let t_rptr_bound2 = env.t_rptr_late_bound(2);
-        env.check_glb(env.t_fn(&[t_rptr_bound1], env.tcx().types.isize),
-                      env.t_fn(&[t_rptr_bound2], env.tcx().types.isize),
-                      env.t_fn(&[t_rptr_bound1], env.tcx().types.isize));
-    })
-}
-
-#[test]
-fn glb_bound_free() {
-    test_env(EMPTY_SOURCE_STR, errors(&[]), |mut env| {
-        env.create_simple_region_hierarchy();
-        let t_rptr_bound1 = env.t_rptr_late_bound(1);
-        let t_rptr_free1 = env.t_rptr_free(1);
-        env.check_glb(env.t_fn(&[t_rptr_bound1], env.tcx().types.isize),
-                      env.t_fn(&[t_rptr_free1], env.tcx().types.isize),
-                      env.t_fn(&[t_rptr_bound1], env.tcx().types.isize));
-    })
-}
-
-#[test]
-fn glb_bound_free_infer() {
-    test_env(EMPTY_SOURCE_STR, errors(&[]), |env| {
-        let t_rptr_bound1 = env.t_rptr_late_bound(1);
-        let t_infer1 = env.infcx.next_ty_var(TypeVariableOrigin::MiscVariable(DUMMY_SP));
-
-        // compute GLB(fn(_) -> isize, for<'b> fn(&'b isize) -> isize),
-        // which should yield for<'b> fn(&'b isize) -> isize
-        env.check_glb(env.t_fn(&[t_rptr_bound1], env.tcx().types.isize),
-                      env.t_fn(&[t_infer1], env.tcx().types.isize),
-                      env.t_fn(&[t_rptr_bound1], env.tcx().types.isize));
-
-        // as a side-effect, computing GLB should unify `_` with
-        // `&'_ isize`
-        let t_resolve1 = env.infcx.shallow_resolve(t_infer1);
-        match t_resolve1.sty {
-            ty::TyRef(..) => {}
-            _ => {
-                panic!("t_resolve1={:?}", t_resolve1);
-            }
-        }
-    })
-}
-
-#[test]
-fn glb_bound_static() {
-    test_env(EMPTY_SOURCE_STR, errors(&[]), |env| {
-        let t_rptr_bound1 = env.t_rptr_late_bound(1);
-        let t_rptr_static = env.t_rptr_static();
-        env.check_glb(env.t_fn(&[t_rptr_bound1], env.tcx().types.isize),
-                      env.t_fn(&[t_rptr_static], env.tcx().types.isize),
-                      env.t_fn(&[t_rptr_bound1], env.tcx().types.isize));
-    })
-}
-
 /// Test substituting a bound region into a function, which introduces another level of binding.
 /// This requires adjusting the Debruijn index.
 #[test]
diff --git a/src/test/run-pass/lub-glb-with-unbound-infer-var.rs b/src/test/run-pass/lub-glb-with-unbound-infer-var.rs
new file mode 100644
index 00000000000..6b9bd67f9a5
--- /dev/null
+++ b/src/test/run-pass/lub-glb-with-unbound-infer-var.rs
@@ -0,0 +1,24 @@
+// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// Test for a specific corner case: when we compute the LUB of two fn
+// types and their parameters have unbound variables. In that case, we
+// wind up relating those two variables. This was causing an ICE in an
+// in-progress PR.
+
+fn main() {
+    let a_f: fn(_) = |_| ();
+    let b_f: fn(_) = |_| ();
+    let c_f = match 22 {
+        0 => a_f,
+        _ => b_f,
+    };
+    c_f(4);
+}
diff --git a/src/test/ui/lub-glb/old-lub-glb-hr.rs b/src/test/ui/lub-glb/old-lub-glb-hr.rs
new file mode 100644
index 00000000000..85c90bb375f
--- /dev/null
+++ b/src/test/ui/lub-glb/old-lub-glb-hr.rs
@@ -0,0 +1,36 @@
+// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// Test that we give a note when the old LUB/GLB algorithm would have
+// succeeded but the new code (which is stricter) gives an error.
+
+fn foo(
+    x: fn(&u8, &u8),
+    y: for<'a> fn(&'a u8, &'a u8),
+) {
+    let z = match 22 {
+        0 => x,
+        _ => y,
+    };
+}
+
+fn bar(
+    x: fn(&u8, &u8),
+    y: for<'a> fn(&'a u8, &'a u8),
+) {
+    let z = match 22 {
+        // No error with an explicit cast:
+        0 => x as for<'a> fn(&'a u8, &'a u8),
+        _ => y,
+    };
+}
+
+fn main() {
+}
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..4a310a5e6b2
--- /dev/null
+++ b/src/test/ui/lub-glb/old-lub-glb-hr.stderr
@@ -0,0 +1,22 @@
+error[E0308]: match arms have incompatible types
+  --> $DIR/old-lub-glb-hr.rs:18:13
+   |
+18 |       let z = match 22 {
+   |  _____________^
+19 | |         0 => x,
+20 | |         _ => y,
+21 | |     };
+   | |_____^ expected bound lifetime parameter, found concrete lifetime
+   |
+   = note: expected type `for<'r, 's> fn(&'r u8, &'s u8)`
+              found type `for<'a> fn(&'a u8, &'a u8)`
+   = note: this was previously accepted by the compiler but has been phased out
+   = note: for more information, see https://github.com/rust-lang/rust/issues/45852
+note: match arm with an incompatible type
+  --> $DIR/old-lub-glb-hr.rs:20:14
+   |
+20 |         _ => y,
+   |              ^
+
+error: aborting due to previous error
+
diff --git a/src/test/ui/lub-glb/old-lub-glb-object.rs b/src/test/ui/lub-glb/old-lub-glb-object.rs
new file mode 100644
index 00000000000..7cf89b68be1
--- /dev/null
+++ b/src/test/ui/lub-glb/old-lub-glb-object.rs
@@ -0,0 +1,38 @@
+// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// Test that we give a note when the old LUB/GLB algorithm would have
+// succeeded but the new code (which is stricter) gives an error.
+
+trait Foo<T, U> { }
+
+fn foo(
+    x: &for<'a, 'b> Foo<&'a u8, &'b u8>,
+    y: &for<'a> Foo<&'a u8, &'a u8>,
+) {
+    let z = match 22 {
+        0 => x,
+        _ => y,
+    };
+}
+
+fn bar(
+    x: &for<'a, 'b> Foo<&'a u8, &'b u8>,
+    y: &for<'a> Foo<&'a u8, &'a u8>,
+) {
+    // Accepted with explicit case:
+    let z = match 22 {
+        0 => x as &for<'a> Foo<&'a u8, &'a u8>,
+        _ => y,
+    };
+}
+
+fn main() {
+}
diff --git a/src/test/ui/lub-glb/old-lub-glb-object.stderr b/src/test/ui/lub-glb/old-lub-glb-object.stderr
new file mode 100644
index 00000000000..a1077f40bf5
--- /dev/null
+++ b/src/test/ui/lub-glb/old-lub-glb-object.stderr
@@ -0,0 +1,22 @@
+error[E0308]: match arms have incompatible types
+  --> $DIR/old-lub-glb-object.rs:20:13
+   |
+20 |       let z = match 22 {
+   |  _____________^
+21 | |         0 => x,
+22 | |         _ => y,
+23 | |     };
+   | |_____^ expected bound lifetime parameter 'a, found concrete lifetime
+   |
+   = note: expected type `&for<'a, 'b> Foo<&'a u8, &'b u8>`
+              found type `&for<'a> Foo<&'a u8, &'a u8>`
+   = note: this was previously accepted by the compiler but has been phased out
+   = note: for more information, see https://github.com/rust-lang/rust/issues/45852
+note: match arm with an incompatible type
+  --> $DIR/old-lub-glb-object.rs:22:14
+   |
+22 |         _ => y,
+   |              ^
+
+error: aborting due to previous error
+