about summary refs log tree commit diff
diff options
context:
space:
mode:
authorNiko Matsakis <niko@alum.mit.edu>2020-06-08 23:12:01 +0000
committerNiko Matsakis <niko@alum.mit.edu>2020-06-22 18:51:08 +0000
commit6929013b850db7c8ac55de4bcd0df8310ddb788b (patch)
tree0993004d03df7d50a6abebf5f973ccd5bdce335f
parentc88a76e37b869d6ca343c6ba5d9f0c65deddbca2 (diff)
downloadrust-6929013b850db7c8ac55de4bcd0df8310ddb788b.tar.gz
rust-6929013b850db7c8ac55de4bcd0df8310ddb788b.zip
fix subtle bug in NLL type checker
The bug was revealed by the behavior of the old-lub-glb-hr-noteq1.rs
test. The old-lub-glb-hr-noteq2 test shows the current 'order dependent'
behavior of coercions around higher-ranked functions, at least when
running with `-Zborrowck=mir`.

Also, run compare-mode=nll.
-rw-r--r--src/librustc_infer/infer/nll_relate/mod.rs8
-rw-r--r--src/librustc_mir/borrow_check/type_check/relate_tys.rs2
-rw-r--r--src/librustc_typeck/check/coercion.rs20
-rw-r--r--src/test/ui/associated-types/associated-types-eq-hr.nll.stderr33
-rw-r--r--src/test/ui/associated-types/higher-ranked-projection.bad.nll.stderr8
-rw-r--r--src/test/ui/generator/resume-arg-late-bound.nll.stderr8
-rw-r--r--src/test/ui/hr-subtype/hr-subtype.bound_a_b_ret_a_vs_bound_a_ret_a.nll.stderr14
-rw-r--r--src/test/ui/hr-subtype/hr-subtype.bound_a_vs_free_x.nll.stderr14
-rw-r--r--src/test/ui/hr-subtype/hr-subtype.bound_inv_a_b_vs_bound_inv_a.nll.stderr26
-rw-r--r--src/test/ui/hrtb/hrtb-conflate-regions.nll.stderr14
-rw-r--r--src/test/ui/hrtb/hrtb-exists-forall-fn.nll.stderr8
-rw-r--r--src/test/ui/hrtb/hrtb-exists-forall-trait-contravariant.nll.stderr8
-rw-r--r--src/test/ui/hrtb/hrtb-exists-forall-trait-invariant.nll.stderr8
-rw-r--r--src/test/ui/hrtb/hrtb-just-for-static.nll.stderr24
-rw-r--r--src/test/ui/hrtb/issue-46989.nll.stderr8
-rw-r--r--src/test/ui/issues/issue-40000.nll.stderr8
-rw-r--r--src/test/ui/lub-glb/old-lub-glb-hr-eq.rs27
-rw-r--r--src/test/ui/lub-glb/old-lub-glb-hr-noteq1.nll.stderr8
-rw-r--r--src/test/ui/lub-glb/old-lub-glb-hr-noteq1.rs24
-rw-r--r--src/test/ui/lub-glb/old-lub-glb-hr-noteq1.stderr (renamed from src/test/ui/lub-glb/old-lub-glb-hr.stderr)2
-rw-r--r--src/test/ui/lub-glb/old-lub-glb-hr-noteq2.rs33
-rw-r--r--src/test/ui/lub-glb/old-lub-glb-hr-noteq2.stderr18
-rw-r--r--src/test/ui/lub-glb/old-lub-glb-hr.rs57
-rw-r--r--src/test/ui/lub-glb/old-lub-glb-object.nll.stderr14
-rw-r--r--src/test/ui/mismatched_types/closure-arg-type-mismatch.nll.stderr27
-rw-r--r--src/test/ui/mismatched_types/closure-mismatch.nll.stderr14
-rw-r--r--src/test/ui/regions-fn-subtyping-return-static-fail.nll.stderr8
-rw-r--r--src/test/ui/rfc1623.nll.stderr68
-rw-r--r--src/test/ui/type-alias-impl-trait/issue-57611-trait-alias.nll.stderr14
-rw-r--r--src/test/ui/where-clauses/where-for-self-2.nll.stderr8
30 files changed, 472 insertions, 61 deletions
diff --git a/src/librustc_infer/infer/nll_relate/mod.rs b/src/librustc_infer/infer/nll_relate/mod.rs
index 8de89251006..2350c28dfaa 100644
--- a/src/librustc_infer/infer/nll_relate/mod.rs
+++ b/src/librustc_infer/infer/nll_relate/mod.rs
@@ -522,7 +522,13 @@ where
         }
 
         if a == b {
-            return Ok(a);
+            // Subtle: if a or b has a bound variable that we are lazilly
+            // substituting, then even if a == b, it could be that the values we
+            // will substitute for those bound variables are *not* the same, and
+            // hence returning `Ok(a)` is incorrect.
+            if !a.has_escaping_bound_vars() && !b.has_escaping_bound_vars() {
+                return Ok(a);
+            }
         }
 
         match (&a.kind, &b.kind) {
diff --git a/src/librustc_mir/borrow_check/type_check/relate_tys.rs b/src/librustc_mir/borrow_check/type_check/relate_tys.rs
index 7ff12820db8..285d9ed6469 100644
--- a/src/librustc_mir/borrow_check/type_check/relate_tys.rs
+++ b/src/librustc_mir/borrow_check/type_check/relate_tys.rs
@@ -25,7 +25,7 @@ pub(super) fn relate_types<'tcx>(
     category: ConstraintCategory,
     borrowck_context: Option<&mut BorrowCheckContext<'_, 'tcx>>,
 ) -> Fallible<()> {
-    debug!("eq_types(a={:?}, b={:?}, locations={:?})", a, b, locations);
+    debug!("relate_types(a={:?}, v={:?}, b={:?}, locations={:?})", a, v, b, locations);
     TypeRelating::new(
         infcx,
         NllTypeRelatingDelegate::new(infcx, borrowck_context, locations, category),
diff --git a/src/librustc_typeck/check/coercion.rs b/src/librustc_typeck/check/coercion.rs
index dec53c369bb..b6cd8da2362 100644
--- a/src/librustc_typeck/check/coercion.rs
+++ b/src/librustc_typeck/check/coercion.rs
@@ -895,7 +895,12 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
     {
         let prev_ty = self.resolve_vars_with_obligations(prev_ty);
         let new_ty = self.resolve_vars_with_obligations(new_ty);
-        debug!("coercion::try_find_coercion_lub({:?}, {:?})", prev_ty, new_ty);
+        debug!(
+            "coercion::try_find_coercion_lub({:?}, {:?}, exprs={:?} exprs)",
+            prev_ty,
+            new_ty,
+            exprs.len()
+        );
 
         // Special-case that coercion alone cannot handle:
         // Function items or non-capturing closures of differing IDs or InternalSubsts.
@@ -1001,6 +1006,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                 Ok(ok) => {
                     let (adjustments, target) = self.register_infer_ok_obligations(ok);
                     self.apply_adjustments(new, adjustments);
+                    debug!(
+                        "coercion::try_find_coercion_lub: was able to coerce from previous type {:?} to new type {:?}",
+                        prev_ty, new_ty,
+                    );
                     return Ok(target);
                 }
                 Err(e) => first_error = Some(e),
@@ -1031,6 +1040,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
             };
 
             if !noop {
+                debug!(
+                    "coercion::try_find_coercion_lub: older expression {:?} had adjustments, requiring LUB",
+                    expr,
+                );
+
                 return self
                     .commit_if_ok(|_| self.at(cause, self.param_env).lub(prev_ty, new_ty))
                     .map(|ok| self.register_infer_ok_obligations(ok));
@@ -1048,6 +1062,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                 }
             }
             Ok(ok) => {
+                debug!(
+                    "coercion::try_find_coercion_lub: was able to coerce previous type {:?} to new type {:?}",
+                    prev_ty, new_ty,
+                );
                 let (adjustments, target) = self.register_infer_ok_obligations(ok);
                 for expr in exprs {
                     let expr = expr.as_coercion_site();
diff --git a/src/test/ui/associated-types/associated-types-eq-hr.nll.stderr b/src/test/ui/associated-types/associated-types-eq-hr.nll.stderr
new file mode 100644
index 00000000000..25e9f726ba5
--- /dev/null
+++ b/src/test/ui/associated-types/associated-types-eq-hr.nll.stderr
@@ -0,0 +1,33 @@
+error[E0271]: type mismatch resolving `for<'x> <UintStruct as TheTrait<&'x isize>>::A == &'x isize`
+  --> $DIR/associated-types-eq-hr.rs:87:5
+   |
+LL | fn foo<T>()
+   |    --- required by a bound in this
+LL | where
+LL |     T: for<'x> TheTrait<&'x isize, A = &'x isize>,
+   |                                    ------------- required by this bound in `foo`
+...
+LL |     foo::<UintStruct>();
+   |     ^^^^^^^^^^^^^^^^^ expected `isize`, found `usize`
+   |
+   = note: expected reference `&isize`
+              found reference `&usize`
+
+error[E0271]: type mismatch resolving `for<'x> <IntStruct as TheTrait<&'x isize>>::A == &'x usize`
+  --> $DIR/associated-types-eq-hr.rs:91:5
+   |
+LL | fn bar<T>()
+   |    --- required by a bound in this
+LL | where
+LL |     T: for<'x> TheTrait<&'x isize, A = &'x usize>,
+   |                                    ------------- required by this bound in `bar`
+...
+LL |     bar::<IntStruct>();
+   |     ^^^^^^^^^^^^^^^^ expected `usize`, found `isize`
+   |
+   = note: expected reference `&usize`
+              found reference `&isize`
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0271`.
diff --git a/src/test/ui/associated-types/higher-ranked-projection.bad.nll.stderr b/src/test/ui/associated-types/higher-ranked-projection.bad.nll.stderr
new file mode 100644
index 00000000000..2e03986a9ed
--- /dev/null
+++ b/src/test/ui/associated-types/higher-ranked-projection.bad.nll.stderr
@@ -0,0 +1,8 @@
+error: higher-ranked subtype error
+  --> $DIR/higher-ranked-projection.rs:25:5
+   |
+LL |     foo(());
+   |     ^^^^^^^
+
+error: aborting due to previous error
+
diff --git a/src/test/ui/generator/resume-arg-late-bound.nll.stderr b/src/test/ui/generator/resume-arg-late-bound.nll.stderr
new file mode 100644
index 00000000000..7d712191924
--- /dev/null
+++ b/src/test/ui/generator/resume-arg-late-bound.nll.stderr
@@ -0,0 +1,8 @@
+error: higher-ranked subtype error
+  --> $DIR/resume-arg-late-bound.rs:15:5
+   |
+LL |     test(gen);
+   |     ^^^^^^^^^
+
+error: aborting due to previous error
+
diff --git a/src/test/ui/hr-subtype/hr-subtype.bound_a_b_ret_a_vs_bound_a_ret_a.nll.stderr b/src/test/ui/hr-subtype/hr-subtype.bound_a_b_ret_a_vs_bound_a_ret_a.nll.stderr
new file mode 100644
index 00000000000..d5343566633
--- /dev/null
+++ b/src/test/ui/hr-subtype/hr-subtype.bound_a_b_ret_a_vs_bound_a_ret_a.nll.stderr
@@ -0,0 +1,14 @@
+error: higher-ranked subtype error
+  --> $DIR/hr-subtype.rs:45:13
+   |
+LL |               gimme::<$t1>(None::<$t2>);
+   |               ^^^^^^^^^^^^^^^^^^^^^^^^^
+...
+LL | / check! { bound_a_b_ret_a_vs_bound_a_ret_a: (for<'a,'b> fn(&'a u32, &'b u32) -> &'a u32,
+LL | | for<'a>    fn(&'a u32, &'a u32) -> &'a u32) }
+   | |_____________________________________________- in this macro invocation
+   |
+   = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error: aborting due to previous error
+
diff --git a/src/test/ui/hr-subtype/hr-subtype.bound_a_vs_free_x.nll.stderr b/src/test/ui/hr-subtype/hr-subtype.bound_a_vs_free_x.nll.stderr
new file mode 100644
index 00000000000..f1156093967
--- /dev/null
+++ b/src/test/ui/hr-subtype/hr-subtype.bound_a_vs_free_x.nll.stderr
@@ -0,0 +1,14 @@
+error: higher-ranked subtype error
+  --> $DIR/hr-subtype.rs:45:13
+   |
+LL |               gimme::<$t1>(None::<$t2>);
+   |               ^^^^^^^^^^^^^^^^^^^^^^^^^
+...
+LL | / check! { bound_a_vs_free_x: (for<'a> fn(&'a u32),
+LL | | fn(&'x u32)) }
+   | |______________- in this macro invocation
+   |
+   = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error: aborting due to previous error
+
diff --git a/src/test/ui/hr-subtype/hr-subtype.bound_inv_a_b_vs_bound_inv_a.nll.stderr b/src/test/ui/hr-subtype/hr-subtype.bound_inv_a_b_vs_bound_inv_a.nll.stderr
new file mode 100644
index 00000000000..4541c462ee0
--- /dev/null
+++ b/src/test/ui/hr-subtype/hr-subtype.bound_inv_a_b_vs_bound_inv_a.nll.stderr
@@ -0,0 +1,26 @@
+error: higher-ranked subtype error
+  --> $DIR/hr-subtype.rs:45:13
+   |
+LL |               gimme::<$t1>(None::<$t2>);
+   |               ^^^^^^^^^^^^^^^^^^^^^^^^^
+...
+LL | / check! { bound_inv_a_b_vs_bound_inv_a: (for<'a,'b> fn(Inv<'a>, Inv<'b>),
+LL | | for<'a>    fn(Inv<'a>, Inv<'a>)) }
+   | |__________________________________- in this macro invocation
+   |
+   = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error: higher-ranked subtype error
+  --> $DIR/hr-subtype.rs:45:13
+   |
+LL |               gimme::<$t1>(None::<$t2>);
+   |               ^^^^^^^^^^^^^^^^^^^^^^^^^
+...
+LL | / check! { bound_inv_a_b_vs_bound_inv_a: (for<'a,'b> fn(Inv<'a>, Inv<'b>),
+LL | | for<'a>    fn(Inv<'a>, Inv<'a>)) }
+   | |__________________________________- in this macro invocation
+   |
+   = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error: aborting due to 2 previous errors
+
diff --git a/src/test/ui/hrtb/hrtb-conflate-regions.nll.stderr b/src/test/ui/hrtb/hrtb-conflate-regions.nll.stderr
new file mode 100644
index 00000000000..f290a93326f
--- /dev/null
+++ b/src/test/ui/hrtb/hrtb-conflate-regions.nll.stderr
@@ -0,0 +1,14 @@
+error: higher-ranked subtype error
+  --> $DIR/hrtb-conflate-regions.rs:27:10
+   |
+LL | fn b() { want_foo2::<SomeStruct>(); }
+   |          ^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: higher-ranked subtype error
+  --> $DIR/hrtb-conflate-regions.rs:27:10
+   |
+LL | fn b() { want_foo2::<SomeStruct>(); }
+   |          ^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to 2 previous errors
+
diff --git a/src/test/ui/hrtb/hrtb-exists-forall-fn.nll.stderr b/src/test/ui/hrtb/hrtb-exists-forall-fn.nll.stderr
new file mode 100644
index 00000000000..11390d9e2d2
--- /dev/null
+++ b/src/test/ui/hrtb/hrtb-exists-forall-fn.nll.stderr
@@ -0,0 +1,8 @@
+error: higher-ranked subtype error
+  --> $DIR/hrtb-exists-forall-fn.rs:17:12
+   |
+LL |     let _: for<'b> fn(&'b u32) = foo();
+   |            ^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to previous error
+
diff --git a/src/test/ui/hrtb/hrtb-exists-forall-trait-contravariant.nll.stderr b/src/test/ui/hrtb/hrtb-exists-forall-trait-contravariant.nll.stderr
new file mode 100644
index 00000000000..a4c3ffd1f6c
--- /dev/null
+++ b/src/test/ui/hrtb/hrtb-exists-forall-trait-contravariant.nll.stderr
@@ -0,0 +1,8 @@
+error: higher-ranked subtype error
+  --> $DIR/hrtb-exists-forall-trait-contravariant.rs:34:5
+   |
+LL |     foo::<()>();
+   |     ^^^^^^^^^^^
+
+error: aborting due to previous error
+
diff --git a/src/test/ui/hrtb/hrtb-exists-forall-trait-invariant.nll.stderr b/src/test/ui/hrtb/hrtb-exists-forall-trait-invariant.nll.stderr
new file mode 100644
index 00000000000..e2a399b2faa
--- /dev/null
+++ b/src/test/ui/hrtb/hrtb-exists-forall-trait-invariant.nll.stderr
@@ -0,0 +1,8 @@
+error: higher-ranked subtype error
+  --> $DIR/hrtb-exists-forall-trait-invariant.rs:28:5
+   |
+LL |     foo::<()>();
+   |     ^^^^^^^^^^^
+
+error: aborting due to previous error
+
diff --git a/src/test/ui/hrtb/hrtb-just-for-static.nll.stderr b/src/test/ui/hrtb/hrtb-just-for-static.nll.stderr
new file mode 100644
index 00000000000..8901a1b4681
--- /dev/null
+++ b/src/test/ui/hrtb/hrtb-just-for-static.nll.stderr
@@ -0,0 +1,24 @@
+error: higher-ranked subtype error
+  --> $DIR/hrtb-just-for-static.rs:24:5
+   |
+LL |     want_hrtb::<StaticInt>()
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: lifetime may not live long enough
+  --> $DIR/hrtb-just-for-static.rs:30:5
+   |
+LL | fn give_some<'a>() {
+   |              -- lifetime `'a` defined here
+LL |     want_hrtb::<&'a u32>()
+   |     ^^^^^^^^^^^^^^^^^^^^ requires that `'a` must outlive `'static`
+   |
+   = help: consider replacing `'a` with `'static`
+
+error: higher-ranked subtype error
+  --> $DIR/hrtb-just-for-static.rs:30:5
+   |
+LL |     want_hrtb::<&'a u32>()
+   |     ^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to 3 previous errors
+
diff --git a/src/test/ui/hrtb/issue-46989.nll.stderr b/src/test/ui/hrtb/issue-46989.nll.stderr
new file mode 100644
index 00000000000..6c127b92d97
--- /dev/null
+++ b/src/test/ui/hrtb/issue-46989.nll.stderr
@@ -0,0 +1,8 @@
+error: higher-ranked subtype error
+  --> $DIR/issue-46989.rs:38:5
+   |
+LL |     assert_foo::<fn(&i32)>();
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to previous error
+
diff --git a/src/test/ui/issues/issue-40000.nll.stderr b/src/test/ui/issues/issue-40000.nll.stderr
new file mode 100644
index 00000000000..f673fbae8b7
--- /dev/null
+++ b/src/test/ui/issues/issue-40000.nll.stderr
@@ -0,0 +1,8 @@
+error: higher-ranked subtype error
+  --> $DIR/issue-40000.rs:6:9
+   |
+LL |     foo(bar);
+   |         ^^^
+
+error: aborting due to previous error
+
diff --git a/src/test/ui/lub-glb/old-lub-glb-hr-eq.rs b/src/test/ui/lub-glb/old-lub-glb-hr-eq.rs
new file mode 100644
index 00000000000..fbf4aee0204
--- /dev/null
+++ b/src/test/ui/lub-glb/old-lub-glb-hr-eq.rs
@@ -0,0 +1,27 @@
+// Test that we give a note when the old LUB/GLB algorithm would have
+// succeeded but the new code (which requires equality) gives an
+// error. However, now that we handle subtyping correctly, we no
+// longer get an error, because we recognize these two types as
+// equivalent!
+//
+// check-pass
+
+fn foo(x: fn(&u8, &u8), y: for<'a> fn(&'a u8, &'a u8)) {
+    // The two types above are actually equivalent. With the older
+    // leak check, though, we didn't consider them as equivalent, and
+    // hence we gave errors. But now we've fixed that.
+    let z = match 22 {
+        0 => x,
+        _ => y,
+    };
+}
+
+fn foo_cast(x: fn(&u8, &u8), y: for<'a> fn(&'a u8, &'a u8)) {
+    let z = match 22 {
+        // No error with an explicit cast:
+        0 => x as for<'a> fn(&'a u8, &'a u8),
+        _ => y,
+    };
+}
+
+fn main() {}
diff --git a/src/test/ui/lub-glb/old-lub-glb-hr-noteq1.nll.stderr b/src/test/ui/lub-glb/old-lub-glb-hr-noteq1.nll.stderr
new file mode 100644
index 00000000000..b95e247d2a8
--- /dev/null
+++ b/src/test/ui/lub-glb/old-lub-glb-hr-noteq1.nll.stderr
@@ -0,0 +1,8 @@
+error: higher-ranked subtype error
+  --> $DIR/old-lub-glb-hr-noteq1.rs:11:14
+   |
+LL |         _ => y,
+   |              ^
+
+error: aborting due to previous error
+
diff --git a/src/test/ui/lub-glb/old-lub-glb-hr-noteq1.rs b/src/test/ui/lub-glb/old-lub-glb-hr-noteq1.rs
new file mode 100644
index 00000000000..918542d471b
--- /dev/null
+++ b/src/test/ui/lub-glb/old-lub-glb-hr-noteq1.rs
@@ -0,0 +1,24 @@
+// Test taking the LUB of two function types that are not equatable but where one is more
+// general than the other. Test the case where the more general type (`x`) is the first
+// match arm specifically.
+
+fn foo(x: for<'a, 'b> fn(&'a u8, &'b u8) -> &'a u8, y: for<'a> fn(&'a u8, &'a u8) -> &'a u8) {
+    // The two types above are not equivalent. With the older LUB/GLB
+    // algorithm, this may have worked (I don't remember), but now it
+    // doesn't because we require equality.
+    let z = match 22 {
+        0 => x,
+        _ => y, //~ ERROR `match` arms have incompatible types
+    };
+}
+
+fn foo_cast(x: for<'a, 'b> fn(&'a u8, &'b u8) -> &'a u8, y: for<'a> fn(&'a u8, &'a u8) -> &'a u8) {
+    // But we can *upcast* explicitly the type of `x` and figure
+    // things out:
+    let z = match 22 {
+        0 => x as for<'a> fn(&'a u8, &'a u8) -> &'a u8,
+        _ => y,
+    };
+}
+
+fn main() {}
diff --git a/src/test/ui/lub-glb/old-lub-glb-hr.stderr b/src/test/ui/lub-glb/old-lub-glb-hr-noteq1.stderr
index f9ad4e5814e..305e952d604 100644
--- a/src/test/ui/lub-glb/old-lub-glb-hr.stderr
+++ b/src/test/ui/lub-glb/old-lub-glb-hr-noteq1.stderr
@@ -1,5 +1,5 @@
 error[E0308]: `match` arms have incompatible types
-  --> $DIR/old-lub-glb-hr.rs:40:14
+  --> $DIR/old-lub-glb-hr-noteq1.rs:11:14
    |
 LL |       let z = match 22 {
    |  _____________-
diff --git a/src/test/ui/lub-glb/old-lub-glb-hr-noteq2.rs b/src/test/ui/lub-glb/old-lub-glb-hr-noteq2.rs
new file mode 100644
index 00000000000..0e069bc6f84
--- /dev/null
+++ b/src/test/ui/lub-glb/old-lub-glb-hr-noteq2.rs
@@ -0,0 +1,33 @@
+// Test taking the LUB of two function types that are not equatable but where
+// one is more general than the other. Test the case where the more general type
+// (`x`) is the second match arm specifically.
+//
+// Skip for compare-mode because the pure NLL checker accepts this test. (Note
+// that it still errors in old-lub-glb-hr-noteq1.rs). What happens is that, due
+// to the ordering of the match arms, we pick the correct "more general" fn
+// type, and we ignore the errors from the non-NLL type checker that requires
+// equality. The NLL type checker only requires a subtyping relationship, and
+// that holds.
+//
+// ignore-compare-mode-nll
+
+fn foo(x: for<'a, 'b> fn(&'a u8, &'b u8) -> &'a u8, y: for<'a> fn(&'a u8, &'a u8) -> &'a u8) {
+    // The two types above are not equivalent. With the older LUB/GLB
+    // algorithm, this may have worked (I don't remember), but now it
+    // doesn't because we require equality.
+    let z = match 22 {
+        0 => y,
+        _ => x, //~ ERROR `match` arms have incompatible types
+    };
+}
+
+fn foo_cast(x: for<'a, 'b> fn(&'a u8, &'b u8) -> &'a u8, y: for<'a> fn(&'a u8, &'a u8) -> &'a u8) {
+    // But we can *upcast* explicitly the type of `x` and figure
+    // things out:
+    let z = match 22 {
+        0 => x as for<'a> fn(&'a u8, &'a u8) -> &'a u8,
+        _ => y,
+    };
+}
+
+fn main() {}
diff --git a/src/test/ui/lub-glb/old-lub-glb-hr-noteq2.stderr b/src/test/ui/lub-glb/old-lub-glb-hr-noteq2.stderr
new file mode 100644
index 00000000000..252e13aada0
--- /dev/null
+++ b/src/test/ui/lub-glb/old-lub-glb-hr-noteq2.stderr
@@ -0,0 +1,18 @@
+error[E0308]: `match` arms have incompatible types
+  --> $DIR/old-lub-glb-hr-noteq2.rs:20:14
+   |
+LL |       let z = match 22 {
+   |  _____________-
+LL | |         0 => y,
+   | |              - this is found to be of type `for<'a> fn(&'a u8, &'a u8) -> &'a u8`
+LL | |         _ => x,
+   | |              ^ one type is more general than the other
+LL | |     };
+   | |_____- `match` arms have incompatible types
+   |
+   = note: expected fn pointer `for<'a> fn(&'a u8, &'a u8) -> &'a u8`
+              found fn pointer `for<'a, 'b> fn(&'a u8, &'b u8) -> &'a u8`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0308`.
diff --git a/src/test/ui/lub-glb/old-lub-glb-hr.rs b/src/test/ui/lub-glb/old-lub-glb-hr.rs
deleted file mode 100644
index 5e24a99bcc3..00000000000
--- a/src/test/ui/lub-glb/old-lub-glb-hr.rs
+++ /dev/null
@@ -1,57 +0,0 @@
-// Test that we give a note when the old LUB/GLB algorithm would have
-// succeeded but the new code (which requires equality) gives an
-// error. However, now that we handle subtyping correctly, we no
-// longer get an error, because we recognize these two types as
-// equivalent!
-
-fn foo(
-    x: fn(&u8, &u8),
-    y: for<'a> fn(&'a u8, &'a u8),
-) {
-    // The two types above are actually equivalent. With the older
-    // leak check, though, we didn't consider them as equivalent, and
-    // hence we gave errors. But now we've fixed that.
-    let z = match 22 {
-        0 => x,
-        _ => y,
-    };
-}
-
-fn foo_cast(
-    x: fn(&u8, &u8),
-    y: for<'a> fn(&'a u8, &'a u8),
-) {
-    let z = match 22 {
-        // No error with an explicit cast:
-        0 => x as for<'a> fn(&'a u8, &'a u8),
-        _ => y,
-    };
-}
-
-fn bar(
-    x: for<'a, 'b> fn(&'a u8, &'b u8)-> &'a u8,
-    y: for<'a> fn(&'a u8, &'a u8) -> &'a u8,
-) {
-    // The two types above are not equivalent. With the older LUB/GLB
-    // algorithm, this may have worked (I don't remember), but now it
-    // doesn't because we require equality.
-    let z = match 22 {
-        0 => x,
-        _ => y, //~ ERROR `match` arms have incompatible types
-    };
-}
-
-fn bar_cast(
-    x: for<'a, 'b> fn(&'a u8, &'b u8)-> &'a u8,
-    y: for<'a> fn(&'a u8, &'a u8) -> &'a u8,
-) {
-    // But we can *upcast* explicitly the type of `x` and figure
-    // things out:
-    let z = match 22 {
-        0 => x as for<'a> fn(&'a u8, &'a u8) -> &'a u8,
-        _ => y,
-    };
-}
-
-fn main() {
-}
diff --git a/src/test/ui/lub-glb/old-lub-glb-object.nll.stderr b/src/test/ui/lub-glb/old-lub-glb-object.nll.stderr
new file mode 100644
index 00000000000..51bf96f3233
--- /dev/null
+++ b/src/test/ui/lub-glb/old-lub-glb-object.nll.stderr
@@ -0,0 +1,14 @@
+error: higher-ranked subtype error
+  --> $DIR/old-lub-glb-object.rs:10:14
+   |
+LL |         _ => y,
+   |              ^
+
+error: higher-ranked subtype error
+  --> $DIR/old-lub-glb-object.rs:10:14
+   |
+LL |         _ => y,
+   |              ^
+
+error: aborting due to 2 previous errors
+
diff --git a/src/test/ui/mismatched_types/closure-arg-type-mismatch.nll.stderr b/src/test/ui/mismatched_types/closure-arg-type-mismatch.nll.stderr
new file mode 100644
index 00000000000..6ed91b20ab8
--- /dev/null
+++ b/src/test/ui/mismatched_types/closure-arg-type-mismatch.nll.stderr
@@ -0,0 +1,27 @@
+error[E0631]: type mismatch in closure arguments
+  --> $DIR/closure-arg-type-mismatch.rs:3:14
+   |
+LL |     a.iter().map(|_: (u32, u32)| 45);
+   |              ^^^ ------------------ found signature of `fn((u32, u32)) -> _`
+   |              |
+   |              expected signature of `fn(&(u32, u32)) -> _`
+
+error[E0631]: type mismatch in closure arguments
+  --> $DIR/closure-arg-type-mismatch.rs:4:14
+   |
+LL |     a.iter().map(|_: &(u16, u16)| 45);
+   |              ^^^ ------------------- found signature of `for<'r> fn(&'r (u16, u16)) -> _`
+   |              |
+   |              expected signature of `fn(&(u32, u32)) -> _`
+
+error[E0631]: type mismatch in closure arguments
+  --> $DIR/closure-arg-type-mismatch.rs:5:14
+   |
+LL |     a.iter().map(|_: (u16, u16)| 45);
+   |              ^^^ ------------------ found signature of `fn((u16, u16)) -> _`
+   |              |
+   |              expected signature of `fn(&(u32, u32)) -> _`
+
+error: aborting due to 3 previous errors
+
+For more information about this error, try `rustc --explain E0631`.
diff --git a/src/test/ui/mismatched_types/closure-mismatch.nll.stderr b/src/test/ui/mismatched_types/closure-mismatch.nll.stderr
new file mode 100644
index 00000000000..745a61b866e
--- /dev/null
+++ b/src/test/ui/mismatched_types/closure-mismatch.nll.stderr
@@ -0,0 +1,14 @@
+error: higher-ranked subtype error
+  --> $DIR/closure-mismatch.rs:8:5
+   |
+LL |     baz(|_| ());
+   |     ^^^^^^^^^^^
+
+error: higher-ranked subtype error
+  --> $DIR/closure-mismatch.rs:8:5
+   |
+LL |     baz(|_| ());
+   |     ^^^^^^^^^^^
+
+error: aborting due to 2 previous errors
+
diff --git a/src/test/ui/regions-fn-subtyping-return-static-fail.nll.stderr b/src/test/ui/regions-fn-subtyping-return-static-fail.nll.stderr
new file mode 100644
index 00000000000..d762f55f9d5
--- /dev/null
+++ b/src/test/ui/regions-fn-subtyping-return-static-fail.nll.stderr
@@ -0,0 +1,8 @@
+error: higher-ranked subtype error
+  --> $DIR/regions-fn-subtyping-return-static-fail.rs:48:5
+   |
+LL |     want_G(baz);
+   |     ^^^^^^^^^^^
+
+error: aborting due to previous error
+
diff --git a/src/test/ui/rfc1623.nll.stderr b/src/test/ui/rfc1623.nll.stderr
new file mode 100644
index 00000000000..848d4fef1ab
--- /dev/null
+++ b/src/test/ui/rfc1623.nll.stderr
@@ -0,0 +1,68 @@
+error[E0277]: `dyn for<'a, 'b> std::ops::Fn(&'a Foo<'b>) -> &'a Foo<'b>` cannot be shared between threads safely
+  --> $DIR/rfc1623.rs:21:1
+   |
+LL | / static SOME_STRUCT: &SomeStruct = &SomeStruct {
+LL | |     foo: &Foo { bools: &[false, true] },
+LL | |     bar: &Bar { bools: &[true, true] },
+LL | |     f: &id,
+LL | |
+LL | | };
+   | |__^ `dyn for<'a, 'b> std::ops::Fn(&'a Foo<'b>) -> &'a Foo<'b>` cannot be shared between threads safely
+   |
+   = help: within `&SomeStruct`, the trait `std::marker::Sync` is not implemented for `dyn for<'a, 'b> std::ops::Fn(&'a Foo<'b>) -> &'a Foo<'b>`
+   = note: required because it appears within the type `&dyn for<'a, 'b> std::ops::Fn(&'a Foo<'b>) -> &'a Foo<'b>`
+   = note: required because it appears within the type `SomeStruct`
+   = note: required because it appears within the type `&SomeStruct`
+   = note: shared static variables must have a type that implements `Sync`
+
+error: higher-ranked subtype error
+  --> $DIR/rfc1623.rs:21:35
+   |
+LL |   static SOME_STRUCT: &SomeStruct = &SomeStruct {
+   |  ___________________________________^
+LL | |     foo: &Foo { bools: &[false, true] },
+LL | |     bar: &Bar { bools: &[true, true] },
+LL | |     f: &id,
+LL | |
+LL | | };
+   | |_^
+
+error: higher-ranked subtype error
+  --> $DIR/rfc1623.rs:21:35
+   |
+LL |   static SOME_STRUCT: &SomeStruct = &SomeStruct {
+   |  ___________________________________^
+LL | |     foo: &Foo { bools: &[false, true] },
+LL | |     bar: &Bar { bools: &[true, true] },
+LL | |     f: &id,
+LL | |
+LL | | };
+   | |_^
+
+error: higher-ranked subtype error
+  --> $DIR/rfc1623.rs:21:35
+   |
+LL |   static SOME_STRUCT: &SomeStruct = &SomeStruct {
+   |  ___________________________________^
+LL | |     foo: &Foo { bools: &[false, true] },
+LL | |     bar: &Bar { bools: &[true, true] },
+LL | |     f: &id,
+LL | |
+LL | | };
+   | |_^
+
+error: higher-ranked subtype error
+  --> $DIR/rfc1623.rs:21:35
+   |
+LL |   static SOME_STRUCT: &SomeStruct = &SomeStruct {
+   |  ___________________________________^
+LL | |     foo: &Foo { bools: &[false, true] },
+LL | |     bar: &Bar { bools: &[true, true] },
+LL | |     f: &id,
+LL | |
+LL | | };
+   | |_^
+
+error: aborting due to 5 previous errors
+
+For more information about this error, try `rustc --explain E0277`.
diff --git a/src/test/ui/type-alias-impl-trait/issue-57611-trait-alias.nll.stderr b/src/test/ui/type-alias-impl-trait/issue-57611-trait-alias.nll.stderr
new file mode 100644
index 00000000000..8c9cb742fac
--- /dev/null
+++ b/src/test/ui/type-alias-impl-trait/issue-57611-trait-alias.nll.stderr
@@ -0,0 +1,14 @@
+error: higher-ranked subtype error
+  --> $DIR/issue-57611-trait-alias.rs:21:9
+   |
+LL |         |x| x
+   |         ^^^^^
+
+error: higher-ranked subtype error
+  --> $DIR/issue-57611-trait-alias.rs:21:9
+   |
+LL |         |x| x
+   |         ^^^^^
+
+error: aborting due to 2 previous errors
+
diff --git a/src/test/ui/where-clauses/where-for-self-2.nll.stderr b/src/test/ui/where-clauses/where-for-self-2.nll.stderr
new file mode 100644
index 00000000000..d0c476dc6ec
--- /dev/null
+++ b/src/test/ui/where-clauses/where-for-self-2.nll.stderr
@@ -0,0 +1,8 @@
+error: higher-ranked subtype error
+  --> $DIR/where-for-self-2.rs:23:5
+   |
+LL |     foo(&X);
+   |     ^^^^^^^
+
+error: aborting due to previous error
+