diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-17 12:03:36 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-17 12:03:36 +0000 |
commit | 17d40c6057c88f4c432b0d7bac88e1b84cb7e67f (patch) | |
tree | 3f66c4a5918660bb8a758ab6cda5ff8ee4f6cdcd /src/test/ui/higher-rank-trait-bounds | |
parent | Adding upstream version 1.64.0+dfsg1. (diff) | |
download | rustc-17d40c6057c88f4c432b0d7bac88e1b84cb7e67f.tar.xz rustc-17d40c6057c88f4c432b0d7bac88e1b84cb7e67f.zip |
Adding upstream version 1.65.0+dfsg1.upstream/1.65.0+dfsg1
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'src/test/ui/higher-rank-trait-bounds')
47 files changed, 1392 insertions, 22 deletions
diff --git a/src/test/ui/higher-rank-trait-bounds/complex.rs b/src/test/ui/higher-rank-trait-bounds/complex.rs new file mode 100644 index 000000000..8cdfe247e --- /dev/null +++ b/src/test/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/src/test/ui/higher-rank-trait-bounds/due-to-where-clause.rs b/src/test/ui/higher-rank-trait-bounds/due-to-where-clause.rs new file mode 100644 index 000000000..1afd15613 --- /dev/null +++ b/src/test/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/src/test/ui/higher-rank-trait-bounds/due-to-where-clause.stderr b/src/test/ui/higher-rank-trait-bounds/due-to-where-clause.stderr new file mode 100644 index 000000000..520938a63 --- /dev/null +++ b/src/test/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/src/test/ui/higher-rank-trait-bounds/hrtb-cache-issue-54302.rs b/src/test/ui/higher-rank-trait-bounds/hrtb-cache-issue-54302.rs new file mode 100644 index 000000000..a20d03c77 --- /dev/null +++ b/src/test/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/src/test/ui/higher-rank-trait-bounds/hrtb-cache-issue-54302.stderr b/src/test/ui/higher-rank-trait-bounds/hrtb-cache-issue-54302.stderr new file mode 100644 index 000000000..f014eab86 --- /dev/null +++ b/src/test/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/src/test/ui/higher-rank-trait-bounds/hrtb-conflate-regions.rs b/src/test/ui/higher-rank-trait-bounds/hrtb-conflate-regions.rs new file mode 100644 index 000000000..e83686404 --- /dev/null +++ b/src/test/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/src/test/ui/higher-rank-trait-bounds/hrtb-conflate-regions.stderr b/src/test/ui/higher-rank-trait-bounds/hrtb-conflate-regions.stderr new file mode 100644 index 000000000..46f5308dd --- /dev/null +++ b/src/test/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/src/test/ui/higher-rank-trait-bounds/hrtb-debruijn-in-receiver.rs b/src/test/ui/higher-rank-trait-bounds/hrtb-debruijn-in-receiver.rs new file mode 100644 index 000000000..05d3e1a43 --- /dev/null +++ b/src/test/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/src/test/ui/higher-rank-trait-bounds/hrtb-debruijn-in-receiver.stderr b/src/test/ui/higher-rank-trait-bounds/hrtb-debruijn-in-receiver.stderr new file mode 100644 index 000000000..fa391ecba --- /dev/null +++ b/src/test/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/src/test/ui/higher-rank-trait-bounds/hrtb-exists-forall-fn.rs b/src/test/ui/higher-rank-trait-bounds/hrtb-exists-forall-fn.rs new file mode 100644 index 000000000..567802376 --- /dev/null +++ b/src/test/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/src/test/ui/higher-rank-trait-bounds/hrtb-exists-forall-fn.stderr b/src/test/ui/higher-rank-trait-bounds/hrtb-exists-forall-fn.stderr new file mode 100644 index 000000000..9914783d9 --- /dev/null +++ b/src/test/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/src/test/ui/higher-rank-trait-bounds/hrtb-exists-forall-trait-contravariant.rs b/src/test/ui/higher-rank-trait-bounds/hrtb-exists-forall-trait-contravariant.rs new file mode 100644 index 000000000..921061916 --- /dev/null +++ b/src/test/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/src/test/ui/higher-rank-trait-bounds/hrtb-exists-forall-trait-contravariant.stderr b/src/test/ui/higher-rank-trait-bounds/hrtb-exists-forall-trait-contravariant.stderr new file mode 100644 index 000000000..364b613fc --- /dev/null +++ b/src/test/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/src/test/ui/higher-rank-trait-bounds/hrtb-exists-forall-trait-covariant.rs b/src/test/ui/higher-rank-trait-bounds/hrtb-exists-forall-trait-covariant.rs new file mode 100644 index 000000000..f95496a6c --- /dev/null +++ b/src/test/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/src/test/ui/higher-rank-trait-bounds/hrtb-exists-forall-trait-invariant.rs b/src/test/ui/higher-rank-trait-bounds/hrtb-exists-forall-trait-invariant.rs new file mode 100644 index 000000000..9b9e4496a --- /dev/null +++ b/src/test/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/src/test/ui/higher-rank-trait-bounds/hrtb-exists-forall-trait-invariant.stderr b/src/test/ui/higher-rank-trait-bounds/hrtb-exists-forall-trait-invariant.stderr new file mode 100644 index 000000000..cb2ce8a41 --- /dev/null +++ b/src/test/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/src/test/ui/higher-rank-trait-bounds/hrtb-higher-ranker-supertraits-transitive.rs b/src/test/ui/higher-rank-trait-bounds/hrtb-higher-ranker-supertraits-transitive.rs new file mode 100644 index 000000000..f9ae1429e --- /dev/null +++ b/src/test/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/src/test/ui/higher-rank-trait-bounds/hrtb-higher-ranker-supertraits-transitive.stderr b/src/test/ui/higher-rank-trait-bounds/hrtb-higher-ranker-supertraits-transitive.stderr new file mode 100644 index 000000000..8cda76b94 --- /dev/null +++ b/src/test/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/src/test/ui/higher-rank-trait-bounds/hrtb-higher-ranker-supertraits.rs b/src/test/ui/higher-rank-trait-bounds/hrtb-higher-ranker-supertraits.rs new file mode 100644 index 000000000..48ebe5017 --- /dev/null +++ b/src/test/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/src/test/ui/higher-rank-trait-bounds/hrtb-higher-ranker-supertraits.stderr b/src/test/ui/higher-rank-trait-bounds/hrtb-higher-ranker-supertraits.stderr new file mode 100644 index 000000000..88793a152 --- /dev/null +++ b/src/test/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/src/test/ui/higher-rank-trait-bounds/hrtb-identity-fn-borrows.rs b/src/test/ui/higher-rank-trait-bounds/hrtb-identity-fn-borrows.rs new file mode 100644 index 000000000..89fc4705a --- /dev/null +++ b/src/test/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/src/test/ui/higher-rank-trait-bounds/hrtb-identity-fn-borrows.stderr b/src/test/ui/higher-rank-trait-bounds/hrtb-identity-fn-borrows.stderr new file mode 100644 index 000000000..4886a3c8b --- /dev/null +++ b/src/test/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/src/test/ui/higher-rank-trait-bounds/hrtb-just-for-static.rs b/src/test/ui/higher-rank-trait-bounds/hrtb-just-for-static.rs new file mode 100644 index 000000000..8fb4218f8 --- /dev/null +++ b/src/test/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/src/test/ui/higher-rank-trait-bounds/hrtb-just-for-static.stderr b/src/test/ui/higher-rank-trait-bounds/hrtb-just-for-static.stderr new file mode 100644 index 000000000..31e11e128 --- /dev/null +++ b/src/test/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/src/test/ui/higher-rank-trait-bounds/hrtb-perfect-forwarding.polonius.stderr b/src/test/ui/higher-rank-trait-bounds/hrtb-perfect-forwarding.polonius.stderr new file mode 100644 index 000000000..a94c80eb3 --- /dev/null +++ b/src/test/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/src/test/ui/higher-rank-trait-bounds/hrtb-perfect-forwarding.rs b/src/test/ui/higher-rank-trait-bounds/hrtb-perfect-forwarding.rs new file mode 100644 index 000000000..d45fa183c --- /dev/null +++ b/src/test/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/src/test/ui/higher-rank-trait-bounds/hrtb-perfect-forwarding.stderr b/src/test/ui/higher-rank-trait-bounds/hrtb-perfect-forwarding.stderr new file mode 100644 index 000000000..5e75a4cc8 --- /dev/null +++ b/src/test/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 + | + = 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>, + | |______________________________^ 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/src/test/ui/higher-rank-trait-bounds/issue-30786.rs b/src/test/ui/higher-rank-trait-bounds/issue-30786.rs new file mode 100644 index 000000000..e5f46f711 --- /dev/null +++ b/src/test/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/src/test/ui/higher-rank-trait-bounds/issue-30786.stderr b/src/test/ui/higher-rank-trait-bounds/issue-30786.stderr new file mode 100644 index 000000000..ffe3d7b81 --- /dev/null +++ b/src/test/ui/higher-rank-trait-bounds/issue-30786.stderr @@ -0,0 +1,45 @@ +error[E0599]: the method `filterx` exists for struct `Map<Repeat, [closure@$DIR/issue-30786.rs:117:27: 117:34]>`, 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@$DIR/issue-30786.rs:117:27: 117:34]>` 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<'r> fn(&'r u64) -> &'r u64 {identity::<u64>}>, [closure@$DIR/issue-30786.rs:129:30: 129:37]>`, 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 on `Filter<Map<Repeat, for<'r> fn(&'r u64) -> &'r u64 {identity::<u64>}>, [closure@$DIR/issue-30786.rs:129:30: 129:37]>` due to unsatisfied trait bounds + | +note: the following trait bounds were not satisfied: + `&'a mut &Filter<Map<Repeat, for<'r> fn(&'r u64) -> &'r u64 {identity::<u64>}>, [closure@$DIR/issue-30786.rs:129:30: 129:37]>: Stream` + `&'a mut &mut Filter<Map<Repeat, for<'r> fn(&'r u64) -> &'r u64 {identity::<u64>}>, [closure@$DIR/issue-30786.rs:129:30: 129:37]>: Stream` + `&'a mut Filter<Map<Repeat, for<'r> fn(&'r u64) -> &'r 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/src/test/ui/higher-rank-trait-bounds/issue-46989.rs b/src/test/ui/higher-rank-trait-bounds/issue-46989.rs new file mode 100644 index 000000000..4a09f4be1 --- /dev/null +++ b/src/test/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/src/test/ui/higher-rank-trait-bounds/issue-46989.stderr b/src/test/ui/higher-rank-trait-bounds/issue-46989.stderr new file mode 100644 index 000000000..309e1a676 --- /dev/null +++ b/src/test/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<'r> fn(&'r 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/src/test/ui/higher-rank-trait-bounds/issue-57639.rs b/src/test/ui/higher-rank-trait-bounds/issue-57639.rs new file mode 100644 index 000000000..392e7233b --- /dev/null +++ b/src/test/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/src/test/ui/higher-rank-trait-bounds/issue-58451.rs b/src/test/ui/higher-rank-trait-bounds/issue-58451.rs new file mode 100644 index 000000000..f36d549e4 --- /dev/null +++ b/src/test/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 this function takes 1 argument +} diff --git a/src/test/ui/higher-rank-trait-bounds/issue-58451.stderr b/src/test/ui/higher-rank-trait-bounds/issue-58451.stderr new file mode 100644 index 000000000..09e25f4dc --- /dev/null +++ b/src/test/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(/* value */)]); + | ~~~~~~~~~~~~~ + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0061`. diff --git a/src/test/ui/higher-rank-trait-bounds/issue-62203-hrtb-ice.rs b/src/test/ui/higher-rank-trait-bounds/issue-62203-hrtb-ice.rs new file mode 100644 index 000000000..e70f6fc34 --- /dev/null +++ b/src/test/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/src/test/ui/higher-rank-trait-bounds/issue-62203-hrtb-ice.stderr b/src/test/ui/higher-rank-trait-bounds/issue-62203-hrtb-ice.stderr new file mode 100644 index 000000000..ab5598e36 --- /dev/null +++ b/src/test/ui/higher-rank-trait-bounds/issue-62203-hrtb-ice.stderr @@ -0,0 +1,63 @@ +error[E0271]: type mismatch resolving `for<'r> <L<[closure@$DIR/issue-62203-hrtb-ice.rs:42:16: 42:19]> 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@$DIR/issue-62203-hrtb-ice.rs:42:16: 42:19]> 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@$DIR/issue-62203-hrtb-ice.rs:42:16: 42:19]` 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> + | ^^^^^^^^^ ^^^^ +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/src/test/ui/higher-rank-trait-bounds/issue-88446.rs b/src/test/ui/higher-rank-trait-bounds/issue-88446.rs new file mode 100644 index 000000000..571b85317 --- /dev/null +++ b/src/test/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/src/test/ui/higher-rank-trait-bounds/issue-90177.rs b/src/test/ui/higher-rank-trait-bounds/issue-90177.rs new file mode 100644 index 000000000..b151a9d3a --- /dev/null +++ b/src/test/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/src/test/ui/higher-rank-trait-bounds/issue-95034.rs b/src/test/ui/higher-rank-trait-bounds/issue-95034.rs new file mode 100644 index 000000000..d8edbe7e5 --- /dev/null +++ b/src/test/ui/higher-rank-trait-bounds/issue-95034.rs @@ -0,0 +1,98 @@ +// known-bug: #95034 +// failure-status: 101 +// compile-flags: --edition=2021 --crate-type=lib +// rustc-env:RUST_BACKTRACE=0 + +// normalize-stderr-test "thread 'rustc' panicked.*" -> "thread 'rustc' panicked" +// normalize-stderr-test "note:.*RUST_BACKTRACE=1.*\n" -> "" +// normalize-stderr-test "\nerror: internal compiler error.*\n\n" -> "" +// normalize-stderr-test "note:.*unexpectedly panicked.*\n\n" -> "" +// normalize-stderr-test "note: we would appreciate a bug report.*\n\n" -> "" +// normalize-stderr-test "note: compiler flags.*\n\n" -> "" +// normalize-stderr-test "note: rustc.*running on.*\n\n" -> "" +// normalize-stderr-test "query stack during panic:\n" -> "" +// normalize-stderr-test "we're just showing a limited slice of the query stack\n" -> "" +// normalize-stderr-test "end of query stack\n" -> "" +// normalize-stderr-test "#.*\n" -> "" + +// This should not ICE. + +// Refer to the issue for more minimized versions. + +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/src/test/ui/higher-rank-trait-bounds/issue-95034.stderr b/src/test/ui/higher-rank-trait-bounds/issue-95034.stderr new file mode 100644 index 000000000..1d8329142 --- /dev/null +++ b/src/test/ui/higher-rank-trait-bounds/issue-95034.stderr @@ -0,0 +1 @@ +thread 'rustc' panicked diff --git a/src/test/ui/higher-rank-trait-bounds/issue-95230.rs b/src/test/ui/higher-rank-trait-bounds/issue-95230.rs new file mode 100644 index 000000000..92c506eab --- /dev/null +++ b/src/test/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/src/test/ui/higher-rank-trait-bounds/normalize-under-binder/issue-62529-3.stderr b/src/test/ui/higher-rank-trait-bounds/normalize-under-binder/issue-62529-3.stderr index 066bf431a..b30dd36d2 100644 --- a/src/test/ui/higher-rank-trait-bounds/normalize-under-binder/issue-62529-3.stderr +++ b/src/test/ui/higher-rank-trait-bounds/normalize-under-binder/issue-62529-3.stderr @@ -1,8 +1,10 @@ error[E0277]: expected a `Fn<(<_ as ATC<'a>>::Type,)>` closure, found `F` - --> $DIR/issue-62529-3.rs:25:9 + --> $DIR/issue-62529-3.rs:25:14 | LL | call(f, ()); - | ^^^^ expected an `Fn<(<_ as ATC<'a>>::Type,)>` closure, found `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,)` diff --git a/src/test/ui/higher-rank-trait-bounds/normalize-under-binder/issue-85455.rs b/src/test/ui/higher-rank-trait-bounds/normalize-under-binder/issue-85455.rs index 172bf218c..de9348f53 100644 --- a/src/test/ui/higher-rank-trait-bounds/normalize-under-binder/issue-85455.rs +++ b/src/test/ui/higher-rank-trait-bounds/normalize-under-binder/issue-85455.rs @@ -7,7 +7,6 @@ trait SomeTrait<'a> { fn give_me_ice<T>() { callee::<fn(&()) -> <T as SomeTrait<'_>>::Associated>(); //~^ ERROR the trait bound `for<'r> T: SomeTrait<'r>` is not satisfied [E0277] - //~| ERROR the trait bound `for<'r> T: SomeTrait<'r>` is not satisfied [E0277] } fn callee<T: Fn<(&'static (),)>>() { diff --git a/src/test/ui/higher-rank-trait-bounds/normalize-under-binder/issue-85455.stderr b/src/test/ui/higher-rank-trait-bounds/normalize-under-binder/issue-85455.stderr index ecca4b999..6a948a116 100644 --- a/src/test/ui/higher-rank-trait-bounds/normalize-under-binder/issue-85455.stderr +++ b/src/test/ui/higher-rank-trait-bounds/normalize-under-binder/issue-85455.stderr @@ -9,17 +9,6 @@ help: consider restricting type parameter `T` LL | fn give_me_ice<T: for<'r> SomeTrait<'r>>() { | +++++++++++++++++++++++ -error[E0277]: the trait bound `for<'r> T: SomeTrait<'r>` is not satisfied - --> $DIR/issue-85455.rs:8:14 - | -LL | callee::<fn(&()) -> <T as SomeTrait<'_>>::Associated>(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `for<'r> SomeTrait<'r>` is not implemented for `T` - | -help: consider restricting type parameter `T` - | -LL | fn give_me_ice<T: for<'r> SomeTrait<'r>>() { - | +++++++++++++++++++++++ - -error: aborting due to 2 previous errors +error: aborting due to previous error For more information about this error, try `rustc --explain E0277`. diff --git a/src/test/ui/higher-rank-trait-bounds/normalize-under-binder/issue-89118.stderr b/src/test/ui/higher-rank-trait-bounds/normalize-under-binder/issue-89118.stderr index a6858154d..14fe1803b 100644 --- a/src/test/ui/higher-rank-trait-bounds/normalize-under-binder/issue-89118.stderr +++ b/src/test/ui/higher-rank-trait-bounds/normalize-under-binder/issue-89118.stderr @@ -4,7 +4,7 @@ error[E0277]: the trait bound `for<'a> &'a (): BufferMut` is not satisfied LL | C: StackContext, | ^^^^^^^^^^^^ the trait `for<'a> BufferMut` is not implemented for `&'a ()` | -note: required because of the requirements on the impl of `for<'a> BufferUdpStateContext<&'a ()>` for `Ctx<()>` +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 {} @@ -24,7 +24,7 @@ error[E0277]: the trait bound `for<'a> &'a (): BufferMut` is not satisfied LL | impl<C> EthernetWorker<C> {} | ^^^^^^^^^^^^^^^^^ the trait `for<'a> BufferMut` is not implemented for `&'a ()` | -note: required because of the requirements on the impl of `for<'a> BufferUdpStateContext<&'a ()>` for `Ctx<()>` +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 {} @@ -44,7 +44,7 @@ error[E0277]: the trait bound `for<'a> &'a (): BufferMut` is not satisfied LL | type Handler = Ctx<C::Dispatcher>; | ^^^^^^^^^^^^^^^^^^ the trait `for<'a> BufferMut` is not implemented for `&'a ()` | -note: required because of the requirements on the impl of `for<'a> BufferUdpStateContext<&'a ()>` for `Ctx<()>` +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 {} diff --git a/src/test/ui/higher-rank-trait-bounds/normalize-under-binder/issue-90612.rs b/src/test/ui/higher-rank-trait-bounds/normalize-under-binder/issue-90612.rs index e150ecfe9..effc32945 100644 --- a/src/test/ui/higher-rank-trait-bounds/normalize-under-binder/issue-90612.rs +++ b/src/test/ui/higher-rank-trait-bounds/normalize-under-binder/issue-90612.rs @@ -1,7 +1,5 @@ // check-pass -#![feature(generic_associated_types)] - use std::marker::PhantomData; trait Family: Sized { diff --git a/src/test/ui/higher-rank-trait-bounds/normalize-under-binder/issue-90638.rs b/src/test/ui/higher-rank-trait-bounds/normalize-under-binder/issue-90638.rs index 18b7f3834..628b5cba1 100644 --- a/src/test/ui/higher-rank-trait-bounds/normalize-under-binder/issue-90638.rs +++ b/src/test/ui/higher-rank-trait-bounds/normalize-under-binder/issue-90638.rs @@ -1,7 +1,5 @@ //check-pass -#![feature(generic_associated_types)] - trait Yokeable<'a>: 'static { type Output: 'a; } |