summaryrefslogtreecommitdiffstats
path: root/tests/ui/higher-ranked/trait-bounds/normalize-under-binder
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-05-30 03:57:31 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-05-30 03:57:31 +0000
commitdc0db358abe19481e475e10c32149b53370f1a1c (patch)
treeab8ce99c4b255ce46f99ef402c27916055b899ee /tests/ui/higher-ranked/trait-bounds/normalize-under-binder
parentReleasing progress-linux version 1.71.1+dfsg1-2~progress7.99u1. (diff)
downloadrustc-dc0db358abe19481e475e10c32149b53370f1a1c.tar.xz
rustc-dc0db358abe19481e475e10c32149b53370f1a1c.zip
Merging upstream version 1.72.1+dfsg1.
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'tests/ui/higher-ranked/trait-bounds/normalize-under-binder')
-rw-r--r--tests/ui/higher-ranked/trait-bounds/normalize-under-binder/issue-44005.rs31
-rw-r--r--tests/ui/higher-ranked/trait-bounds/normalize-under-binder/issue-56556.rs30
-rw-r--r--tests/ui/higher-ranked/trait-bounds/normalize-under-binder/issue-62529-1.rs88
-rw-r--r--tests/ui/higher-ranked/trait-bounds/normalize-under-binder/issue-62529-2.rs33
-rw-r--r--tests/ui/higher-ranked/trait-bounds/normalize-under-binder/issue-62529-3.rs32
-rw-r--r--tests/ui/higher-ranked/trait-bounds/normalize-under-binder/issue-62529-3.stderr19
-rw-r--r--tests/ui/higher-ranked/trait-bounds/normalize-under-binder/issue-62529-4.rs39
-rw-r--r--tests/ui/higher-ranked/trait-bounds/normalize-under-binder/issue-62529-5.rs27
-rw-r--r--tests/ui/higher-ranked/trait-bounds/normalize-under-binder/issue-62529-6.rs77
-rw-r--r--tests/ui/higher-ranked/trait-bounds/normalize-under-binder/issue-70120.rs31
-rw-r--r--tests/ui/higher-ranked/trait-bounds/normalize-under-binder/issue-71955.migrate.stderr79
-rw-r--r--tests/ui/higher-ranked/trait-bounds/normalize-under-binder/issue-71955.rs51
-rw-r--r--tests/ui/higher-ranked/trait-bounds/normalize-under-binder/issue-71955.stderr79
-rw-r--r--tests/ui/higher-ranked/trait-bounds/normalize-under-binder/issue-74261.rs30
-rw-r--r--tests/ui/higher-ranked/trait-bounds/normalize-under-binder/issue-76956.rs15
-rw-r--r--tests/ui/higher-ranked/trait-bounds/normalize-under-binder/issue-80706.rs71
-rw-r--r--tests/ui/higher-ranked/trait-bounds/normalize-under-binder/issue-80956.rs21
-rw-r--r--tests/ui/higher-ranked/trait-bounds/normalize-under-binder/issue-81809.rs21
-rw-r--r--tests/ui/higher-ranked/trait-bounds/normalize-under-binder/issue-85455.rs19
-rw-r--r--tests/ui/higher-ranked/trait-bounds/normalize-under-binder/issue-85455.stderr25
-rw-r--r--tests/ui/higher-ranked/trait-bounds/normalize-under-binder/issue-89118.rs32
-rw-r--r--tests/ui/higher-ranked/trait-bounds/normalize-under-binder/issue-89118.stderr69
-rw-r--r--tests/ui/higher-ranked/trait-bounds/normalize-under-binder/issue-89436.rs44
-rw-r--r--tests/ui/higher-ranked/trait-bounds/normalize-under-binder/issue-90612.rs41
-rw-r--r--tests/ui/higher-ranked/trait-bounds/normalize-under-binder/issue-90638.rs35
-rw-r--r--tests/ui/higher-ranked/trait-bounds/normalize-under-binder/issue-90875.rs31
-rw-r--r--tests/ui/higher-ranked/trait-bounds/normalize-under-binder/issue-90950.rs53
-rw-r--r--tests/ui/higher-ranked/trait-bounds/normalize-under-binder/issue-90950.stderr21
-rw-r--r--tests/ui/higher-ranked/trait-bounds/normalize-under-binder/norm-before-method-resolution.rs23
-rw-r--r--tests/ui/higher-ranked/trait-bounds/normalize-under-binder/norm-before-method-resolution.stderr18
30 files changed, 1185 insertions, 0 deletions
diff --git a/tests/ui/higher-ranked/trait-bounds/normalize-under-binder/issue-44005.rs b/tests/ui/higher-ranked/trait-bounds/normalize-under-binder/issue-44005.rs
new file mode 100644
index 000000000..f255eac0c
--- /dev/null
+++ b/tests/ui/higher-ranked/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-ranked/trait-bounds/normalize-under-binder/issue-56556.rs b/tests/ui/higher-ranked/trait-bounds/normalize-under-binder/issue-56556.rs
new file mode 100644
index 000000000..4d38cb19e
--- /dev/null
+++ b/tests/ui/higher-ranked/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-ranked/trait-bounds/normalize-under-binder/issue-62529-1.rs b/tests/ui/higher-ranked/trait-bounds/normalize-under-binder/issue-62529-1.rs
new file mode 100644
index 000000000..c6f29fa59
--- /dev/null
+++ b/tests/ui/higher-ranked/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-ranked/trait-bounds/normalize-under-binder/issue-62529-2.rs b/tests/ui/higher-ranked/trait-bounds/normalize-under-binder/issue-62529-2.rs
new file mode 100644
index 000000000..002054732
--- /dev/null
+++ b/tests/ui/higher-ranked/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-ranked/trait-bounds/normalize-under-binder/issue-62529-3.rs b/tests/ui/higher-ranked/trait-bounds/normalize-under-binder/issue-62529-3.rs
new file mode 100644
index 000000000..d84e30f49
--- /dev/null
+++ b/tests/ui/higher-ranked/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-ranked/trait-bounds/normalize-under-binder/issue-62529-3.stderr b/tests/ui/higher-ranked/trait-bounds/normalize-under-binder/issue-62529-3.stderr
new file mode 100644
index 000000000..b30dd36d2
--- /dev/null
+++ b/tests/ui/higher-ranked/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-ranked/trait-bounds/normalize-under-binder/issue-62529-4.rs b/tests/ui/higher-ranked/trait-bounds/normalize-under-binder/issue-62529-4.rs
new file mode 100644
index 000000000..8c2a59868
--- /dev/null
+++ b/tests/ui/higher-ranked/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-ranked/trait-bounds/normalize-under-binder/issue-62529-5.rs b/tests/ui/higher-ranked/trait-bounds/normalize-under-binder/issue-62529-5.rs
new file mode 100644
index 000000000..03f257a02
--- /dev/null
+++ b/tests/ui/higher-ranked/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-ranked/trait-bounds/normalize-under-binder/issue-62529-6.rs b/tests/ui/higher-ranked/trait-bounds/normalize-under-binder/issue-62529-6.rs
new file mode 100644
index 000000000..0ea736dee
--- /dev/null
+++ b/tests/ui/higher-ranked/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-ranked/trait-bounds/normalize-under-binder/issue-70120.rs b/tests/ui/higher-ranked/trait-bounds/normalize-under-binder/issue-70120.rs
new file mode 100644
index 000000000..3ced40230
--- /dev/null
+++ b/tests/ui/higher-ranked/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-ranked/trait-bounds/normalize-under-binder/issue-71955.migrate.stderr b/tests/ui/higher-ranked/trait-bounds/normalize-under-binder/issue-71955.migrate.stderr
new file mode 100644
index 000000000..0f38f8e32
--- /dev/null
+++ b/tests/ui/higher-ranked/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-ranked/trait-bounds/normalize-under-binder/issue-71955.rs b/tests/ui/higher-ranked/trait-bounds/normalize-under-binder/issue-71955.rs
new file mode 100644
index 000000000..1d90226a3
--- /dev/null
+++ b/tests/ui/higher-ranked/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-ranked/trait-bounds/normalize-under-binder/issue-71955.stderr b/tests/ui/higher-ranked/trait-bounds/normalize-under-binder/issue-71955.stderr
new file mode 100644
index 000000000..4ef96cd95
--- /dev/null
+++ b/tests/ui/higher-ranked/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-ranked/trait-bounds/normalize-under-binder/issue-74261.rs b/tests/ui/higher-ranked/trait-bounds/normalize-under-binder/issue-74261.rs
new file mode 100644
index 000000000..93ccb4268
--- /dev/null
+++ b/tests/ui/higher-ranked/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-ranked/trait-bounds/normalize-under-binder/issue-76956.rs b/tests/ui/higher-ranked/trait-bounds/normalize-under-binder/issue-76956.rs
new file mode 100644
index 000000000..583470080
--- /dev/null
+++ b/tests/ui/higher-ranked/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-ranked/trait-bounds/normalize-under-binder/issue-80706.rs b/tests/ui/higher-ranked/trait-bounds/normalize-under-binder/issue-80706.rs
new file mode 100644
index 000000000..00a866f22
--- /dev/null
+++ b/tests/ui/higher-ranked/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-ranked/trait-bounds/normalize-under-binder/issue-80956.rs b/tests/ui/higher-ranked/trait-bounds/normalize-under-binder/issue-80956.rs
new file mode 100644
index 000000000..6316ceea1
--- /dev/null
+++ b/tests/ui/higher-ranked/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-ranked/trait-bounds/normalize-under-binder/issue-81809.rs b/tests/ui/higher-ranked/trait-bounds/normalize-under-binder/issue-81809.rs
new file mode 100644
index 000000000..f6ab9c203
--- /dev/null
+++ b/tests/ui/higher-ranked/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-ranked/trait-bounds/normalize-under-binder/issue-85455.rs b/tests/ui/higher-ranked/trait-bounds/normalize-under-binder/issue-85455.rs
new file mode 100644
index 000000000..8aa29926d
--- /dev/null
+++ b/tests/ui/higher-ranked/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-ranked/trait-bounds/normalize-under-binder/issue-85455.stderr b/tests/ui/higher-ranked/trait-bounds/normalize-under-binder/issue-85455.stderr
new file mode 100644
index 000000000..3240518fb
--- /dev/null
+++ b/tests/ui/higher-ranked/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-ranked/trait-bounds/normalize-under-binder/issue-89118.rs b/tests/ui/higher-ranked/trait-bounds/normalize-under-binder/issue-89118.rs
new file mode 100644
index 000000000..fffb54f86
--- /dev/null
+++ b/tests/ui/higher-ranked/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-ranked/trait-bounds/normalize-under-binder/issue-89118.stderr b/tests/ui/higher-ranked/trait-bounds/normalize-under-binder/issue-89118.stderr
new file mode 100644
index 000000000..edef6ccd3
--- /dev/null
+++ b/tests/ui/higher-ranked/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 trait
+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 struct
+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 trait
+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-ranked/trait-bounds/normalize-under-binder/issue-89436.rs b/tests/ui/higher-ranked/trait-bounds/normalize-under-binder/issue-89436.rs
new file mode 100644
index 000000000..f7e467b37
--- /dev/null
+++ b/tests/ui/higher-ranked/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-ranked/trait-bounds/normalize-under-binder/issue-90612.rs b/tests/ui/higher-ranked/trait-bounds/normalize-under-binder/issue-90612.rs
new file mode 100644
index 000000000..effc32945
--- /dev/null
+++ b/tests/ui/higher-ranked/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-ranked/trait-bounds/normalize-under-binder/issue-90638.rs b/tests/ui/higher-ranked/trait-bounds/normalize-under-binder/issue-90638.rs
new file mode 100644
index 000000000..628b5cba1
--- /dev/null
+++ b/tests/ui/higher-ranked/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-ranked/trait-bounds/normalize-under-binder/issue-90875.rs b/tests/ui/higher-ranked/trait-bounds/normalize-under-binder/issue-90875.rs
new file mode 100644
index 000000000..ffd6857d8
--- /dev/null
+++ b/tests/ui/higher-ranked/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-ranked/trait-bounds/normalize-under-binder/issue-90950.rs b/tests/ui/higher-ranked/trait-bounds/normalize-under-binder/issue-90950.rs
new file mode 100644
index 000000000..ab9d9a7ce
--- /dev/null
+++ b/tests/ui/higher-ranked/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-ranked/trait-bounds/normalize-under-binder/issue-90950.stderr b/tests/ui/higher-ranked/trait-bounds/normalize-under-binder/issue-90950.stderr
new file mode 100644
index 000000000..5be33bccd
--- /dev/null
+++ b/tests/ui/higher-ranked/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 function
+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-ranked/trait-bounds/normalize-under-binder/norm-before-method-resolution.rs b/tests/ui/higher-ranked/trait-bounds/normalize-under-binder/norm-before-method-resolution.rs
new file mode 100644
index 000000000..7693b1182
--- /dev/null
+++ b/tests/ui/higher-ranked/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-ranked/trait-bounds/normalize-under-binder/norm-before-method-resolution.stderr b/tests/ui/higher-ranked/trait-bounds/normalize-under-binder/norm-before-method-resolution.stderr
new file mode 100644
index 000000000..73388a725
--- /dev/null
+++ b/tests/ui/higher-ranked/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 function
+...
+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`.