summaryrefslogtreecommitdiffstats
path: root/tests/ui/higher-rank-trait-bounds
diff options
context:
space:
mode:
Diffstat (limited to 'tests/ui/higher-rank-trait-bounds')
-rw-r--r--tests/ui/higher-rank-trait-bounds/complex.rs28
-rw-r--r--tests/ui/higher-rank-trait-bounds/due-to-where-clause.rs13
-rw-r--r--tests/ui/higher-rank-trait-bounds/due-to-where-clause.stderr11
-rw-r--r--tests/ui/higher-rank-trait-bounds/hang-on-deeply-nested-dyn.rs16
-rw-r--r--tests/ui/higher-rank-trait-bounds/hang-on-deeply-nested-dyn.stderr22
-rw-r--r--tests/ui/higher-rank-trait-bounds/hrtb-binder-levels-in-object-types.rs29
-rw-r--r--tests/ui/higher-rank-trait-bounds/hrtb-cache-issue-54302.rs24
-rw-r--r--tests/ui/higher-rank-trait-bounds/hrtb-cache-issue-54302.stderr11
-rw-r--r--tests/ui/higher-rank-trait-bounds/hrtb-conflate-regions.rs31
-rw-r--r--tests/ui/higher-rank-trait-bounds/hrtb-conflate-regions.stderr20
-rw-r--r--tests/ui/higher-rank-trait-bounds/hrtb-debruijn-in-receiver.rs18
-rw-r--r--tests/ui/higher-rank-trait-bounds/hrtb-debruijn-in-receiver.stderr14
-rw-r--r--tests/ui/higher-rank-trait-bounds/hrtb-debruijn-object-types-in-closures.rs16
-rw-r--r--tests/ui/higher-rank-trait-bounds/hrtb-exists-forall-fn.rs18
-rw-r--r--tests/ui/higher-rank-trait-bounds/hrtb-exists-forall-fn.stderr12
-rw-r--r--tests/ui/higher-rank-trait-bounds/hrtb-exists-forall-trait-contravariant.rs36
-rw-r--r--tests/ui/higher-rank-trait-bounds/hrtb-exists-forall-trait-contravariant.stderr11
-rw-r--r--tests/ui/higher-rank-trait-bounds/hrtb-exists-forall-trait-covariant.rs37
-rw-r--r--tests/ui/higher-rank-trait-bounds/hrtb-exists-forall-trait-invariant.rs29
-rw-r--r--tests/ui/higher-rank-trait-bounds/hrtb-exists-forall-trait-invariant.stderr11
-rw-r--r--tests/ui/higher-rank-trait-bounds/hrtb-fn-like-trait-object.rs27
-rw-r--r--tests/ui/higher-rank-trait-bounds/hrtb-fn-like-trait.rs27
-rw-r--r--tests/ui/higher-rank-trait-bounds/hrtb-higher-ranker-supertraits-transitive.rs50
-rw-r--r--tests/ui/higher-rank-trait-bounds/hrtb-higher-ranker-supertraits-transitive.stderr23
-rw-r--r--tests/ui/higher-rank-trait-bounds/hrtb-higher-ranker-supertraits.rs48
-rw-r--r--tests/ui/higher-rank-trait-bounds/hrtb-higher-ranker-supertraits.stderr43
-rw-r--r--tests/ui/higher-rank-trait-bounds/hrtb-identity-fn-borrows.rs26
-rw-r--r--tests/ui/higher-rank-trait-bounds/hrtb-identity-fn-borrows.stderr14
-rw-r--r--tests/ui/higher-rank-trait-bounds/hrtb-just-for-static.rs35
-rw-r--r--tests/ui/higher-rank-trait-bounds/hrtb-just-for-static.stderr34
-rw-r--r--tests/ui/higher-rank-trait-bounds/hrtb-malformed-lifetime-generics.rs20
-rw-r--r--tests/ui/higher-rank-trait-bounds/hrtb-malformed-lifetime-generics.stderr62
-rw-r--r--tests/ui/higher-rank-trait-bounds/hrtb-opt-in-copy.rs28
-rw-r--r--tests/ui/higher-rank-trait-bounds/hrtb-parse.rs36
-rw-r--r--tests/ui/higher-rank-trait-bounds/hrtb-perfect-forwarding.polonius.stderr71
-rw-r--r--tests/ui/higher-rank-trait-bounds/hrtb-perfect-forwarding.rs56
-rw-r--r--tests/ui/higher-rank-trait-bounds/hrtb-perfect-forwarding.stderr79
-rw-r--r--tests/ui/higher-rank-trait-bounds/hrtb-precedence-of-plus-where-clause.rs25
-rw-r--r--tests/ui/higher-rank-trait-bounds/hrtb-precedence-of-plus.rs13
-rw-r--r--tests/ui/higher-rank-trait-bounds/hrtb-resolve-lifetime.rs14
-rw-r--r--tests/ui/higher-rank-trait-bounds/hrtb-trait-object-paren-notation.rs26
-rw-r--r--tests/ui/higher-rank-trait-bounds/hrtb-trait-object-passed-to-closure.rs25
-rw-r--r--tests/ui/higher-rank-trait-bounds/hrtb-type-outlives.rs46
-rw-r--r--tests/ui/higher-rank-trait-bounds/hrtb-unboxed-closure-trait.rs11
-rw-r--r--tests/ui/higher-rank-trait-bounds/hrtb-wrong-kind.rs7
-rw-r--r--tests/ui/higher-rank-trait-bounds/hrtb-wrong-kind.stderr14
-rw-r--r--tests/ui/higher-rank-trait-bounds/issue-100689.rs29
-rw-r--r--tests/ui/higher-rank-trait-bounds/issue-102899.rs32
-rw-r--r--tests/ui/higher-rank-trait-bounds/issue-30786.rs134
-rw-r--r--tests/ui/higher-rank-trait-bounds/issue-30786.stderr45
-rw-r--r--tests/ui/higher-rank-trait-bounds/issue-36139-normalize-closure-sig.rs19
-rw-r--r--tests/ui/higher-rank-trait-bounds/issue-42114.rs20
-rw-r--r--tests/ui/higher-rank-trait-bounds/issue-43623.rs21
-rw-r--r--tests/ui/higher-rank-trait-bounds/issue-46989.rs40
-rw-r--r--tests/ui/higher-rank-trait-bounds/issue-46989.stderr11
-rw-r--r--tests/ui/higher-rank-trait-bounds/issue-57639.rs29
-rw-r--r--tests/ui/higher-rank-trait-bounds/issue-58451.rs13
-rw-r--r--tests/ui/higher-rank-trait-bounds/issue-58451.stderr19
-rw-r--r--tests/ui/higher-rank-trait-bounds/issue-59311.rs22
-rw-r--r--tests/ui/higher-rank-trait-bounds/issue-59311.stderr18
-rw-r--r--tests/ui/higher-rank-trait-bounds/issue-60283.rs20
-rw-r--r--tests/ui/higher-rank-trait-bounds/issue-62203-hrtb-ice.rs54
-rw-r--r--tests/ui/higher-rank-trait-bounds/issue-62203-hrtb-ice.stderr66
-rw-r--r--tests/ui/higher-rank-trait-bounds/issue-88446.rs35
-rw-r--r--tests/ui/higher-rank-trait-bounds/issue-88586-hr-self-outlives-in-trait-def.rs13
-rw-r--r--tests/ui/higher-rank-trait-bounds/issue-90177.rs32
-rw-r--r--tests/ui/higher-rank-trait-bounds/issue-95034.rs80
-rw-r--r--tests/ui/higher-rank-trait-bounds/issue-95230.rs7
-rw-r--r--tests/ui/higher-rank-trait-bounds/normalize-under-binder/issue-44005.rs31
-rw-r--r--tests/ui/higher-rank-trait-bounds/normalize-under-binder/issue-56556.rs30
-rw-r--r--tests/ui/higher-rank-trait-bounds/normalize-under-binder/issue-62529-1.rs88
-rw-r--r--tests/ui/higher-rank-trait-bounds/normalize-under-binder/issue-62529-2.rs33
-rw-r--r--tests/ui/higher-rank-trait-bounds/normalize-under-binder/issue-62529-3.rs32
-rw-r--r--tests/ui/higher-rank-trait-bounds/normalize-under-binder/issue-62529-3.stderr19
-rw-r--r--tests/ui/higher-rank-trait-bounds/normalize-under-binder/issue-62529-4.rs39
-rw-r--r--tests/ui/higher-rank-trait-bounds/normalize-under-binder/issue-62529-5.rs27
-rw-r--r--tests/ui/higher-rank-trait-bounds/normalize-under-binder/issue-62529-6.rs77
-rw-r--r--tests/ui/higher-rank-trait-bounds/normalize-under-binder/issue-70120.rs31
-rw-r--r--tests/ui/higher-rank-trait-bounds/normalize-under-binder/issue-71955.migrate.stderr79
-rw-r--r--tests/ui/higher-rank-trait-bounds/normalize-under-binder/issue-71955.rs51
-rw-r--r--tests/ui/higher-rank-trait-bounds/normalize-under-binder/issue-71955.stderr79
-rw-r--r--tests/ui/higher-rank-trait-bounds/normalize-under-binder/issue-74261.rs30
-rw-r--r--tests/ui/higher-rank-trait-bounds/normalize-under-binder/issue-76956.rs15
-rw-r--r--tests/ui/higher-rank-trait-bounds/normalize-under-binder/issue-80706.rs71
-rw-r--r--tests/ui/higher-rank-trait-bounds/normalize-under-binder/issue-80956.rs21
-rw-r--r--tests/ui/higher-rank-trait-bounds/normalize-under-binder/issue-81809.rs21
-rw-r--r--tests/ui/higher-rank-trait-bounds/normalize-under-binder/issue-85455.rs19
-rw-r--r--tests/ui/higher-rank-trait-bounds/normalize-under-binder/issue-85455.stderr25
-rw-r--r--tests/ui/higher-rank-trait-bounds/normalize-under-binder/issue-89118.rs32
-rw-r--r--tests/ui/higher-rank-trait-bounds/normalize-under-binder/issue-89118.stderr69
-rw-r--r--tests/ui/higher-rank-trait-bounds/normalize-under-binder/issue-89436.rs44
-rw-r--r--tests/ui/higher-rank-trait-bounds/normalize-under-binder/issue-90612.rs41
-rw-r--r--tests/ui/higher-rank-trait-bounds/normalize-under-binder/issue-90638.rs35
-rw-r--r--tests/ui/higher-rank-trait-bounds/normalize-under-binder/issue-90875.rs31
-rw-r--r--tests/ui/higher-rank-trait-bounds/normalize-under-binder/issue-90950.rs53
-rw-r--r--tests/ui/higher-rank-trait-bounds/normalize-under-binder/issue-90950.stderr21
-rw-r--r--tests/ui/higher-rank-trait-bounds/normalize-under-binder/norm-before-method-resolution.rs23
-rw-r--r--tests/ui/higher-rank-trait-bounds/normalize-under-binder/norm-before-method-resolution.stderr18
98 files changed, 3211 insertions, 0 deletions
diff --git a/tests/ui/higher-rank-trait-bounds/complex.rs b/tests/ui/higher-rank-trait-bounds/complex.rs
new file mode 100644
index 000000000..8cdfe247e
--- /dev/null
+++ b/tests/ui/higher-rank-trait-bounds/complex.rs
@@ -0,0 +1,28 @@
+// check-pass
+
+trait A<'a> {}
+trait B<'b> {}
+fn foo<T>() where for<'a> T: A<'a> + 'a {}
+trait C<'c>: for<'a> A<'a> + for<'b> B<'b> {
+ type As;
+}
+struct D<T> where T: for<'c> C<'c, As=&'c ()> {
+ t: std::marker::PhantomData<T>,
+}
+trait E<'e, 'g> {
+ type As;
+}
+trait F<'f>: for<'a> A<'a> + for<'e> E<'e, 'f> {}
+struct G<T> where T: for<'f> F<'f, As=&'f ()> {
+ t: std::marker::PhantomData<T>,
+}
+trait H<'a, 'b> {
+ type As;
+}
+trait I<'a>: for<'b> H<'a, 'b> {}
+
+struct J<T> where T: for<'i> I<'i, As=&'i ()> {
+ t: std::marker::PhantomData<T>,
+}
+
+fn main() {}
diff --git a/tests/ui/higher-rank-trait-bounds/due-to-where-clause.rs b/tests/ui/higher-rank-trait-bounds/due-to-where-clause.rs
new file mode 100644
index 000000000..1afd15613
--- /dev/null
+++ b/tests/ui/higher-rank-trait-bounds/due-to-where-clause.rs
@@ -0,0 +1,13 @@
+fn main() {
+ test::<FooS>(&mut 42); //~ ERROR implementation of `Foo` is not general enough
+}
+
+trait Foo<'a> {}
+
+struct FooS<'a> {
+ data: &'a mut u32,
+}
+
+impl<'a, 'b: 'a> Foo<'b> for FooS<'a> {}
+
+fn test<'a, F>(data: &'a mut u32) where F: for<'b> Foo<'b> {}
diff --git a/tests/ui/higher-rank-trait-bounds/due-to-where-clause.stderr b/tests/ui/higher-rank-trait-bounds/due-to-where-clause.stderr
new file mode 100644
index 000000000..520938a63
--- /dev/null
+++ b/tests/ui/higher-rank-trait-bounds/due-to-where-clause.stderr
@@ -0,0 +1,11 @@
+error: implementation of `Foo` is not general enough
+ --> $DIR/due-to-where-clause.rs:2:5
+ |
+LL | test::<FooS>(&mut 42);
+ | ^^^^^^^^^^^^ implementation of `Foo` is not general enough
+ |
+ = note: `FooS<'_>` must implement `Foo<'0>`, for any lifetime `'0`...
+ = note: ...but `FooS<'_>` actually implements `Foo<'1>`, for some specific lifetime `'1`
+
+error: aborting due to previous error
+
diff --git a/tests/ui/higher-rank-trait-bounds/hang-on-deeply-nested-dyn.rs b/tests/ui/higher-rank-trait-bounds/hang-on-deeply-nested-dyn.rs
new file mode 100644
index 000000000..d34b7a296
--- /dev/null
+++ b/tests/ui/higher-rank-trait-bounds/hang-on-deeply-nested-dyn.rs
@@ -0,0 +1,16 @@
+// normalize-stderr-test: "long-type-\d+" -> "long-type-hash"
+
+fn id(
+ f: &dyn Fn(u32),
+) -> &dyn Fn(
+ &dyn Fn(
+ &dyn Fn(
+ &dyn Fn(&dyn Fn(&dyn Fn(&dyn Fn(&dyn Fn(&dyn Fn(&dyn Fn(&dyn Fn(&dyn Fn(u32))))))))),
+ ),
+ ),
+) {
+ f
+ //~^ ERROR mismatched types
+}
+
+fn main() {}
diff --git a/tests/ui/higher-rank-trait-bounds/hang-on-deeply-nested-dyn.stderr b/tests/ui/higher-rank-trait-bounds/hang-on-deeply-nested-dyn.stderr
new file mode 100644
index 000000000..71e196c32
--- /dev/null
+++ b/tests/ui/higher-rank-trait-bounds/hang-on-deeply-nested-dyn.stderr
@@ -0,0 +1,22 @@
+error[E0308]: mismatched types
+ --> $DIR/hang-on-deeply-nested-dyn.rs:12:5
+ |
+LL | ) -> &dyn Fn(
+ | ______-
+LL | | &dyn Fn(
+LL | | &dyn Fn(
+LL | | &dyn Fn(&dyn Fn(&dyn Fn(&dyn Fn(&dyn Fn(&dyn Fn(&dyn Fn(&dyn Fn(&dyn Fn(u32))))))))),
+LL | | ),
+LL | | ),
+LL | | ) {
+ | |_- expected `&dyn for<'a> Fn(&'a (dyn for<'a> Fn(&'a (dyn for<'a> Fn(&'a (dyn for<'a> Fn(&'a (dyn for<'a> Fn(&'a (dyn for<'a> Fn(&'a (dyn for<'a> Fn(&'a (dyn for<'a> Fn(&'a (dyn for<'a> Fn(&'a (dyn for<'a> Fn(&'a (dyn for<'a> Fn(&'a (dyn Fn(u32) + 'a)) + 'a)) + 'a)) + 'a)) + 'a)) + 'a)) + 'a)) + 'a)) + 'a)) + 'a)) + 'a))` because of return type
+LL | f
+ | ^ expected reference, found `u32`
+ |
+ = note: expected reference `&dyn for<'a> Fn(&'a (dyn for<'a> Fn(&'a (dyn for<'a> Fn(&'a (dyn for<'a> Fn(&'a ...) + 'a)) + 'a)) + 'a))`
+ the full type name has been written to '$TEST_BUILD_DIR/higher-rank-trait-bounds/hang-on-deeply-nested-dyn/hang-on-deeply-nested-dyn.long-type-hash.txt'
+ found reference `&dyn Fn(u32)`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0308`.
diff --git a/tests/ui/higher-rank-trait-bounds/hrtb-binder-levels-in-object-types.rs b/tests/ui/higher-rank-trait-bounds/hrtb-binder-levels-in-object-types.rs
new file mode 100644
index 000000000..cc766c060
--- /dev/null
+++ b/tests/ui/higher-rank-trait-bounds/hrtb-binder-levels-in-object-types.rs
@@ -0,0 +1,29 @@
+// run-pass
+#![allow(dead_code)]
+#![allow(unused_variables)]
+// Test that we handle binder levels in object types correctly.
+// Initially, the reference to `'tcx` in the object type
+// `&Typer<'tcx>` was getting an incorrect binder level, yielding
+// weird compilation ICEs and so forth.
+
+// pretty-expanded FIXME #23616
+
+trait Typer<'tcx> {
+ fn method(&self, data: &'tcx isize) -> &'tcx isize { data }
+}
+
+struct Tcx<'tcx> {
+ fields: &'tcx isize
+}
+
+impl<'tcx> Typer<'tcx> for Tcx<'tcx> {
+}
+
+fn g<'tcx>(typer: &dyn Typer<'tcx>) {
+}
+
+fn check_static_type<'x>(tcx: &Tcx<'x>) {
+ g(tcx)
+}
+
+fn main() { }
diff --git a/tests/ui/higher-rank-trait-bounds/hrtb-cache-issue-54302.rs b/tests/ui/higher-rank-trait-bounds/hrtb-cache-issue-54302.rs
new file mode 100644
index 000000000..a20d03c77
--- /dev/null
+++ b/tests/ui/higher-rank-trait-bounds/hrtb-cache-issue-54302.rs
@@ -0,0 +1,24 @@
+// Regression test for #54302.
+//
+// We were incorrectly using the "evaluation cache" (which ignored
+// region results) to conclude that `&'static str: Deserialize`, even
+// though it would require that `for<'de> 'de: 'static`, which is
+// clearly false.
+
+trait Deserialize<'de> {}
+
+trait DeserializeOwned: for<'de> Deserialize<'de> {}
+impl<T> DeserializeOwned for T where T: for<'de> Deserialize<'de> {}
+
+// Based on this impl, `&'static str` only implements Deserialize<'static>.
+// It does not implement for<'de> Deserialize<'de>.
+impl<'de: 'a, 'a> Deserialize<'de> for &'a str {}
+
+fn main() {
+ fn assert_deserialize_owned<T: DeserializeOwned>() {}
+ assert_deserialize_owned::<&'static str>(); //~ ERROR
+
+ // It correctly does not implement for<'de> Deserialize<'de>.
+ // fn assert_hrtb<T: for<'de> Deserialize<'de>>() {}
+ // assert_hrtb::<&'static str>();
+}
diff --git a/tests/ui/higher-rank-trait-bounds/hrtb-cache-issue-54302.stderr b/tests/ui/higher-rank-trait-bounds/hrtb-cache-issue-54302.stderr
new file mode 100644
index 000000000..f014eab86
--- /dev/null
+++ b/tests/ui/higher-rank-trait-bounds/hrtb-cache-issue-54302.stderr
@@ -0,0 +1,11 @@
+error: implementation of `Deserialize` is not general enough
+ --> $DIR/hrtb-cache-issue-54302.rs:19:5
+ |
+LL | assert_deserialize_owned::<&'static str>();
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ implementation of `Deserialize` is not general enough
+ |
+ = note: `&'static str` must implement `Deserialize<'0>`, for any lifetime `'0`...
+ = note: ...but `&str` actually implements `Deserialize<'1>`, for some specific lifetime `'1`
+
+error: aborting due to previous error
+
diff --git a/tests/ui/higher-rank-trait-bounds/hrtb-conflate-regions.rs b/tests/ui/higher-rank-trait-bounds/hrtb-conflate-regions.rs
new file mode 100644
index 000000000..e83686404
--- /dev/null
+++ b/tests/ui/higher-rank-trait-bounds/hrtb-conflate-regions.rs
@@ -0,0 +1,31 @@
+// Test that an impl with only one bound region `'a` cannot be used to
+// satisfy a constraint where there are two bound regions.
+
+trait Foo<X> {
+ fn foo(&self, x: X) { }
+}
+
+fn want_foo2<T>()
+ where T : for<'a,'b> Foo<(&'a isize, &'b isize)>
+{
+}
+
+fn want_foo1<T>()
+ where T : for<'z> Foo<(&'z isize, &'z isize)>
+{
+}
+
+// Expressed as a where clause
+
+struct SomeStruct;
+
+impl<'a> Foo<(&'a isize, &'a isize)> for SomeStruct
+{
+}
+
+fn a() { want_foo1::<SomeStruct>(); } // OK -- foo wants just one region
+fn b() { want_foo2::<SomeStruct>(); }
+//~^ ERROR implementation of
+//~| ERROR implementation of
+
+fn main() { }
diff --git a/tests/ui/higher-rank-trait-bounds/hrtb-conflate-regions.stderr b/tests/ui/higher-rank-trait-bounds/hrtb-conflate-regions.stderr
new file mode 100644
index 000000000..46f5308dd
--- /dev/null
+++ b/tests/ui/higher-rank-trait-bounds/hrtb-conflate-regions.stderr
@@ -0,0 +1,20 @@
+error: implementation of `Foo` is not general enough
+ --> $DIR/hrtb-conflate-regions.rs:27:10
+ |
+LL | fn b() { want_foo2::<SomeStruct>(); }
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^ implementation of `Foo` is not general enough
+ |
+ = note: `SomeStruct` must implement `Foo<(&'0 isize, &'1 isize)>`, for any two lifetimes `'0` and `'1`...
+ = note: ...but it actually implements `Foo<(&'2 isize, &'2 isize)>`, for some specific lifetime `'2`
+
+error: implementation of `Foo` is not general enough
+ --> $DIR/hrtb-conflate-regions.rs:27:10
+ |
+LL | fn b() { want_foo2::<SomeStruct>(); }
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^ implementation of `Foo` is not general enough
+ |
+ = note: `SomeStruct` must implement `Foo<(&'0 isize, &'1 isize)>`, for any two lifetimes `'0` and `'1`...
+ = note: ...but it actually implements `Foo<(&'2 isize, &'2 isize)>`, for some specific lifetime `'2`
+
+error: aborting due to 2 previous errors
+
diff --git a/tests/ui/higher-rank-trait-bounds/hrtb-debruijn-in-receiver.rs b/tests/ui/higher-rank-trait-bounds/hrtb-debruijn-in-receiver.rs
new file mode 100644
index 000000000..05d3e1a43
--- /dev/null
+++ b/tests/ui/higher-rank-trait-bounds/hrtb-debruijn-in-receiver.rs
@@ -0,0 +1,18 @@
+// Test the case where the `Self` type has a bound lifetime that must
+// be adjusted in the fn signature. Issue #19537.
+
+use std::collections::HashMap;
+
+struct Foo<'a> {
+ map: HashMap<usize, &'a str>
+}
+
+impl<'a> Foo<'a> {
+ fn new() -> Foo<'a> { panic!() }
+ fn insert(&'a mut self) { }
+}
+fn main() {
+ let mut foo = Foo::new();
+ foo.insert();
+ foo.insert(); //~ ERROR cannot borrow
+}
diff --git a/tests/ui/higher-rank-trait-bounds/hrtb-debruijn-in-receiver.stderr b/tests/ui/higher-rank-trait-bounds/hrtb-debruijn-in-receiver.stderr
new file mode 100644
index 000000000..fa391ecba
--- /dev/null
+++ b/tests/ui/higher-rank-trait-bounds/hrtb-debruijn-in-receiver.stderr
@@ -0,0 +1,14 @@
+error[E0499]: cannot borrow `foo` as mutable more than once at a time
+ --> $DIR/hrtb-debruijn-in-receiver.rs:17:5
+ |
+LL | foo.insert();
+ | ------------ first mutable borrow occurs here
+LL | foo.insert();
+ | ^^^^^^^^^^^^
+ | |
+ | second mutable borrow occurs here
+ | first borrow later used here
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0499`.
diff --git a/tests/ui/higher-rank-trait-bounds/hrtb-debruijn-object-types-in-closures.rs b/tests/ui/higher-rank-trait-bounds/hrtb-debruijn-object-types-in-closures.rs
new file mode 100644
index 000000000..8431226a3
--- /dev/null
+++ b/tests/ui/higher-rank-trait-bounds/hrtb-debruijn-object-types-in-closures.rs
@@ -0,0 +1,16 @@
+// run-pass
+#![allow(dead_code)]
+// pretty-expanded FIXME #23616
+
+trait Typer<'tcx> {
+ fn method(&self, data: &'tcx isize) -> &'tcx isize { data }
+ fn dummy(&self) { }
+}
+
+fn g<F>(_: F) where F: FnOnce(&dyn Typer) {}
+
+fn h() {
+ g(|typer| typer.dummy())
+}
+
+fn main() { }
diff --git a/tests/ui/higher-rank-trait-bounds/hrtb-exists-forall-fn.rs b/tests/ui/higher-rank-trait-bounds/hrtb-exists-forall-fn.rs
new file mode 100644
index 000000000..567802376
--- /dev/null
+++ b/tests/ui/higher-rank-trait-bounds/hrtb-exists-forall-fn.rs
@@ -0,0 +1,18 @@
+// Test an `exists<'a> { forall<'b> { 'a = 'b } }` pattern -- which should not compile!
+//
+// In particular, we test this pattern in trait solving, where it is not connected
+// to any part of the source code.
+
+fn foo<'a>() -> fn(&'a u32) {
+ panic!()
+}
+
+fn main() {
+ // Here, proving that `fn(&'a u32) <: for<'b> fn(&'b u32)`:
+ //
+ // - instantiates `'b` with a placeholder `!b`,
+ // - requires that `&!b u32 <: &'a u32` and hence that `!b: 'a`,
+ // - but we can never know this.
+
+ let _: for<'b> fn(&'b u32) = foo(); //~ ERROR mismatched types
+}
diff --git a/tests/ui/higher-rank-trait-bounds/hrtb-exists-forall-fn.stderr b/tests/ui/higher-rank-trait-bounds/hrtb-exists-forall-fn.stderr
new file mode 100644
index 000000000..9914783d9
--- /dev/null
+++ b/tests/ui/higher-rank-trait-bounds/hrtb-exists-forall-fn.stderr
@@ -0,0 +1,12 @@
+error[E0308]: mismatched types
+ --> $DIR/hrtb-exists-forall-fn.rs:17:34
+ |
+LL | let _: for<'b> fn(&'b u32) = foo();
+ | ^^^^^ one type is more general than the other
+ |
+ = note: expected fn pointer `for<'b> fn(&'b u32)`
+ found fn pointer `fn(&u32)`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0308`.
diff --git a/tests/ui/higher-rank-trait-bounds/hrtb-exists-forall-trait-contravariant.rs b/tests/ui/higher-rank-trait-bounds/hrtb-exists-forall-trait-contravariant.rs
new file mode 100644
index 000000000..921061916
--- /dev/null
+++ b/tests/ui/higher-rank-trait-bounds/hrtb-exists-forall-trait-contravariant.rs
@@ -0,0 +1,36 @@
+// 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.
+
+trait Trait<T> {}
+
+fn foo<T>()
+where
+ T: Trait<for<'b> fn(&'b u32)>,
+{
+}
+
+impl<'a> Trait<fn(&'a u32)> for () {}
+
+fn main() {
+ // Here, proving that `(): Trait<for<'b> fn(&'b u32)>` uses the impl:
+ //
+ // - The impl provides the clause `forall<'a> { (): Trait<fn(&'a u32)> }`
+ // - We instantiate `'a` existentially to get `(): Trait<fn(&?a u32)>`
+ // - We unify `fn(&?a u32)` with `for<'b> fn(&'b u32)` -- this does a
+ // "bidirectional" subtyping check, so we wind up with:
+ // - `fn(&?a u32) <: for<'b> fn(&'b u32)` :-
+ // - `&'!b u32 <: &?a u32`
+ // - `!'b: ?a` -- solveable if `?a` is inferred to `'empty`
+ // - `for<'b> fn(&'b u32) <: fn(&?a u32)` :-
+ // - `&?a u32 u32 <: &?b u32`
+ // - `?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 implementation of `Trait` is not general enough
+}
diff --git a/tests/ui/higher-rank-trait-bounds/hrtb-exists-forall-trait-contravariant.stderr b/tests/ui/higher-rank-trait-bounds/hrtb-exists-forall-trait-contravariant.stderr
new file mode 100644
index 000000000..364b613fc
--- /dev/null
+++ b/tests/ui/higher-rank-trait-bounds/hrtb-exists-forall-trait-contravariant.stderr
@@ -0,0 +1,11 @@
+error: implementation of `Trait` is not general enough
+ --> $DIR/hrtb-exists-forall-trait-contravariant.rs:34:5
+ |
+LL | foo::<()>();
+ | ^^^^^^^^^^^ implementation of `Trait` is not general enough
+ |
+ = note: `()` must implement `Trait<for<'b> fn(&'b u32)>`
+ = note: ...but it actually implements `Trait<fn(&'0 u32)>`, for some specific lifetime `'0`
+
+error: aborting due to previous error
+
diff --git a/tests/ui/higher-rank-trait-bounds/hrtb-exists-forall-trait-covariant.rs b/tests/ui/higher-rank-trait-bounds/hrtb-exists-forall-trait-covariant.rs
new file mode 100644
index 000000000..f95496a6c
--- /dev/null
+++ b/tests/ui/higher-rank-trait-bounds/hrtb-exists-forall-trait-covariant.rs
@@ -0,0 +1,37 @@
+// 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.
+//
+// check-pass
+
+trait Trait<T> {}
+
+fn foo<T>()
+where
+ T: Trait<for<'b> fn(fn(&'b u32))>,
+{
+}
+
+impl<'a> Trait<fn(fn(&'a u32))> for () {}
+
+fn main() {
+ // Here, proving that `(): Trait<for<'b> fn(&'b u32)>` uses the impl:
+ //
+ // - The impl provides the clause `forall<'a> { (): Trait<fn(fn(&'a u32))> }`
+ // - We instantiate `'a` existentially to get `(): Trait<fn(fn(&?a u32))>`
+ // - We unify `fn(fn(&?a u32))` with `for<'b> fn(fn(&'b u32))` -- this does a
+ // "bidirectional" subtyping check, so we wind up with:
+ // - `fn(fn(&?a u32)) <: for<'b> fn(fn(&'b u32))` :-
+ // - `fn(&!b u32) <: fn(&?a u32)`
+ // - `&?a u32 <: &!b u32`
+ // - `?a: !'b` -- solveable if `?a` is inferred to `'static`
+ // - `for<'b> fn(fn(&'b u32)) <: fn(fn(&?a u32))` :-
+ // - `fn(&?a u32) <: fn(&?b u32)`
+ // - `&?b u32 <: &?a u32`
+ // - `?b: ?a` -- solveable if `?b` is inferred to `'static`
+ // - So the subtyping check succeeds, somewhat surprisingly.
+ // This is because we can use `'static`.
+
+ foo::<()>();
+}
diff --git a/tests/ui/higher-rank-trait-bounds/hrtb-exists-forall-trait-invariant.rs b/tests/ui/higher-rank-trait-bounds/hrtb-exists-forall-trait-invariant.rs
new file mode 100644
index 000000000..9b9e4496a
--- /dev/null
+++ b/tests/ui/higher-rank-trait-bounds/hrtb-exists-forall-trait-invariant.rs
@@ -0,0 +1,29 @@
+// Test an `exists<'a> { forall<'b> { 'a = 'b } }` pattern -- which should not compile!
+//
+// In particular, we test this pattern in trait solving, where it is not connected
+// to any part of the source code.
+
+use std::cell::Cell;
+
+trait Trait<T> {}
+
+fn foo<T>()
+where
+ T: Trait<for<'b> fn(Cell<&'b u32>)>,
+{
+}
+
+impl<'a> Trait<fn(Cell<&'a u32>)> for () {}
+
+fn main() {
+ // Here, proving that `(): Trait<for<'b> fn(&'b u32)>` uses the impl:
+ //
+ // - The impl provides the clause `forall<'a> { (): Trait<fn(&'a u32)> }`
+ // - We instantiate `'a` existentially to get `(): Trait<fn(&?a u32)>`
+ // - We unify `fn(&?a u32)` with `for<'b> fn(&'b u32)`
+ // - This requires (among other things) instantiating `'b` universally,
+ // 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 implementation of `Trait` is not general enough
+}
diff --git a/tests/ui/higher-rank-trait-bounds/hrtb-exists-forall-trait-invariant.stderr b/tests/ui/higher-rank-trait-bounds/hrtb-exists-forall-trait-invariant.stderr
new file mode 100644
index 000000000..cb2ce8a41
--- /dev/null
+++ b/tests/ui/higher-rank-trait-bounds/hrtb-exists-forall-trait-invariant.stderr
@@ -0,0 +1,11 @@
+error: implementation of `Trait` is not general enough
+ --> $DIR/hrtb-exists-forall-trait-invariant.rs:28:5
+ |
+LL | foo::<()>();
+ | ^^^^^^^^^^^ implementation of `Trait` is not general enough
+ |
+ = note: `()` must implement `Trait<for<'b> fn(Cell<&'b u32>)>`
+ = note: ...but it actually implements `Trait<fn(Cell<&'0 u32>)>`, for some specific lifetime `'0`
+
+error: aborting due to previous error
+
diff --git a/tests/ui/higher-rank-trait-bounds/hrtb-fn-like-trait-object.rs b/tests/ui/higher-rank-trait-bounds/hrtb-fn-like-trait-object.rs
new file mode 100644
index 000000000..ff84ad9d2
--- /dev/null
+++ b/tests/ui/higher-rank-trait-bounds/hrtb-fn-like-trait-object.rs
@@ -0,0 +1,27 @@
+// run-pass
+// A basic test of using a higher-ranked trait bound.
+
+
+trait FnLike<A,R> {
+ fn call(&self, arg: A) -> R;
+}
+
+type FnObject<'b> = dyn for<'a> FnLike<&'a isize, &'a isize> + 'b;
+
+struct Identity;
+
+impl<'a, T> FnLike<&'a T, &'a T> for Identity {
+ fn call(&self, arg: &'a T) -> &'a T {
+ arg
+ }
+}
+
+fn call_repeatedly(f: &FnObject) {
+ let x = 3;
+ let y = f.call(&x);
+ assert_eq!(3, *y);
+}
+
+fn main() {
+ call_repeatedly(&Identity);
+}
diff --git a/tests/ui/higher-rank-trait-bounds/hrtb-fn-like-trait.rs b/tests/ui/higher-rank-trait-bounds/hrtb-fn-like-trait.rs
new file mode 100644
index 000000000..afab9986c
--- /dev/null
+++ b/tests/ui/higher-rank-trait-bounds/hrtb-fn-like-trait.rs
@@ -0,0 +1,27 @@
+// run-pass
+// A basic test of using a higher-ranked trait bound.
+
+
+trait FnLike<A,R> {
+ fn call(&self, arg: A) -> R;
+}
+
+struct Identity;
+
+impl<'a, T> FnLike<&'a T, &'a T> for Identity {
+ fn call(&self, arg: &'a T) -> &'a T {
+ arg
+ }
+}
+
+fn call_repeatedly<F>(f: F)
+ where F : for<'a> FnLike<&'a isize, &'a isize>
+{
+ let x = 3;
+ let y = f.call(&x);
+ assert_eq!(3, *y);
+}
+
+fn main() {
+ call_repeatedly(Identity);
+}
diff --git a/tests/ui/higher-rank-trait-bounds/hrtb-higher-ranker-supertraits-transitive.rs b/tests/ui/higher-rank-trait-bounds/hrtb-higher-ranker-supertraits-transitive.rs
new file mode 100644
index 000000000..f9ae1429e
--- /dev/null
+++ b/tests/ui/higher-rank-trait-bounds/hrtb-higher-ranker-supertraits-transitive.rs
@@ -0,0 +1,50 @@
+// Test HRTB supertraits with several levels of expansion required.
+
+trait Foo<'tcx>
+{
+ fn foo(&'tcx self) -> &'tcx isize;
+}
+
+trait Bar<'ccx>
+ : for<'tcx> Foo<'tcx>
+{
+ fn bar(&'ccx self) -> &'ccx isize;
+}
+
+trait Baz
+ : for<'ccx> Bar<'ccx>
+{
+ fn dummy(&self);
+}
+
+trait Qux
+ : Bar<'static>
+{
+ fn dummy(&self);
+}
+
+fn want_foo_for_any_tcx<F>(f: &F)
+ where F : for<'tcx> Foo<'tcx>
+{
+}
+
+fn want_bar_for_any_ccx<B>(b: &B)
+ where B : for<'ccx> Bar<'ccx>
+{
+}
+
+fn want_baz<B>(b: &B)
+ where B : Baz
+{
+ want_foo_for_any_tcx(b);
+ want_bar_for_any_ccx(b);
+}
+
+fn want_qux<B>(b: &B)
+ where B : Qux
+{
+ want_foo_for_any_tcx(b);
+ want_bar_for_any_ccx(b); //~ ERROR
+}
+
+fn main() {}
diff --git a/tests/ui/higher-rank-trait-bounds/hrtb-higher-ranker-supertraits-transitive.stderr b/tests/ui/higher-rank-trait-bounds/hrtb-higher-ranker-supertraits-transitive.stderr
new file mode 100644
index 000000000..8cda76b94
--- /dev/null
+++ b/tests/ui/higher-rank-trait-bounds/hrtb-higher-ranker-supertraits-transitive.stderr
@@ -0,0 +1,23 @@
+error[E0277]: the trait bound `for<'ccx> B: Bar<'ccx>` is not satisfied
+ --> $DIR/hrtb-higher-ranker-supertraits-transitive.rs:47:26
+ |
+LL | want_bar_for_any_ccx(b);
+ | -------------------- ^ the trait `for<'ccx> Bar<'ccx>` is not implemented for `B`
+ | |
+ | required by a bound introduced by this call
+ |
+note: required by a bound in `want_bar_for_any_ccx`
+ --> $DIR/hrtb-higher-ranker-supertraits-transitive.rs:32:15
+ |
+LL | fn want_bar_for_any_ccx<B>(b: &B)
+ | -------------------- required by a bound in this
+LL | where B : for<'ccx> Bar<'ccx>
+ | ^^^^^^^^^^^^^^^^^^^ required by this bound in `want_bar_for_any_ccx`
+help: consider further restricting this bound
+ |
+LL | where B : Qux + for<'ccx> Bar<'ccx>
+ | +++++++++++++++++++++
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0277`.
diff --git a/tests/ui/higher-rank-trait-bounds/hrtb-higher-ranker-supertraits.rs b/tests/ui/higher-rank-trait-bounds/hrtb-higher-ranker-supertraits.rs
new file mode 100644
index 000000000..48ebe5017
--- /dev/null
+++ b/tests/ui/higher-rank-trait-bounds/hrtb-higher-ranker-supertraits.rs
@@ -0,0 +1,48 @@
+// Test a trait (`Bar`) with a higher-ranked supertrait.
+
+trait Foo<'tcx>
+{
+ fn foo(&'tcx self) -> &'tcx isize;
+}
+
+trait Bar<'ccx>
+ : for<'tcx> Foo<'tcx>
+{
+ fn bar(&'ccx self) -> &'ccx isize;
+}
+
+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 not satisfied
+}
+
+fn want_foo_for_any_tcx<F>(f: &F)
+ where F : for<'tcx> Foo<'tcx>
+{
+ want_foo_for_some_tcx(f);
+ want_foo_for_any_tcx(f);
+}
+
+fn want_bar_for_some_ccx<'x,B>(b: &B)
+ where B : Bar<'x>
+{
+ want_foo_for_some_tcx(b);
+ want_foo_for_any_tcx(b);
+
+ want_bar_for_some_ccx(b);
+ want_bar_for_any_ccx(b); //~ ERROR not satisfied
+}
+
+fn want_bar_for_any_ccx<B>(b: &B)
+ where B : for<'ccx> Bar<'ccx>
+{
+ want_foo_for_some_tcx(b);
+ want_foo_for_any_tcx(b);
+
+ want_bar_for_some_ccx(b);
+ want_bar_for_any_ccx(b);
+}
+
+fn main() {}
diff --git a/tests/ui/higher-rank-trait-bounds/hrtb-higher-ranker-supertraits.stderr b/tests/ui/higher-rank-trait-bounds/hrtb-higher-ranker-supertraits.stderr
new file mode 100644
index 000000000..88793a152
--- /dev/null
+++ b/tests/ui/higher-rank-trait-bounds/hrtb-higher-ranker-supertraits.stderr
@@ -0,0 +1,43 @@
+error[E0277]: the trait bound `for<'tcx> F: Foo<'tcx>` is not satisfied
+ --> $DIR/hrtb-higher-ranker-supertraits.rs:18:26
+ |
+LL | want_foo_for_any_tcx(f);
+ | -------------------- ^ the trait `for<'tcx> Foo<'tcx>` is not implemented for `F`
+ | |
+ | required by a bound introduced by this call
+ |
+note: required by a bound in `want_foo_for_any_tcx`
+ --> $DIR/hrtb-higher-ranker-supertraits.rs:22:15
+ |
+LL | fn want_foo_for_any_tcx<F>(f: &F)
+ | -------------------- required by a bound in this
+LL | where F : for<'tcx> Foo<'tcx>
+ | ^^^^^^^^^^^^^^^^^^^ required by this bound in `want_foo_for_any_tcx`
+help: consider further restricting this bound
+ |
+LL | where F : Foo<'x> + for<'tcx> Foo<'tcx>
+ | +++++++++++++++++++++
+
+error[E0277]: the trait bound `for<'ccx> B: Bar<'ccx>` is not satisfied
+ --> $DIR/hrtb-higher-ranker-supertraits.rs:35:26
+ |
+LL | want_bar_for_any_ccx(b);
+ | -------------------- ^ the trait `for<'ccx> Bar<'ccx>` is not implemented for `B`
+ | |
+ | required by a bound introduced by this call
+ |
+note: required by a bound in `want_bar_for_any_ccx`
+ --> $DIR/hrtb-higher-ranker-supertraits.rs:39:15
+ |
+LL | fn want_bar_for_any_ccx<B>(b: &B)
+ | -------------------- required by a bound in this
+LL | where B : for<'ccx> Bar<'ccx>
+ | ^^^^^^^^^^^^^^^^^^^ required by this bound in `want_bar_for_any_ccx`
+help: consider further restricting this bound
+ |
+LL | where B : Bar<'x> + for<'ccx> Bar<'ccx>
+ | +++++++++++++++++++++
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0277`.
diff --git a/tests/ui/higher-rank-trait-bounds/hrtb-identity-fn-borrows.rs b/tests/ui/higher-rank-trait-bounds/hrtb-identity-fn-borrows.rs
new file mode 100644
index 000000000..89fc4705a
--- /dev/null
+++ b/tests/ui/higher-rank-trait-bounds/hrtb-identity-fn-borrows.rs
@@ -0,0 +1,26 @@
+// Test that the `'a` in the where clause correctly links the region
+// of the output to the region of the input.
+
+trait FnLike<A,R> {
+ fn call(&self, arg: A) -> R;
+}
+
+fn call_repeatedly<F>(f: F)
+ where F : for<'a> FnLike<&'a isize, &'a isize>
+{
+ // Result is stored: cannot re-assign `x`
+ let mut x = 3;
+ let y = f.call(&x);
+ x = 5; //~ ERROR cannot assign to `x` because it is borrowed
+
+ // Result is not stored: can re-assign `x`
+ let mut x = 3;
+ f.call(&x);
+ f.call(&x);
+ f.call(&x);
+ x = 5;
+ drop(y);
+}
+
+fn main() {
+}
diff --git a/tests/ui/higher-rank-trait-bounds/hrtb-identity-fn-borrows.stderr b/tests/ui/higher-rank-trait-bounds/hrtb-identity-fn-borrows.stderr
new file mode 100644
index 000000000..4886a3c8b
--- /dev/null
+++ b/tests/ui/higher-rank-trait-bounds/hrtb-identity-fn-borrows.stderr
@@ -0,0 +1,14 @@
+error[E0506]: cannot assign to `x` because it is borrowed
+ --> $DIR/hrtb-identity-fn-borrows.rs:14:5
+ |
+LL | let y = f.call(&x);
+ | -- borrow of `x` occurs here
+LL | x = 5;
+ | ^^^^^ assignment to borrowed `x` occurs here
+...
+LL | drop(y);
+ | - borrow later used here
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0506`.
diff --git a/tests/ui/higher-rank-trait-bounds/hrtb-just-for-static.rs b/tests/ui/higher-rank-trait-bounds/hrtb-just-for-static.rs
new file mode 100644
index 000000000..8fb4218f8
--- /dev/null
+++ b/tests/ui/higher-rank-trait-bounds/hrtb-just-for-static.rs
@@ -0,0 +1,35 @@
+// Test a case where you have an impl of `Foo<X>` for all `X` that
+// is being applied to `for<'a> Foo<&'a mut X>`. Issue #19730.
+
+trait Foo<X> {
+ fn foo(&self, x: X) { }
+}
+
+fn want_hrtb<T>()
+ where T : for<'a> Foo<&'a isize>
+{
+}
+
+// AnyInt implements Foo<&'a isize> for any 'a, so it is a match.
+struct AnyInt;
+impl<'a> Foo<&'a isize> for AnyInt { }
+fn give_any() {
+ want_hrtb::<AnyInt>()
+}
+
+// StaticInt only implements Foo<&'static isize>, so it is an error.
+struct StaticInt;
+impl Foo<&'static isize> for StaticInt { }
+fn give_static() {
+ want_hrtb::<StaticInt>() //~ ERROR
+}
+
+// &'a u32 only implements Foo<&'a isize> for specific 'a, so it is an error.
+impl<'a> Foo<&'a isize> for &'a u32 { }
+fn give_some<'a>() {
+ want_hrtb::<&'a u32>()
+ //~^ ERROR lifetime may not live long enough
+ //~| ERROR implementation of `Foo` is not general enough
+}
+
+fn main() { }
diff --git a/tests/ui/higher-rank-trait-bounds/hrtb-just-for-static.stderr b/tests/ui/higher-rank-trait-bounds/hrtb-just-for-static.stderr
new file mode 100644
index 000000000..31e11e128
--- /dev/null
+++ b/tests/ui/higher-rank-trait-bounds/hrtb-just-for-static.stderr
@@ -0,0 +1,34 @@
+error: implementation of `Foo` is not general enough
+ --> $DIR/hrtb-just-for-static.rs:24:5
+ |
+LL | want_hrtb::<StaticInt>()
+ | ^^^^^^^^^^^^^^^^^^^^^^ implementation of `Foo` is not general enough
+ |
+ = note: `StaticInt` must implement `Foo<&'0 isize>`, for any lifetime `'0`...
+ = note: ...but it actually implements `Foo<&'static isize>`
+
+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`
+ |
+note: due to current limitations in the borrow checker, this implies a `'static` lifetime
+ --> $DIR/hrtb-just-for-static.rs:9:15
+ |
+LL | where T : for<'a> Foo<&'a isize>
+ | ^^^^^^^^^^^^^^^^^^^^^^
+
+error: implementation of `Foo` is not general enough
+ --> $DIR/hrtb-just-for-static.rs:30:5
+ |
+LL | want_hrtb::<&'a u32>()
+ | ^^^^^^^^^^^^^^^^^^^^ implementation of `Foo` is not general enough
+ |
+ = note: `Foo<&'0 isize>` would have to be implemented for the type `&u32`, for any lifetime `'0`...
+ = note: ...but `Foo<&'1 isize>` is actually implemented for the type `&'1 u32`, for some specific lifetime `'1`
+
+error: aborting due to 3 previous errors
+
diff --git a/tests/ui/higher-rank-trait-bounds/hrtb-malformed-lifetime-generics.rs b/tests/ui/higher-rank-trait-bounds/hrtb-malformed-lifetime-generics.rs
new file mode 100644
index 000000000..4b096be59
--- /dev/null
+++ b/tests/ui/higher-rank-trait-bounds/hrtb-malformed-lifetime-generics.rs
@@ -0,0 +1,20 @@
+// Test that Fn-family traits with lifetime parameters shouldn't compile and
+// we suggest the usage of higher-rank trait bounds instead.
+
+fn fa(_: impl Fn<'a>(&'a str) -> bool) {}
+//~^ ERROR `Fn` traits cannot take lifetime parameters
+
+fn fb(_: impl FnMut<'a, 'b>(&'a str, &'b str) -> bool) {}
+//~^ ERROR `Fn` traits cannot take lifetime parameters
+
+fn fc(_: impl std::fmt::Display + FnOnce<'a>(&'a str) -> bool + std::fmt::Debug) {}
+//~^ ERROR `Fn` traits cannot take lifetime parameters
+
+use std::ops::Fn as AliasedFn;
+fn fd(_: impl AliasedFn<'a>(&'a str) -> bool) {}
+//~^ ERROR `Fn` traits cannot take lifetime parameters
+
+fn fe<F>(_: F) where F: Fn<'a>(&'a str) -> bool {}
+//~^ ERROR `Fn` traits cannot take lifetime parameters
+
+fn main() {}
diff --git a/tests/ui/higher-rank-trait-bounds/hrtb-malformed-lifetime-generics.stderr b/tests/ui/higher-rank-trait-bounds/hrtb-malformed-lifetime-generics.stderr
new file mode 100644
index 000000000..e8f6d63b5
--- /dev/null
+++ b/tests/ui/higher-rank-trait-bounds/hrtb-malformed-lifetime-generics.stderr
@@ -0,0 +1,62 @@
+error: `Fn` traits cannot take lifetime parameters
+ --> $DIR/hrtb-malformed-lifetime-generics.rs:4:17
+ |
+LL | fn fa(_: impl Fn<'a>(&'a str) -> bool) {}
+ | ^^^^
+ |
+help: consider using a higher-ranked trait bound instead
+ |
+LL - fn fa(_: impl Fn<'a>(&'a str) -> bool) {}
+LL + fn fa(_: impl for<'a> Fn(&'a str) -> bool) {}
+ |
+
+error: `Fn` traits cannot take lifetime parameters
+ --> $DIR/hrtb-malformed-lifetime-generics.rs:7:20
+ |
+LL | fn fb(_: impl FnMut<'a, 'b>(&'a str, &'b str) -> bool) {}
+ | ^^^^^^^^
+ |
+help: consider using a higher-ranked trait bound instead
+ |
+LL - fn fb(_: impl FnMut<'a, 'b>(&'a str, &'b str) -> bool) {}
+LL + fn fb(_: impl for<'a, 'b> FnMut(&'a str, &'b str) -> bool) {}
+ |
+
+error: `Fn` traits cannot take lifetime parameters
+ --> $DIR/hrtb-malformed-lifetime-generics.rs:10:41
+ |
+LL | fn fc(_: impl std::fmt::Display + FnOnce<'a>(&'a str) -> bool + std::fmt::Debug) {}
+ | ^^^^
+ |
+help: consider using a higher-ranked trait bound instead
+ |
+LL - fn fc(_: impl std::fmt::Display + FnOnce<'a>(&'a str) -> bool + std::fmt::Debug) {}
+LL + fn fc(_: impl std::fmt::Display + for<'a> FnOnce(&'a str) -> bool + std::fmt::Debug) {}
+ |
+
+error: `Fn` traits cannot take lifetime parameters
+ --> $DIR/hrtb-malformed-lifetime-generics.rs:14:24
+ |
+LL | fn fd(_: impl AliasedFn<'a>(&'a str) -> bool) {}
+ | ^^^^
+ |
+help: consider using a higher-ranked trait bound instead
+ |
+LL - fn fd(_: impl AliasedFn<'a>(&'a str) -> bool) {}
+LL + fn fd(_: impl for<'a> AliasedFn(&'a str) -> bool) {}
+ |
+
+error: `Fn` traits cannot take lifetime parameters
+ --> $DIR/hrtb-malformed-lifetime-generics.rs:17:27
+ |
+LL | fn fe<F>(_: F) where F: Fn<'a>(&'a str) -> bool {}
+ | ^^^^
+ |
+help: consider using a higher-ranked trait bound instead
+ |
+LL - fn fe<F>(_: F) where F: Fn<'a>(&'a str) -> bool {}
+LL + fn fe<F>(_: F) where F: for<'a> Fn(&'a str) -> bool {}
+ |
+
+error: aborting due to 5 previous errors
+
diff --git a/tests/ui/higher-rank-trait-bounds/hrtb-opt-in-copy.rs b/tests/ui/higher-rank-trait-bounds/hrtb-opt-in-copy.rs
new file mode 100644
index 000000000..04519f116
--- /dev/null
+++ b/tests/ui/higher-rank-trait-bounds/hrtb-opt-in-copy.rs
@@ -0,0 +1,28 @@
+// run-pass
+// Test that we handle binder levels correctly when checking whether a
+// type can implement `Copy`. In particular, we had a bug where we failed to
+// liberate the late-bound regions from the impl, and thus wound up
+// searching for an impl of `for<'tcx> Foo<&'tcx T>`. The impl that
+// exists however is `impl<T> Copy for Foo<T>` and the current rules
+// did not consider that a match (something I would like to revise in
+// a later PR).
+
+#![allow(dead_code)]
+
+use std::marker::PhantomData;
+
+#[derive(Copy, Clone)]
+struct Foo<T> { x: T }
+
+type Ty<'tcx> = &'tcx TyS<'tcx>;
+
+enum TyS<'tcx> {
+ Boop(PhantomData<*mut &'tcx ()>)
+}
+
+#[derive(Copy, Clone)]
+enum Bar<'tcx> {
+ Baz(Foo<Ty<'tcx>>)
+}
+
+fn main() { }
diff --git a/tests/ui/higher-rank-trait-bounds/hrtb-parse.rs b/tests/ui/higher-rank-trait-bounds/hrtb-parse.rs
new file mode 100644
index 000000000..1fab9758c
--- /dev/null
+++ b/tests/ui/higher-rank-trait-bounds/hrtb-parse.rs
@@ -0,0 +1,36 @@
+// run-pass
+// Test that we can parse all the various places that a `for` keyword
+// can appear representing universal quantification.
+
+// pretty-expanded FIXME #23616
+
+#![allow(unused_variables)]
+#![allow(dead_code)]
+
+trait Get<A,R> {
+ fn get(&self, arg: A) -> R;
+}
+
+// Parse HRTB with explicit `for` in a where-clause:
+
+fn foo00<T>(t: T)
+ where T : for<'a> Get<&'a i32, &'a i32>
+{
+}
+
+fn foo01<T: for<'a> Get<&'a i32, &'a i32>>(t: T)
+{
+}
+
+// Parse HRTB with explicit `for` in various sorts of types:
+
+fn foo10(t: Box<dyn for<'a> Get<i32, i32>>) { }
+fn foo11(t: Box<dyn for<'a> Fn(i32) -> i32>) { }
+
+fn foo20(t: for<'a> fn(i32) -> i32) { }
+fn foo21(t: for<'a> unsafe fn(i32) -> i32) { }
+fn foo22(t: for<'a> extern "C" fn(i32) -> i32) { }
+fn foo23(t: for<'a> unsafe extern "C" fn(i32) -> i32) { }
+
+fn main() {
+}
diff --git a/tests/ui/higher-rank-trait-bounds/hrtb-perfect-forwarding.polonius.stderr b/tests/ui/higher-rank-trait-bounds/hrtb-perfect-forwarding.polonius.stderr
new file mode 100644
index 000000000..a94c80eb3
--- /dev/null
+++ b/tests/ui/higher-rank-trait-bounds/hrtb-perfect-forwarding.polonius.stderr
@@ -0,0 +1,71 @@
+warning: function cannot return without recursing
+ --> $DIR/hrtb-perfect-forwarding.rs:16:1
+ |
+LL | / fn no_hrtb<'b, T>(mut t: T)
+LL | | where
+LL | | T: Bar<&'b isize>,
+LL | | {
+... |
+LL | | no_hrtb(&mut t);
+ | | --------------- recursive call site
+LL | | }
+ | |_^ cannot return without recursing
+ |
+ = note: `#[warn(unconditional_recursion)]` on by default
+ = help: a `loop` may express intention better if this is on purpose
+
+warning: function cannot return without recursing
+ --> $DIR/hrtb-perfect-forwarding.rs:25:1
+ |
+LL | / fn bar_hrtb<T>(mut t: T)
+LL | | where
+LL | | T: for<'b> Bar<&'b isize>,
+LL | | {
+... |
+LL | | bar_hrtb(&mut t);
+ | | ---------------- recursive call site
+LL | | }
+ | |_^ cannot return without recursing
+ |
+ = help: a `loop` may express intention better if this is on purpose
+
+warning: function cannot return without recursing
+ --> $DIR/hrtb-perfect-forwarding.rs:35:1
+ |
+LL | / fn foo_hrtb_bar_not<'b, T>(mut t: T)
+LL | | where
+LL | | T: for<'a> Foo<&'a isize> + Bar<&'b isize>,
+LL | | {
+... |
+LL | | foo_hrtb_bar_not(&mut t);
+ | | ------------------------ recursive call site
+LL | |
+LL | |
+LL | | }
+ | |_^ cannot return without recursing
+ |
+ = help: a `loop` may express intention better if this is on purpose
+
+error: higher-ranked subtype error
+ --> $DIR/hrtb-perfect-forwarding.rs:43:5
+ |
+LL | foo_hrtb_bar_not(&mut t);
+ | ^^^^^^^^^^^^^^^^^^^^^^^^
+
+warning: function cannot return without recursing
+ --> $DIR/hrtb-perfect-forwarding.rs:48:1
+ |
+LL | / fn foo_hrtb_bar_hrtb<T>(mut t: T)
+LL | | where
+LL | | T: for<'a> Foo<&'a isize> + for<'b> Bar<&'b isize>,
+LL | | {
+LL | | // OK -- now we have `T : for<'b> Bar<&'b isize>`.
+LL | | foo_hrtb_bar_hrtb(&mut t);
+ | | ------------------------- recursive call site
+LL | | }
+ | |_^ cannot return without recursing
+ |
+ = help: a `loop` may express intention better if this is on purpose
+
+error: aborting due to previous error; 4 warnings emitted
+
diff --git a/tests/ui/higher-rank-trait-bounds/hrtb-perfect-forwarding.rs b/tests/ui/higher-rank-trait-bounds/hrtb-perfect-forwarding.rs
new file mode 100644
index 000000000..d45fa183c
--- /dev/null
+++ b/tests/ui/higher-rank-trait-bounds/hrtb-perfect-forwarding.rs
@@ -0,0 +1,56 @@
+// Test a case where you have an impl of `Foo<X>` for all `X` that
+// is being applied to `for<'a> Foo<&'a mut X>`. Issue #19730.
+
+trait Foo<X> {
+ fn foo(&mut self, x: X) {}
+}
+
+trait Bar<X> {
+ fn bar(&mut self, x: X) {}
+}
+
+impl<'a, X, F> Foo<X> for &'a mut F where F: Foo<X> + Bar<X> {}
+
+impl<'a, X, F> Bar<X> for &'a mut F where F: Bar<X> {}
+
+fn no_hrtb<'b, T>(mut t: T) //~ WARN function cannot return
+where
+ T: Bar<&'b isize>,
+{
+ // OK -- `T : Bar<&'b isize>`, and thus the impl above ensures that
+ // `&mut T : Bar<&'b isize>`.
+ no_hrtb(&mut t);
+}
+
+fn bar_hrtb<T>(mut t: T) //~ WARN function cannot return
+where
+ T: for<'b> Bar<&'b isize>,
+{
+ // OK -- `T : for<'b> Bar<&'b isize>`, and thus the impl above
+ // ensures that `&mut T : for<'b> Bar<&'b isize>`. This is an
+ // example of a "perfect forwarding" impl.
+ bar_hrtb(&mut t);
+}
+
+fn foo_hrtb_bar_not<'b, T>(mut t: T) //~ WARN function cannot return
+where
+ T: for<'a> Foo<&'a isize> + Bar<&'b isize>,
+{
+ // Not OK -- The forwarding impl for `Foo` requires that `Bar` also
+ // be implemented. Thus to satisfy `&mut T : for<'a> Foo<&'a
+ // isize>`, we require `T : for<'a> Bar<&'a isize>`, but the where
+ // clause only specifies `T : Bar<&'b isize>`.
+ foo_hrtb_bar_not(&mut t);
+ //~^ ERROR implementation of `Bar` is not general enough
+ //~^^ ERROR lifetime may not live long enough
+}
+
+fn foo_hrtb_bar_hrtb<T>(mut t: T) //~ WARN function cannot return
+where
+ T: for<'a> Foo<&'a isize> + for<'b> Bar<&'b isize>,
+{
+ // OK -- now we have `T : for<'b> Bar<&'b isize>`.
+ foo_hrtb_bar_hrtb(&mut t);
+}
+
+fn main() {}
diff --git a/tests/ui/higher-rank-trait-bounds/hrtb-perfect-forwarding.stderr b/tests/ui/higher-rank-trait-bounds/hrtb-perfect-forwarding.stderr
new file mode 100644
index 000000000..727b9e6be
--- /dev/null
+++ b/tests/ui/higher-rank-trait-bounds/hrtb-perfect-forwarding.stderr
@@ -0,0 +1,79 @@
+warning: function cannot return without recursing
+ --> $DIR/hrtb-perfect-forwarding.rs:16:1
+ |
+LL | / fn no_hrtb<'b, T>(mut t: T)
+LL | | where
+LL | | T: Bar<&'b isize>,
+ | |______________________^ cannot return without recursing
+...
+LL | no_hrtb(&mut t);
+ | --------------- recursive call site
+ |
+ = help: a `loop` may express intention better if this is on purpose
+ = note: `#[warn(unconditional_recursion)]` on by default
+
+warning: function cannot return without recursing
+ --> $DIR/hrtb-perfect-forwarding.rs:25:1
+ |
+LL | / fn bar_hrtb<T>(mut t: T)
+LL | | where
+LL | | T: for<'b> Bar<&'b isize>,
+ | |______________________________^ cannot return without recursing
+...
+LL | bar_hrtb(&mut t);
+ | ---------------- recursive call site
+ |
+ = help: a `loop` may express intention better if this is on purpose
+
+warning: function cannot return without recursing
+ --> $DIR/hrtb-perfect-forwarding.rs:35:1
+ |
+LL | / fn foo_hrtb_bar_not<'b, T>(mut t: T)
+LL | | where
+LL | | T: for<'a> Foo<&'a isize> + Bar<&'b isize>,
+ | |_______________________________________________^ cannot return without recursing
+...
+LL | foo_hrtb_bar_not(&mut t);
+ | ------------------------ recursive call site
+ |
+ = help: a `loop` may express intention better if this is on purpose
+
+error: lifetime may not live long enough
+ --> $DIR/hrtb-perfect-forwarding.rs:43:5
+ |
+LL | fn foo_hrtb_bar_not<'b, T>(mut t: T)
+ | -- lifetime `'b` defined here
+...
+LL | foo_hrtb_bar_not(&mut t);
+ | ^^^^^^^^^^^^^^^^^^^^^^^^ requires that `'b` must outlive `'static`
+ |
+note: due to current limitations in the borrow checker, this implies a `'static` lifetime
+ --> $DIR/hrtb-perfect-forwarding.rs:37:8
+ |
+LL | T: for<'a> Foo<&'a isize> + Bar<&'b isize>,
+ | ^^^^^^^^^^^^^^^^^^^^^^
+
+error: implementation of `Bar` is not general enough
+ --> $DIR/hrtb-perfect-forwarding.rs:43:5
+ |
+LL | foo_hrtb_bar_not(&mut t);
+ | ^^^^^^^^^^^^^^^^^^^^^^^^ implementation of `Bar` is not general enough
+ |
+ = note: `T` must implement `Bar<&'0 isize>`, for any lifetime `'0`...
+ = note: ...but it actually implements `Bar<&'1 isize>`, for some specific lifetime `'1`
+
+warning: function cannot return without recursing
+ --> $DIR/hrtb-perfect-forwarding.rs:48:1
+ |
+LL | / fn foo_hrtb_bar_hrtb<T>(mut t: T)
+LL | | where
+LL | | T: for<'a> Foo<&'a isize> + for<'b> Bar<&'b isize>,
+ | |_______________________________________________________^ cannot return without recursing
+...
+LL | foo_hrtb_bar_hrtb(&mut t);
+ | ------------------------- recursive call site
+ |
+ = help: a `loop` may express intention better if this is on purpose
+
+error: aborting due to 2 previous errors; 4 warnings emitted
+
diff --git a/tests/ui/higher-rank-trait-bounds/hrtb-precedence-of-plus-where-clause.rs b/tests/ui/higher-rank-trait-bounds/hrtb-precedence-of-plus-where-clause.rs
new file mode 100644
index 000000000..42247798f
--- /dev/null
+++ b/tests/ui/higher-rank-trait-bounds/hrtb-precedence-of-plus-where-clause.rs
@@ -0,0 +1,25 @@
+// run-pass
+#![allow(dead_code)]
+#![allow(unused_variables)]
+// pretty-expanded FIXME #23616
+
+// Test that `F : Fn(isize) -> isize + Send` is interpreted as two
+// distinct bounds on `F`.
+
+fn foo1<F>(f: F)
+ where F : FnOnce(isize) -> isize + Send
+{
+ bar(f);
+}
+
+fn foo2<F>(f: F)
+ where F : FnOnce(isize) -> isize + Send
+{
+ baz(f);
+}
+
+fn bar<F:Send>(f: F) { }
+
+fn baz<F:FnOnce(isize) -> isize>(f: F) { }
+
+fn main() {}
diff --git a/tests/ui/higher-rank-trait-bounds/hrtb-precedence-of-plus.rs b/tests/ui/higher-rank-trait-bounds/hrtb-precedence-of-plus.rs
new file mode 100644
index 000000000..6834c392d
--- /dev/null
+++ b/tests/ui/higher-rank-trait-bounds/hrtb-precedence-of-plus.rs
@@ -0,0 +1,13 @@
+// run-pass
+#![allow(dead_code)]
+// pretty-expanded FIXME #23616
+
+// Test that `Fn(isize) -> isize + 'static` parses as `(Fn(isize) -> isize) +
+// 'static` and not `Fn(isize) -> (isize + 'static)`. The latter would
+// cause a compilation error. Issue #18772.
+
+fn adder(y: isize) -> Box<dyn Fn(isize) -> isize + 'static> {
+ Box::new(move |x| y + x)
+}
+
+fn main() {}
diff --git a/tests/ui/higher-rank-trait-bounds/hrtb-resolve-lifetime.rs b/tests/ui/higher-rank-trait-bounds/hrtb-resolve-lifetime.rs
new file mode 100644
index 000000000..b97fdf4df
--- /dev/null
+++ b/tests/ui/higher-rank-trait-bounds/hrtb-resolve-lifetime.rs
@@ -0,0 +1,14 @@
+// run-pass
+#![allow(dead_code)]
+// A basic test of using a higher-ranked trait bound.
+
+// pretty-expanded FIXME #23616
+
+trait FnLike<A,R> {
+ fn call(&self, arg: A) -> R;
+}
+
+type FnObject<'b> = dyn for<'a> FnLike<&'a isize, &'a isize> + 'b;
+
+fn main() {
+}
diff --git a/tests/ui/higher-rank-trait-bounds/hrtb-trait-object-paren-notation.rs b/tests/ui/higher-rank-trait-bounds/hrtb-trait-object-paren-notation.rs
new file mode 100644
index 000000000..d8c726cdd
--- /dev/null
+++ b/tests/ui/higher-rank-trait-bounds/hrtb-trait-object-paren-notation.rs
@@ -0,0 +1,26 @@
+// run-pass
+// A basic test of using a higher-ranked trait bound.
+
+trait FnLike<A,R> {
+ fn call(&self, arg: A) -> R;
+}
+
+type FnObject<'b> = dyn for<'a> FnLike<(&'a i32,), &'a i32> + 'b;
+
+struct Identity;
+
+impl<'a, T> FnLike<(&'a T,), &'a T> for Identity {
+ fn call(&self, (arg,): (&'a T,)) -> &'a T {
+ arg
+ }
+}
+
+fn call_repeatedly(f: &FnObject) {
+ let x = 3;
+ let y = f.call((&x,));
+ assert_eq!(3, *y);
+}
+
+fn main() {
+ call_repeatedly(&Identity);
+}
diff --git a/tests/ui/higher-rank-trait-bounds/hrtb-trait-object-passed-to-closure.rs b/tests/ui/higher-rank-trait-bounds/hrtb-trait-object-passed-to-closure.rs
new file mode 100644
index 000000000..41ebb3f5a
--- /dev/null
+++ b/tests/ui/higher-rank-trait-bounds/hrtb-trait-object-passed-to-closure.rs
@@ -0,0 +1,25 @@
+// run-pass
+#![allow(dead_code)]
+// Test that `&PrinterSupport`, which is really short for `&'a
+// PrinterSupport<'b>`, gets properly expanded when it appears in a
+// closure type. This used to result in messed up De Bruijn indices.
+
+// pretty-expanded FIXME #23616
+
+trait PrinterSupport<'ast> {
+ fn ast_map(&self) -> Option<&'ast usize> { None }
+}
+
+struct NoAnn<'ast> {
+ f: Option<&'ast usize>
+}
+
+impl<'ast> PrinterSupport<'ast> for NoAnn<'ast> {
+}
+
+fn foo<'ast, G>(f: Option<&'ast usize>, g: G) where G: FnOnce(&dyn PrinterSupport) {
+ let annotation = NoAnn { f: f };
+ g(&annotation)
+}
+
+fn main() {}
diff --git a/tests/ui/higher-rank-trait-bounds/hrtb-type-outlives.rs b/tests/ui/higher-rank-trait-bounds/hrtb-type-outlives.rs
new file mode 100644
index 000000000..88d396101
--- /dev/null
+++ b/tests/ui/higher-rank-trait-bounds/hrtb-type-outlives.rs
@@ -0,0 +1,46 @@
+// run-pass
+#![allow(dead_code)]
+#![allow(unused_variables)]
+// Test what happens when a HR obligation is applied to an impl with
+// "outlives" bounds. Currently we're pretty conservative here; this
+// will probably improve in time.
+
+trait Foo<X> {
+ fn foo(&self, x: X) { }
+}
+
+fn want_foo<T>()
+ where T : for<'a> Foo<&'a isize>
+{
+}
+
+// Expressed as a where clause
+
+struct SomeStruct<X> {
+ x: X
+}
+
+impl<'a,X> Foo<&'a isize> for SomeStruct<X>
+ where X : 'a
+{
+}
+
+fn one() {
+ want_foo::<SomeStruct<usize>>();
+}
+
+// Expressed as shorthand
+
+struct AnotherStruct<X> {
+ x: X
+}
+
+impl<'a,X:'a> Foo<&'a isize> for AnotherStruct<X>
+{
+}
+
+fn two() {
+ want_foo::<AnotherStruct<usize>>();
+}
+
+fn main() { }
diff --git a/tests/ui/higher-rank-trait-bounds/hrtb-unboxed-closure-trait.rs b/tests/ui/higher-rank-trait-bounds/hrtb-unboxed-closure-trait.rs
new file mode 100644
index 000000000..a4a8a5ac6
--- /dev/null
+++ b/tests/ui/higher-rank-trait-bounds/hrtb-unboxed-closure-trait.rs
@@ -0,0 +1,11 @@
+// run-pass
+// Test HRTB used with the `Fn` trait.
+
+fn foo<F:Fn(&isize)>(f: F) {
+ let x = 22;
+ f(&x);
+}
+
+fn main() {
+ foo(|x: &isize| println!("{}", *x));
+}
diff --git a/tests/ui/higher-rank-trait-bounds/hrtb-wrong-kind.rs b/tests/ui/higher-rank-trait-bounds/hrtb-wrong-kind.rs
new file mode 100644
index 000000000..1a9bb2523
--- /dev/null
+++ b/tests/ui/higher-rank-trait-bounds/hrtb-wrong-kind.rs
@@ -0,0 +1,7 @@
+fn a() where for<T> T: Copy {}
+//~^ ERROR only lifetime parameters can be used in this context
+
+fn b() where for<const C: usize> [(); C]: Copy {}
+//~^ ERROR only lifetime parameters can be used in this context
+
+fn main() {}
diff --git a/tests/ui/higher-rank-trait-bounds/hrtb-wrong-kind.stderr b/tests/ui/higher-rank-trait-bounds/hrtb-wrong-kind.stderr
new file mode 100644
index 000000000..f31aa5546
--- /dev/null
+++ b/tests/ui/higher-rank-trait-bounds/hrtb-wrong-kind.stderr
@@ -0,0 +1,14 @@
+error: only lifetime parameters can be used in this context
+ --> $DIR/hrtb-wrong-kind.rs:1:18
+ |
+LL | fn a() where for<T> T: Copy {}
+ | ^
+
+error: only lifetime parameters can be used in this context
+ --> $DIR/hrtb-wrong-kind.rs:4:24
+ |
+LL | fn b() where for<const C: usize> [(); C]: Copy {}
+ | ^
+
+error: aborting due to 2 previous errors
+
diff --git a/tests/ui/higher-rank-trait-bounds/issue-100689.rs b/tests/ui/higher-rank-trait-bounds/issue-100689.rs
new file mode 100644
index 000000000..2db7f8a35
--- /dev/null
+++ b/tests/ui/higher-rank-trait-bounds/issue-100689.rs
@@ -0,0 +1,29 @@
+// check-pass
+
+struct Foo<'a> {
+ foo: &'a mut usize,
+}
+
+trait Bar<'a> {
+ type FooRef<'b>
+ where
+ 'a: 'b;
+ fn uwu(foo: Foo<'a>, f: impl for<'b> FnMut(Self::FooRef<'b>));
+}
+impl<'a> Bar<'a> for () {
+ type FooRef<'b>
+ =
+ &'b Foo<'a>
+ where
+ 'a : 'b,
+ ;
+
+ fn uwu(
+ foo: Foo<'a>,
+ mut f: impl for<'b> FnMut(&'b Foo<'a>), //relevant part
+ ) {
+ f(&foo);
+ }
+}
+
+fn main() {}
diff --git a/tests/ui/higher-rank-trait-bounds/issue-102899.rs b/tests/ui/higher-rank-trait-bounds/issue-102899.rs
new file mode 100644
index 000000000..952b81584
--- /dev/null
+++ b/tests/ui/higher-rank-trait-bounds/issue-102899.rs
@@ -0,0 +1,32 @@
+// check-pass
+
+pub trait BufferTrait<'buffer> {
+ type Subset<'channel>
+ where
+ 'buffer: 'channel;
+
+ fn for_each_subset<F>(&self, f: F)
+ where
+ F: for<'channel> Fn(Self::Subset<'channel>);
+}
+
+pub struct SomeBuffer<'buffer> {
+ samples: &'buffer [()],
+}
+
+impl<'buffer> BufferTrait<'buffer> for SomeBuffer<'buffer> {
+ type Subset<'subset> = Subset<'subset> where 'buffer: 'subset;
+
+ fn for_each_subset<F>(&self, _f: F)
+ where
+ F: for<'subset> Fn(Subset<'subset>),
+ {
+ todo!()
+ }
+}
+
+pub struct Subset<'subset> {
+ buffer: &'subset [()],
+}
+
+fn main() {}
diff --git a/tests/ui/higher-rank-trait-bounds/issue-30786.rs b/tests/ui/higher-rank-trait-bounds/issue-30786.rs
new file mode 100644
index 000000000..e5f46f711
--- /dev/null
+++ b/tests/ui/higher-rank-trait-bounds/issue-30786.rs
@@ -0,0 +1,134 @@
+// rust-lang/rust#30786: the use of `for<'b> &'b mut A: Stream<Item=T`
+// should act as assertion that item does not borrow from its stream;
+// but an earlier buggy rustc allowed `.map(|x: &_| x)` which does
+// have such an item.
+//
+// This tests double-checks that we do not allow such behavior to leak
+// through again.
+
+pub trait Stream {
+ type Item;
+ fn next(self) -> Option<Self::Item>;
+}
+
+// Example stream
+pub struct Repeat(u64);
+
+impl<'a> Stream for &'a mut Repeat {
+ type Item = &'a u64;
+ fn next(self) -> Option<Self::Item> {
+ Some(&self.0)
+ }
+}
+
+pub struct Map<S, F> {
+ stream: S,
+ func: F,
+}
+
+impl<'a, A, F, T> Stream for &'a mut Map<A, F>
+where
+ &'a mut A: Stream,
+ F: FnMut(<&'a mut A as Stream>::Item) -> T,
+{
+ type Item = T;
+ fn next(self) -> Option<T> {
+ match self.stream.next() {
+ Some(item) => Some((self.func)(item)),
+ None => None,
+ }
+ }
+}
+
+pub struct Filter<S, F> {
+ stream: S,
+ func: F,
+}
+
+impl<'a, A, F, T> Stream for &'a mut Filter<A, F>
+where
+ for<'b> &'b mut A: Stream<Item = T>, // <---- BAD
+ F: FnMut(&T) -> bool,
+{
+ type Item = <&'a mut A as Stream>::Item;
+ fn next(self) -> Option<Self::Item> {
+ while let Some(item) = self.stream.next() {
+ if (self.func)(&item) {
+ return Some(item);
+ }
+ }
+ None
+ }
+}
+
+pub trait StreamExt
+where
+ for<'b> &'b mut Self: Stream,
+{
+ fn mapx<F>(self, func: F) -> Map<Self, F>
+ where
+ Self: Sized,
+ for<'a> &'a mut Map<Self, F>: Stream,
+ {
+ Map { func: func, stream: self }
+ }
+
+ fn filterx<F>(self, func: F) -> Filter<Self, F>
+ where
+ Self: Sized,
+ for<'a> &'a mut Filter<Self, F>: Stream,
+ {
+ Filter { func: func, stream: self }
+ }
+
+ fn countx(mut self) -> usize
+ where
+ Self: Sized,
+ {
+ let mut count = 0;
+ while let Some(_) = self.next() {
+ count += 1;
+ }
+ count
+ }
+}
+
+impl<T> StreamExt for T where for<'a> &'a mut T: Stream {}
+
+fn identity<T>(x: &T) -> &T {
+ x
+}
+
+fn variant1() {
+ let source = Repeat(10);
+
+ // Here, the call to `mapx` returns a type `T` to which `StreamExt`
+ // is not applicable, because `for<'b> &'b mut T: Stream`) doesn't hold.
+ //
+ // More concretely, the type `T` is `Map<Repeat, Closure>`, and
+ // the where clause doesn't hold because the signature of the
+ // closure gets inferred to a signature like `|&'_ Stream| -> &'_`
+ // for some specific `'_`, rather than a more generic
+ // signature.
+ //
+ // Why *exactly* we opt for this signature is a bit unclear to me,
+ // we deduce it somehow from a reuqirement that `Map: Stream` I
+ // guess.
+ let map = source.mapx(|x: &_| x);
+ let filter = map.filterx(|x: &_| true);
+ //~^ ERROR the method
+}
+
+fn variant2() {
+ let source = Repeat(10);
+
+ // Here, we use a function, which is not subject to the vagaries
+ // of closure signature inference. In this case, we get the error
+ // on `countx` as, I think, the test originally expected.
+ let map = source.mapx(identity);
+ let filter = map.filterx(|x: &_| true);
+ let count = filter.countx();
+ //~^ ERROR the method
+}
+
+fn main() {}
diff --git a/tests/ui/higher-rank-trait-bounds/issue-30786.stderr b/tests/ui/higher-rank-trait-bounds/issue-30786.stderr
new file mode 100644
index 000000000..0458d2535
--- /dev/null
+++ b/tests/ui/higher-rank-trait-bounds/issue-30786.stderr
@@ -0,0 +1,45 @@
+error[E0599]: the method `filterx` exists for struct `Map<Repeat, [closure@issue-30786.rs:117:27]>`, but its trait bounds were not satisfied
+ --> $DIR/issue-30786.rs:118:22
+ |
+LL | pub struct Map<S, F> {
+ | --------------------
+ | |
+ | method `filterx` not found for this struct
+ | doesn't satisfy `_: StreamExt`
+...
+LL | let filter = map.filterx(|x: &_| true);
+ | ^^^^^^^ method cannot be called on `Map<Repeat, [closure@issue-30786.rs:117:27]>` due to unsatisfied trait bounds
+ |
+note: the following trait bounds were not satisfied:
+ `&'a mut &Map<Repeat, [closure@$DIR/issue-30786.rs:117:27: 117:34]>: Stream`
+ `&'a mut &mut Map<Repeat, [closure@$DIR/issue-30786.rs:117:27: 117:34]>: Stream`
+ `&'a mut Map<Repeat, [closure@$DIR/issue-30786.rs:117:27: 117:34]>: Stream`
+ --> $DIR/issue-30786.rs:96:50
+ |
+LL | impl<T> StreamExt for T where for<'a> &'a mut T: Stream {}
+ | --------- - ^^^^^^ unsatisfied trait bound introduced here
+
+error[E0599]: the method `countx` exists for struct `Filter<Map<Repeat, for<'a> fn(&'a u64) -> &'a u64 {identity::<u64>}>, [closure@issue-30786.rs:129:30]>`, but its trait bounds were not satisfied
+ --> $DIR/issue-30786.rs:130:24
+ |
+LL | pub struct Filter<S, F> {
+ | -----------------------
+ | |
+ | method `countx` not found for this struct
+ | doesn't satisfy `_: StreamExt`
+...
+LL | let count = filter.countx();
+ | ^^^^^^ method cannot be called due to unsatisfied trait bounds
+ |
+note: the following trait bounds were not satisfied:
+ `&'a mut &Filter<Map<Repeat, for<'a> fn(&'a u64) -> &'a u64 {identity::<u64>}>, [closure@$DIR/issue-30786.rs:129:30: 129:37]>: Stream`
+ `&'a mut &mut Filter<Map<Repeat, for<'a> fn(&'a u64) -> &'a u64 {identity::<u64>}>, [closure@$DIR/issue-30786.rs:129:30: 129:37]>: Stream`
+ `&'a mut Filter<Map<Repeat, for<'a> fn(&'a u64) -> &'a u64 {identity::<u64>}>, [closure@$DIR/issue-30786.rs:129:30: 129:37]>: Stream`
+ --> $DIR/issue-30786.rs:96:50
+ |
+LL | impl<T> StreamExt for T where for<'a> &'a mut T: Stream {}
+ | --------- - ^^^^^^ unsatisfied trait bound introduced here
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0599`.
diff --git a/tests/ui/higher-rank-trait-bounds/issue-36139-normalize-closure-sig.rs b/tests/ui/higher-rank-trait-bounds/issue-36139-normalize-closure-sig.rs
new file mode 100644
index 000000000..2d49151ff
--- /dev/null
+++ b/tests/ui/higher-rank-trait-bounds/issue-36139-normalize-closure-sig.rs
@@ -0,0 +1,19 @@
+// run-pass
+// Previously the closure's argument would be inferred to
+// <S as ITrait<'a>>::Item, causing an error in MIR type
+// checking
+
+trait ITrait<'a> {type Item;}
+
+struct S {}
+
+impl<'a> ITrait<'a> for S { type Item = &'a mut usize; }
+
+fn m<T, I, F>(_: F)
+ where I: for<'a> ITrait<'a>,
+ F: for<'a> FnMut(<I as ITrait<'a>>::Item) { }
+
+
+fn main() {
+ m::<usize,S,_>(|x| { *x += 1; });
+}
diff --git a/tests/ui/higher-rank-trait-bounds/issue-42114.rs b/tests/ui/higher-rank-trait-bounds/issue-42114.rs
new file mode 100644
index 000000000..01515fdc9
--- /dev/null
+++ b/tests/ui/higher-rank-trait-bounds/issue-42114.rs
@@ -0,0 +1,20 @@
+// check-pass
+
+fn lifetime<'a>()
+where
+ &'a (): 'a,
+{
+ /* do nothing */
+}
+
+fn doesnt_work()
+where
+ for<'a> &'a (): 'a,
+{
+ /* do nothing */
+}
+
+fn main() {
+ lifetime();
+ doesnt_work();
+}
diff --git a/tests/ui/higher-rank-trait-bounds/issue-43623.rs b/tests/ui/higher-rank-trait-bounds/issue-43623.rs
new file mode 100644
index 000000000..cedcf7c36
--- /dev/null
+++ b/tests/ui/higher-rank-trait-bounds/issue-43623.rs
@@ -0,0 +1,21 @@
+// check-pass
+
+pub trait Trait<'a> {
+ type Assoc;
+}
+
+pub struct Type;
+
+impl<'a> Trait<'a> for Type {
+ type Assoc = ();
+}
+
+pub fn break_me<T, F>(f: F)
+where
+ T: for<'b> Trait<'b>,
+ F: for<'b> FnMut(<T as Trait<'b>>::Assoc),
+{
+ break_me::<Type, fn(_)>;
+}
+
+fn main() {}
diff --git a/tests/ui/higher-rank-trait-bounds/issue-46989.rs b/tests/ui/higher-rank-trait-bounds/issue-46989.rs
new file mode 100644
index 000000000..4a09f4be1
--- /dev/null
+++ b/tests/ui/higher-rank-trait-bounds/issue-46989.rs
@@ -0,0 +1,40 @@
+// 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 implementation of `Foo` is not general enough
+}
diff --git a/tests/ui/higher-rank-trait-bounds/issue-46989.stderr b/tests/ui/higher-rank-trait-bounds/issue-46989.stderr
new file mode 100644
index 000000000..3f874220a
--- /dev/null
+++ b/tests/ui/higher-rank-trait-bounds/issue-46989.stderr
@@ -0,0 +1,11 @@
+error: implementation of `Foo` is not general enough
+ --> $DIR/issue-46989.rs:38:5
+ |
+LL | assert_foo::<fn(&i32)>();
+ | ^^^^^^^^^^^^^^^^^^^^^^^^ implementation of `Foo` is not general enough
+ |
+ = note: `Foo` would have to be implemented for the type `for<'a> fn(&'a i32)`
+ = note: ...but `Foo` is actually implemented for the type `fn(&'0 i32)`, for some specific lifetime `'0`
+
+error: aborting due to previous error
+
diff --git a/tests/ui/higher-rank-trait-bounds/issue-57639.rs b/tests/ui/higher-rank-trait-bounds/issue-57639.rs
new file mode 100644
index 000000000..392e7233b
--- /dev/null
+++ b/tests/ui/higher-rank-trait-bounds/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.
+//
+// check-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/tests/ui/higher-rank-trait-bounds/issue-58451.rs b/tests/ui/higher-rank-trait-bounds/issue-58451.rs
new file mode 100644
index 000000000..6006a108c
--- /dev/null
+++ b/tests/ui/higher-rank-trait-bounds/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 function takes 1 argument
+}
diff --git a/tests/ui/higher-rank-trait-bounds/issue-58451.stderr b/tests/ui/higher-rank-trait-bounds/issue-58451.stderr
new file mode 100644
index 000000000..0f051be21
--- /dev/null
+++ b/tests/ui/higher-rank-trait-bounds/issue-58451.stderr
@@ -0,0 +1,19 @@
+error[E0061]: this function takes 1 argument but 0 arguments were supplied
+ --> $DIR/issue-58451.rs:12:9
+ |
+LL | f(&[f()]);
+ | ^-- an argument is missing
+ |
+note: function defined here
+ --> $DIR/issue-58451.rs:5:4
+ |
+LL | fn f<I>(i: I)
+ | ^ ----
+help: provide the argument
+ |
+LL | f(&[f(/* i */)]);
+ | ~~~~~~~~~
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0061`.
diff --git a/tests/ui/higher-rank-trait-bounds/issue-59311.rs b/tests/ui/higher-rank-trait-bounds/issue-59311.rs
new file mode 100644
index 000000000..3ad548450
--- /dev/null
+++ b/tests/ui/higher-rank-trait-bounds/issue-59311.rs
@@ -0,0 +1,22 @@
+// Regression test for #59311. The test is taken from
+// rust-lang/rust/issues/71546#issuecomment-620638437
+// as they seem to have the same cause.
+
+// FIXME: It's not clear that this code ought to report
+// an error, but the regression test is here to ensure
+// that it does not ICE. See discussion on #74889 for details.
+
+pub trait T {
+ fn t<F: Fn()>(&self, _: F) {}
+}
+
+pub fn crash<V>(v: &V)
+where
+ for<'a> &'a V: T + 'static,
+{
+ v.t(|| {});
+ //~^ ERROR: higher-ranked lifetime error
+ //~| ERROR: higher-ranked lifetime error
+}
+
+fn main() {}
diff --git a/tests/ui/higher-rank-trait-bounds/issue-59311.stderr b/tests/ui/higher-rank-trait-bounds/issue-59311.stderr
new file mode 100644
index 000000000..c01ab8e34
--- /dev/null
+++ b/tests/ui/higher-rank-trait-bounds/issue-59311.stderr
@@ -0,0 +1,18 @@
+error: higher-ranked lifetime error
+ --> $DIR/issue-59311.rs:17:5
+ |
+LL | v.t(|| {});
+ | ^^^^^^^^^^
+ |
+ = note: could not prove `[closure@$DIR/issue-59311.rs:17:9: 17:11] well-formed`
+
+error: higher-ranked lifetime error
+ --> $DIR/issue-59311.rs:17:9
+ |
+LL | v.t(|| {});
+ | ^^^^^
+ |
+ = note: could not prove `for<'a> &'a V: 'static`
+
+error: aborting due to 2 previous errors
+
diff --git a/tests/ui/higher-rank-trait-bounds/issue-60283.rs b/tests/ui/higher-rank-trait-bounds/issue-60283.rs
new file mode 100644
index 000000000..05315b3f9
--- /dev/null
+++ b/tests/ui/higher-rank-trait-bounds/issue-60283.rs
@@ -0,0 +1,20 @@
+// check-pass
+
+pub trait Trait<'a> {
+ type Item;
+}
+
+impl<'a> Trait<'a> for () {
+ type Item = ();
+}
+
+pub fn foo<T, F>(_: T, _: F)
+where
+ T: for<'a> Trait<'a>,
+ F: for<'a> FnMut(<T as Trait<'a>>::Item),
+{
+}
+
+fn main() {
+ foo((), drop)
+}
diff --git a/tests/ui/higher-rank-trait-bounds/issue-62203-hrtb-ice.rs b/tests/ui/higher-rank-trait-bounds/issue-62203-hrtb-ice.rs
new file mode 100644
index 000000000..e70f6fc34
--- /dev/null
+++ b/tests/ui/higher-rank-trait-bounds/issue-62203-hrtb-ice.rs
@@ -0,0 +1,54 @@
+trait T0<'a, A> {
+ type O;
+}
+
+struct L<T> {
+ f: T,
+}
+
+// explicitly named variants of what one would normally denote by the
+// unit type `()`. Why do this? So that we can differentiate them in
+// the diagnostic output.
+struct Unit1;
+struct Unit2;
+struct Unit3;
+struct Unit4;
+
+impl<'a, A, T> T0<'a, A> for L<T>
+where
+ T: FnMut(A) -> Unit3,
+{
+ type O = T::Output;
+}
+
+trait T1: for<'r> Ty<'r> {
+ fn m<'a, B: Ty<'a>, F>(&self, f: F) -> Unit1
+ where
+ F: for<'r> T0<'r, (<Self as Ty<'r>>::V,), O = <B as Ty<'r>>::V>,
+ {
+ unimplemented!();
+ }
+}
+
+trait Ty<'a> {
+ type V;
+}
+
+fn main() {
+ let v = Unit2.m(
+ L {
+ //~^ ERROR to be a closure that returns `Unit3`, but it returns `Unit4`
+ //~| ERROR type mismatch
+ f: |x| {
+ drop(x);
+ Unit4
+ },
+ },
+ );
+}
+
+impl<'a> Ty<'a> for Unit2 {
+ type V = &'a u8;
+}
+
+impl T1 for Unit2 {}
diff --git a/tests/ui/higher-rank-trait-bounds/issue-62203-hrtb-ice.stderr b/tests/ui/higher-rank-trait-bounds/issue-62203-hrtb-ice.stderr
new file mode 100644
index 000000000..810f7c28c
--- /dev/null
+++ b/tests/ui/higher-rank-trait-bounds/issue-62203-hrtb-ice.stderr
@@ -0,0 +1,66 @@
+error[E0271]: type mismatch resolving `for<'r> <L<[closure@issue-62203-hrtb-ice.rs:42:16]> as T0<'r, (&'r u8,)>>::O == <_ as Ty<'r>>::V`
+ --> $DIR/issue-62203-hrtb-ice.rs:39:9
+ |
+LL | let v = Unit2.m(
+ | - required by a bound introduced by this call
+LL | / L {
+LL | |
+LL | |
+LL | | f: |x| {
+... |
+LL | | },
+LL | | },
+ | |_________^ type mismatch resolving `for<'r> <L<[closure@issue-62203-hrtb-ice.rs:42:16]> as T0<'r, (&'r u8,)>>::O == <_ as Ty<'r>>::V`
+ |
+note: expected this to be `<_ as Ty<'_>>::V`
+ --> $DIR/issue-62203-hrtb-ice.rs:21:14
+ |
+LL | type O = T::Output;
+ | ^^^^^^^^^
+ = note: expected associated type `<_ as Ty<'_>>::V`
+ found struct `Unit4`
+ = help: consider constraining the associated type `<_ as Ty<'_>>::V` to `Unit4` or calling a method that returns `<_ as Ty<'_>>::V`
+ = note: for more information, visit https://doc.rust-lang.org/book/ch19-03-advanced-traits.html
+note: required by a bound in `T1::m`
+ --> $DIR/issue-62203-hrtb-ice.rs:27:51
+ |
+LL | fn m<'a, B: Ty<'a>, F>(&self, f: F) -> Unit1
+ | - required by a bound in this
+LL | where
+LL | F: for<'r> T0<'r, (<Self as Ty<'r>>::V,), O = <B as Ty<'r>>::V>,
+ | ^^^^^^^^^^^^^^^^^^^^ required by this bound in `T1::m`
+
+error[E0271]: expected `[closure@issue-62203-hrtb-ice.rs:42:16]` to be a closure that returns `Unit3`, but it returns `Unit4`
+ --> $DIR/issue-62203-hrtb-ice.rs:39:9
+ |
+LL | let v = Unit2.m(
+ | - required by a bound introduced by this call
+LL | / L {
+LL | |
+LL | |
+LL | | f: |x| {
+... |
+LL | | },
+LL | | },
+ | |_________^ expected struct `Unit3`, found struct `Unit4`
+ |
+note: required for `L<[closure@$DIR/issue-62203-hrtb-ice.rs:42:16: 42:19]>` to implement `for<'r> T0<'r, (&'r u8,)>`
+ --> $DIR/issue-62203-hrtb-ice.rs:17:16
+ |
+LL | impl<'a, A, T> T0<'a, A> for L<T>
+ | ^^^^^^^^^ ^^^^
+LL | where
+LL | T: FnMut(A) -> Unit3,
+ | ----- unsatisfied trait bound introduced here
+note: required by a bound in `T1::m`
+ --> $DIR/issue-62203-hrtb-ice.rs:27:12
+ |
+LL | fn m<'a, B: Ty<'a>, F>(&self, f: F) -> Unit1
+ | - required by a bound in this
+LL | where
+LL | F: for<'r> T0<'r, (<Self as Ty<'r>>::V,), O = <B as Ty<'r>>::V>,
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `T1::m`
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0271`.
diff --git a/tests/ui/higher-rank-trait-bounds/issue-88446.rs b/tests/ui/higher-rank-trait-bounds/issue-88446.rs
new file mode 100644
index 000000000..571b85317
--- /dev/null
+++ b/tests/ui/higher-rank-trait-bounds/issue-88446.rs
@@ -0,0 +1,35 @@
+// check-pass
+
+trait Yokeable<'a> {
+ type Output: 'a;
+}
+impl<'a> Yokeable<'a> for () {
+ type Output = ();
+}
+
+trait DataMarker<'data> {
+ type Yokeable: for<'a> Yokeable<'a>;
+}
+impl<'data> DataMarker<'data> for () {
+ type Yokeable = ();
+}
+
+struct DataPayload<'data, M>(&'data M);
+
+impl DataPayload<'static, ()> {
+ pub fn map_project_with_capture<M2, T>(
+ _: for<'a> fn(
+ capture: T,
+ std::marker::PhantomData<&'a ()>,
+ ) -> <M2::Yokeable as Yokeable<'a>>::Output,
+ ) -> DataPayload<'static, M2>
+ where
+ M2: DataMarker<'static>,
+ {
+ todo!()
+ }
+}
+
+fn main() {
+ let _: DataPayload<()> = DataPayload::<()>::map_project_with_capture::<_, &()>(|_, _| todo!());
+}
diff --git a/tests/ui/higher-rank-trait-bounds/issue-88586-hr-self-outlives-in-trait-def.rs b/tests/ui/higher-rank-trait-bounds/issue-88586-hr-self-outlives-in-trait-def.rs
new file mode 100644
index 000000000..92b7c5deb
--- /dev/null
+++ b/tests/ui/higher-rank-trait-bounds/issue-88586-hr-self-outlives-in-trait-def.rs
@@ -0,0 +1,13 @@
+// Regression test for #88586: a higher-ranked outlives bound on Self in a trait
+// definition caused an ICE when debug_assertions were enabled.
+//
+// Made to pass as part of fixing #98095.
+//
+// check-pass
+
+trait A where
+ for<'a> Self: 'a,
+{
+}
+
+fn main() {}
diff --git a/tests/ui/higher-rank-trait-bounds/issue-90177.rs b/tests/ui/higher-rank-trait-bounds/issue-90177.rs
new file mode 100644
index 000000000..b151a9d3a
--- /dev/null
+++ b/tests/ui/higher-rank-trait-bounds/issue-90177.rs
@@ -0,0 +1,32 @@
+// check-pass
+
+trait Base<'f> {
+ type Assoc;
+
+ fn do_something(&self);
+}
+
+trait ForAnyLifetime: for<'f> Base<'f> {}
+
+impl<T> ForAnyLifetime for T where T: for<'f> Base<'f> {}
+
+trait CanBeDynamic: ForAnyLifetime + for<'f> Base<'f, Assoc = ()> {}
+
+fn foo(a: &dyn CanBeDynamic) {
+ a.do_something();
+}
+
+struct S;
+
+impl<'a> Base<'a> for S {
+ type Assoc = ();
+
+ fn do_something(&self) {}
+}
+
+impl CanBeDynamic for S {}
+
+fn main() {
+ let s = S;
+ foo(&s);
+}
diff --git a/tests/ui/higher-rank-trait-bounds/issue-95034.rs b/tests/ui/higher-rank-trait-bounds/issue-95034.rs
new file mode 100644
index 000000000..af4946a18
--- /dev/null
+++ b/tests/ui/higher-rank-trait-bounds/issue-95034.rs
@@ -0,0 +1,80 @@
+// check-pass
+// compile-flags: --edition=2021 --crate-type=lib
+
+use std::{
+ future::Future,
+ marker::PhantomData,
+ pin::Pin,
+ task::{Context, Poll},
+};
+
+mod object {
+ use super::*;
+
+ pub trait Object<'a> {
+ type Error;
+ type Future: Future<Output = Self>;
+ fn create() -> Self::Future;
+ }
+
+ impl<'a> Object<'a> for u8 {
+ type Error = ();
+ type Future = Pin<Box<dyn Future<Output = Self>>>;
+ fn create() -> Self::Future {
+ unimplemented!()
+ }
+ }
+
+ impl<'a, E, A: Object<'a, Error = E>> Object<'a> for (A,) {
+ type Error = ();
+ type Future = CustomFut<'a, E, A>;
+ fn create() -> Self::Future {
+ unimplemented!()
+ }
+ }
+
+ pub struct CustomFut<'f, E, A: Object<'f, Error = E>> {
+ ph: PhantomData<(A::Future,)>,
+ }
+
+ impl<'f, E, A: Object<'f, Error = E>> Future for CustomFut<'f, E, A> {
+ type Output = (A,);
+ fn poll(self: Pin<&mut Self>, _: &mut Context<'_>) -> Poll<Self::Output> {
+ unimplemented!()
+ }
+ }
+}
+
+mod async_fn {
+ use super::*;
+
+ pub trait AsyncFn {
+ type Future: Future<Output = ()>;
+ fn call(&self) -> Self::Future;
+ }
+
+ impl<F, Fut> AsyncFn for F
+ where
+ F: Fn() -> Fut,
+ Fut: Future<Output = ()>,
+ {
+ type Future = Fut;
+ fn call(&self) -> Self::Future {
+ (self)()
+ }
+ }
+}
+
+pub async fn test() {
+ use self::{async_fn::AsyncFn, object::Object};
+
+ async fn create<T: Object<'static>>() {
+ T::create().await;
+ }
+
+ async fn call_async_fn(inner: impl AsyncFn) {
+ inner.call().await;
+ }
+
+ call_async_fn(create::<(u8,)>).await;
+}
diff --git a/tests/ui/higher-rank-trait-bounds/issue-95230.rs b/tests/ui/higher-rank-trait-bounds/issue-95230.rs
new file mode 100644
index 000000000..92c506eab
--- /dev/null
+++ b/tests/ui/higher-rank-trait-bounds/issue-95230.rs
@@ -0,0 +1,7 @@
+// check-pass
+
+pub struct Bar
+where
+ for<'a> &'a mut Self:;
+
+fn main() {}
diff --git a/tests/ui/higher-rank-trait-bounds/normalize-under-binder/issue-44005.rs b/tests/ui/higher-rank-trait-bounds/normalize-under-binder/issue-44005.rs
new file mode 100644
index 000000000..f255eac0c
--- /dev/null
+++ b/tests/ui/higher-rank-trait-bounds/normalize-under-binder/issue-44005.rs
@@ -0,0 +1,31 @@
+// check-pass
+
+pub trait Foo<'a> {
+ type Bar;
+ fn foo(&'a self) -> Self::Bar;
+}
+
+impl<'a, 'b, T: 'a> Foo<'a> for &'b T {
+ type Bar = &'a T;
+ fn foo(&'a self) -> &'a T {
+ self
+ }
+}
+
+pub fn uncallable<T, F>(x: T, f: F)
+where
+ T: for<'a> Foo<'a>,
+ F: for<'a> Fn(<T as Foo<'a>>::Bar),
+{
+ f(x.foo());
+}
+
+pub fn catalyst(x: &i32) {
+ broken(x, |_| {})
+}
+
+pub fn broken<F: Fn(&i32)>(x: &i32, f: F) {
+ uncallable(x, |y| f(y));
+}
+
+fn main() {}
diff --git a/tests/ui/higher-rank-trait-bounds/normalize-under-binder/issue-56556.rs b/tests/ui/higher-rank-trait-bounds/normalize-under-binder/issue-56556.rs
new file mode 100644
index 000000000..4d38cb19e
--- /dev/null
+++ b/tests/ui/higher-rank-trait-bounds/normalize-under-binder/issue-56556.rs
@@ -0,0 +1,30 @@
+// check-pass
+
+fn foo<T>(t: T) -> usize
+where
+ for<'a> &'a T: IntoIterator,
+ for<'a> <&'a T as IntoIterator>::IntoIter: ExactSizeIterator,
+{
+ t.into_iter().len()
+}
+
+fn main() {
+ foo::<Vec<u32>>(vec![]);
+}
+
+mod another {
+ use std::ops::Deref;
+
+ fn test<T, TDeref>()
+ where
+ T: Deref<Target = TDeref>,
+ TDeref: ?Sized,
+ for<'a> &'a TDeref: IntoIterator,
+ for<'a> <&'a TDeref as IntoIterator>::IntoIter: Clone,
+ {
+ }
+
+ fn main() {
+ test::<Vec<u8>, _>();
+ }
+}
diff --git a/tests/ui/higher-rank-trait-bounds/normalize-under-binder/issue-62529-1.rs b/tests/ui/higher-rank-trait-bounds/normalize-under-binder/issue-62529-1.rs
new file mode 100644
index 000000000..c6f29fa59
--- /dev/null
+++ b/tests/ui/higher-rank-trait-bounds/normalize-under-binder/issue-62529-1.rs
@@ -0,0 +1,88 @@
+// check-pass
+
+// FamilyType (GAT workaround)
+pub trait FamilyLt<'a> {
+ type Out;
+}
+
+struct RefMutFamily<T>(std::marker::PhantomData<T>, ());
+impl<'a, T: 'a> FamilyLt<'a> for RefMutFamily<T> {
+ type Out = &'a mut T;
+}
+
+pub trait Execute {
+ type E: Inject;
+ fn execute(self, value: <<Self::E as Inject>::I as FamilyLt>::Out);
+}
+
+pub trait Inject
+where
+ Self: Sized,
+{
+ type I: for<'a> FamilyLt<'a>;
+ fn inject(_: &()) -> <Self::I as FamilyLt>::Out;
+}
+
+impl<T: 'static> Inject for RefMutFamily<T> {
+ type I = Self;
+ fn inject(_: &()) -> <Self::I as FamilyLt>::Out {
+ unimplemented!()
+ }
+}
+
+// This struct is only used to give a hint to the compiler about the type `Q`
+struct Annotate<Q>(std::marker::PhantomData<Q>);
+impl<Q> Annotate<Q> {
+ fn new() -> Self {
+ Self(std::marker::PhantomData)
+ }
+}
+
+// This function annotate a closure so it can have Higher-Rank Lifetime Bounds
+//
+// See 'annotate' workaround: https://github.com/rust-lang/rust/issues/58052
+fn annotate<F, Q>(_q: Annotate<Q>, func: F) -> impl Execute + 'static
+where
+ F: for<'r> FnOnce(<<Q as Inject>::I as FamilyLt<'r>>::Out) + 'static,
+ Q: Inject + 'static,
+{
+ let wrapper: Wrapper<Q, F> = Wrapper(std::marker::PhantomData, func);
+ wrapper
+}
+
+struct Wrapper<Q, F>(std::marker::PhantomData<Q>, F);
+impl<Q, F> Execute for Wrapper<Q, F>
+ where
+ Q: Inject,
+ F: for<'r> FnOnce(<<Q as Inject>::I as FamilyLt<'r>>::Out),
+{
+ type E = Q;
+
+ fn execute(self, value: <<Self::E as Inject>::I as FamilyLt>::Out) {
+ (self.1)(value)
+ }
+}
+
+struct Task {
+ _processor: Box<dyn FnOnce()>,
+}
+
+// This function consume the closure
+fn task<P>(processor: P) -> Task
+where P: Execute + 'static {
+ Task {
+ _processor: Box::new(move || {
+ let q = P::E::inject(&());
+ processor.execute(q);
+ })
+ }
+}
+
+fn main() {
+ task(annotate(
+ Annotate::<RefMutFamily<usize>>::new(),
+ |value: &mut usize| {
+ *value = 2;
+ }
+ ));
+}
diff --git a/tests/ui/higher-rank-trait-bounds/normalize-under-binder/issue-62529-2.rs b/tests/ui/higher-rank-trait-bounds/normalize-under-binder/issue-62529-2.rs
new file mode 100644
index 000000000..002054732
--- /dev/null
+++ b/tests/ui/higher-rank-trait-bounds/normalize-under-binder/issue-62529-2.rs
@@ -0,0 +1,33 @@
+// check-pass
+
+use std::marker::PhantomData;
+
+trait Lt<'a> {
+ type T;
+}
+struct Id<T>(PhantomData<T>);
+impl<'a,T> Lt<'a> for Id<T> {
+ type T = T;
+}
+
+struct Ref<T>(PhantomData<T>) where T: ?Sized;
+impl<'a,T> Lt<'a> for Ref<T>
+where T: 'a + Lt<'a> + ?Sized
+{
+ type T = &'a T;
+}
+struct Mut<T>(PhantomData<T>) where T: ?Sized;
+impl<'a,T> Lt<'a> for Mut<T>
+where T: 'a + Lt<'a> + ?Sized
+{
+ type T = &'a mut T;
+}
+
+struct C<I,O>(for<'a> fn(<I as Lt<'a>>::T) -> O) where I: for<'a> Lt<'a>;
+
+
+fn main() {
+ let c = C::<Id<_>,_>(|()| 3);
+ c.0(());
+
+}
diff --git a/tests/ui/higher-rank-trait-bounds/normalize-under-binder/issue-62529-3.rs b/tests/ui/higher-rank-trait-bounds/normalize-under-binder/issue-62529-3.rs
new file mode 100644
index 000000000..d84e30f49
--- /dev/null
+++ b/tests/ui/higher-rank-trait-bounds/normalize-under-binder/issue-62529-3.rs
@@ -0,0 +1,32 @@
+trait ATC<'a> {
+ type Type: Sized;
+}
+
+trait WithDefault: for<'a> ATC<'a> {
+ fn with_default<F: for<'a> Fn(<Self as ATC<'a>>::Type)>(f: F);
+}
+
+fn call<'b, T: for<'a> ATC<'a>, F: for<'a> Fn(<T as ATC<'a>>::Type)>(
+ f: F,
+ x: <T as ATC<'b>>::Type,
+) {
+ f(x);
+}
+
+impl<'a> ATC<'a> for () {
+ type Type = Self;
+}
+
+impl WithDefault for () {
+ fn with_default<F: for<'a> Fn(<Self as ATC<'a>>::Type)>(f: F) {
+ // Errors with a bogus type mismatch.
+ //f(());
+ // Going through another generic function works fine.
+ call(f, ());
+ //~^ expected a
+ }
+}
+
+fn main() {
+ // <()>::with_default(|_| {});
+}
diff --git a/tests/ui/higher-rank-trait-bounds/normalize-under-binder/issue-62529-3.stderr b/tests/ui/higher-rank-trait-bounds/normalize-under-binder/issue-62529-3.stderr
new file mode 100644
index 000000000..b30dd36d2
--- /dev/null
+++ b/tests/ui/higher-rank-trait-bounds/normalize-under-binder/issue-62529-3.stderr
@@ -0,0 +1,19 @@
+error[E0277]: expected a `Fn<(<_ as ATC<'a>>::Type,)>` closure, found `F`
+ --> $DIR/issue-62529-3.rs:25:14
+ |
+LL | call(f, ());
+ | ---- ^ expected an `Fn<(<_ as ATC<'a>>::Type,)>` closure, found `F`
+ | |
+ | required by a bound introduced by this call
+ |
+ = note: expected a closure with arguments `((),)`
+ found a closure with arguments `(<_ as ATC<'a>>::Type,)`
+note: required by a bound in `call`
+ --> $DIR/issue-62529-3.rs:9:36
+ |
+LL | fn call<'b, T: for<'a> ATC<'a>, F: for<'a> Fn(<T as ATC<'a>>::Type)>(
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `call`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0277`.
diff --git a/tests/ui/higher-rank-trait-bounds/normalize-under-binder/issue-62529-4.rs b/tests/ui/higher-rank-trait-bounds/normalize-under-binder/issue-62529-4.rs
new file mode 100644
index 000000000..8c2a59868
--- /dev/null
+++ b/tests/ui/higher-rank-trait-bounds/normalize-under-binder/issue-62529-4.rs
@@ -0,0 +1,39 @@
+// check-pass
+
+use std::marker::PhantomData;
+use std::mem;
+
+trait Container<'a> {
+ type Root: 'a;
+}
+
+type RootOf<'a, T> = <T as Container<'a>>::Root;
+
+struct Test<'a, T> where T: Container<'a> {
+ pub root: T::Root,
+ marker: PhantomData<&'a mut &'a mut ()>,
+}
+
+impl<'a, 'b> Container<'b> for &'a str {
+ type Root = &'b str;
+}
+
+impl<'a, T> Test<'a, T> where T: for<'b> Container<'b> {
+ fn new(root: RootOf<'a, T>) -> Test<'a, T> {
+ Test {
+ root: root,
+ marker: PhantomData
+ }
+ }
+
+ fn with_mut<F, R>(&mut self, f: F) -> R where
+ F: for<'b> FnOnce(&'b mut RootOf<'b, T>) -> R {
+ f(unsafe { mem::transmute(&mut self.root) })
+ }
+}
+
+fn main() {
+ let val = "root";
+ let mut test: Test<&str> = Test::new(val);
+ test.with_mut(|_| { });
+}
diff --git a/tests/ui/higher-rank-trait-bounds/normalize-under-binder/issue-62529-5.rs b/tests/ui/higher-rank-trait-bounds/normalize-under-binder/issue-62529-5.rs
new file mode 100644
index 000000000..03f257a02
--- /dev/null
+++ b/tests/ui/higher-rank-trait-bounds/normalize-under-binder/issue-62529-5.rs
@@ -0,0 +1,27 @@
+// check-pass
+
+pub struct Struct {}
+
+pub trait Trait<'a> {
+ type Assoc;
+
+ fn method() -> Self::Assoc;
+}
+
+impl<'a> Trait<'a> for Struct {
+ type Assoc = ();
+
+ fn method() -> Self::Assoc {}
+}
+
+pub fn function<F, T>(f: F)
+where
+ F: for<'a> FnOnce(<T as Trait<'a>>::Assoc),
+ T: for<'b> Trait<'b>,
+{
+ f(T::method());
+}
+
+fn main() {
+ function::<_, Struct>(|_| {});
+}
diff --git a/tests/ui/higher-rank-trait-bounds/normalize-under-binder/issue-62529-6.rs b/tests/ui/higher-rank-trait-bounds/normalize-under-binder/issue-62529-6.rs
new file mode 100644
index 000000000..74a4785e4
--- /dev/null
+++ b/tests/ui/higher-rank-trait-bounds/normalize-under-binder/issue-62529-6.rs
@@ -0,0 +1,77 @@
+// check-pass
+
+use std::cell::RefMut;
+
+fn main() {
+ StateMachine2::Init.resume();
+}
+
+enum StateMachine2<'a> {
+ Init,
+ #[allow(dead_code)] // match required for ICE
+ AfterTwoYields {
+ p: Backed<'a, *mut String>,
+ },
+}
+
+impl<'a> StateMachine2<'a> {
+ fn take(&self) -> Self {
+ StateMachine2::Init
+ }
+}
+
+impl<'a> StateMachine2<'a> {
+ fn resume(&mut self) -> () {
+ use StateMachine2::*;
+ match self.take() {
+ AfterTwoYields { p } => {
+ p.with(|_| {});
+ }
+ _ => panic!("Resume after completed."),
+ }
+ }
+}
+
+unsafe trait Unpack<'a> {
+ type Unpacked: 'a;
+
+ fn unpack(&self) -> Self::Unpacked {
+ unsafe { std::mem::transmute_copy(&self) }
+ }
+}
+
+unsafe trait Pack {
+ type Packed;
+
+ fn pack(&self) -> Self::Packed {
+ unsafe { std::mem::transmute_copy(&self) }
+ }
+}
+
+unsafe impl<'a> Unpack<'a> for String {
+ type Unpacked = String;
+}
+
+unsafe impl Pack for String {
+ type Packed = String;
+}
+
+unsafe impl<'a> Unpack<'a> for *mut String {
+ type Unpacked = &'a mut String;
+}
+
+unsafe impl<'a> Pack for &'a mut String {
+ type Packed = *mut String;
+}
+
+struct Backed<'a, U>(RefMut<'a, Option<String>>, U);
+
+impl<'a, 'b, U: Unpack<'b>> Backed<'a, U> {
+ fn with<F>(self, f: F) -> Backed<'a, ()>
+ where
+ F: for<'f> FnOnce(<U as Unpack<'f>>::Unpacked) -> (),
+ {
+ let result = f(self.1.unpack());
+ Backed(self.0, result)
+ }
+}
diff --git a/tests/ui/higher-rank-trait-bounds/normalize-under-binder/issue-70120.rs b/tests/ui/higher-rank-trait-bounds/normalize-under-binder/issue-70120.rs
new file mode 100644
index 000000000..3ced40230
--- /dev/null
+++ b/tests/ui/higher-rank-trait-bounds/normalize-under-binder/issue-70120.rs
@@ -0,0 +1,31 @@
+// check-pass
+
+pub trait MyTrait<'a> {
+ type Output: 'a;
+ fn gimme_value(&self) -> Self::Output;
+}
+
+pub struct MyStruct;
+
+impl<'a> MyTrait<'a> for MyStruct {
+ type Output = &'a usize;
+ fn gimme_value(&self) -> Self::Output {
+ unimplemented!()
+ }
+}
+
+fn meow<T, F>(t: T, f: F)
+where
+ T: for<'any> MyTrait<'any>,
+ F: for<'any2> Fn(<T as MyTrait<'any2>>::Output),
+{
+ let v = t.gimme_value();
+ f(v);
+}
+
+fn main() {
+ let struc = MyStruct;
+ meow(struc, |foo| {
+ println!("{:?}", foo);
+ })
+}
diff --git a/tests/ui/higher-rank-trait-bounds/normalize-under-binder/issue-71955.migrate.stderr b/tests/ui/higher-rank-trait-bounds/normalize-under-binder/issue-71955.migrate.stderr
new file mode 100644
index 000000000..0f38f8e32
--- /dev/null
+++ b/tests/ui/higher-rank-trait-bounds/normalize-under-binder/issue-71955.migrate.stderr
@@ -0,0 +1,79 @@
+error[E0308]: mismatched types
+ --> $DIR/issue-71955.rs:54:5
+ |
+LL | foo(bar, "string", |s| s.len() == 5);
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ one type is more general than the other
+ |
+ = note: expected type `for<'r, 's> FnOnce<(&'r &'s str,)>`
+ found type `for<'r> FnOnce<(&'r &str,)>`
+note: this closure does not fulfill the lifetime requirements
+ --> $DIR/issue-71955.rs:54:24
+ |
+LL | foo(bar, "string", |s| s.len() == 5);
+ | ^^^^^^^^^^^^^^^^
+note: the lifetime requirement is introduced here
+ --> $DIR/issue-71955.rs:34:9
+ |
+LL | F2: FnOnce(&<F1 as Parser>::Output) -> bool
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error[E0308]: mismatched types
+ --> $DIR/issue-71955.rs:54:5
+ |
+LL | foo(bar, "string", |s| s.len() == 5);
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ one type is more general than the other
+ |
+ = note: expected type `FnOnce<(&&str,)>`
+ found type `for<'r> FnOnce<(&'r &str,)>`
+note: this closure does not fulfill the lifetime requirements
+ --> $DIR/issue-71955.rs:54:24
+ |
+LL | foo(bar, "string", |s| s.len() == 5);
+ | ^^^^^^^^^^^^^^^^
+note: the lifetime requirement is introduced here
+ --> $DIR/issue-71955.rs:34:44
+ |
+LL | F2: FnOnce(&<F1 as Parser>::Output) -> bool
+ | ^^^^
+
+error[E0308]: mismatched types
+ --> $DIR/issue-71955.rs:58:5
+ |
+LL | foo(baz, "string", |s| s.0.len() == 5);
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ one type is more general than the other
+ |
+ = note: expected type `for<'r, 's> FnOnce<(&'r Wrapper<'s>,)>`
+ found type `for<'r> FnOnce<(&'r Wrapper<'_>,)>`
+note: this closure does not fulfill the lifetime requirements
+ --> $DIR/issue-71955.rs:58:24
+ |
+LL | foo(baz, "string", |s| s.0.len() == 5);
+ | ^^^^^^^^^^^^^^^^^^
+note: the lifetime requirement is introduced here
+ --> $DIR/issue-71955.rs:34:9
+ |
+LL | F2: FnOnce(&<F1 as Parser>::Output) -> bool
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error[E0308]: mismatched types
+ --> $DIR/issue-71955.rs:58:5
+ |
+LL | foo(baz, "string", |s| s.0.len() == 5);
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ one type is more general than the other
+ |
+ = note: expected type `FnOnce<(&Wrapper<'_>,)>`
+ found type `for<'r> FnOnce<(&'r Wrapper<'_>,)>`
+note: this closure does not fulfill the lifetime requirements
+ --> $DIR/issue-71955.rs:58:24
+ |
+LL | foo(baz, "string", |s| s.0.len() == 5);
+ | ^^^^^^^^^^^^^^^^^^
+note: the lifetime requirement is introduced here
+ --> $DIR/issue-71955.rs:34:44
+ |
+LL | F2: FnOnce(&<F1 as Parser>::Output) -> bool
+ | ^^^^
+
+error: aborting due to 4 previous errors
+
+For more information about this error, try `rustc --explain E0308`.
diff --git a/tests/ui/higher-rank-trait-bounds/normalize-under-binder/issue-71955.rs b/tests/ui/higher-rank-trait-bounds/normalize-under-binder/issue-71955.rs
new file mode 100644
index 000000000..1d90226a3
--- /dev/null
+++ b/tests/ui/higher-rank-trait-bounds/normalize-under-binder/issue-71955.rs
@@ -0,0 +1,51 @@
+// check-fail
+#![feature(rustc_attrs)]
+
+trait Parser<'s> {
+ type Output;
+
+ fn call(&self, input: &'s str) -> (&'s str, Self::Output);
+}
+
+impl<'s, F, T> Parser<'s> for F
+where F: Fn(&'s str) -> (&'s str, T) {
+ type Output = T;
+ fn call(&self, input: &'s str) -> (&'s str, T) {
+ self(input)
+ }
+}
+
+fn foo<F1, F2>(
+ f1: F1,
+ base: &'static str,
+ f2: F2
+)
+where
+ F1: for<'a> Parser<'a>,
+ F2: FnOnce(&<F1 as Parser>::Output) -> bool
+{
+ let s: String = base.to_owned();
+ let str_ref = s.as_ref();
+ let (remaining, produced) = f1.call(str_ref);
+ assert!(f2(&produced));
+ assert_eq!(remaining.len(), 0);
+}
+
+struct Wrapper<'a>(&'a str);
+
+fn main() {
+ fn bar<'a>(s: &'a str) -> (&'a str, &'a str) {
+ (&s[..1], &s[..])
+ }
+
+ fn baz<'a>(s: &'a str) -> (&'a str, Wrapper<'a>) {
+ (&s[..1], Wrapper(&s[..]))
+ }
+
+ foo(bar, "string", |s| s.len() == 5);
+ //~^ ERROR mismatched types
+ //~| ERROR mismatched types
+ foo(baz, "string", |s| s.0.len() == 5);
+ //~^ ERROR mismatched types
+ //~| ERROR mismatched types
+}
diff --git a/tests/ui/higher-rank-trait-bounds/normalize-under-binder/issue-71955.stderr b/tests/ui/higher-rank-trait-bounds/normalize-under-binder/issue-71955.stderr
new file mode 100644
index 000000000..4ef96cd95
--- /dev/null
+++ b/tests/ui/higher-rank-trait-bounds/normalize-under-binder/issue-71955.stderr
@@ -0,0 +1,79 @@
+error[E0308]: mismatched types
+ --> $DIR/issue-71955.rs:45:5
+ |
+LL | foo(bar, "string", |s| s.len() == 5);
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ one type is more general than the other
+ |
+ = note: expected trait `for<'a, 'b> FnOnce<(&'a &'b str,)>`
+ found trait `for<'a> FnOnce<(&'a &str,)>`
+note: this closure does not fulfill the lifetime requirements
+ --> $DIR/issue-71955.rs:45:24
+ |
+LL | foo(bar, "string", |s| s.len() == 5);
+ | ^^^
+note: the lifetime requirement is introduced here
+ --> $DIR/issue-71955.rs:25:9
+ |
+LL | F2: FnOnce(&<F1 as Parser>::Output) -> bool
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error[E0308]: mismatched types
+ --> $DIR/issue-71955.rs:45:5
+ |
+LL | foo(bar, "string", |s| s.len() == 5);
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ one type is more general than the other
+ |
+ = note: expected trait `for<'a, 'b> FnOnce<(&'a &'b str,)>`
+ found trait `for<'a> FnOnce<(&'a &str,)>`
+note: this closure does not fulfill the lifetime requirements
+ --> $DIR/issue-71955.rs:45:24
+ |
+LL | foo(bar, "string", |s| s.len() == 5);
+ | ^^^
+note: the lifetime requirement is introduced here
+ --> $DIR/issue-71955.rs:25:44
+ |
+LL | F2: FnOnce(&<F1 as Parser>::Output) -> bool
+ | ^^^^
+
+error[E0308]: mismatched types
+ --> $DIR/issue-71955.rs:48:5
+ |
+LL | foo(baz, "string", |s| s.0.len() == 5);
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ one type is more general than the other
+ |
+ = note: expected trait `for<'a, 'b> FnOnce<(&'a Wrapper<'b>,)>`
+ found trait `for<'a> FnOnce<(&'a Wrapper<'_>,)>`
+note: this closure does not fulfill the lifetime requirements
+ --> $DIR/issue-71955.rs:48:24
+ |
+LL | foo(baz, "string", |s| s.0.len() == 5);
+ | ^^^
+note: the lifetime requirement is introduced here
+ --> $DIR/issue-71955.rs:25:9
+ |
+LL | F2: FnOnce(&<F1 as Parser>::Output) -> bool
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error[E0308]: mismatched types
+ --> $DIR/issue-71955.rs:48:5
+ |
+LL | foo(baz, "string", |s| s.0.len() == 5);
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ one type is more general than the other
+ |
+ = note: expected trait `for<'a, 'b> FnOnce<(&'a Wrapper<'b>,)>`
+ found trait `for<'a> FnOnce<(&'a Wrapper<'_>,)>`
+note: this closure does not fulfill the lifetime requirements
+ --> $DIR/issue-71955.rs:48:24
+ |
+LL | foo(baz, "string", |s| s.0.len() == 5);
+ | ^^^
+note: the lifetime requirement is introduced here
+ --> $DIR/issue-71955.rs:25:44
+ |
+LL | F2: FnOnce(&<F1 as Parser>::Output) -> bool
+ | ^^^^
+
+error: aborting due to 4 previous errors
+
+For more information about this error, try `rustc --explain E0308`.
diff --git a/tests/ui/higher-rank-trait-bounds/normalize-under-binder/issue-74261.rs b/tests/ui/higher-rank-trait-bounds/normalize-under-binder/issue-74261.rs
new file mode 100644
index 000000000..93ccb4268
--- /dev/null
+++ b/tests/ui/higher-rank-trait-bounds/normalize-under-binder/issue-74261.rs
@@ -0,0 +1,30 @@
+// check-pass
+
+use std::marker::PhantomData;
+
+trait A<'a> {
+ type B;
+ fn b(self) -> Self::B;
+}
+
+struct T;
+struct S<'a>(PhantomData<&'a ()>);
+
+impl<'a> A<'a> for T {
+ type B = S<'a>;
+ fn b(self) -> Self::B {
+ S(PhantomData)
+ }
+}
+
+fn s<TT, F>(t: TT, f: F)
+where
+ TT: for<'a> A<'a>,
+ F: for<'a> FnOnce(<TT as A<'a>>::B)
+{
+ f(t.b());
+}
+
+fn main() {
+ s(T, |_| {});
+}
diff --git a/tests/ui/higher-rank-trait-bounds/normalize-under-binder/issue-76956.rs b/tests/ui/higher-rank-trait-bounds/normalize-under-binder/issue-76956.rs
new file mode 100644
index 000000000..583470080
--- /dev/null
+++ b/tests/ui/higher-rank-trait-bounds/normalize-under-binder/issue-76956.rs
@@ -0,0 +1,15 @@
+// check-pass
+
+use std::ops::Deref;
+
+struct Data {
+ boxed: Box<&'static i32>
+}
+
+impl Data {
+ fn use_data(&self, user: impl for <'a> FnOnce(<Box<&'a i32> as Deref>::Target)) {
+ user(*self.boxed)
+ }
+}
+
+fn main() {}
diff --git a/tests/ui/higher-rank-trait-bounds/normalize-under-binder/issue-80706.rs b/tests/ui/higher-rank-trait-bounds/normalize-under-binder/issue-80706.rs
new file mode 100644
index 000000000..00a866f22
--- /dev/null
+++ b/tests/ui/higher-rank-trait-bounds/normalize-under-binder/issue-80706.rs
@@ -0,0 +1,71 @@
+// build-pass
+// edition:2018
+
+type BoxFuture<T> = std::pin::Pin<Box<dyn std::future::Future<Output=T>>>;
+
+fn main() {
+ f();
+}
+
+async fn f() {
+ run("dependency").await;
+}
+
+struct InMemoryStorage;
+
+struct User<'dep> {
+ dep: &'dep str,
+}
+
+impl<'a> StorageRequest<InMemoryStorage> for SaveUser<'a> {
+ fn execute(&self) -> BoxFuture<Result<(), String>> {
+ todo!()
+ }
+}
+
+trait Storage {
+ type Error;
+}
+
+impl Storage for InMemoryStorage {
+ type Error = String;
+}
+
+trait StorageRequestReturnType {
+ type Output;
+}
+
+trait StorageRequest<S: Storage>: StorageRequestReturnType {
+ fn execute(
+ &self,
+ ) -> BoxFuture<Result<<Self as StorageRequestReturnType>::Output, <S as Storage>::Error>>;
+}
+
+struct SaveUser<'a> {
+ name: &'a str,
+}
+
+impl<'a> StorageRequestReturnType for SaveUser<'a> {
+ type Output = ();
+}
+
+impl<'dep> User<'dep> {
+ async fn save<S>(self)
+ where
+ S: Storage,
+ for<'a> SaveUser<'a>: StorageRequest<S>,
+ {
+ SaveUser { name: "Joe" }
+ .execute()
+ .await;
+ }
+}
+
+async fn run<S>(dep: &str)
+where
+ S: Storage,
+ for<'a> SaveUser<'a>: StorageRequest<S>,
+ for<'a> SaveUser<'a>: StorageRequestReturnType,
+{
+ User { dep }.save().await;
+}
diff --git a/tests/ui/higher-rank-trait-bounds/normalize-under-binder/issue-80956.rs b/tests/ui/higher-rank-trait-bounds/normalize-under-binder/issue-80956.rs
new file mode 100644
index 000000000..6316ceea1
--- /dev/null
+++ b/tests/ui/higher-rank-trait-bounds/normalize-under-binder/issue-80956.rs
@@ -0,0 +1,21 @@
+// check-pass
+
+trait Bar {
+ type Type;
+}
+struct Foo<'a>(&'a ());
+impl<'a> Bar for Foo<'a> {
+ type Type = ();
+}
+
+fn func<'a>(_: <Foo<'a> as Bar>::Type) {}
+fn assert_is_func<A>(_: fn(A)) {}
+
+fn test()
+where
+ for<'a> <Foo<'a> as Bar>::Type: Sized,
+{
+ assert_is_func(func);
+}
+
+fn main() {}
diff --git a/tests/ui/higher-rank-trait-bounds/normalize-under-binder/issue-81809.rs b/tests/ui/higher-rank-trait-bounds/normalize-under-binder/issue-81809.rs
new file mode 100644
index 000000000..f6ab9c203
--- /dev/null
+++ b/tests/ui/higher-rank-trait-bounds/normalize-under-binder/issue-81809.rs
@@ -0,0 +1,21 @@
+// check-pass
+
+pub trait Indexable {
+ type Idx;
+}
+impl Indexable for u8 {
+ type Idx = u8;
+}
+impl Indexable for u16 {
+ type Idx = u16;
+}
+
+pub trait Indexer<T: Indexable>: std::ops::Index<T::Idx, Output = T> {}
+
+trait StoreIndex: Indexer<u8> + Indexer<u16> {}
+
+fn foo(st: &impl StoreIndex) -> &dyn StoreIndex {
+ st as &dyn StoreIndex
+}
+
+fn main() {}
diff --git a/tests/ui/higher-rank-trait-bounds/normalize-under-binder/issue-85455.rs b/tests/ui/higher-rank-trait-bounds/normalize-under-binder/issue-85455.rs
new file mode 100644
index 000000000..8aa29926d
--- /dev/null
+++ b/tests/ui/higher-rank-trait-bounds/normalize-under-binder/issue-85455.rs
@@ -0,0 +1,19 @@
+#![feature(unboxed_closures)]
+
+trait SomeTrait<'a> {
+ type Associated;
+}
+
+fn give_me_ice<T>() {
+ callee::<fn(&()) -> <T as SomeTrait<'_>>::Associated>();
+ //~^ ERROR the trait bound `for<'a> T: SomeTrait<'a>` is not satisfied [E0277]
+ //~| ERROR the trait bound `for<'a> T: SomeTrait<'a>` is not satisfied [E0277]
+}
+
+fn callee<T: Fn<(&'static (),)>>() {
+ println!("{}", std::any::type_name::<<T as FnOnce<(&'static (),)>>::Output>());
+}
+
+fn main() {
+ give_me_ice::<()>();
+}
diff --git a/tests/ui/higher-rank-trait-bounds/normalize-under-binder/issue-85455.stderr b/tests/ui/higher-rank-trait-bounds/normalize-under-binder/issue-85455.stderr
new file mode 100644
index 000000000..3240518fb
--- /dev/null
+++ b/tests/ui/higher-rank-trait-bounds/normalize-under-binder/issue-85455.stderr
@@ -0,0 +1,25 @@
+error[E0277]: the trait bound `for<'a> T: SomeTrait<'a>` is not satisfied
+ --> $DIR/issue-85455.rs:8:14
+ |
+LL | callee::<fn(&()) -> <T as SomeTrait<'_>>::Associated>();
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `for<'a> SomeTrait<'a>` is not implemented for `T`
+ |
+help: consider restricting type parameter `T`
+ |
+LL | fn give_me_ice<T: for<'a> SomeTrait<'a>>() {
+ | +++++++++++++++++++++++
+
+error[E0277]: the trait bound `for<'a> T: SomeTrait<'a>` is not satisfied
+ --> $DIR/issue-85455.rs:8:5
+ |
+LL | callee::<fn(&()) -> <T as SomeTrait<'_>>::Associated>();
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `for<'a> SomeTrait<'a>` is not implemented for `T`
+ |
+help: consider restricting type parameter `T`
+ |
+LL | fn give_me_ice<T: for<'a> SomeTrait<'a>>() {
+ | +++++++++++++++++++++++
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0277`.
diff --git a/tests/ui/higher-rank-trait-bounds/normalize-under-binder/issue-89118.rs b/tests/ui/higher-rank-trait-bounds/normalize-under-binder/issue-89118.rs
new file mode 100644
index 000000000..fffb54f86
--- /dev/null
+++ b/tests/ui/higher-rank-trait-bounds/normalize-under-binder/issue-89118.rs
@@ -0,0 +1,32 @@
+trait BufferMut {}
+struct Ctx<D>(D);
+
+trait BufferUdpStateContext<B> {}
+impl<B: BufferMut, C> BufferUdpStateContext<B> for C {}
+
+trait StackContext
+where
+ Ctx<()>: for<'a> BufferUdpStateContext<&'a ()>,
+{
+ type Dispatcher;
+}
+
+trait TimerContext {
+ type Handler;
+}
+impl<C> TimerContext for C
+where
+ C: StackContext,
+ //~^ ERROR: is not satisfied [E0277]
+{
+ type Handler = Ctx<C::Dispatcher>;
+ //~^ ERROR: is not satisfied [E0277]
+}
+
+struct EthernetWorker<C>(C)
+where
+ Ctx<()>: for<'a> BufferUdpStateContext<&'a ()>;
+impl<C> EthernetWorker<C> {}
+//~^ ERROR: is not satisfied [E0277]
+
+fn main() {}
diff --git a/tests/ui/higher-rank-trait-bounds/normalize-under-binder/issue-89118.stderr b/tests/ui/higher-rank-trait-bounds/normalize-under-binder/issue-89118.stderr
new file mode 100644
index 000000000..62d0128fd
--- /dev/null
+++ b/tests/ui/higher-rank-trait-bounds/normalize-under-binder/issue-89118.stderr
@@ -0,0 +1,69 @@
+error[E0277]: the trait bound `for<'a> &'a (): BufferMut` is not satisfied
+ --> $DIR/issue-89118.rs:19:8
+ |
+LL | C: StackContext,
+ | ^^^^^^^^^^^^ the trait `for<'a> BufferMut` is not implemented for `&'a ()`
+ |
+note: required for `Ctx<()>` to implement `for<'a> BufferUdpStateContext<&'a ()>`
+ --> $DIR/issue-89118.rs:5:23
+ |
+LL | impl<B: BufferMut, C> BufferUdpStateContext<B> for C {}
+ | --------- ^^^^^^^^^^^^^^^^^^^^^^^^ ^
+ | |
+ | unsatisfied trait bound introduced here
+note: required by a bound in `StackContext`
+ --> $DIR/issue-89118.rs:9:14
+ |
+LL | trait StackContext
+ | ------------ required by a bound in this
+LL | where
+LL | Ctx<()>: for<'a> BufferUdpStateContext<&'a ()>,
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `StackContext`
+
+error[E0277]: the trait bound `for<'a> &'a (): BufferMut` is not satisfied
+ --> $DIR/issue-89118.rs:29:9
+ |
+LL | impl<C> EthernetWorker<C> {}
+ | ^^^^^^^^^^^^^^^^^ the trait `for<'a> BufferMut` is not implemented for `&'a ()`
+ |
+note: required for `Ctx<()>` to implement `for<'a> BufferUdpStateContext<&'a ()>`
+ --> $DIR/issue-89118.rs:5:23
+ |
+LL | impl<B: BufferMut, C> BufferUdpStateContext<B> for C {}
+ | --------- ^^^^^^^^^^^^^^^^^^^^^^^^ ^
+ | |
+ | unsatisfied trait bound introduced here
+note: required by a bound in `EthernetWorker`
+ --> $DIR/issue-89118.rs:28:14
+ |
+LL | struct EthernetWorker<C>(C)
+ | -------------- required by a bound in this
+LL | where
+LL | Ctx<()>: for<'a> BufferUdpStateContext<&'a ()>;
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `EthernetWorker`
+
+error[E0277]: the trait bound `for<'a> &'a (): BufferMut` is not satisfied
+ --> $DIR/issue-89118.rs:22:20
+ |
+LL | type Handler = Ctx<C::Dispatcher>;
+ | ^^^^^^^^^^^^^^^^^^ the trait `for<'a> BufferMut` is not implemented for `&'a ()`
+ |
+note: required for `Ctx<()>` to implement `for<'a> BufferUdpStateContext<&'a ()>`
+ --> $DIR/issue-89118.rs:5:23
+ |
+LL | impl<B: BufferMut, C> BufferUdpStateContext<B> for C {}
+ | --------- ^^^^^^^^^^^^^^^^^^^^^^^^ ^
+ | |
+ | unsatisfied trait bound introduced here
+note: required by a bound in `StackContext`
+ --> $DIR/issue-89118.rs:9:14
+ |
+LL | trait StackContext
+ | ------------ required by a bound in this
+LL | where
+LL | Ctx<()>: for<'a> BufferUdpStateContext<&'a ()>,
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `StackContext`
+
+error: aborting due to 3 previous errors
+
+For more information about this error, try `rustc --explain E0277`.
diff --git a/tests/ui/higher-rank-trait-bounds/normalize-under-binder/issue-89436.rs b/tests/ui/higher-rank-trait-bounds/normalize-under-binder/issue-89436.rs
new file mode 100644
index 000000000..f7e467b37
--- /dev/null
+++ b/tests/ui/higher-rank-trait-bounds/normalize-under-binder/issue-89436.rs
@@ -0,0 +1,44 @@
+// check-pass
+
+#![allow(unused)]
+
+trait MiniYokeable<'a> {
+ type Output;
+}
+
+struct MiniYoke<Y: for<'a> MiniYokeable<'a>> {
+ pub yokeable: Y,
+}
+
+fn map_project_broken<Y, P>(
+ source: MiniYoke<Y>,
+ f: impl for<'a> FnOnce(
+ <Y as MiniYokeable<'a>>::Output,
+ core::marker::PhantomData<&'a ()>,
+ ) -> <P as MiniYokeable<'a>>::Output,
+) -> MiniYoke<P>
+where
+ Y: for<'a> MiniYokeable<'a>,
+ P: for<'a> MiniYokeable<'a>
+{
+ unimplemented!()
+}
+
+struct Bar<'a> {
+ string_1: &'a str,
+ string_2: &'a str,
+}
+
+impl<'a> MiniYokeable<'a> for Bar<'static> {
+ type Output = Bar<'a>;
+}
+
+impl<'a> MiniYokeable<'a> for &'static str {
+ type Output = &'a str;
+}
+
+fn demo_broken(bar: MiniYoke<Bar<'static>>) -> MiniYoke<&'static str> {
+ map_project_broken(bar, |bar, _| bar.string_1)
+}
+
+fn main() {}
diff --git a/tests/ui/higher-rank-trait-bounds/normalize-under-binder/issue-90612.rs b/tests/ui/higher-rank-trait-bounds/normalize-under-binder/issue-90612.rs
new file mode 100644
index 000000000..effc32945
--- /dev/null
+++ b/tests/ui/higher-rank-trait-bounds/normalize-under-binder/issue-90612.rs
@@ -0,0 +1,41 @@
+// check-pass
+
+use std::marker::PhantomData;
+
+trait Family: Sized {
+ type Item<'a>;
+
+ fn apply_all<F>(&self, f: F)
+ where
+ F: FamilyItemFn<Self> { }
+}
+
+struct Array<T>(PhantomData<T>);
+
+impl<T: 'static> Family for Array<T> {
+ type Item<'a> = &'a T;
+}
+
+trait FamilyItemFn<T: Family> {
+ fn apply(&self, item: T::Item<'_>);
+}
+
+impl<T, F> FamilyItemFn<T> for F
+where
+ T: Family,
+ for<'a> F: Fn(T::Item<'a>)
+{
+ fn apply(&self, item: T::Item<'_>) {
+ (*self)(item);
+ }
+}
+
+fn process<T: 'static>(array: Array<T>) {
+ // Works
+ array.apply_all(|x: &T| { });
+
+ // ICE: NoSolution
+ array.apply_all(|x: <Array<T> as Family>::Item<'_>| { });
+}
+
+fn main() {}
diff --git a/tests/ui/higher-rank-trait-bounds/normalize-under-binder/issue-90638.rs b/tests/ui/higher-rank-trait-bounds/normalize-under-binder/issue-90638.rs
new file mode 100644
index 000000000..628b5cba1
--- /dev/null
+++ b/tests/ui/higher-rank-trait-bounds/normalize-under-binder/issue-90638.rs
@@ -0,0 +1,35 @@
+//check-pass
+
+trait Yokeable<'a>: 'static {
+ type Output: 'a;
+}
+
+trait IsCovariant<'a> {}
+
+struct Yoke<Y: for<'a> Yokeable<'a>> {
+ data: Y,
+}
+
+impl<Y: for<'a> Yokeable<'a>> Yoke<Y> {
+ fn project<Y2: for<'a> Yokeable<'a>>(&self, _f: for<'a> fn(<Y as Yokeable<'a>>::Output, &'a ())
+ -> <Y2 as Yokeable<'a>>::Output) -> Yoke<Y2> {
+
+ unimplemented!()
+ }
+}
+
+fn _upcast<Y>(x: Yoke<Y>) -> Yoke<Box<dyn IsCovariant<'static> + 'static>> where
+ Y: for<'a> Yokeable<'a>,
+ for<'a> <Y as Yokeable<'a>>::Output: IsCovariant<'a>
+ {
+ x.project(|data, _| {
+ Box::new(data)
+ })
+}
+
+
+impl<'a> Yokeable<'a> for Box<dyn IsCovariant<'static> + 'static> {
+ type Output = Box<dyn IsCovariant<'a> + 'a>;
+}
+
+fn main() {}
diff --git a/tests/ui/higher-rank-trait-bounds/normalize-under-binder/issue-90875.rs b/tests/ui/higher-rank-trait-bounds/normalize-under-binder/issue-90875.rs
new file mode 100644
index 000000000..ffd6857d8
--- /dev/null
+++ b/tests/ui/higher-rank-trait-bounds/normalize-under-binder/issue-90875.rs
@@ -0,0 +1,31 @@
+// check-pass
+
+trait Variable<'a> {
+ type Type;
+}
+
+impl Variable<'_> for () {
+ type Type = ();
+}
+
+fn check<F, T>(_: F)
+where
+ F: Fn(T), // <- if removed, all fn_* then require type annotations
+ F: for<'a> Fn(<T as Variable<'a>>::Type),
+ T: for<'a> Variable<'a>,
+{
+}
+
+fn test(arg: impl Fn(())) {
+ fn fn_1(_: ()) {}
+ let fn_2 = |_: ()| ();
+ let fn_3 = |a| fn_1(a);
+ let fn_4 = arg;
+
+ check(fn_1); // Error
+ check(fn_2); // Ok
+ check(fn_3); // Ok
+ check(fn_4); // Error
+}
+
+fn main() {}
diff --git a/tests/ui/higher-rank-trait-bounds/normalize-under-binder/issue-90950.rs b/tests/ui/higher-rank-trait-bounds/normalize-under-binder/issue-90950.rs
new file mode 100644
index 000000000..ab9d9a7ce
--- /dev/null
+++ b/tests/ui/higher-rank-trait-bounds/normalize-under-binder/issue-90950.rs
@@ -0,0 +1,53 @@
+// check-fail
+// known-bug: #90950
+
+trait Yokeable<'a>: 'static {
+ type Output: 'a;
+}
+
+
+trait IsCovariant<'a> {}
+
+struct Yoke<Y: for<'a> Yokeable<'a>> {
+ data: Y,
+}
+
+
+// impl<Y: for<'a> Yokeable<'a>> Yoke<Y> {
+// fn project<Y2: for<'a> Yokeable<'a>>(
+// &self,
+// f: for<'a> fn(<Y as Yokeable<'a>>::Output, &'a (),
+// ) -> <Y2 as Yokeable<'a>>::Output) -> Yoke<Y2> {
+// unimplemented!()
+// }
+// }
+
+fn upcast<Y>(x: Yoke<Y>) -> Yoke<Box<dyn IsCovariant<'static> + 'static>> where
+ Y: for<'a> Yokeable<'a>,
+ for<'a> <Y as Yokeable<'a>>::Output: IsCovariant<'a>
+ {
+ // x.project(|data, _| {
+ // Box::new(data)
+ // })
+ unimplemented!()
+}
+
+
+impl<'a> Yokeable<'a> for Box<dyn IsCovariant<'static> + 'static> {
+ type Output = Box<dyn IsCovariant<'a> + 'a>;
+}
+
+// this impl is mostly an example and unnecessary for the pure repro
+use std::borrow::*;
+impl<'a, T: ToOwned + ?Sized> Yokeable<'a> for Cow<'static, T> {
+ type Output = Cow<'a, T>;
+}
+impl<'a, T: ToOwned + ?Sized> IsCovariant<'a> for Cow<'a, T> {}
+
+
+
+fn upcast_yoke(y: Yoke<Cow<'static, str>>) -> Yoke<Box<dyn IsCovariant<'static> + 'static>> {
+ upcast(y)
+}
+
+fn main() {}
diff --git a/tests/ui/higher-rank-trait-bounds/normalize-under-binder/issue-90950.stderr b/tests/ui/higher-rank-trait-bounds/normalize-under-binder/issue-90950.stderr
new file mode 100644
index 000000000..6206b167b
--- /dev/null
+++ b/tests/ui/higher-rank-trait-bounds/normalize-under-binder/issue-90950.stderr
@@ -0,0 +1,21 @@
+error[E0277]: the trait bound `for<'a> <_ as Yokeable<'a>>::Output: IsCovariant<'a>` is not satisfied
+ --> $DIR/issue-90950.rs:50:12
+ |
+LL | upcast(y)
+ | ------ ^ the trait `for<'a> IsCovariant<'a>` is not implemented for `<_ as Yokeable<'a>>::Output`
+ | |
+ | required by a bound introduced by this call
+ |
+ = help: the trait `IsCovariant<'a>` is implemented for `std::borrow::Cow<'a, T>`
+note: required by a bound in `upcast`
+ --> $DIR/issue-90950.rs:27:42
+ |
+LL | fn upcast<Y>(x: Yoke<Y>) -> Yoke<Box<dyn IsCovariant<'static> + 'static>> where
+ | ------ required by a bound in this
+LL | Y: for<'a> Yokeable<'a>,
+LL | for<'a> <Y as Yokeable<'a>>::Output: IsCovariant<'a>
+ | ^^^^^^^^^^^^^^^ required by this bound in `upcast`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0277`.
diff --git a/tests/ui/higher-rank-trait-bounds/normalize-under-binder/norm-before-method-resolution.rs b/tests/ui/higher-rank-trait-bounds/normalize-under-binder/norm-before-method-resolution.rs
new file mode 100644
index 000000000..7693b1182
--- /dev/null
+++ b/tests/ui/higher-rank-trait-bounds/normalize-under-binder/norm-before-method-resolution.rs
@@ -0,0 +1,23 @@
+// check-fail
+// known-bug: #89196
+
+// Should pass, but we normalize and check bounds before we resolve the generics
+// of the function (which we know because of the return type).
+
+trait Trait<'a> {
+ type Out;
+}
+
+impl<'a, T> Trait<'a> for T {
+ type Out = T;
+}
+
+fn weird_bound<X>() -> X
+ where
+ for<'a> X: Trait<'a>,
+ for<'a> <X as Trait<'a>>::Out: Copy
+{ todo!() }
+
+fn main() {
+ let _: () = weird_bound();
+}
diff --git a/tests/ui/higher-rank-trait-bounds/normalize-under-binder/norm-before-method-resolution.stderr b/tests/ui/higher-rank-trait-bounds/normalize-under-binder/norm-before-method-resolution.stderr
new file mode 100644
index 000000000..51c964600
--- /dev/null
+++ b/tests/ui/higher-rank-trait-bounds/normalize-under-binder/norm-before-method-resolution.stderr
@@ -0,0 +1,18 @@
+error[E0277]: the trait bound `for<'a> <_ as Trait<'a>>::Out: Copy` is not satisfied
+ --> $DIR/norm-before-method-resolution.rs:22:17
+ |
+LL | let _: () = weird_bound();
+ | ^^^^^^^^^^^ the trait `for<'a> Copy` is not implemented for `<_ as Trait<'a>>::Out`
+ |
+note: required by a bound in `weird_bound`
+ --> $DIR/norm-before-method-resolution.rs:18:40
+ |
+LL | fn weird_bound<X>() -> X
+ | ----------- required by a bound in this
+...
+LL | for<'a> <X as Trait<'a>>::Out: Copy
+ | ^^^^ required by this bound in `weird_bound`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0277`.