diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-06-19 09:26:03 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-06-19 09:26:03 +0000 |
commit | 9918693037dce8aa4bb6f08741b6812923486c18 (patch) | |
tree | 21d2b40bec7e6a7ea664acee056eb3d08e15a1cf /tests/ui/traits/next-solver | |
parent | Releasing progress-linux version 1.75.0+dfsg1-5~progress7.99u1. (diff) | |
download | rustc-9918693037dce8aa4bb6f08741b6812923486c18.tar.xz rustc-9918693037dce8aa4bb6f08741b6812923486c18.zip |
Merging upstream version 1.76.0+dfsg1.
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'tests/ui/traits/next-solver')
165 files changed, 4008 insertions, 0 deletions
diff --git a/tests/ui/traits/next-solver/alias-bound-preference.rs b/tests/ui/traits/next-solver/alias-bound-preference.rs new file mode 100644 index 000000000..1c6e12096 --- /dev/null +++ b/tests/ui/traits/next-solver/alias-bound-preference.rs @@ -0,0 +1,39 @@ +// revisions: old next +//[next] compile-flags: -Znext-solver +// run-pass + +// A test for https://github.com/rust-lang/trait-system-refactor-initiative/issues/45. + +trait Trait { + type Assoc: Into<u32>; +} +impl<T: Into<u32>> Trait for T { + type Assoc = T; +} +fn prefer_alias_bound_projection<T: Trait>(x: T::Assoc) { + // There are two possible types for `x`: + // - `u32` by using the "alias bound" of `<T as Trait>::Assoc` + // - `<T as Trait>::Assoc`, i.e. `u16`, by using `impl<T> From<T> for T` + // + // We infer the type of `x` to be `u32` here as it is highly likely + // that this is expected by the user. + let x = x.into(); + assert_eq!(std::mem::size_of_val(&x), 4); +} + +fn impl_trait() -> impl Into<u32> { + 0u16 +} + +fn main() { + // There are two possible types for `x`: + // - `u32` by using the "alias bound" of `impl Into<u32>` + // - `impl Into<u32>`, i.e. `u16`, by using `impl<T> From<T> for T` + // + // We infer the type of `x` to be `u32` here as it is highly likely + // that this is expected by the user. + let x = impl_trait().into(); + assert_eq!(std::mem::size_of_val(&x), 4); + + prefer_alias_bound_projection::<u16>(1); +} diff --git a/tests/ui/traits/next-solver/alias-bound-unsound.rs b/tests/ui/traits/next-solver/alias-bound-unsound.rs new file mode 100644 index 000000000..4e279a84a --- /dev/null +++ b/tests/ui/traits/next-solver/alias-bound-unsound.rs @@ -0,0 +1,32 @@ +// compile-flags: -Znext-solver + +// Makes sure that alias bounds are not unsound! + +#![feature(trivial_bounds)] + +trait Foo { + type Item: Copy + where + <Self as Foo>::Item: Copy; + + fn copy_me(x: &Self::Item) -> Self::Item { + *x + } +} + +impl Foo for () { + type Item = String where String: Copy; + //~^ ERROR overflow evaluating the requirement `<() as Foo>::Item: Copy` +} + +fn main() { + let x = String::from("hello, world"); + drop(<() as Foo>::copy_me(&x)); + //~^ ERROR overflow evaluating the requirement `<() as Foo>::Item: Sized` + //~| ERROR overflow evaluating the requirement `<() as Foo>::Item == _` + //~| ERROR overflow evaluating the requirement `<() as Foo>::Item well-formed` + //~| ERROR overflow evaluating the requirement `String <: <() as Foo>::Item` + //~| ERROR overflow evaluating the requirement `&<() as Foo>::Item well-formed` + //~| ERROR overflow evaluating the requirement `<() as Foo>::Item normalizes-to _` + println!("{x}"); +} diff --git a/tests/ui/traits/next-solver/alias-bound-unsound.stderr b/tests/ui/traits/next-solver/alias-bound-unsound.stderr new file mode 100644 index 000000000..ac3f19b3f --- /dev/null +++ b/tests/ui/traits/next-solver/alias-bound-unsound.stderr @@ -0,0 +1,65 @@ +error[E0275]: overflow evaluating the requirement `<() as Foo>::Item: Copy` + --> $DIR/alias-bound-unsound.rs:18:17 + | +LL | type Item = String where String: Copy; + | ^^^^^^ + | + = help: consider increasing the recursion limit by adding a `#![recursion_limit = "256"]` attribute to your crate (`alias_bound_unsound`) +note: required by a bound in `Foo::Item` + --> $DIR/alias-bound-unsound.rs:8:16 + | +LL | type Item: Copy + | ^^^^ required by this bound in `Foo::Item` + +error[E0275]: overflow evaluating the requirement `String <: <() as Foo>::Item` + --> $DIR/alias-bound-unsound.rs:24:31 + | +LL | drop(<() as Foo>::copy_me(&x)); + | ^^ + | + = help: consider increasing the recursion limit by adding a `#![recursion_limit = "256"]` attribute to your crate (`alias_bound_unsound`) + +error[E0275]: overflow evaluating the requirement `<() as Foo>::Item == _` + --> $DIR/alias-bound-unsound.rs:24:10 + | +LL | drop(<() as Foo>::copy_me(&x)); + | ^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: consider increasing the recursion limit by adding a `#![recursion_limit = "256"]` attribute to your crate (`alias_bound_unsound`) + +error[E0275]: overflow evaluating the requirement `<() as Foo>::Item: Sized` + --> $DIR/alias-bound-unsound.rs:24:10 + | +LL | drop(<() as Foo>::copy_me(&x)); + | ^^^^^^^^^^^^^^^^^^^^ + | + = help: consider increasing the recursion limit by adding a `#![recursion_limit = "256"]` attribute to your crate (`alias_bound_unsound`) + = note: the return type of a function must have a statically known size + +error[E0275]: overflow evaluating the requirement `&<() as Foo>::Item well-formed` + --> $DIR/alias-bound-unsound.rs:24:31 + | +LL | drop(<() as Foo>::copy_me(&x)); + | ^^ + | + = help: consider increasing the recursion limit by adding a `#![recursion_limit = "256"]` attribute to your crate (`alias_bound_unsound`) + +error[E0275]: overflow evaluating the requirement `<() as Foo>::Item well-formed` + --> $DIR/alias-bound-unsound.rs:24:10 + | +LL | drop(<() as Foo>::copy_me(&x)); + | ^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: consider increasing the recursion limit by adding a `#![recursion_limit = "256"]` attribute to your crate (`alias_bound_unsound`) + +error[E0275]: overflow evaluating the requirement `<() as Foo>::Item normalizes-to _` + --> $DIR/alias-bound-unsound.rs:24:10 + | +LL | drop(<() as Foo>::copy_me(&x)); + | ^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: consider increasing the recursion limit by adding a `#![recursion_limit = "256"]` attribute to your crate (`alias_bound_unsound`) + +error: aborting due to 7 previous errors + +For more information about this error, try `rustc --explain E0275`. diff --git a/tests/ui/traits/next-solver/alias-eq-in-canonical-response.rs b/tests/ui/traits/next-solver/alias-eq-in-canonical-response.rs new file mode 100644 index 000000000..aa7c94791 --- /dev/null +++ b/tests/ui/traits/next-solver/alias-eq-in-canonical-response.rs @@ -0,0 +1,40 @@ +// check-pass +// compile-flags: -Znext-solver + +trait Foo { + type Gat<'a> + where + Self: 'a; + fn bar(&self) -> Self::Gat<'_>; +} + +enum Option<T> { + Some(T), + None, +} + +impl<T> Option<T> { + fn as_ref(&self) -> Option<&T> { + match self { + Option::Some(t) => Option::Some(t), + Option::None => Option::None, + } + } + + fn map<U>(self, f: impl FnOnce(T) -> U) -> Option<U> { + match self { + Option::Some(t) => Option::Some(f(t)), + Option::None => Option::None, + } + } +} + +impl<T: Foo + 'static> Foo for Option<T> { + type Gat<'a> = Option<<T as Foo>::Gat<'a>> where Self: 'a; + + fn bar(&self) -> Self::Gat<'_> { + self.as_ref().map(Foo::bar) + } +} + +fn main() {} diff --git a/tests/ui/traits/next-solver/alias-relate/deeply-nested-no-hang.rs b/tests/ui/traits/next-solver/alias-relate/deeply-nested-no-hang.rs new file mode 100644 index 000000000..91cfda37a --- /dev/null +++ b/tests/ui/traits/next-solver/alias-relate/deeply-nested-no-hang.rs @@ -0,0 +1,22 @@ +// check-pass +// compile-flags: -Znext-solver +// regression test for trait-system-refactor-initiative#68 +trait Identity { + type Assoc: ?Sized; +} + +impl<T: ?Sized> Identity for T { + type Assoc = T; +} + +type Id<T> = <T as Identity>::Assoc; + +type Five<T> = Id<Id<Id<Id<Id<T>>>>>; +type Ty<T> = Five<Five<Five<Five<Five<T>>>>>; + +trait Trait<T> {} + +impl<T> Trait<T> for Ty<T> {} +impl Trait<u32> for Ty<i32> {} + +fn main() {} diff --git a/tests/ui/traits/next-solver/alias-relate/opaque-hidden-ty-is-rigid-alias.rs b/tests/ui/traits/next-solver/alias-relate/opaque-hidden-ty-is-rigid-alias.rs new file mode 100644 index 000000000..88bbd13f9 --- /dev/null +++ b/tests/ui/traits/next-solver/alias-relate/opaque-hidden-ty-is-rigid-alias.rs @@ -0,0 +1,8 @@ +// check-pass +// compile-flags: -Znext-solver + +fn test<T: Iterator>(x: T::Item) -> impl Sized { + x +} + +fn main() {} diff --git a/tests/ui/traits/next-solver/alias-sub.rs b/tests/ui/traits/next-solver/alias-sub.rs new file mode 100644 index 000000000..f7f23a024 --- /dev/null +++ b/tests/ui/traits/next-solver/alias-sub.rs @@ -0,0 +1,34 @@ +// compile-flags: -Znext-solver +// check-pass + +trait Trait { + type Assoc: Sized; +} + +impl Trait for &'static str { + type Assoc = &'static str; +} + +// Wrapper is just here to get around stupid `Sized` obligations in mir typeck +struct Wrapper<T: ?Sized>(std::marker::PhantomData<T>); +fn mk<T: Trait>(x: T) -> Wrapper<<T as Trait>::Assoc> { todo!() } + + +trait IsStaticStr {} +impl IsStaticStr for (&'static str,) {} +fn define<T: IsStaticStr>(_: T) {} + +fn foo<'a, T: Trait>() { + let y = Default::default(); + + // `<?0 as Trait>::Assoc <: &'a str` + // In the old solver, this would *equate* the LHS and RHS. + let _: Wrapper<&'a str> = mk(y); + + // ... then later on, we constrain `?0 = &'static str` + // but that should not mean that `'a = 'static`, because + // we should use *sub* above. + define((y,)); +} + +fn main() {} diff --git a/tests/ui/traits/next-solver/alias_eq_cant_be_furthur_normalized.rs b/tests/ui/traits/next-solver/alias_eq_cant_be_furthur_normalized.rs new file mode 100644 index 000000000..04d1b9496 --- /dev/null +++ b/tests/ui/traits/next-solver/alias_eq_cant_be_furthur_normalized.rs @@ -0,0 +1,29 @@ +// check-pass +// compile-flags: -Znext-solver + +// check that a goal such as `alias-eq(<T as TraitB>::Assoc<bool>, <T as TraitB>::Assoc<?0>)` +// succeeds with a constraint that `?0 = bool` + +// FIXME(deferred_projection_equality): add a test that this is true during coherence + +trait TraitA {} + +trait TraitB { + type Assoc<T: ?Sized>; +} + +impl<T: TraitB> TraitA for (T, T::Assoc<bool>) {} + +impl TraitB for i32 { + type Assoc<T: ?Sized> = u32; +} + +fn needs_a<T: TraitA>() {} + +fn bar<T: TraitB>() { + needs_a::<(T, <T as TraitB>::Assoc<_>)>(); +} + +fn main() { + bar::<i32>(); +} diff --git a/tests/ui/traits/next-solver/alias_eq_dont_use_normalizes_to_if_substs_eq.rs b/tests/ui/traits/next-solver/alias_eq_dont_use_normalizes_to_if_substs_eq.rs new file mode 100644 index 000000000..48157192a --- /dev/null +++ b/tests/ui/traits/next-solver/alias_eq_dont_use_normalizes_to_if_substs_eq.rs @@ -0,0 +1,47 @@ +// compile-flags: -Znext-solver + +// check-pass +// (should not pass, should be turned into a coherence-only test) + +// check that when computing `alias-eq(<() as Foo<u16, T>>::Assoc, <() as Foo<?0, T>>::Assoc)` +// we do not infer `?0 = u8` via the `for<STOP> (): Foo<u8, STOP>` impl or `?0 = u16` by +// relating substs as either could be a valid solution. + +trait Foo<T, STOP> { + type Assoc; +} + +impl<STOP> Foo<u8, STOP> for () +where + (): Foo<u16, STOP>, +{ + type Assoc = <() as Foo<u16, STOP>>::Assoc; +} + +impl Foo<u16, i8> for () { + type Assoc = u8; +} + +impl Foo<u16, i16> for () { + type Assoc = u16; +} + +fn output<T, U>() -> <() as Foo<T, U>>::Assoc +where + (): Foo<T, U>, +{ + todo!() +} + +fn incomplete<T>() +where + (): Foo<u16, T>, +{ + // `<() as Foo<u16, STOP>>::Assoc == <() as Foo<_, STOP>>::Assoc` + let _: <() as Foo<u16, T>>::Assoc = output::<_, T>(); + + // let _: <() as Foo<u16, T>>::Assoc = output::<u8, T>(); // OK + // let _: <() as Foo<u16, T>>::Assoc = output::<u16, T>(); // OK +} + +fn main() {} diff --git a/tests/ui/traits/next-solver/alias_eq_simple.rs b/tests/ui/traits/next-solver/alias_eq_simple.rs new file mode 100644 index 000000000..21ad1a4fa --- /dev/null +++ b/tests/ui/traits/next-solver/alias_eq_simple.rs @@ -0,0 +1,22 @@ +// check-pass +// compile-flags: -Znext-solver + +// test that the new solver can handle `alias-eq(<i32 as TraitB>::Assoc, u32)` + +trait TraitA {} + +trait TraitB { + type Assoc; +} + +impl<T: TraitB> TraitA for (T, T::Assoc) {} + +impl TraitB for i32 { + type Assoc = u32; +} + +fn needs_a<T: TraitA>() {} + +fn main() { + needs_a::<(i32, u32)>(); +} diff --git a/tests/ui/traits/next-solver/alias_eq_substs_eq_not_intercrate.rs b/tests/ui/traits/next-solver/alias_eq_substs_eq_not_intercrate.rs new file mode 100644 index 000000000..4717aa804 --- /dev/null +++ b/tests/ui/traits/next-solver/alias_eq_substs_eq_not_intercrate.rs @@ -0,0 +1,17 @@ +// compile-flags: -Znext-solver + +// check that a `alias-eq(<?a as TraitB>::Assoc, <?b as TraitB>::Assoc)` goal fails +// during coherence. We must not incorrectly constrain `?a` and `?b` to be +// equal. + +trait TraitB { + type Assoc; +} + +trait Overlaps<T> {} + +impl<T: TraitB> Overlaps<Box<T>> for <T as TraitB>::Assoc {} +impl<U: TraitB> Overlaps<U> for <U as TraitB>::Assoc {} +//~^ ERROR conflicting implementations of trait + +fn main() {} diff --git a/tests/ui/traits/next-solver/alias_eq_substs_eq_not_intercrate.stderr b/tests/ui/traits/next-solver/alias_eq_substs_eq_not_intercrate.stderr new file mode 100644 index 000000000..8c6840f72 --- /dev/null +++ b/tests/ui/traits/next-solver/alias_eq_substs_eq_not_intercrate.stderr @@ -0,0 +1,13 @@ +error[E0119]: conflicting implementations of trait `Overlaps<Box<_>>` for type `<_ as TraitB>::Assoc` + --> $DIR/alias_eq_substs_eq_not_intercrate.rs:14:1 + | +LL | impl<T: TraitB> Overlaps<Box<T>> for <T as TraitB>::Assoc {} + | --------------------------------------------------------- first implementation here +LL | impl<U: TraitB> Overlaps<U> for <U as TraitB>::Assoc {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `<_ as TraitB>::Assoc` + | + = note: downstream crates may implement trait `TraitB` for type `std::boxed::Box<_>` + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0119`. diff --git a/tests/ui/traits/next-solver/array-default.rs b/tests/ui/traits/next-solver/array-default.rs new file mode 100644 index 000000000..6bfbce7d4 --- /dev/null +++ b/tests/ui/traits/next-solver/array-default.rs @@ -0,0 +1,8 @@ +// compile-flags: -Znext-solver +// check-pass + +fn has_default<const N: usize>() where [(); N]: Default {} + +fn main() { + has_default::<1>(); +} diff --git a/tests/ui/traits/next-solver/assembly/assemble-normalizing-self-ty-impl-ambiguity.rs b/tests/ui/traits/next-solver/assembly/assemble-normalizing-self-ty-impl-ambiguity.rs new file mode 100644 index 000000000..4401abd07 --- /dev/null +++ b/tests/ui/traits/next-solver/assembly/assemble-normalizing-self-ty-impl-ambiguity.rs @@ -0,0 +1,27 @@ +// compile-flags: -Znext-solver +// check-pass + +// Checks that we do not get ambiguity by considering an impl +// multiple times if we're able to normalize the self type. + +trait Trait<'a> {} + +impl<'a, T: 'a> Trait<'a> for T {} + +fn impls_trait<'a, T: Trait<'a>>() {} + +trait Id { + type Assoc; +} +impl<T> Id for T { + type Assoc = T; +} + +fn call<T>() { + impls_trait::<<T as Id>::Assoc>(); +} + +fn main() { + call::<()>(); + impls_trait::<<<() as Id>::Assoc as Id>::Assoc>(); +} diff --git a/tests/ui/traits/next-solver/assembly/runaway-impl-candidate-selection.rs b/tests/ui/traits/next-solver/assembly/runaway-impl-candidate-selection.rs new file mode 100644 index 000000000..1edc1a8c5 --- /dev/null +++ b/tests/ui/traits/next-solver/assembly/runaway-impl-candidate-selection.rs @@ -0,0 +1,15 @@ +// compile-flags: -Znext-solver + +// In the new solver, we are trying to select `<?0 as Iterator>::Item: Debug`, +// which, naively can be unified with every impl of `Debug` if we're not careful. +// This test makes sure that we treat projections with inference var substs as +// placeholders during fast reject. + +fn iter<T: Iterator>() -> <T as Iterator>::Item { + todo!() +} + +fn main() { + println!("{:?}", iter::<_>()); + //~^ ERROR type annotations needed +} diff --git a/tests/ui/traits/next-solver/assembly/runaway-impl-candidate-selection.stderr b/tests/ui/traits/next-solver/assembly/runaway-impl-candidate-selection.stderr new file mode 100644 index 000000000..4bd55ee80 --- /dev/null +++ b/tests/ui/traits/next-solver/assembly/runaway-impl-candidate-selection.stderr @@ -0,0 +1,16 @@ +error[E0283]: type annotations needed + --> $DIR/runaway-impl-candidate-selection.rs:13:22 + | +LL | println!("{:?}", iter::<_>()); + | ^^^^^^^^^ cannot infer type of the type parameter `T` declared on the function `iter` + | + = note: cannot satisfy `_: Iterator` +note: required by a bound in `iter` + --> $DIR/runaway-impl-candidate-selection.rs:8:12 + | +LL | fn iter<T: Iterator>() -> <T as Iterator>::Item { + | ^^^^^^^^ required by this bound in `iter` + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0283`. diff --git a/tests/ui/traits/next-solver/async.fail.stderr b/tests/ui/traits/next-solver/async.fail.stderr new file mode 100644 index 000000000..ebd0ada26 --- /dev/null +++ b/tests/ui/traits/next-solver/async.fail.stderr @@ -0,0 +1,17 @@ +error[E0271]: type mismatch resolving `<{async block@$DIR/async.rs:12:17: 12:25} as Future>::Output == i32` + --> $DIR/async.rs:12:17 + | +LL | needs_async(async {}); + | ----------- ^^^^^^^^ types differ + | | + | required by a bound introduced by this call + | +note: required by a bound in `needs_async` + --> $DIR/async.rs:8:31 + | +LL | fn needs_async(_: impl Future<Output = i32>) {} + | ^^^^^^^^^^^^ required by this bound in `needs_async` + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0271`. diff --git a/tests/ui/traits/next-solver/async.rs b/tests/ui/traits/next-solver/async.rs new file mode 100644 index 000000000..5833c0522 --- /dev/null +++ b/tests/ui/traits/next-solver/async.rs @@ -0,0 +1,19 @@ +// compile-flags: -Znext-solver +// edition: 2021 +// revisions: pass fail +//[pass] check-pass + +use std::future::Future; + +fn needs_async(_: impl Future<Output = i32>) {} + +#[cfg(fail)] +fn main() { + needs_async(async {}); + //[fail]~^ ERROR type mismatch +} + +#[cfg(pass)] +fn main() { + needs_async(async { 1i32 }); +} diff --git a/tests/ui/traits/next-solver/auto-with-drop_tracking_mir.fail.stderr b/tests/ui/traits/next-solver/auto-with-drop_tracking_mir.fail.stderr new file mode 100644 index 000000000..ac05dfb2d --- /dev/null +++ b/tests/ui/traits/next-solver/auto-with-drop_tracking_mir.fail.stderr @@ -0,0 +1,18 @@ +error[E0277]: `impl Future<Output = ()>` cannot be sent between threads safely + --> $DIR/auto-with-drop_tracking_mir.rs:25:13 + | +LL | is_send(foo()); + | ------- ^^^^^ `impl Future<Output = ()>` cannot be sent between threads safely + | | + | required by a bound introduced by this call + | + = help: the trait `Send` is not implemented for `impl Future<Output = ()>` +note: required by a bound in `is_send` + --> $DIR/auto-with-drop_tracking_mir.rs:24:24 + | +LL | fn is_send(_: impl Send) {} + | ^^^^ required by this bound in `is_send` + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/traits/next-solver/auto-with-drop_tracking_mir.rs b/tests/ui/traits/next-solver/auto-with-drop_tracking_mir.rs new file mode 100644 index 000000000..d4010a552 --- /dev/null +++ b/tests/ui/traits/next-solver/auto-with-drop_tracking_mir.rs @@ -0,0 +1,27 @@ +// compile-flags: -Znext-solver +// edition: 2021 +// revisions: pass fail +//[pass] check-pass + +#![feature(negative_impls)] + +struct NotSync; +impl !Sync for NotSync {} + +async fn foo() { + #[cfg(pass)] + let x = &(); + #[cfg(fail)] + let x = &NotSync; + bar().await; + #[allow(dropping_references)] + drop(x); +} + +async fn bar() {} + +fn main() { + fn is_send(_: impl Send) {} + is_send(foo()); + //[fail]~^ ERROR `impl Future<Output = ()>` cannot be sent between threads safely +} diff --git a/tests/ui/traits/next-solver/borrowck-error.rs b/tests/ui/traits/next-solver/borrowck-error.rs new file mode 100644 index 000000000..25f144594 --- /dev/null +++ b/tests/ui/traits/next-solver/borrowck-error.rs @@ -0,0 +1,11 @@ +// compile-flags: -Znext-solver + +use std::collections::HashMap; + +fn foo() -> &'static HashMap<i32, i32> +{ + &HashMap::new() + //~^ ERROR cannot return reference to temporary value +} + +fn main() {} diff --git a/tests/ui/traits/next-solver/borrowck-error.stderr b/tests/ui/traits/next-solver/borrowck-error.stderr new file mode 100644 index 000000000..4cb41e7d5 --- /dev/null +++ b/tests/ui/traits/next-solver/borrowck-error.stderr @@ -0,0 +1,12 @@ +error[E0515]: cannot return reference to temporary value + --> $DIR/borrowck-error.rs:7:5 + | +LL | &HashMap::new() + | ^-------------- + | || + | |temporary value created here + | returns a reference to data owned by the current function + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0515`. diff --git a/tests/ui/traits/next-solver/builtin-fn-must-return-sized.rs b/tests/ui/traits/next-solver/builtin-fn-must-return-sized.rs new file mode 100644 index 000000000..eab25214d --- /dev/null +++ b/tests/ui/traits/next-solver/builtin-fn-must-return-sized.rs @@ -0,0 +1,17 @@ +// compile-flags: -Znext-solver + +#![feature(fn_traits)] +#![feature(unboxed_closures)] +#![feature(tuple_trait)] + +use std::ops::Fn; +use std::marker::Tuple; + +fn foo<F: Fn<T>, T: Tuple>(f: Option<F>, t: T) { + let y = (f.unwrap()).call(t); +} + +fn main() { + foo::<fn() -> str, _>(None, ()); + //~^ expected a `Fn<_>` closure, found `fn() -> str` +} diff --git a/tests/ui/traits/next-solver/builtin-fn-must-return-sized.stderr b/tests/ui/traits/next-solver/builtin-fn-must-return-sized.stderr new file mode 100644 index 000000000..08047852f --- /dev/null +++ b/tests/ui/traits/next-solver/builtin-fn-must-return-sized.stderr @@ -0,0 +1,16 @@ +error[E0277]: expected a `Fn<_>` closure, found `fn() -> str` + --> $DIR/builtin-fn-must-return-sized.rs:15:11 + | +LL | foo::<fn() -> str, _>(None, ()); + | ^^^^^^^^^^^ expected an `Fn<_>` closure, found `fn() -> str` + | + = help: the trait `Fn<_>` is not implemented for `fn() -> str` +note: required by a bound in `foo` + --> $DIR/builtin-fn-must-return-sized.rs:10:11 + | +LL | fn foo<F: Fn<T>, T: Tuple>(f: Option<F>, t: T) { + | ^^^^^ required by this bound in `foo` + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/traits/next-solver/canonical-int-var-eq-in-response.rs b/tests/ui/traits/next-solver/canonical-int-var-eq-in-response.rs new file mode 100644 index 000000000..ea2740523 --- /dev/null +++ b/tests/ui/traits/next-solver/canonical-int-var-eq-in-response.rs @@ -0,0 +1,22 @@ +// compile-flags: -Znext-solver +// check-pass + +trait Mirror { + type Assoc; +} + +impl<T> Mirror for T { + type Assoc = T; +} + +trait Test {} +impl Test for i64 {} +impl Test for u64 {} + +fn mirror_me<T: Mirror>(t: T, s: <T as Mirror>::Assoc) where <T as Mirror>::Assoc: Test {} + +fn main() { + let mut x = 0; + mirror_me(x, 1); + x = 1i64; +} diff --git a/tests/ui/traits/next-solver/canonical-ty-var-eq-in-response.rs b/tests/ui/traits/next-solver/canonical-ty-var-eq-in-response.rs new file mode 100644 index 000000000..b1e4a9e58 --- /dev/null +++ b/tests/ui/traits/next-solver/canonical-ty-var-eq-in-response.rs @@ -0,0 +1,39 @@ +// check-pass +// compile-flags: -Znext-solver + +trait Mirror { + type Item; +} + +struct Wrapper<T>(T); +impl<T> Mirror for Wrapper<T> { + type Item = T; +} + +fn mirror<T>() +where + Wrapper<T>: Mirror<Item = i32>, +{ +} + +fn main() { + mirror::<_ /* ?0 */>(); + + // Solving `<Wrapper<?0> as Mirror>::Item = i32` + + // First, we replace the term with a fresh infer var: + // `<Wrapper<?0> as Mirror>::Item = ?1` + + // We select the impl candidate on line #6, which leads us to learn that + // `?0 == ?1`. + + // That should be reflected in our canonical response, which should have + // `^0 = ^0, ^1 = ^0` + // !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + // !! We used to return a totally unconstrained response here :< !! + // !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + + // Then, during the "equate term" part of the projection solving, we + // instantiate the response from the unconstrained projection predicate, + // and equate `?0 == i32`. +} diff --git a/tests/ui/traits/next-solver/canonicalize-effect-var.rs b/tests/ui/traits/next-solver/canonicalize-effect-var.rs new file mode 100644 index 000000000..4a13ba373 --- /dev/null +++ b/tests/ui/traits/next-solver/canonicalize-effect-var.rs @@ -0,0 +1,22 @@ +// compile-flags: -Znext-solver +// check-pass + +#![feature(effects)] +#![feature(const_trait_impl)] + +#[const_trait] +trait Foo { + fn foo(); +} + +trait Bar {} + +impl const Foo for i32 { + fn foo() {} +} + +impl<T> const Foo for T where T: Bar { + fn foo() {} +} + +fn main() {} diff --git a/tests/ui/traits/next-solver/cast-checks-handling-projections.rs b/tests/ui/traits/next-solver/cast-checks-handling-projections.rs new file mode 100644 index 000000000..406b4dc12 --- /dev/null +++ b/tests/ui/traits/next-solver/cast-checks-handling-projections.rs @@ -0,0 +1,6 @@ +// compile-flags: -Znext-solver +// check-pass + +fn main() { + (0u8 + 0u8) as char; +} diff --git a/tests/ui/traits/next-solver/closure-inference-guidance.rs b/tests/ui/traits/next-solver/closure-inference-guidance.rs new file mode 100644 index 000000000..8175b92f8 --- /dev/null +++ b/tests/ui/traits/next-solver/closure-inference-guidance.rs @@ -0,0 +1,11 @@ +// compile-flags: -Znext-solver +// check-pass + +fn foo(i: isize) -> isize { i + 1 } + +fn apply<A, F>(f: F, v: A) -> A where F: FnOnce(A) -> A { f(v) } + +pub fn main() { + let f = |i| foo(i); + assert_eq!(apply(f, 2), 3); +} diff --git a/tests/ui/traits/next-solver/closure-signature-inference-2.rs b/tests/ui/traits/next-solver/closure-signature-inference-2.rs new file mode 100644 index 000000000..8fece7ba9 --- /dev/null +++ b/tests/ui/traits/next-solver/closure-signature-inference-2.rs @@ -0,0 +1,21 @@ +// compile-flags: -Znext-solver +// check-pass + +fn map<T: Default, U, F: FnOnce(T) -> U>(f: F) { + f(T::default()); +} + +fn main() { + map::<i32, _ /* ?U */, _ /* ?F */>(|x| x.to_string()); + // PREVIOUSLY when confirming the `map` call, we register: + // + // (1.) ?F: FnOnce<(i32,)> + // (2.) <?F as FnOnce<(i32,)>>::Output projects-to ?U + // + // While (1.) is ambiguous, (2.) immediately gets processed + // and we infer `?U := <?F as FnOnce<(i32,)>>::Output`. + // + // Thus, the only pending obligation that remains is (1.). + // Since it is a trait obligation, we don't use it to deduce + // the closure signature, and we fail! +} diff --git a/tests/ui/traits/next-solver/closure-signature-inference.rs b/tests/ui/traits/next-solver/closure-signature-inference.rs new file mode 100644 index 000000000..355fc7902 --- /dev/null +++ b/tests/ui/traits/next-solver/closure-signature-inference.rs @@ -0,0 +1,15 @@ +// compile-flags: -Znext-solver +// check-pass + +struct A; +impl A { + fn hi(self) {} +} + +fn hello() -> Result<(A,), ()> { + Err(()) +} + +fn main() { + let x = hello().map(|(x,)| x.hi()); +} diff --git a/tests/ui/traits/next-solver/closure-substs-ambiguity.rs b/tests/ui/traits/next-solver/closure-substs-ambiguity.rs new file mode 100644 index 000000000..cc9ee58f2 --- /dev/null +++ b/tests/ui/traits/next-solver/closure-substs-ambiguity.rs @@ -0,0 +1,7 @@ +// compile-flags: -Znext-solver +// check-pass + +fn main() { + let mut x: Vec<_> = vec![]; + x.extend(Some(1i32).into_iter().map(|x| x)); +} diff --git a/tests/ui/traits/next-solver/coerce-ambig-alias-to-rigid-alias.rs b/tests/ui/traits/next-solver/coerce-ambig-alias-to-rigid-alias.rs new file mode 100644 index 000000000..bcb48b5ac --- /dev/null +++ b/tests/ui/traits/next-solver/coerce-ambig-alias-to-rigid-alias.rs @@ -0,0 +1,15 @@ +// compile-flags: -Znext-solver +// check-pass + +trait Trait { + type Assoc; +} + +fn call<T: Trait>(_: <T as Trait>::Assoc, _: T) {} + +fn foo<T: Trait>(rigid: <T as Trait>::Assoc, t: T) { + // Check that we can coerce `<?0 as Trait>::Assoc` to `<T as Trait>::Assoc`. + call::<_ /* ?0 */>(rigid, t); +} + +fn main() {} diff --git a/tests/ui/traits/next-solver/coherence/issue-102048.rs b/tests/ui/traits/next-solver/coherence/issue-102048.rs new file mode 100644 index 000000000..600e63d4d --- /dev/null +++ b/tests/ui/traits/next-solver/coherence/issue-102048.rs @@ -0,0 +1,44 @@ +// This must fail coherence. +// +// Getting this to pass was fairly difficult, so here's an explanation +// of what's happening: +// +// Normalizing projections currently tries to replace them with inference variables +// while emitting a nested `Projection` obligation. This cannot be done if the projection +// has bound variables which is the case here. +// +// So the projections stay until after normalization. When unifying two projections we +// currently treat them as if they are injective, so we **incorrectly** unify their +// substs. This means that coherence for the two impls ends up unifying `?T` and `?U` +// as it tries to unify `<?T as WithAssoc1<'a>>::Assoc` with `<?U as WithAssoc1<'a>>::Assoc`. +// +// `impl1` therefore has the projection `<?T as WithAssoc2<'a>>::Assoc` and we have the +// assumption `?T: for<'a> WithAssoc2<'a, Assoc = i32>` in the `param_env`, so we normalize +// that to `i32`. We then try to unify `i32` from `impl1` with `u32` from `impl2` which fails, +// causing coherence to consider these two impls distinct. + +// compile-flags: -Znext-solver +pub trait Trait<T> {} + +pub trait WithAssoc1<'a> { + type Assoc; +} +pub trait WithAssoc2<'a> { + type Assoc; +} + +// impl 1 +impl<T, U> Trait<for<'a> fn(<T as WithAssoc1<'a>>::Assoc, <U as WithAssoc2<'a>>::Assoc)> for (T, U) +where + T: for<'a> WithAssoc1<'a> + for<'a> WithAssoc2<'a, Assoc = i32>, + U: for<'a> WithAssoc2<'a>, +{ +} + +// impl 2 +impl<T, U> Trait<for<'a> fn(<U as WithAssoc1<'a>>::Assoc, u32)> for (T, U) where + U: for<'a> WithAssoc1<'a> //~^ ERROR conflicting implementations of trait +{ +} + +fn main() {} diff --git a/tests/ui/traits/next-solver/coherence/issue-102048.stderr b/tests/ui/traits/next-solver/coherence/issue-102048.stderr new file mode 100644 index 000000000..4e93ae284 --- /dev/null +++ b/tests/ui/traits/next-solver/coherence/issue-102048.stderr @@ -0,0 +1,16 @@ +error[E0119]: conflicting implementations of trait `Trait<for<'a> fn(<_ as WithAssoc1<'a>>::Assoc, <_ as WithAssoc2<'a>>::Assoc)>` for type `(_, _)` + --> $DIR/issue-102048.rs:39:1 + | +LL | / impl<T, U> Trait<for<'a> fn(<T as WithAssoc1<'a>>::Assoc, <U as WithAssoc2<'a>>::Assoc)> for (T, U) +LL | | where +LL | | T: for<'a> WithAssoc1<'a> + for<'a> WithAssoc2<'a, Assoc = i32>, +LL | | U: for<'a> WithAssoc2<'a>, + | |______________________________- first implementation here +... +LL | / impl<T, U> Trait<for<'a> fn(<U as WithAssoc1<'a>>::Assoc, u32)> for (T, U) where +LL | | U: for<'a> WithAssoc1<'a> + | |_____________________________^ conflicting implementation for `(_, _)` + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0119`. diff --git a/tests/ui/traits/next-solver/coherence/trait_ref_is_knowable-norm-overflow.rs b/tests/ui/traits/next-solver/coherence/trait_ref_is_knowable-norm-overflow.rs new file mode 100644 index 000000000..af471b5e1 --- /dev/null +++ b/tests/ui/traits/next-solver/coherence/trait_ref_is_knowable-norm-overflow.rs @@ -0,0 +1,20 @@ +// compile-flags: -Znext-solver + +// Coherence should handle overflow while normalizing for +// `trait_ref_is_knowable` correctly. + +trait Overflow { + type Assoc; +} +impl<T> Overflow for T { + type Assoc = <T as Overflow>::Assoc; +} + + +trait Trait {} +impl<T: Copy> Trait for T {} +struct LocalTy; +impl Trait for <LocalTy as Overflow>::Assoc {} +//~^ ERROR conflicting implementations of trait `Trait` for type `<LocalTy as Overflow>::Assoc` + +fn main() {} diff --git a/tests/ui/traits/next-solver/coherence/trait_ref_is_knowable-norm-overflow.stderr b/tests/ui/traits/next-solver/coherence/trait_ref_is_knowable-norm-overflow.stderr new file mode 100644 index 000000000..e3c0dabf5 --- /dev/null +++ b/tests/ui/traits/next-solver/coherence/trait_ref_is_knowable-norm-overflow.stderr @@ -0,0 +1,12 @@ +error[E0119]: conflicting implementations of trait `Trait` for type `<LocalTy as Overflow>::Assoc` + --> $DIR/trait_ref_is_knowable-norm-overflow.rs:17:1 + | +LL | impl<T: Copy> Trait for T {} + | ------------------------- first implementation here +LL | struct LocalTy; +LL | impl Trait for <LocalTy as Overflow>::Assoc {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `<LocalTy as Overflow>::Assoc` + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0119`. diff --git a/tests/ui/traits/next-solver/coherence/trait_ref_is_knowable-normalization-1.rs b/tests/ui/traits/next-solver/coherence/trait_ref_is_knowable-normalization-1.rs new file mode 100644 index 000000000..e6ffb55b4 --- /dev/null +++ b/tests/ui/traits/next-solver/coherence/trait_ref_is_knowable-normalization-1.rs @@ -0,0 +1,22 @@ +// compile-flags: -Znext-solver +// check-pass + +trait Id { + type Assoc; +} +impl<T> Id for T { + type Assoc = T; +} + + +// Coherence should be able to reason that `<LocalTy as Id>::Assoc: Copy` +// does not hold. +// +// See https://github.com/rust-lang/trait-system-refactor-initiative/issues/51 +// for more details. +trait Trait {} +impl<T: Copy> Trait for T {} +struct LocalTy; +impl Trait for <LocalTy as Id>::Assoc {} + +fn main() {} diff --git a/tests/ui/traits/next-solver/coherence/trait_ref_is_knowable-normalization-2.rs b/tests/ui/traits/next-solver/coherence/trait_ref_is_knowable-normalization-2.rs new file mode 100644 index 000000000..d16f9d22c --- /dev/null +++ b/tests/ui/traits/next-solver/coherence/trait_ref_is_knowable-normalization-2.rs @@ -0,0 +1,25 @@ +// compile-flags: -Znext-solver +// check-pass + +use std::future::{Future, IntoFuture}; +use std::pin::Pin; + +// We check that this does not overlap with the following impl from std: +// impl<P> Future for Pin<P> where P: DerefMut, <P as Deref>::Target: Future { .. } +// This should fail because we know ` <&mut Value as Deref>::Target: Future` not to hold. +// For this to work we have to normalize in the `trait_ref_is_knowable` check as we +// otherwise add an ambiguous candidate here. +// +// See https://github.com/rust-lang/trait-system-refactor-initiative/issues/51 +// for more details. +struct Value; +impl<'a> IntoFuture for Pin<&'a mut Value> { + type Output = (); + type IntoFuture = Pin<Box<dyn Future<Output = ()> + Send>>; + + fn into_future(self) -> Self::IntoFuture { + todo!() + } +} + +fn main() {} diff --git a/tests/ui/traits/next-solver/coherence/trait_ref_is_knowable-normalization-3.rs b/tests/ui/traits/next-solver/coherence/trait_ref_is_knowable-normalization-3.rs new file mode 100644 index 000000000..90de6b847 --- /dev/null +++ b/tests/ui/traits/next-solver/coherence/trait_ref_is_knowable-normalization-3.rs @@ -0,0 +1,24 @@ +// compile-flags: -Znext-solver +// check-pass + +trait Id { + type Assoc; +} +impl<T> Id for T { + type Assoc = T; +} + + +// Coherence should be able to reason that `(): PartialEq<<T as Id>::Assoc>>` +// does not hold. +// +// See https://github.com/rust-lang/trait-system-refactor-initiative/issues/51 +// for more details. +trait Trait {} +impl<T> Trait for T +where + (): PartialEq<T> {} +struct LocalTy; +impl Trait for <LocalTy as Id>::Assoc {} + +fn main() {} diff --git a/tests/ui/traits/next-solver/const-param-placeholder.fail.stderr b/tests/ui/traits/next-solver/const-param-placeholder.fail.stderr new file mode 100644 index 000000000..163710706 --- /dev/null +++ b/tests/ui/traits/next-solver/const-param-placeholder.fail.stderr @@ -0,0 +1,16 @@ +error[E0277]: the trait bound `[T; N]: Foo` is not satisfied + --> $DIR/const-param-placeholder.rs:17:17 + | +LL | needs_foo::<[T; N]>(); + | ^^^^^^ the trait `Foo` is not implemented for `[T; N]` + | + = help: the trait `Foo` is implemented for `[T; 1]` +note: required by a bound in `needs_foo` + --> $DIR/const-param-placeholder.rs:8:17 + | +LL | fn needs_foo<F: Foo>() {} + | ^^^ required by this bound in `needs_foo` + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/traits/next-solver/const-param-placeholder.rs b/tests/ui/traits/next-solver/const-param-placeholder.rs new file mode 100644 index 000000000..c22bc54cf --- /dev/null +++ b/tests/ui/traits/next-solver/const-param-placeholder.rs @@ -0,0 +1,21 @@ +// compile-flags: -Znext-solver +// revisions: pass fail +//[pass] check-pass + +struct Wrapper<T, const N: usize>([T; N]); + +trait Foo {} +fn needs_foo<F: Foo>() {} + +#[cfg(fail)] +impl<T> Foo for [T; 1] {} + +#[cfg(pass)] +impl<T, const N: usize> Foo for [T; N] {} + +fn test<T, const N: usize>() { + needs_foo::<[T; N]>(); + //[fail]~^ ERROR the trait bound `[T; N]: Foo` is not satisfied +} + +fn main() {} diff --git a/tests/ui/traits/next-solver/coroutine.fail.stderr b/tests/ui/traits/next-solver/coroutine.fail.stderr new file mode 100644 index 000000000..14e67727d --- /dev/null +++ b/tests/ui/traits/next-solver/coroutine.fail.stderr @@ -0,0 +1,64 @@ +error[E0277]: the trait bound `{coroutine@$DIR/coroutine.rs:18:21: 18:23}: Coroutine<A>` is not satisfied + --> $DIR/coroutine.rs:18:21 + | +LL | needs_coroutine(|| { + | _____---------------_^ + | | | + | | required by a bound introduced by this call +LL | | +LL | | +LL | | +LL | | yield (); +LL | | }); + | |_____^ the trait `Coroutine<A>` is not implemented for `{coroutine@$DIR/coroutine.rs:18:21: 18:23}` + | +note: required by a bound in `needs_coroutine` + --> $DIR/coroutine.rs:14:28 + | +LL | fn needs_coroutine(_: impl Coroutine<A, Yield = B, Return = C>) {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `needs_coroutine` + +error[E0271]: type mismatch resolving `<{coroutine@$DIR/coroutine.rs:18:21: 18:23} as Coroutine<A>>::Yield == B` + --> $DIR/coroutine.rs:18:21 + | +LL | needs_coroutine(|| { + | _____---------------_^ + | | | + | | required by a bound introduced by this call +LL | | +LL | | +LL | | +LL | | yield (); +LL | | }); + | |_____^ types differ + | +note: required by a bound in `needs_coroutine` + --> $DIR/coroutine.rs:14:41 + | +LL | fn needs_coroutine(_: impl Coroutine<A, Yield = B, Return = C>) {} + | ^^^^^^^^^ required by this bound in `needs_coroutine` + +error[E0271]: type mismatch resolving `<{coroutine@$DIR/coroutine.rs:18:21: 18:23} as Coroutine<A>>::Return == C` + --> $DIR/coroutine.rs:18:21 + | +LL | needs_coroutine(|| { + | _____---------------_^ + | | | + | | required by a bound introduced by this call +LL | | +LL | | +LL | | +LL | | yield (); +LL | | }); + | |_____^ types differ + | +note: required by a bound in `needs_coroutine` + --> $DIR/coroutine.rs:14:52 + | +LL | fn needs_coroutine(_: impl Coroutine<A, Yield = B, Return = C>) {} + | ^^^^^^^^^^ required by this bound in `needs_coroutine` + +error: aborting due to 3 previous errors + +Some errors have detailed explanations: E0271, E0277. +For more information about an error, try `rustc --explain E0271`. diff --git a/tests/ui/traits/next-solver/coroutine.rs b/tests/ui/traits/next-solver/coroutine.rs new file mode 100644 index 000000000..727e23568 --- /dev/null +++ b/tests/ui/traits/next-solver/coroutine.rs @@ -0,0 +1,32 @@ +// compile-flags: -Znext-solver +// edition: 2021 +// revisions: pass fail +//[pass] check-pass + +#![feature(coroutine_trait, coroutines)] + +use std::ops::Coroutine; + +struct A; +struct B; +struct C; + +fn needs_coroutine(_: impl Coroutine<A, Yield = B, Return = C>) {} + +#[cfg(fail)] +fn main() { + needs_coroutine(|| { + //[fail]~^ ERROR Coroutine<A>` is not satisfied + //[fail]~| ERROR as Coroutine<A>>::Yield == B` + //[fail]~| ERROR as Coroutine<A>>::Return == C` + yield (); + }); +} + +#[cfg(pass)] +fn main() { + needs_coroutine(|_: A| { + let _: A = yield B; + C + }) +} diff --git a/tests/ui/traits/next-solver/cycles/coinduction/fixpoint-exponential-growth.rs b/tests/ui/traits/next-solver/cycles/coinduction/fixpoint-exponential-growth.rs new file mode 100644 index 000000000..947b52da7 --- /dev/null +++ b/tests/ui/traits/next-solver/cycles/coinduction/fixpoint-exponential-growth.rs @@ -0,0 +1,35 @@ +// compile-flags: -Znext-solver + +// Proving `W<?0>: Trait` instantiates `?0` with `(W<?1>, W<?2>)` and then +// proves `W<?1>: Trait` and `W<?2>: Trait`, resulting in a coinductive cycle. +// +// Proving coinductive cycles runs until we reach a fixpoint. However, after +// computing `try_evaluate_added_goals` in the second fixpoint iteration, the +// self type already has a depth equal to the number of steps. This results +// in enormous constraints, causing the canonicalizer to hang without ever +// reaching the recursion limit. We currently avoid that by erasing the constraints +// from overflow. +// +// This previously caused a hang in the trait solver, see +// https://github.com/rust-lang/trait-system-refactor-initiative/issues/13. + +#![feature(rustc_attrs)] + +#[rustc_coinductive] +trait Trait {} + +struct W<T>(T); + +impl<T, U> Trait for W<(W<T>, W<U>)> +where + W<T>: Trait, + W<U>: Trait, +{ +} + +fn impls<T: Trait>() {} + +fn main() { + impls::<W<_>>(); + //~^ ERROR overflow evaluating the requirement +} diff --git a/tests/ui/traits/next-solver/cycles/coinduction/fixpoint-exponential-growth.stderr b/tests/ui/traits/next-solver/cycles/coinduction/fixpoint-exponential-growth.stderr new file mode 100644 index 000000000..150100f2c --- /dev/null +++ b/tests/ui/traits/next-solver/cycles/coinduction/fixpoint-exponential-growth.stderr @@ -0,0 +1,16 @@ +error[E0275]: overflow evaluating the requirement `W<_>: Trait` + --> $DIR/fixpoint-exponential-growth.rs:33:13 + | +LL | impls::<W<_>>(); + | ^^^^ + | + = help: consider increasing the recursion limit by adding a `#![recursion_limit = "256"]` attribute to your crate (`fixpoint_exponential_growth`) +note: required by a bound in `impls` + --> $DIR/fixpoint-exponential-growth.rs:30:13 + | +LL | fn impls<T: Trait>() {} + | ^^^^^ required by this bound in `impls` + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0275`. diff --git a/tests/ui/traits/next-solver/cycles/coinduction/incompleteness-unstable-result.rs b/tests/ui/traits/next-solver/cycles/coinduction/incompleteness-unstable-result.rs new file mode 100644 index 000000000..a3c07b987 --- /dev/null +++ b/tests/ui/traits/next-solver/cycles/coinduction/incompleteness-unstable-result.rs @@ -0,0 +1,69 @@ +// compile-flags: -Znext-solver +#![feature(rustc_attrs)] + +// This test is incredibly subtle. At its core the goal is to get a coinductive cycle, +// which, depending on its root goal, either holds or errors. We achieve this by getting +// incomplete inference via a `ParamEnv` candidate in the `A<T>` impl and required +// inference from an `Impl` candidate in the `B<T>` impl. +// +// To make global cache accesses stronger than the guidance from the where-bounds, we add +// another coinductive cycle from `A<T>: Trait<U, V, D>` to `A<T>: Trait<U, D, V>` and only +// constrain `D` directly. This means that any candidates which rely on `V` only make +// progress in the second iteration, allowing a cache access in the first iteration to take +// precedence. +// +// tl;dr: our caching of coinductive cycles was broken and this is a regression +// test for that. + +#[rustc_coinductive] +trait Trait<T: ?Sized, V: ?Sized, D: ?Sized> {} +struct A<T: ?Sized>(*const T); +struct B<T: ?Sized>(*const T); + +trait IncompleteGuidance<T: ?Sized, V: ?Sized> {} +impl<T: ?Sized, U: ?Sized + 'static> IncompleteGuidance<U, u8> for T {} +impl<T: ?Sized, U: ?Sized + 'static> IncompleteGuidance<U, i8> for T {} +impl<T: ?Sized, U: ?Sized + 'static> IncompleteGuidance<U, i16> for T {} + +trait ImplGuidance<T: ?Sized, V: ?Sized> {} +impl<T: ?Sized> ImplGuidance<u32, u8> for T {} +impl<T: ?Sized> ImplGuidance<i32, i8> for T {} + +impl<T: ?Sized, U: ?Sized, V: ?Sized, D: ?Sized> Trait<U, V, D> for A<T> +where + T: IncompleteGuidance<U, V>, + A<T>: Trait<U, D, V>, + B<T>: Trait<U, V, D>, + (): ToU8<D>, +{ +} + +trait ToU8<T: ?Sized> {} +impl ToU8<u8> for () {} + +impl<T: ?Sized, U: ?Sized, V: ?Sized, D: ?Sized> Trait<U, V, D> for B<T> +where + T: ImplGuidance<U, V>, + A<T>: Trait<U, V, D>, +{ +} + +fn impls_trait<T: ?Sized + Trait<U, V, D>, U: ?Sized, V: ?Sized, D: ?Sized>() {} + +fn with_bound<X>() +where + X: IncompleteGuidance<i32, u8>, + X: IncompleteGuidance<u32, i8>, + X: IncompleteGuidance<u32, i16>, +{ + impls_trait::<B<X>, _, _, _>(); // entering the cycle from `B` works + + // entering the cycle from `A` fails, but would work if we were to use the cache + // result of `B<X>`. + impls_trait::<A<X>, _, _, _>(); + //~^ ERROR the trait bound `A<X>: Trait<_, _, _>` is not satisfied +} + +fn main() { + with_bound::<u32>(); +} diff --git a/tests/ui/traits/next-solver/cycles/coinduction/incompleteness-unstable-result.stderr b/tests/ui/traits/next-solver/cycles/coinduction/incompleteness-unstable-result.stderr new file mode 100644 index 000000000..d49321917 --- /dev/null +++ b/tests/ui/traits/next-solver/cycles/coinduction/incompleteness-unstable-result.stderr @@ -0,0 +1,16 @@ +error[E0277]: the trait bound `A<X>: Trait<_, _, _>` is not satisfied + --> $DIR/incompleteness-unstable-result.rs:63:19 + | +LL | impls_trait::<A<X>, _, _, _>(); + | ^^^^ the trait `Trait<_, _, _>` is not implemented for `A<X>` + | + = help: the trait `Trait<U, V, D>` is implemented for `A<T>` +note: required by a bound in `impls_trait` + --> $DIR/incompleteness-unstable-result.rs:51:28 + | +LL | fn impls_trait<T: ?Sized + Trait<U, V, D>, U: ?Sized, V: ?Sized, D: ?Sized>() {} + | ^^^^^^^^^^^^^^ required by this bound in `impls_trait` + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/traits/next-solver/cycles/double-cycle-inductive-coinductive.rs b/tests/ui/traits/next-solver/cycles/double-cycle-inductive-coinductive.rs new file mode 100644 index 000000000..0f19bc2c5 --- /dev/null +++ b/tests/ui/traits/next-solver/cycles/double-cycle-inductive-coinductive.rs @@ -0,0 +1,37 @@ +// compile-flags: -Znext-solver +#![feature(rustc_attrs)] + +// Test that having both an inductive and a coinductive cycle +// is handled correctly. + +#[rustc_coinductive] +trait Trait {} +impl<T: Inductive + Coinductive> Trait for T {} + +trait Inductive {} +impl<T: Trait> Inductive for T {} +#[rustc_coinductive] +trait Coinductive {} +impl<T: Trait> Coinductive for T {} + +fn impls_trait<T: Trait>() {} + +#[rustc_coinductive] +trait TraitRev {} +impl<T: CoinductiveRev + InductiveRev> TraitRev for T {} + +trait InductiveRev {} +impl<T: TraitRev> InductiveRev for T {} +#[rustc_coinductive] +trait CoinductiveRev {} +impl<T: TraitRev> CoinductiveRev for T {} + +fn impls_trait_rev<T: TraitRev>() {} + +fn main() { + impls_trait::<()>(); + //~^ ERROR overflow evaluating the requirement + + impls_trait_rev::<()>(); + //~^ ERROR overflow evaluating the requirement +} diff --git a/tests/ui/traits/next-solver/cycles/double-cycle-inductive-coinductive.stderr b/tests/ui/traits/next-solver/cycles/double-cycle-inductive-coinductive.stderr new file mode 100644 index 000000000..a3404da51 --- /dev/null +++ b/tests/ui/traits/next-solver/cycles/double-cycle-inductive-coinductive.stderr @@ -0,0 +1,29 @@ +error[E0275]: overflow evaluating the requirement `(): Trait` + --> $DIR/double-cycle-inductive-coinductive.rs:32:19 + | +LL | impls_trait::<()>(); + | ^^ + | + = help: consider increasing the recursion limit by adding a `#![recursion_limit = "256"]` attribute to your crate (`double_cycle_inductive_coinductive`) +note: required by a bound in `impls_trait` + --> $DIR/double-cycle-inductive-coinductive.rs:17:19 + | +LL | fn impls_trait<T: Trait>() {} + | ^^^^^ required by this bound in `impls_trait` + +error[E0275]: overflow evaluating the requirement `(): TraitRev` + --> $DIR/double-cycle-inductive-coinductive.rs:35:23 + | +LL | impls_trait_rev::<()>(); + | ^^ + | + = help: consider increasing the recursion limit by adding a `#![recursion_limit = "256"]` attribute to your crate (`double_cycle_inductive_coinductive`) +note: required by a bound in `impls_trait_rev` + --> $DIR/double-cycle-inductive-coinductive.rs:29:23 + | +LL | fn impls_trait_rev<T: TraitRev>() {} + | ^^^^^^^^ required by this bound in `impls_trait_rev` + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0275`. diff --git a/tests/ui/traits/next-solver/cycles/fixpoint-rerun-all-cycle-heads.rs b/tests/ui/traits/next-solver/cycles/fixpoint-rerun-all-cycle-heads.rs new file mode 100644 index 000000000..c7e2e2d5e --- /dev/null +++ b/tests/ui/traits/next-solver/cycles/fixpoint-rerun-all-cycle-heads.rs @@ -0,0 +1,53 @@ +// compile-flags: -Znext-solver +#![feature(rustc_attrs)] + +// Check that we correctly rerun the trait solver for heads of cycles, +// even if they are not the root. + +struct A<T: ?Sized>(*const T); +struct B<T: ?Sized>(*const T); +struct C<T: ?Sized>(*const T); + +#[rustc_coinductive] +trait Trait<'a, 'b> {} +trait NotImplemented {} + +impl<'a, 'b, T: ?Sized> Trait<'a, 'b> for A<T> where B<T>: Trait<'a, 'b> {} + +// With this the root of `B<T>` is `A<T>`, even if the other impl does +// not have a cycle with `A<T>`. This candidate never applies because of +// the `A<T>: NotImplemented` bound. +impl<'a, 'b, T: ?Sized> Trait<'a, 'b> for B<T> +where + A<T>: Trait<'a, 'b>, + A<T>: NotImplemented, +{ +} + +// This impl directly requires 'b to be equal to 'static. +// +// Because of the coinductive cycle through `C<T>` it also requires +// 'a to be 'static. +impl<'a, T: ?Sized> Trait<'a, 'static> for B<T> +where + C<T>: Trait<'a, 'a>, +{} + +// In the first iteration of `B<T>: Trait<'a, 'b>` we don't add any +// constraints here, only after setting the provisional result to require +// `'b == 'static` do we also add that constraint for `'a`. +impl<'a, 'b, T: ?Sized> Trait<'a, 'b> for C<T> +where + B<T>: Trait<'a, 'b>, +{} + +fn impls_trait<'a, 'b, T: Trait<'a, 'b> + ?Sized>() {} + +fn check<'a, T: ?Sized>() { + impls_trait::<'a, 'static, A<T>>(); + //~^ ERROR lifetime may not live long enough +} + +fn main() { + check::<()>(); +} diff --git a/tests/ui/traits/next-solver/cycles/fixpoint-rerun-all-cycle-heads.stderr b/tests/ui/traits/next-solver/cycles/fixpoint-rerun-all-cycle-heads.stderr new file mode 100644 index 000000000..7b3075f4f --- /dev/null +++ b/tests/ui/traits/next-solver/cycles/fixpoint-rerun-all-cycle-heads.stderr @@ -0,0 +1,10 @@ +error: lifetime may not live long enough + --> $DIR/fixpoint-rerun-all-cycle-heads.rs:47:5 + | +LL | fn check<'a, T: ?Sized>() { + | -- lifetime `'a` defined here +LL | impls_trait::<'a, 'static, A<T>>(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ requires that `'a` must outlive `'static` + +error: aborting due to 1 previous error + diff --git a/tests/ui/traits/next-solver/cycles/inductive-cycle-but-err.rs b/tests/ui/traits/next-solver/cycles/inductive-cycle-but-err.rs new file mode 100644 index 000000000..fdc7afea3 --- /dev/null +++ b/tests/ui/traits/next-solver/cycles/inductive-cycle-but-err.rs @@ -0,0 +1,48 @@ +// compile-flags: -Znext-solver +#![feature(trivial_bounds, marker_trait_attr)] +#![allow(trivial_bounds)] +// This previously triggered a bug in the provisional cache. +// +// This has the proof tree +// - `MultipleCandidates: Trait` proven via impl-one +// - `MultipleNested: Trait` via impl +// - `MultipleCandidates: Trait` (inductive cycle ~> OVERFLOW) +// - `DoesNotImpl: Trait` (ERR) +// - `MultipleCandidates: Trait` proven via impl-two +// - `MultipleNested: Trait` (in provisional cache ~> OVERFLOW) +// +// We previously incorrectly treated the `MultipleCandidates: Trait` as +// overflow because it was in the cache and reached via an inductive cycle. +// It should be `NoSolution`. + +struct MultipleCandidates; +struct MultipleNested; +struct DoesNotImpl; + +#[marker] +trait Trait {} + +// impl-one +impl Trait for MultipleCandidates +where + MultipleNested: Trait +{} + +// impl-two +impl Trait for MultipleCandidates +where + MultipleNested: Trait, +{} + +impl Trait for MultipleNested +where + MultipleCandidates: Trait, + DoesNotImpl: Trait, +{} + +fn impls_trait<T: Trait>() {} + +fn main() { + impls_trait::<MultipleCandidates>(); + //~^ ERROR the trait bound `MultipleCandidates: Trait` is not satisfied +} diff --git a/tests/ui/traits/next-solver/cycles/inductive-cycle-but-err.stderr b/tests/ui/traits/next-solver/cycles/inductive-cycle-but-err.stderr new file mode 100644 index 000000000..acacaf6a3 --- /dev/null +++ b/tests/ui/traits/next-solver/cycles/inductive-cycle-but-err.stderr @@ -0,0 +1,16 @@ +error[E0277]: the trait bound `MultipleCandidates: Trait` is not satisfied + --> $DIR/inductive-cycle-but-err.rs:46:19 + | +LL | impls_trait::<MultipleCandidates>(); + | ^^^^^^^^^^^^^^^^^^ the trait `Trait` is not implemented for `MultipleCandidates` + | + = help: the trait `Trait` is implemented for `MultipleCandidates` +note: required by a bound in `impls_trait` + --> $DIR/inductive-cycle-but-err.rs:43:19 + | +LL | fn impls_trait<T: Trait>() {} + | ^^^^^ required by this bound in `impls_trait` + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/traits/next-solver/cycles/inductive-cycle-but-ok.rs b/tests/ui/traits/next-solver/cycles/inductive-cycle-but-ok.rs new file mode 100644 index 000000000..d6d9762bb --- /dev/null +++ b/tests/ui/traits/next-solver/cycles/inductive-cycle-but-ok.rs @@ -0,0 +1,44 @@ +// compile-flags: -Znext-solver +// check-pass +#![feature(trivial_bounds, marker_trait_attr)] +#![allow(trivial_bounds)] + +// This previously triggered a bug in the provisional cache. +// +// This has the proof tree +// - `Root: Trait` proven via impl +// - `MultipleCandidates: Trait` +// - candidate: overflow-impl +// - `Root: Trait` (inductive cycle ~> OVERFLOW) +// - candidate: trivial-impl ~> YES +// - merge respones ~> YES +// - `MultipleCandidates: Trait` (in provisional cache ~> OVERFLOW) +// +// We previously incorrectly treated the `MultipleCandidates: Trait` as +// overflow because it was in the cache and reached via an inductive cycle. +// It should be `YES`. + +struct Root; +struct MultipleCandidates; + +#[marker] +trait Trait {} +impl Trait for Root +where + MultipleCandidates: Trait, + MultipleCandidates: Trait, +{} + +// overflow-impl +impl Trait for MultipleCandidates +where + Root: Trait, +{} +// trivial-impl +impl Trait for MultipleCandidates {} + +fn impls_trait<T: Trait>() {} + +fn main() { + impls_trait::<Root>(); +} diff --git a/tests/ui/traits/next-solver/cycles/inductive-cycle-discarded-coinductive-constraints.rs b/tests/ui/traits/next-solver/cycles/inductive-cycle-discarded-coinductive-constraints.rs new file mode 100644 index 000000000..a32f7a13a --- /dev/null +++ b/tests/ui/traits/next-solver/cycles/inductive-cycle-discarded-coinductive-constraints.rs @@ -0,0 +1,36 @@ +// check-pass +// compile-flags: -Znext-solver +#![feature(rustc_attrs, marker_trait_attr)] +#[rustc_coinductive] +trait Trait {} + +impl<T, U> Trait for (T, U) +where + (U, T): Trait, + (T, U): Inductive, + (): ConstrainToU32<T>, +{} + +trait ConstrainToU32<T> {} +impl ConstrainToU32<u32> for () {} + +// We only prefer the candidate without an inductive cycle +// once the inductive cycle has the same constraints as the +// other goal. +#[marker] +trait Inductive {} +impl<T, U> Inductive for (T, U) +where + (T, U): Trait, +{} + +impl Inductive for (u32, u32) {} + +fn impls_trait<T, U>() +where + (T, U): Trait, +{} + +fn main() { + impls_trait::<_, _>(); +} diff --git a/tests/ui/traits/next-solver/cycles/inductive-fixpoint-hang.rs b/tests/ui/traits/next-solver/cycles/inductive-fixpoint-hang.rs new file mode 100644 index 000000000..efeb8d023 --- /dev/null +++ b/tests/ui/traits/next-solver/cycles/inductive-fixpoint-hang.rs @@ -0,0 +1,33 @@ +// compile-flags: -Znext-solver + +// This currently hangs if we do not erase constraints from +// overflow. +// +// We set the provisional result of `W<?0>` to `?0 := W<_>`. +// The next iteration does not simply result in a `?0 := W<W<_>` constraint as +// one might expect, but instead each time we evaluate the nested `W<T>` goal we +// apply the previously returned constraints: the first fixpoint iteration goes +// as follows: `W<?1>: Trait` constrains `?1` to `W<?2>`, we then evaluate +// `W<W<?2>>: Trait` the next time we try to prove the nested goal. This results +// inn `W<W<W<?3>>>` and so on. This goes on until we reach overflow in +// `try_evaluate_added_goals`. This means the provisional result after the +// second fixpoint iteration is already `W<W<W<...>>>` with a size proportional +// to the number of steps in `try_evaluate_added_goals`. The size then continues +// to grow. The exponential blowup from having 2 nested goals per impl causes +// the solver to hang without hitting the recursion limit. +trait Trait {} + +struct W<T: ?Sized>(*const T); + +impl<T: ?Sized> Trait for W<W<T>> +where + W<T>: Trait, + W<T>: Trait, +{} + +fn impls_trait<T: Trait>() {} + +fn main() { + impls_trait::<W<_>>(); + //~^ ERROR overflow evaluating the requirement +} diff --git a/tests/ui/traits/next-solver/cycles/inductive-fixpoint-hang.stderr b/tests/ui/traits/next-solver/cycles/inductive-fixpoint-hang.stderr new file mode 100644 index 000000000..424519207 --- /dev/null +++ b/tests/ui/traits/next-solver/cycles/inductive-fixpoint-hang.stderr @@ -0,0 +1,16 @@ +error[E0275]: overflow evaluating the requirement `W<_>: Trait` + --> $DIR/inductive-fixpoint-hang.rs:31:19 + | +LL | impls_trait::<W<_>>(); + | ^^^^ + | + = help: consider increasing the recursion limit by adding a `#![recursion_limit = "256"]` attribute to your crate (`inductive_fixpoint_hang`) +note: required by a bound in `impls_trait` + --> $DIR/inductive-fixpoint-hang.rs:28:19 + | +LL | fn impls_trait<T: Trait>() {} + | ^^^^^ required by this bound in `impls_trait` + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0275`. diff --git a/tests/ui/traits/next-solver/cycles/inductive-not-on-stack.rs b/tests/ui/traits/next-solver/cycles/inductive-not-on-stack.rs new file mode 100644 index 000000000..f2f6e009d --- /dev/null +++ b/tests/ui/traits/next-solver/cycles/inductive-not-on-stack.rs @@ -0,0 +1,46 @@ +// compile-flags: -Znext-solver +#![feature(rustc_attrs, trivial_bounds)] + +// We have to be careful here: +// +// We either have the provisional result of `A -> B -> A` on the +// stack, which is a fully coinductive cycle. Accessing the +// provisional result for `B` as part of the `A -> C -> B -> A` cycle +// has to make sure we don't just use the result of `A -> B -> A` as the +// new cycle is inductive. +// +// Alternatively, if we have `A -> C -> A` first, then `A -> B -> A` has +// a purely inductive stack, so something could also go wrong here. + +#[rustc_coinductive] +trait A {} +#[rustc_coinductive] +trait B {} +trait C {} + +impl<T: B + C> A for T {} +impl<T: A> B for T {} +impl<T: B> C for T {} + +fn impls_a<T: A>() {} + +// The same test with reordered where clauses to make sure we're actually testing anything. +#[rustc_coinductive] +trait AR {} +#[rustc_coinductive] +trait BR {} +trait CR {} + +impl<T: CR + BR> AR for T {} +impl<T: AR> BR for T {} +impl<T: BR> CR for T {} + +fn impls_ar<T: AR>() {} + +fn main() { + impls_a::<()>(); + //~^ ERROR overflow evaluating the requirement `(): A` + + impls_ar::<()>(); + //~^ ERROR overflow evaluating the requirement `(): AR` +} diff --git a/tests/ui/traits/next-solver/cycles/inductive-not-on-stack.stderr b/tests/ui/traits/next-solver/cycles/inductive-not-on-stack.stderr new file mode 100644 index 000000000..859b3f3f1 --- /dev/null +++ b/tests/ui/traits/next-solver/cycles/inductive-not-on-stack.stderr @@ -0,0 +1,29 @@ +error[E0275]: overflow evaluating the requirement `(): A` + --> $DIR/inductive-not-on-stack.rs:41:15 + | +LL | impls_a::<()>(); + | ^^ + | + = help: consider increasing the recursion limit by adding a `#![recursion_limit = "256"]` attribute to your crate (`inductive_not_on_stack`) +note: required by a bound in `impls_a` + --> $DIR/inductive-not-on-stack.rs:25:15 + | +LL | fn impls_a<T: A>() {} + | ^ required by this bound in `impls_a` + +error[E0275]: overflow evaluating the requirement `(): AR` + --> $DIR/inductive-not-on-stack.rs:44:16 + | +LL | impls_ar::<()>(); + | ^^ + | + = help: consider increasing the recursion limit by adding a `#![recursion_limit = "256"]` attribute to your crate (`inductive_not_on_stack`) +note: required by a bound in `impls_ar` + --> $DIR/inductive-not-on-stack.rs:38:16 + | +LL | fn impls_ar<T: AR>() {} + | ^^ required by this bound in `impls_ar` + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0275`. diff --git a/tests/ui/traits/next-solver/cycles/leak-check-coinductive-cycle.rs b/tests/ui/traits/next-solver/cycles/leak-check-coinductive-cycle.rs new file mode 100644 index 000000000..9ff362ec8 --- /dev/null +++ b/tests/ui/traits/next-solver/cycles/leak-check-coinductive-cycle.rs @@ -0,0 +1,33 @@ +// compile-flags: -Znext-solver +// check-pass +#![feature(rustc_attrs)] + +#[rustc_coinductive] +trait Trait<T> {} +impl<'a, 'b, T> Trait<T> for (&'a (), &'b ()) +where + 'b: 'a, + &'a (): Trait<T>, +{} + +impl Trait<i32> for &'static () {} +impl<'a> Trait<u32> for &'a () +where + for<'b> (&'a (), &'b ()): Trait<u32>, +{} + + +fn impls_trait<T: Trait<U>, U>() {} + +fn main() { + // This infers to `impls_trait::<(&'static (), &'static ()), i32>();` + // + // In the first attempt we have 2 candidates for `&'a (): Trait<_>` + // and we get ambiguity. The result is therefore ambiguity with a `'b: 'a` + // constraint. The next attempt then uses that provisional result when + // trying to apply `impl<'a> Trait<u32> for &'a ()`. This means we get a + // `for<'b> 'b: 'a` bound which fails the leak check. Because of this we + // end up with a single impl for `&'a (): Trait<_>` which infers `_` to `i32` + // and succeeds. + impls_trait::<(&(), &()), _>(); +} diff --git a/tests/ui/traits/next-solver/cycles/provisional-result-done.rs b/tests/ui/traits/next-solver/cycles/provisional-result-done.rs new file mode 100644 index 000000000..0f3b84ce5 --- /dev/null +++ b/tests/ui/traits/next-solver/cycles/provisional-result-done.rs @@ -0,0 +1,33 @@ +// compile-flags: -Znext-solver +// check-pass + +// This tests checks that we update results in the provisional cache when +// we pop a goal from the stack. +#![feature(auto_traits)] +auto trait Coinductive {} +struct Foo<T>(T); +struct Bar<T>(T); + +impl<T> Coinductive for Foo<T> +where + Bar<T>: Coinductive +{} + +impl<T> Coinductive for Bar<T> +where + Foo<T>: Coinductive, + Bar<T>: ConstrainInfer, +{} + +trait ConstrainInfer {} +impl ConstrainInfer for Bar<u8> {} +impl ConstrainInfer for Foo<u16> {} + +fn impls<T: Coinductive>() -> T { todo!() } + +fn constrain<T: ConstrainInfer>(_: T) {} + +fn main() { + // This should constrain `_` to `u8`. + impls::<Foo<_>>(); +} diff --git a/tests/ui/traits/next-solver/deduce-closure-signature-after-normalization.rs b/tests/ui/traits/next-solver/deduce-closure-signature-after-normalization.rs new file mode 100644 index 000000000..08f26686b --- /dev/null +++ b/tests/ui/traits/next-solver/deduce-closure-signature-after-normalization.rs @@ -0,0 +1,10 @@ +// compile-flags: -Znext-solver +// check-pass + +trait Foo { + fn test() -> impl Fn(u32) -> u32 { + |x| x.count_ones() + } +} + +fn main() {} diff --git a/tests/ui/traits/next-solver/deduce-ty-from-object.rs b/tests/ui/traits/next-solver/deduce-ty-from-object.rs new file mode 100644 index 000000000..b627fd720 --- /dev/null +++ b/tests/ui/traits/next-solver/deduce-ty-from-object.rs @@ -0,0 +1,6 @@ +// check-pass +// compile-flags: -Znext-solver + +fn main() { + let x: Box<dyn Iterator<Item = ()>> = Box::new(std::iter::empty()); +} diff --git a/tests/ui/traits/next-solver/dedup-regions.rs b/tests/ui/traits/next-solver/dedup-regions.rs new file mode 100644 index 000000000..dd406333f --- /dev/null +++ b/tests/ui/traits/next-solver/dedup-regions.rs @@ -0,0 +1,31 @@ +// compile-flags: -Znext-solver +// check-pass + +struct A(*mut ()); + +unsafe impl Send for A where A: 'static {} + +macro_rules! mk { + ($name:ident $ty:ty) => { + struct $name($ty, $ty, $ty, $ty, $ty, $ty, $ty, $ty, $ty, $ty); + }; +} + +mk!(B A); +mk!(C B); +mk!(D C); +mk!(E D); +mk!(F E); +mk!(G F); +mk!(H G); +mk!(I H); +mk!(J I); +mk!(K J); +mk!(L K); +mk!(M L); + +fn needs_send<T: Send>() {} + +fn main() { + needs_send::<M>(); +} diff --git a/tests/ui/traits/next-solver/destruct.rs b/tests/ui/traits/next-solver/destruct.rs new file mode 100644 index 000000000..5093344e4 --- /dev/null +++ b/tests/ui/traits/next-solver/destruct.rs @@ -0,0 +1,13 @@ +// compile-flags: -Znext-solver +// check-pass + +#![feature(const_trait_impl)] + +fn foo(_: impl std::marker::Destruct) {} + +struct MyAdt; + +fn main() { + foo(1); + foo(MyAdt); +} diff --git a/tests/ui/traits/next-solver/dont-coerce-infer-to-dyn.rs b/tests/ui/traits/next-solver/dont-coerce-infer-to-dyn.rs new file mode 100644 index 000000000..da07869f3 --- /dev/null +++ b/tests/ui/traits/next-solver/dont-coerce-infer-to-dyn.rs @@ -0,0 +1,17 @@ +// compile-flags: -Znext-solver +// check-pass + +use std::fmt::Display; +use std::rc::Rc; + +fn mk<T: ?Sized>(t: Option<&T>) -> Rc<T> { + todo!() +} + +fn main() { + let mut x = None; + let y = mk(x); + // Don't treat the line below as a unsize coercion `Rc<?0> ~> Rc<dyn Display>` + let z: Rc<dyn Display> = y; + x = Some(&1 as &dyn Display); +} diff --git a/tests/ui/traits/next-solver/dont-elaborate-for-projections.rs b/tests/ui/traits/next-solver/dont-elaborate-for-projections.rs new file mode 100644 index 000000000..9123871db --- /dev/null +++ b/tests/ui/traits/next-solver/dont-elaborate-for-projections.rs @@ -0,0 +1,12 @@ +// compile-flags: -Znext-solver +// check-pass + +trait Iter<'a, I: 'a>: Iterator<Item = &'a I> {} + +fn needs_iter<'a, T: Iter<'a, I> + ?Sized, I: 'a>(_: &T) {} + +fn test(x: &dyn Iter<'_, ()>) { + needs_iter(x); +} + +fn main() {} diff --git a/tests/ui/traits/next-solver/dont-ice-on-assoc-projection.rs b/tests/ui/traits/next-solver/dont-ice-on-assoc-projection.rs new file mode 100644 index 000000000..1e1ef8c23 --- /dev/null +++ b/tests/ui/traits/next-solver/dont-ice-on-assoc-projection.rs @@ -0,0 +1,19 @@ +// compile-flags: -Znext-solver=coherence + +// Makes sure we don't ICE on associated const projection when the feature gate +// is not enabled, since we should avoid encountering ICEs on stable if possible. + +trait Bar { + const ASSOC: usize; +} +impl Bar for () { + const ASSOC: usize = 1; +} + +trait Foo {} +impl Foo for () {} +impl<T> Foo for T where T: Bar<ASSOC = 0> {} +//~^ ERROR associated const equality is incomplete +//~| ERROR conflicting implementations of trait `Foo` for type `()` + +fn main() {} diff --git a/tests/ui/traits/next-solver/dont-ice-on-assoc-projection.stderr b/tests/ui/traits/next-solver/dont-ice-on-assoc-projection.stderr new file mode 100644 index 000000000..368f5cd0c --- /dev/null +++ b/tests/ui/traits/next-solver/dont-ice-on-assoc-projection.stderr @@ -0,0 +1,21 @@ +error[E0658]: associated const equality is incomplete + --> $DIR/dont-ice-on-assoc-projection.rs:15:32 + | +LL | impl<T> Foo for T where T: Bar<ASSOC = 0> {} + | ^^^^^^^^^ + | + = note: see issue #92827 <https://github.com/rust-lang/rust/issues/92827> for more information + = help: add `#![feature(associated_const_equality)]` to the crate attributes to enable + +error[E0119]: conflicting implementations of trait `Foo` for type `()` + --> $DIR/dont-ice-on-assoc-projection.rs:15:1 + | +LL | impl Foo for () {} + | --------------- first implementation here +LL | impl<T> Foo for T where T: Bar<ASSOC = 0> {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `()` + +error: aborting due to 2 previous errors + +Some errors have detailed explanations: E0119, E0658. +For more information about an error, try `rustc --explain E0119`. diff --git a/tests/ui/traits/next-solver/dont-loop-fulfill-on-region-constraints.rs b/tests/ui/traits/next-solver/dont-loop-fulfill-on-region-constraints.rs new file mode 100644 index 000000000..a85098a95 --- /dev/null +++ b/tests/ui/traits/next-solver/dont-loop-fulfill-on-region-constraints.rs @@ -0,0 +1,32 @@ +// compile-flags: -Znext-solver +// check-pass + +trait Eq<'a, 'b, T> {} + +trait Ambig {} +impl Ambig for () {} + +impl<'a, T> Eq<'a, 'a, T> for () where T: Ambig {} + +fn eq<'a, 'b, T>(t: T) +where + (): Eq<'a, 'b, T>, +{ +} + +fn test<'r>() { + let mut x = Default::default(); + + // When we evaluate `(): Eq<'r, 'r, ?0>` we uniquify the regions. + // That leads us to evaluate `(): Eq<'?0, '?1, ?0>`. The response of this + // will be ambiguous (because `?0: Ambig` is ambig) and also not an "identity" + // response, since the region constraints will contain `'?0 == '?1` (so + // `is_changed` will return true). Since it's both ambig and changed, + // fulfillment will both re-register the goal AND loop again. This hits the + // overflow limit. This should neither be considered overflow, nor ICE. + eq::<'r, 'r, _>(x); + + x = (); +} + +fn main() {} diff --git a/tests/ui/traits/next-solver/dont-normalize-proj-with-error.rs b/tests/ui/traits/next-solver/dont-normalize-proj-with-error.rs new file mode 100644 index 000000000..fd1682cd6 --- /dev/null +++ b/tests/ui/traits/next-solver/dont-normalize-proj-with-error.rs @@ -0,0 +1,22 @@ +// compile-flags: -Znext-solver + +// Test that we don't incorrectly leak unconstrained inference variables +// if the projection contained an error. This caused an ICE in writeback. + +trait Mirror { + type Assoc: ?Sized; +} + +struct Wrapper<T: ?Sized>(T); +impl<T: ?Sized> Mirror for Wrapper<T> { + type Assoc = T; +} + +fn mirror<W: Mirror>(_: W) -> Box<W::Assoc> { todo!() } + +fn type_error() -> TypeError { todo!() } +//~^ ERROR cannot find type `TypeError` in this scope + +fn main() { + let x = mirror(type_error()); +} diff --git a/tests/ui/traits/next-solver/dont-normalize-proj-with-error.stderr b/tests/ui/traits/next-solver/dont-normalize-proj-with-error.stderr new file mode 100644 index 000000000..576ede52a --- /dev/null +++ b/tests/ui/traits/next-solver/dont-normalize-proj-with-error.stderr @@ -0,0 +1,9 @@ +error[E0412]: cannot find type `TypeError` in this scope + --> $DIR/dont-normalize-proj-with-error.rs:17:20 + | +LL | fn type_error() -> TypeError { todo!() } + | ^^^^^^^^^ not found in this scope + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0412`. diff --git a/tests/ui/traits/next-solver/dont-remap-tait-substs.rs b/tests/ui/traits/next-solver/dont-remap-tait-substs.rs new file mode 100644 index 000000000..b089f0df3 --- /dev/null +++ b/tests/ui/traits/next-solver/dont-remap-tait-substs.rs @@ -0,0 +1,19 @@ +// compile-flags: -Znext-solver +// check-pass + +// Makes sure we don't prepopulate the MIR typeck of `define` +// with `Foo<T, U> = T`, but instead, `Foo<B, A> = B`, so that +// the param-env predicates actually apply. + +#![feature(type_alias_impl_trait)] + +type Foo<T: Send, U> = impl NeedsSend<T>; + +trait NeedsSend<T> {} +impl<T: Send> NeedsSend<T> for T {} + +fn define<A, B: Send>(a: A, b: B, _: Foo<B, A>) { + let y: Option<Foo<B, A>> = Some(b); +} + +fn main() {} diff --git a/tests/ui/traits/next-solver/dont-type_of-tait-in-defining-scope.not_send.stderr b/tests/ui/traits/next-solver/dont-type_of-tait-in-defining-scope.not_send.stderr new file mode 100644 index 000000000..076dab29d --- /dev/null +++ b/tests/ui/traits/next-solver/dont-type_of-tait-in-defining-scope.not_send.stderr @@ -0,0 +1,16 @@ +error[E0283]: type annotations needed: cannot satisfy `Foo: Send` + --> $DIR/dont-type_of-tait-in-defining-scope.rs:16:18 + | +LL | needs_send::<Foo>(); + | ^^^ + | + = note: cannot satisfy `Foo: Send` +note: required by a bound in `needs_send` + --> $DIR/dont-type_of-tait-in-defining-scope.rs:13:18 + | +LL | fn needs_send<T: Send>() {} + | ^^^^ required by this bound in `needs_send` + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0283`. diff --git a/tests/ui/traits/next-solver/dont-type_of-tait-in-defining-scope.rs b/tests/ui/traits/next-solver/dont-type_of-tait-in-defining-scope.rs new file mode 100644 index 000000000..a1f38e69e --- /dev/null +++ b/tests/ui/traits/next-solver/dont-type_of-tait-in-defining-scope.rs @@ -0,0 +1,24 @@ +// revisions: is_send not_send +// compile-flags: -Znext-solver +//[is_send] check-pass + +#![feature(type_alias_impl_trait)] + +#[cfg(is_send)] +type Foo = impl Send; + +#[cfg(not_send)] +type Foo = impl Sized; + +fn needs_send<T: Send>() {} + +fn test(_: Foo) { + needs_send::<Foo>(); + //[not_send]~^ ERROR type annotations needed: cannot satisfy `Foo: Send` +} + +fn defines(_: Foo) { + let _: Foo = (); +} + +fn main() {} diff --git a/tests/ui/traits/next-solver/dyn-any-dont-prefer-impl.rs b/tests/ui/traits/next-solver/dyn-any-dont-prefer-impl.rs new file mode 100644 index 000000000..bb1c24a00 --- /dev/null +++ b/tests/ui/traits/next-solver/dyn-any-dont-prefer-impl.rs @@ -0,0 +1,17 @@ +// compile-flags: -Znext-solver +// check-pass + +// Test that selection prefers the builtin trait object impl for `Any` +// instead of the user defined impl. Both impls apply to the trait +// object. + +use std::any::Any; + +fn needs_usize(_: &usize) {} + +fn main() { + let x: &dyn Any = &1usize; + if let Some(x) = x.downcast_ref::<usize>() { + needs_usize(x); + } +} diff --git a/tests/ui/traits/next-solver/elaborate-item-bounds.rs b/tests/ui/traits/next-solver/elaborate-item-bounds.rs new file mode 100644 index 000000000..0f1f6c044 --- /dev/null +++ b/tests/ui/traits/next-solver/elaborate-item-bounds.rs @@ -0,0 +1,12 @@ +// compile-flags: -Znext-solver +// check-pass + +trait Foo { + type Bar: Bar; +} + +trait Bar: Baz {} + +trait Baz {} + +fn main() {} diff --git a/tests/ui/traits/next-solver/equating-projection-cyclically.rs b/tests/ui/traits/next-solver/equating-projection-cyclically.rs new file mode 100644 index 000000000..e7c80cfd7 --- /dev/null +++ b/tests/ui/traits/next-solver/equating-projection-cyclically.rs @@ -0,0 +1,31 @@ +// check-pass +// compile-flags: -Znext-solver + +trait Test { + type Assoc; +} + +fn transform<T: Test>(x: Inv<T>) -> Inv<T::Assoc> { + todo!() +} + +impl Test for i32 { + type Assoc = i32; +} + +impl Test for String { + type Assoc = String; +} + +struct Inv<T>(Option<*mut T>); + +fn main() { + let mut x: Inv<_> = Inv(None); + // This ends up equating `Inv<?x>` with `Inv<<?x as Test>::Assoc>` + // which fails the occurs check when generalizing `?x`. + // + // We end up emitting a delayed obligation, causing this to still + // succeed. + x = transform(x); + x = Inv::<i32>(None); +} diff --git a/tests/ui/traits/next-solver/escaping-bound-vars-in-writeback-normalization.rs b/tests/ui/traits/next-solver/escaping-bound-vars-in-writeback-normalization.rs new file mode 100644 index 000000000..77bedc351 --- /dev/null +++ b/tests/ui/traits/next-solver/escaping-bound-vars-in-writeback-normalization.rs @@ -0,0 +1,18 @@ +// compile-flags: -Znext-solver +// check-pass + +trait Trivial { + type Assoc; +} + +impl<T: ?Sized> Trivial for T { + type Assoc = (); +} + +fn main() { + // During writeback, we call `normalize_erasing_regions`, which will walk past + // the `for<'a>` binder and try to normalize `<&'a () as Trivial>::Assoc` directly. + // We need to handle this case in the new deep normalizer similarly to how it + // is handled in the old solver. + let x: Option<for<'a> fn(<&'a () as Trivial>::Assoc)> = None; +} diff --git a/tests/ui/traits/next-solver/float-canonical.rs b/tests/ui/traits/next-solver/float-canonical.rs new file mode 100644 index 000000000..90d75bacb --- /dev/null +++ b/tests/ui/traits/next-solver/float-canonical.rs @@ -0,0 +1,8 @@ +// compile-flags: -Znext-solver +// check-pass + +fn foo(x: f64) { + let y = x + 1.0; +} + +fn main() {} diff --git a/tests/ui/traits/next-solver/fn-trait-closure.rs b/tests/ui/traits/next-solver/fn-trait-closure.rs new file mode 100644 index 000000000..cd2ae1f6f --- /dev/null +++ b/tests/ui/traits/next-solver/fn-trait-closure.rs @@ -0,0 +1,8 @@ +// compile-flags: -Znext-solver +// check-pass + +fn require_fn(_: impl Fn() -> i32) {} + +fn main() { + require_fn(|| -> i32 { 1i32 }); +} diff --git a/tests/ui/traits/next-solver/fn-trait.rs b/tests/ui/traits/next-solver/fn-trait.rs new file mode 100644 index 000000000..1e3d8a21c --- /dev/null +++ b/tests/ui/traits/next-solver/fn-trait.rs @@ -0,0 +1,32 @@ +// compile-flags: -Znext-solver + +fn require_fn(_: impl Fn() -> i32) {} + +fn f() -> i32 { + 1i32 +} + +extern "C" fn g() -> i32 { + 2i32 +} + +unsafe fn h() -> i32 { + 2i32 +} + +fn main() { + require_fn(f); + require_fn(f as fn() -> i32); + require_fn(f as unsafe fn() -> i32); + //~^ ERROR: expected a `Fn()` closure, found `unsafe fn() -> i32` + //~| ERROR: type mismatch resolving `<unsafe fn() -> i32 as FnOnce<()>>::Output == i32` + require_fn(g); + //~^ ERROR: expected a `Fn()` closure, found `extern "C" fn() -> i32 {g}` + //~| ERROR: type mismatch resolving `<extern "C" fn() -> i32 {g} as FnOnce<()>>::Output == i32` + require_fn(g as extern "C" fn() -> i32); + //~^ ERROR: expected a `Fn()` closure, found `extern "C" fn() -> i32` + //~| ERROR: type mismatch resolving `<extern "C" fn() -> i32 as FnOnce<()>>::Output == i32` + require_fn(h); + //~^ ERROR: expected a `Fn()` closure, found `unsafe fn() -> i32 {h}` + //~| ERROR: type mismatch resolving `<unsafe fn() -> i32 {h} as FnOnce<()>>::Output == i32` +} diff --git a/tests/ui/traits/next-solver/fn-trait.stderr b/tests/ui/traits/next-solver/fn-trait.stderr new file mode 100644 index 000000000..e33487235 --- /dev/null +++ b/tests/ui/traits/next-solver/fn-trait.stderr @@ -0,0 +1,126 @@ +error[E0277]: expected a `Fn()` closure, found `unsafe fn() -> i32` + --> $DIR/fn-trait.rs:20:16 + | +LL | require_fn(f as unsafe fn() -> i32); + | ---------- ^^^^^^^^^^^^^^^^^^^^^^^ call the function in a closure: `|| unsafe { /* code */ }` + | | + | required by a bound introduced by this call + | + = help: the trait `Fn<()>` is not implemented for `unsafe fn() -> i32` + = note: unsafe function cannot be called generically without an unsafe block + = note: wrap the `unsafe fn() -> i32` in a closure with no arguments: `|| { /* code */ }` +note: required by a bound in `require_fn` + --> $DIR/fn-trait.rs:3:23 + | +LL | fn require_fn(_: impl Fn() -> i32) {} + | ^^^^^^^^^^^ required by this bound in `require_fn` + +error[E0271]: type mismatch resolving `<unsafe fn() -> i32 as FnOnce<()>>::Output == i32` + --> $DIR/fn-trait.rs:20:16 + | +LL | require_fn(f as unsafe fn() -> i32); + | ---------- ^^^^^^^^^^^^^^^^^^^^^^^ types differ + | | + | required by a bound introduced by this call + | +note: required by a bound in `require_fn` + --> $DIR/fn-trait.rs:3:31 + | +LL | fn require_fn(_: impl Fn() -> i32) {} + | ^^^ required by this bound in `require_fn` + +error[E0277]: expected a `Fn()` closure, found `extern "C" fn() -> i32 {g}` + --> $DIR/fn-trait.rs:23:16 + | +LL | require_fn(g); + | ---------- ^ expected an `Fn()` closure, found `extern "C" fn() -> i32 {g}` + | | + | required by a bound introduced by this call + | + = help: the trait `Fn<()>` is not implemented for fn item `extern "C" fn() -> i32 {g}` + = note: wrap the `extern "C" fn() -> i32 {g}` in a closure with no arguments: `|| { /* code */ }` +note: required by a bound in `require_fn` + --> $DIR/fn-trait.rs:3:23 + | +LL | fn require_fn(_: impl Fn() -> i32) {} + | ^^^^^^^^^^^ required by this bound in `require_fn` + +error[E0271]: type mismatch resolving `<extern "C" fn() -> i32 {g} as FnOnce<()>>::Output == i32` + --> $DIR/fn-trait.rs:23:16 + | +LL | require_fn(g); + | ---------- ^ types differ + | | + | required by a bound introduced by this call + | +note: required by a bound in `require_fn` + --> $DIR/fn-trait.rs:3:31 + | +LL | fn require_fn(_: impl Fn() -> i32) {} + | ^^^ required by this bound in `require_fn` + +error[E0277]: expected a `Fn()` closure, found `extern "C" fn() -> i32` + --> $DIR/fn-trait.rs:26:16 + | +LL | require_fn(g as extern "C" fn() -> i32); + | ---------- ^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected an `Fn()` closure, found `extern "C" fn() -> i32` + | | + | required by a bound introduced by this call + | + = help: the trait `Fn<()>` is not implemented for `extern "C" fn() -> i32` + = note: wrap the `extern "C" fn() -> i32` in a closure with no arguments: `|| { /* code */ }` +note: required by a bound in `require_fn` + --> $DIR/fn-trait.rs:3:23 + | +LL | fn require_fn(_: impl Fn() -> i32) {} + | ^^^^^^^^^^^ required by this bound in `require_fn` + +error[E0271]: type mismatch resolving `<extern "C" fn() -> i32 as FnOnce<()>>::Output == i32` + --> $DIR/fn-trait.rs:26:16 + | +LL | require_fn(g as extern "C" fn() -> i32); + | ---------- ^^^^^^^^^^^^^^^^^^^^^^^^^^^ types differ + | | + | required by a bound introduced by this call + | +note: required by a bound in `require_fn` + --> $DIR/fn-trait.rs:3:31 + | +LL | fn require_fn(_: impl Fn() -> i32) {} + | ^^^ required by this bound in `require_fn` + +error[E0277]: expected a `Fn()` closure, found `unsafe fn() -> i32 {h}` + --> $DIR/fn-trait.rs:29:16 + | +LL | require_fn(h); + | ---------- ^ call the function in a closure: `|| unsafe { /* code */ }` + | | + | required by a bound introduced by this call + | + = help: the trait `Fn<()>` is not implemented for fn item `unsafe fn() -> i32 {h}` + = note: unsafe function cannot be called generically without an unsafe block + = note: wrap the `unsafe fn() -> i32 {h}` in a closure with no arguments: `|| { /* code */ }` +note: required by a bound in `require_fn` + --> $DIR/fn-trait.rs:3:23 + | +LL | fn require_fn(_: impl Fn() -> i32) {} + | ^^^^^^^^^^^ required by this bound in `require_fn` + +error[E0271]: type mismatch resolving `<unsafe fn() -> i32 {h} as FnOnce<()>>::Output == i32` + --> $DIR/fn-trait.rs:29:16 + | +LL | require_fn(h); + | ---------- ^ types differ + | | + | required by a bound introduced by this call + | +note: required by a bound in `require_fn` + --> $DIR/fn-trait.rs:3:31 + | +LL | fn require_fn(_: impl Fn() -> i32) {} + | ^^^ required by this bound in `require_fn` + +error: aborting due to 8 previous errors + +Some errors have detailed explanations: E0271, E0277. +For more information about an error, try `rustc --explain E0271`. diff --git a/tests/ui/traits/next-solver/generalize/generalize-proj-new-universe-index-1.rs b/tests/ui/traits/next-solver/generalize/generalize-proj-new-universe-index-1.rs new file mode 100644 index 000000000..4a70bd5f8 --- /dev/null +++ b/tests/ui/traits/next-solver/generalize/generalize-proj-new-universe-index-1.rs @@ -0,0 +1,73 @@ +// compile-flags: -Znext-solver +// check-pass + +// A minimization of an ambiguity when using typenum. See +// https://github.com/rust-lang/trait-system-refactor-initiative/issues/55 +// for more details. +trait Id { + type Assoc: ?Sized; +} +impl<T: ?Sized> Id for T { + type Assoc = T; +} + +trait WithAssoc<T: ?Sized> { + type Assoc: ?Sized; +} + + +struct Leaf; +struct Wrapper<U: ?Sized>(U); + +impl<U: ?Sized> WithAssoc<U> for Leaf { + type Assoc = U; +} + +impl<Ul: ?Sized, Ur: ?Sized> WithAssoc<Wrapper<Ur>> for Wrapper<Ul> +where + Ul: WithAssoc<Ur>, +{ + type Assoc = <<Ul as WithAssoc<Ur>>::Assoc as Id>::Assoc; +} + +fn bound<T: ?Sized, U: ?Sized, V: ?Sized>() +where + T: WithAssoc<U, Assoc = V>, +{ +} + +// normalize self type to `Wrapper<Leaf>` +// This succeeds, HOWEVER, instantiating the query response previously +// incremented the universe index counter. +// equate impl headers: +// <Wrapper<Leaf> as WithAssoc<<Wrapper<Leaf> as Id>::Assoc>> +// <Wrapper<?2t> as WithAssoc<Wrapper<?3t>>> +// ~> AliasRelate(<Wrapper<Leaf> as Id>::Assoc, Equate, Wrapper<?3t>) +// add where bounds: +// ~> Leaf: WithAssoc<?3t> +// equate with assoc type: +// ?0t +// <Leaf as WithAssoc<?3t>>::Assoc as Id>::Assoc +// ~> AliasRelate( +// <<Leaf as WithAssoc<?3t>>::Assoc as Id>::Assoc, +// Equate, +// <<Leaf as WithAssoc<?4t>>::Assoc as Id>::Assoc, +// ) +// +// We do not reuse `?3t` during generalization because `?0t` cannot name `?4t` as we created +// it after incrementing the universe index while normalizing the self type. +// +// evaluate_added_goals_and_make_query_response: +// AliasRelate(<Wrapper<Leaf> as Id>::Assoc, Equate, Wrapper<?3t>) +// YES, constrains ?3t to Leaf +// AliasRelate( +// <<Leaf as WithAssoc<Leaf>>::Assoc as Id>::Assoc, +// Equate, +// <<Leaf as WithAssoc<?4t>>::Assoc as Id>::Assoc, +// ) +// +// Normalizing <<Leaf as WithAssoc<?4t>>::Assoc as Id>::Assoc then *correctly* +// results in ambiguity. +fn main() { + bound::<<Wrapper<Leaf> as Id>::Assoc, <Wrapper<Leaf> as Id>::Assoc, _>() +} diff --git a/tests/ui/traits/next-solver/generalize/generalize-proj-new-universe-index-2.rs b/tests/ui/traits/next-solver/generalize/generalize-proj-new-universe-index-2.rs new file mode 100644 index 000000000..70758e7de --- /dev/null +++ b/tests/ui/traits/next-solver/generalize/generalize-proj-new-universe-index-2.rs @@ -0,0 +1,75 @@ +// compile-flags: -Znext-solver +// known-bug: trait-system-refactor-initiative#60 + +// Generalizing a projection containing an inference variable +// which cannot be named by the `root_vid` can result in ambiguity. +// +// Because we do not decrement the universe index when exiting a forall, +// this can cause unexpected failures. +// +// See generalize-proj-new-universe-index-1.rs for more details. + +// For this reproduction we need: +// - an inference variable with a lower universe +// - enter a binder to increment the current universe +// - create a new inference variable which is constrained by proving a goal +// - equate a projection containing the new variable with the first variable +// - generalization creates yet another inference variable which is then +// part of an alias-relate, resulting this to fail with ambiguity. +// +// Because we need to enter the binder in-between the creation of the first +// and second inference variable, this is easiest via +// `assemble_candidates_after_normalizing_self_ty` because eagerly call +// `try_evaluate_added_goals` there before creating the inference variables +// for the impl parameters. +trait Id { + type Assoc: ?Sized; +} +impl<T: ?Sized> Id for T { + type Assoc = T; +} + +// By adding an higher ranked bound to the impl we currently +// propagate this bound to the caller, forcing us to create a new +// universe. +trait IdHigherRankedBound { + type Assoc: ?Sized; +} + +impl<T: ?Sized> IdHigherRankedBound for T +where + for<'a> T: 'a, +{ + type Assoc = T; +} + +trait WithAssoc<T: ?Sized> { + type Assoc: ?Sized; +} + + +struct Leaf; +struct Wrapper<U: ?Sized>(U); +struct Rigid; + +impl<U: ?Sized> WithAssoc<U> for Leaf { + type Assoc = U; +} + + +impl<Ur: ?Sized> WithAssoc<Wrapper<Ur>> for Rigid +where + Leaf: WithAssoc<Ur>, +{ + type Assoc = <<Leaf as WithAssoc<Ur>>::Assoc as Id>::Assoc; +} + +fn bound<T: ?Sized, U: ?Sized, V: ?Sized>() +where + T: WithAssoc<U, Assoc = V>, +{ +} + +fn main() { + bound::<<Rigid as IdHigherRankedBound>::Assoc, <Wrapper<Leaf> as Id>::Assoc, _>() +} diff --git a/tests/ui/traits/next-solver/generalize/generalize-proj-new-universe-index-2.stderr b/tests/ui/traits/next-solver/generalize/generalize-proj-new-universe-index-2.stderr new file mode 100644 index 000000000..4548ab1e2 --- /dev/null +++ b/tests/ui/traits/next-solver/generalize/generalize-proj-new-universe-index-2.stderr @@ -0,0 +1,19 @@ +error[E0284]: type annotations needed + --> $DIR/generalize-proj-new-universe-index-2.rs:74:5 + | +LL | bound::<<Rigid as IdHigherRankedBound>::Assoc, <Wrapper<Leaf> as Id>::Assoc, _>() + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ cannot infer type of the type parameter `V` declared on the function `bound` + | + = note: cannot satisfy `<<Rigid as IdHigherRankedBound>::Assoc as WithAssoc<<Wrapper<Leaf> as Id>::Assoc>>::Assoc == _` +note: required by a bound in `bound` + --> $DIR/generalize-proj-new-universe-index-2.rs:69:21 + | +LL | fn bound<T: ?Sized, U: ?Sized, V: ?Sized>() + | ----- required by a bound in this function +LL | where +LL | T: WithAssoc<U, Assoc = V>, + | ^^^^^^^^^ required by this bound in `bound` + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0284`. diff --git a/tests/ui/traits/next-solver/generalize/occurs-check-nested-alias.next.stderr b/tests/ui/traits/next-solver/generalize/occurs-check-nested-alias.next.stderr new file mode 100644 index 000000000..ad8b24a39 --- /dev/null +++ b/tests/ui/traits/next-solver/generalize/occurs-check-nested-alias.next.stderr @@ -0,0 +1,11 @@ +error[E0275]: overflow evaluating the requirement `<<T as Id<_>>::Id as Unnormalizable>::Assoc == _` + --> $DIR/occurs-check-nested-alias.rs:36:9 + | +LL | x = y; + | ^ + | + = help: consider increasing the recursion limit by adding a `#![recursion_limit = "256"]` attribute to your crate (`occurs_check_nested_alias`) + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0275`. diff --git a/tests/ui/traits/next-solver/generalize/occurs-check-nested-alias.rs b/tests/ui/traits/next-solver/generalize/occurs-check-nested-alias.rs new file mode 100644 index 000000000..e51508d68 --- /dev/null +++ b/tests/ui/traits/next-solver/generalize/occurs-check-nested-alias.rs @@ -0,0 +1,38 @@ +// revisions: old next +//[old] check-pass + +// Currently always fails to generalize the outer alias, even if it +// is treated as rigid by `alias-relate`. +//[next] compile-flags: -Znext-solver +//[next] known-bug: trait-system-refactor-initiative#8 +#![crate_type = "lib"] +#![allow(unused)] +trait Unnormalizable { + type Assoc; +} + +trait Id<T> { + type Id; +} +impl<T, U> Id<T> for U { + type Id = U; +} + +struct Inv<T>(*mut T); + +fn unconstrained<T>() -> T { + todo!() +} + +fn create<T, U: Unnormalizable>( + x: &U, +) -> (Inv<T>, Inv<<<U as Id<T>>::Id as Unnormalizable>::Assoc>) { + todo!() +} + +fn foo<T: Unnormalizable>() { + let q = unconstrained(); + let (mut x, y) = create::<_, _>(&q); + x = y; + drop::<T>(q); +} diff --git a/tests/ui/traits/next-solver/higher-ranked-dyn-bounds.rs b/tests/ui/traits/next-solver/higher-ranked-dyn-bounds.rs new file mode 100644 index 000000000..b87210d7f --- /dev/null +++ b/tests/ui/traits/next-solver/higher-ranked-dyn-bounds.rs @@ -0,0 +1,17 @@ +// compile-flags: -Znext-solver +// check-pass + +trait Trait<'a> { + type Item: for<'b> Trait2<'b>; +} + +trait Trait2<'a> {} +impl Trait2<'_> for () {} + +fn needs_trait(_: Box<impl for<'a> Trait<'a> + ?Sized>) {} + +fn foo(x: Box<dyn for<'a> Trait<'a, Item = ()>>) { + needs_trait(x); +} + +fn main() {} diff --git a/tests/ui/traits/next-solver/int-var-alias-eq.rs b/tests/ui/traits/next-solver/int-var-alias-eq.rs new file mode 100644 index 000000000..26ba7f8e5 --- /dev/null +++ b/tests/ui/traits/next-solver/int-var-alias-eq.rs @@ -0,0 +1,18 @@ +// check-pass +// compile-flags: -Znext-solver + +// HIR typeck ends up equating `<?0i as Add>::Output == ?0i`. +// Want to make sure that we emit an alias-eq goal for this, +// instead of treating it as a type error and bailing. + +fn test() { + // fallback + let x = 1 + 2; +} + +fn test2() -> u32 { + // expectation from return ty + 1 + 2 +} + +fn main() {} diff --git a/tests/ui/traits/next-solver/int-var-is-send.rs b/tests/ui/traits/next-solver/int-var-is-send.rs new file mode 100644 index 000000000..d8b963f20 --- /dev/null +++ b/tests/ui/traits/next-solver/int-var-is-send.rs @@ -0,0 +1,8 @@ +// compile-flags: -Znext-solver +// check-pass + +fn needs_send(_: impl Send) {} + +fn main() { + needs_send(1); +} diff --git a/tests/ui/traits/next-solver/issue-118950-root-region.rs b/tests/ui/traits/next-solver/issue-118950-root-region.rs new file mode 100644 index 000000000..10fb7d525 --- /dev/null +++ b/tests/ui/traits/next-solver/issue-118950-root-region.rs @@ -0,0 +1,22 @@ +// compile-flags: -Znext-solver +// +// This is a gnarly test but I don't know how to minimize it, frankly. + +#![feature(lazy_type_alias)] +//~^ WARN the feature `lazy_type_alias` is incomplete + +trait ToUnit<'a> { + type Unit; +} + +trait Overlap<T> {} + +type Assoc<'a, T> = <*const T as ToUnit<'a>>::Unit; + +impl<T> Overlap<T> for T {} + +impl<T> Overlap<for<'a> fn(Assoc<'a, T>)> for T where Missing: Overlap<T> {} +//~^ ERROR conflicting implementations of trait `Overlap<fn(_)>` for type `fn(_)` +//~| ERROR cannot find type `Missing` in this scope + +fn main() {} diff --git a/tests/ui/traits/next-solver/issue-118950-root-region.stderr b/tests/ui/traits/next-solver/issue-118950-root-region.stderr new file mode 100644 index 000000000..c16a48d5f --- /dev/null +++ b/tests/ui/traits/next-solver/issue-118950-root-region.stderr @@ -0,0 +1,36 @@ +error[E0412]: cannot find type `Missing` in this scope + --> $DIR/issue-118950-root-region.rs:18:55 + | +LL | impl<T> Overlap<for<'a> fn(Assoc<'a, T>)> for T where Missing: Overlap<T> {} + | ^^^^^^^ not found in this scope + +warning: the feature `lazy_type_alias` is incomplete and may not be safe to use and/or cause compiler crashes + --> $DIR/issue-118950-root-region.rs:5:12 + | +LL | #![feature(lazy_type_alias)] + | ^^^^^^^^^^^^^^^ + | + = note: see issue #112792 <https://github.com/rust-lang/rust/issues/112792> for more information + = note: `#[warn(incomplete_features)]` on by default + +WARN rustc_infer::infer::relate::generalize may incompletely handle alias type: Alias(Weak, AliasTy { args: [ReBound(DebruijnIndex(0), BoundRegion { var: 0, kind: BrNamed(DefId(0:15 ~ issue_118950_root_region[d54f]::{impl#1}::'a), 'a) }), ?1t], def_id: DefId(0:8 ~ issue_118950_root_region[d54f]::Assoc) }) +WARN rustc_infer::infer::relate::generalize may incompletely handle alias type: Alias(Weak, AliasTy { args: [RePlaceholder(!1_BoundRegion { var: 0, kind: BrNamed(DefId(0:15 ~ issue_118950_root_region[d54f]::{impl#1}::'a), 'a) }), ?1t], def_id: DefId(0:8 ~ issue_118950_root_region[d54f]::Assoc) }) +WARN rustc_infer::infer::relate::generalize may incompletely handle alias type: Alias(Weak, AliasTy { args: [ReBound(DebruijnIndex(0), BoundRegion { var: 0, kind: BrNamed(DefId(0:15 ~ issue_118950_root_region[d54f]::{impl#1}::'a), 'a) }), ?1t], def_id: DefId(0:8 ~ issue_118950_root_region[d54f]::Assoc) }) +WARN rustc_infer::infer::relate::generalize may incompletely handle alias type: Alias(Weak, AliasTy { args: [RePlaceholder(!1_BoundRegion { var: 0, kind: BrNamed(DefId(0:15 ~ issue_118950_root_region[d54f]::{impl#1}::'a), 'a) }), ?1t], def_id: DefId(0:8 ~ issue_118950_root_region[d54f]::Assoc) }) +WARN rustc_infer::infer::relate::generalize may incompletely handle alias type: Alias(Weak, AliasTy { args: [ReBound(DebruijnIndex(0), BoundRegion { var: 0, kind: BrNamed(DefId(0:15 ~ issue_118950_root_region[d54f]::{impl#1}::'a), 'a) }), ?1t], def_id: DefId(0:8 ~ issue_118950_root_region[d54f]::Assoc) }) +WARN rustc_infer::infer::relate::generalize may incompletely handle alias type: Alias(Weak, AliasTy { args: [RePlaceholder(!1_BoundRegion { var: 0, kind: BrNamed(DefId(0:15 ~ issue_118950_root_region[d54f]::{impl#1}::'a), 'a) }), ?1t], def_id: DefId(0:8 ~ issue_118950_root_region[d54f]::Assoc) }) +WARN rustc_infer::infer::relate::generalize may incompletely handle alias type: Alias(Weak, AliasTy { args: [ReBound(DebruijnIndex(0), BoundRegion { var: 0, kind: BrNamed(DefId(0:15 ~ issue_118950_root_region[d54f]::{impl#1}::'a), 'a) }), ?1t], def_id: DefId(0:8 ~ issue_118950_root_region[d54f]::Assoc) }) +WARN rustc_infer::infer::relate::generalize may incompletely handle alias type: Alias(Weak, AliasTy { args: [RePlaceholder(!1_BoundRegion { var: 0, kind: BrNamed(DefId(0:15 ~ issue_118950_root_region[d54f]::{impl#1}::'a), 'a) }), ?1t], def_id: DefId(0:8 ~ issue_118950_root_region[d54f]::Assoc) }) +error[E0119]: conflicting implementations of trait `Overlap<fn(_)>` for type `fn(_)` + --> $DIR/issue-118950-root-region.rs:18:1 + | +LL | impl<T> Overlap<T> for T {} + | ------------------------ first implementation here +LL | +LL | impl<T> Overlap<for<'a> fn(Assoc<'a, T>)> for T where Missing: Overlap<T> {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `fn(_)` + +error: aborting due to 2 previous errors; 1 warning emitted + +Some errors have detailed explanations: E0119, E0412. +For more information about an error, try `rustc --explain E0119`. diff --git a/tests/ui/traits/next-solver/iter-filter-projection.rs b/tests/ui/traits/next-solver/iter-filter-projection.rs new file mode 100644 index 000000000..f948831ad --- /dev/null +++ b/tests/ui/traits/next-solver/iter-filter-projection.rs @@ -0,0 +1,12 @@ +// compile-flags: -Znext-solver +// check-pass + +use std::{iter, slice}; + +struct Attr; + +fn test<'a, T: Iterator<Item = &'a Attr>>() {} + +fn main() { + test::<iter::Filter<slice::Iter<'_, Attr>, fn(&&Attr) -> bool>>(); +} diff --git a/tests/ui/traits/next-solver/lazy-nested-obligations-1.rs b/tests/ui/traits/next-solver/lazy-nested-obligations-1.rs new file mode 100644 index 000000000..f9e73a93c --- /dev/null +++ b/tests/ui/traits/next-solver/lazy-nested-obligations-1.rs @@ -0,0 +1,13 @@ +// check-pass +// compile-flags: -Znext-solver +// Issue 94358 + +fn foo<C>(_: C) +where + for <'a> &'a C: IntoIterator, + for <'a> <&'a C as IntoIterator>::IntoIter: ExactSizeIterator, +{} + +fn main() { + foo::<_>(vec![true, false]); +} diff --git a/tests/ui/traits/next-solver/lazy-nested-obligations-2.rs b/tests/ui/traits/next-solver/lazy-nested-obligations-2.rs new file mode 100644 index 000000000..b85f9d973 --- /dev/null +++ b/tests/ui/traits/next-solver/lazy-nested-obligations-2.rs @@ -0,0 +1,22 @@ +// compile-flags: -Znext-solver +// check-pass + +pub trait With { + type F; +} + +impl With for i32 { + type F = fn(&str); +} + +fn f(_: &str) {} + +fn main() { + let _: V<i32> = V(f); + pub struct V<T: With>(<T as With>::F); + + pub enum E3<T: With> { + Var(<T as With>::F), + } + let _: E3<i32> = E3::Var(f); +} diff --git a/tests/ui/traits/next-solver/lazy-nested-obligations-3.rs b/tests/ui/traits/next-solver/lazy-nested-obligations-3.rs new file mode 100644 index 000000000..5fb4832dd --- /dev/null +++ b/tests/ui/traits/next-solver/lazy-nested-obligations-3.rs @@ -0,0 +1,38 @@ +// check-pass +// compile-flags: -Znext-solver +// Issue 96750 + +use std::marker::PhantomData; + +trait AsyncFn<Arg> { + type Output; +} +trait RequestFamily { + type Type<'a>; +} +trait Service {} + +struct MyFn; +impl AsyncFn<String> for MyFn { + type Output = (); +} + +impl RequestFamily for String { + type Type<'a> = String; +} + +struct ServiceFromAsyncFn<F, Req>(F, PhantomData<Req>); + +impl<F, Req, O> Service for ServiceFromAsyncFn<F, Req> +where + Req: RequestFamily, + F: AsyncFn<Req>, + F: for<'a> AsyncFn<Req::Type<'a>, Output = O>, +{ +} + +fn assert_service() -> impl Service { + ServiceFromAsyncFn(MyFn, PhantomData) +} + +fn main() {} diff --git a/tests/ui/traits/next-solver/member-constraints-in-root-universe.rs b/tests/ui/traits/next-solver/member-constraints-in-root-universe.rs new file mode 100644 index 000000000..16e95e94c --- /dev/null +++ b/tests/ui/traits/next-solver/member-constraints-in-root-universe.rs @@ -0,0 +1,17 @@ +// compile-flags: -Znext-solver +// check-pass + +trait Trait { + type Ty; +} + +impl Trait for for<'a> fn(&'a u8, &'a u8) { + type Ty = (); +} + +// argument is necessary to create universes before registering the hidden type. +fn test<'a>(_: <fn(&u8, &u8) as Trait>::Ty) -> impl Sized { + "hidden type is `&'?0 str` with '?0 member of ['static,]" +} + +fn main() {} diff --git a/tests/ui/traits/next-solver/more-object-bound.rs b/tests/ui/traits/next-solver/more-object-bound.rs new file mode 100644 index 000000000..8522f034d --- /dev/null +++ b/tests/ui/traits/next-solver/more-object-bound.rs @@ -0,0 +1,27 @@ +// compile-flags: -Znext-solver +// From #80800 + +trait SuperTrait { + type A; + type B; +} + +trait Trait: SuperTrait<A = <Self as SuperTrait>::B> {} + +fn transmute<A, B>(x: A) -> B { + foo::<A, B, dyn Trait<A = A, B = B>>(x) + //~^ ERROR the trait bound `dyn Trait<A = A, B = B>: Trait` is not satisfied +} + +fn foo<A, B, T: ?Sized>(x: T::A) -> B +where + T: Trait<B = B>, +{ + x +} + +static X: u8 = 0; +fn main() { + let x = transmute::<&u8, &[u8; 1_000_000]>(&X); + println!("{:?}", x[100_000]); +} diff --git a/tests/ui/traits/next-solver/more-object-bound.stderr b/tests/ui/traits/next-solver/more-object-bound.stderr new file mode 100644 index 000000000..e3be2931e --- /dev/null +++ b/tests/ui/traits/next-solver/more-object-bound.stderr @@ -0,0 +1,22 @@ +error[E0277]: the trait bound `dyn Trait<A = A, B = B>: Trait` is not satisfied + --> $DIR/more-object-bound.rs:12:5 + | +LL | foo::<A, B, dyn Trait<A = A, B = B>>(x) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Trait` is not implemented for `dyn Trait<A = A, B = B>` + | +note: required by a bound in `foo` + --> $DIR/more-object-bound.rs:18:8 + | +LL | fn foo<A, B, T: ?Sized>(x: T::A) -> B + | --- required by a bound in this function +LL | where +LL | T: Trait<B = B>, + | ^^^^^^^^^^^^ required by this bound in `foo` +help: consider introducing a `where` clause, but there might be an alternative better way to express this requirement + | +LL | fn transmute<A, B>(x: A) -> B where dyn Trait<A = A, B = B>: Trait { + | ++++++++++++++++++++++++++++++++++++ + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/traits/next-solver/negative-coherence-bounds.rs b/tests/ui/traits/next-solver/negative-coherence-bounds.rs new file mode 100644 index 000000000..5436b02c3 --- /dev/null +++ b/tests/ui/traits/next-solver/negative-coherence-bounds.rs @@ -0,0 +1,40 @@ +// check-pass + +// This test verifies that negative trait predicate cannot be satisfied from a +// positive param-env candidate. + +// Negative coherence is one of the only places where we actually construct and +// evaluate negative predicates. Specifically, when verifying whether the first +// and second impls below overlap, we do not want to consider them disjoint, +// otherwise the second impl would be missing an associated type `type Item` +// which is provided by the first impl that it is specializing. + +#![feature(specialization)] +//~^ WARN the feature `specialization` is incomplete +#![feature(with_negative_coherence)] + +trait BoxIter { + type Item; + + fn last(self) -> Option<Self::Item>; +} + +impl<I: Iterator + ?Sized> BoxIter for Box<I> { + type Item = I::Item; + + default fn last(self) -> Option<I::Item> { + todo!() + } +} + +// When checking that this impl does/doesn't overlap the one above, we evaluate +// a negative version of all of the where-clause predicates of the impl below. +// For `I: !Iterator`, we should make sure that the param-env clause `I: Iterator` +// from above doesn't satisfy this predicate. +impl<I: Iterator> BoxIter for Box<I> { + fn last(self) -> Option<I::Item> { + (*self).last() + } +} + +fn main() {} diff --git a/tests/ui/traits/next-solver/negative-coherence-bounds.stderr b/tests/ui/traits/next-solver/negative-coherence-bounds.stderr new file mode 100644 index 000000000..4127f51f5 --- /dev/null +++ b/tests/ui/traits/next-solver/negative-coherence-bounds.stderr @@ -0,0 +1,12 @@ +warning: the feature `specialization` is incomplete and may not be safe to use and/or cause compiler crashes + --> $DIR/negative-coherence-bounds.rs:12:12 + | +LL | #![feature(specialization)] + | ^^^^^^^^^^^^^^ + | + = note: see issue #31844 <https://github.com/rust-lang/rust/issues/31844> for more information + = help: consider using `min_specialization` instead, which is more stable and complete + = note: `#[warn(incomplete_features)]` on by default + +warning: 1 warning emitted + diff --git a/tests/ui/traits/next-solver/nested-alias-bound.rs b/tests/ui/traits/next-solver/nested-alias-bound.rs new file mode 100644 index 000000000..2e3de0ac6 --- /dev/null +++ b/tests/ui/traits/next-solver/nested-alias-bound.rs @@ -0,0 +1,20 @@ +// compile-flags: -Znext-solver +// check-pass + +trait A { + type A: B; +} + +trait B { + type B: C; +} + +trait C {} + +fn needs_c<T: C>() {} + +fn test<T: A>() { + needs_c::<<T::A as B>::B>(); +} + +fn main() {} diff --git a/tests/ui/traits/next-solver/nested-obligations-with-bound-vars-gat.rs b/tests/ui/traits/next-solver/nested-obligations-with-bound-vars-gat.rs new file mode 100644 index 000000000..94c6c2856 --- /dev/null +++ b/tests/ui/traits/next-solver/nested-obligations-with-bound-vars-gat.rs @@ -0,0 +1,43 @@ +// check-pass +// compile-flags: -Znext-solver +// Issue 96230 + +use std::fmt::Debug; + +trait Classic { + type Assoc; +} + +trait Gat { + type Assoc<'a>; +} + +struct Foo; + +impl Classic for Foo { + type Assoc = (); +} + +impl Gat for Foo { + type Assoc<'i> = (); +} + +fn classic_debug<T: Classic>(_: T) +where + T::Assoc: Debug, +{ +} + +fn gat_debug<T: Gat>(_: T) +where + for<'a> T::Assoc<'a>: Debug, +{ +} + +fn main() { + classic_debug::<Foo>(Foo); // fine + classic_debug(Foo); // fine + + gat_debug::<Foo>(Foo); // fine + gat_debug(Foo); // boom +} diff --git a/tests/ui/traits/next-solver/normalize-async-closure-in-trait.rs b/tests/ui/traits/next-solver/normalize-async-closure-in-trait.rs new file mode 100644 index 000000000..b58db2be8 --- /dev/null +++ b/tests/ui/traits/next-solver/normalize-async-closure-in-trait.rs @@ -0,0 +1,9 @@ +// compile-flags: -Znext-solver +// check-pass +// edition:2021 + +trait Foo { + async fn bar() {} +} + +fn main() {} diff --git a/tests/ui/traits/next-solver/normalize-param-env-1.rs b/tests/ui/traits/next-solver/normalize-param-env-1.rs new file mode 100644 index 000000000..92d405137 --- /dev/null +++ b/tests/ui/traits/next-solver/normalize-param-env-1.rs @@ -0,0 +1,40 @@ +// check-pass +// compile-flags: -Znext-solver +// Issue 108933 + +trait Add<Rhs> { + type Sum; +} + +impl Add<()> for () { + type Sum = (); +} + +type Unit = <() as Add<()>>::Sum; + +trait Trait<C> { + type Output; +} + +fn f<T>() +where + T: Trait<()>, + <T as Trait<()>>::Output: Sized, +{ +} + +fn g<T>() +where + T: Trait<Unit>, + <T as Trait<()>>::Output: Sized, +{ +} + +fn h<T>() +where + T: Trait<()>, + <T as Trait<Unit>>::Output: Sized, +{ +} + +fn main() {} diff --git a/tests/ui/traits/next-solver/normalize-param-env-2.rs b/tests/ui/traits/next-solver/normalize-param-env-2.rs new file mode 100644 index 000000000..ce084651b --- /dev/null +++ b/tests/ui/traits/next-solver/normalize-param-env-2.rs @@ -0,0 +1,26 @@ +// check-pass +// compile-flags: -Znext-solver +// Issue 92505 + +trait A<T> { + type I; + + fn f() + where + Self::I: A<T>, + { + } +} + +impl<T> A<T> for () { + type I = (); + + fn f() + where + Self::I: A<T>, + { + <() as A<T>>::f(); + } +} + +fn main() {} diff --git a/tests/ui/traits/next-solver/normalize-param-env-3.rs b/tests/ui/traits/next-solver/normalize-param-env-3.rs new file mode 100644 index 000000000..e15e1155a --- /dev/null +++ b/tests/ui/traits/next-solver/normalize-param-env-3.rs @@ -0,0 +1,32 @@ +// check-pass +// compile-flags: -Znext-solver +// Issue 100177 + +trait GenericTrait<T> {} + +trait Channel<I>: GenericTrait<Self::T> { + type T; +} + +trait Sender { + type Msg; + + fn send<C>() + where + C: Channel<Self::Msg>; +} + +impl<T> Sender for T { + type Msg = (); + + fn send<C>() + where + C: Channel<Self::Msg>, + { + } +} + +// This works +fn foo<I, C>(ch: C) where C: Channel<I> {} + +fn main() {} diff --git a/tests/ui/traits/next-solver/normalize-rcvr-for-inherent.rs b/tests/ui/traits/next-solver/normalize-rcvr-for-inherent.rs new file mode 100644 index 000000000..d308b1695 --- /dev/null +++ b/tests/ui/traits/next-solver/normalize-rcvr-for-inherent.rs @@ -0,0 +1,25 @@ +// compile-flags: -Znext-solver +// check-pass + +// Verify that we can assemble inherent impl candidates on a possibly +// unnormalized self type. + +trait Foo { + type Assoc; +} +impl Foo for i32 { + type Assoc = Bar; +} + +struct Bar; +impl Bar { + fn method(&self) {} +} + +fn build<T: Foo>(_: T) -> T::Assoc { + todo!() +} + +fn main() { + build(1i32).method(); +} diff --git a/tests/ui/traits/next-solver/normalize-unsize-rhs.rs b/tests/ui/traits/next-solver/normalize-unsize-rhs.rs new file mode 100644 index 000000000..08bb0cf42 --- /dev/null +++ b/tests/ui/traits/next-solver/normalize-unsize-rhs.rs @@ -0,0 +1,22 @@ +// compile-flags: -Znext-solver +// check-pass +#![feature(trait_upcasting)] + +trait A {} +trait B: A {} + +impl A for usize {} +impl B for usize {} + +trait Mirror { + type Assoc: ?Sized; +} + +impl<T: ?Sized> Mirror for T { + type Assoc = T; +} + +fn main() { + let x = Box::new(1usize) as Box<<dyn B as Mirror>::Assoc>; + let y = x as Box<<dyn A as Mirror>::Assoc>; +} diff --git a/tests/ui/traits/next-solver/normalized-const-built-in-op.rs b/tests/ui/traits/next-solver/normalized-const-built-in-op.rs new file mode 100644 index 000000000..0fffe7b43 --- /dev/null +++ b/tests/ui/traits/next-solver/normalized-const-built-in-op.rs @@ -0,0 +1,11 @@ +// compile-flags: -Znext-solver +// check-pass + +const fn foo() { + let mut x = [1, 2, 3]; + // We need to fix up `<<[i32; 3] as Index<usize>>::Output as AddAssign>` + // to be treated like a built-in operation. + x[1] += 5; +} + +fn main() {} diff --git a/tests/ui/traits/next-solver/normalizes_to_ignores_unnormalizable_candidate.rs b/tests/ui/traits/next-solver/normalizes_to_ignores_unnormalizable_candidate.rs new file mode 100644 index 000000000..7dc87dacc --- /dev/null +++ b/tests/ui/traits/next-solver/normalizes_to_ignores_unnormalizable_candidate.rs @@ -0,0 +1,40 @@ +// [no_self_infer] check-pass +// compile-flags: -Znext-solver +// revisions: self_infer no_self_infer + +// checks that the new solver is smart enough to infer `?0 = U` when solving: +// `normalizes-to(<Vec<?0> as Trait>::Assoc, u8)` +// with `normalizes-to(<Vec<U> as Trait>::Assoc, u8)` in the paramenv even when +// there is a separate `Vec<T>: Trait` bound in the paramenv. +// +// FIXME(-Znext-solver) +// This could also compile for `normalizes-to(<?0 as Trait>::Assoc, u8)` but +// we currently immediately consider a goal ambiguous if the self type is an +// inference variable. + +trait Trait { + type Assoc; +} + +fn foo<T: Trait<Assoc = u8>>(x: T) {} + +#[cfg(self_infer)] +fn unconstrained<T>() -> T { + todo!() +} + +#[cfg(no_self_infer)] +fn unconstrained<T>() -> Vec<T> { + todo!() +} + +fn bar<T, U>() +where + Vec<T>: Trait, + Vec<U>: Trait<Assoc = u8>, +{ + foo(unconstrained()) + //[self_infer]~^ ERROR type annotations needed +} + +fn main() {} diff --git a/tests/ui/traits/next-solver/normalizes_to_ignores_unnormalizable_candidate.self_infer.stderr b/tests/ui/traits/next-solver/normalizes_to_ignores_unnormalizable_candidate.self_infer.stderr new file mode 100644 index 000000000..c1a8b74df --- /dev/null +++ b/tests/ui/traits/next-solver/normalizes_to_ignores_unnormalizable_candidate.self_infer.stderr @@ -0,0 +1,22 @@ +error[E0283]: type annotations needed + --> $DIR/normalizes_to_ignores_unnormalizable_candidate.rs:36:5 + | +LL | foo(unconstrained()) + | ^^^ --------------- type must be known at this point + | | + | cannot infer type of the type parameter `T` declared on the function `foo` + | + = note: cannot satisfy `_: Trait` +note: required by a bound in `foo` + --> $DIR/normalizes_to_ignores_unnormalizable_candidate.rs:19:11 + | +LL | fn foo<T: Trait<Assoc = u8>>(x: T) {} + | ^^^^^^^^^^^^^^^^^ required by this bound in `foo` +help: consider specifying the generic argument + | +LL | foo::<T>(unconstrained()) + | +++++ + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0283`. diff --git a/tests/ui/traits/next-solver/object-soundness-requires-generalization.rs b/tests/ui/traits/next-solver/object-soundness-requires-generalization.rs new file mode 100644 index 000000000..6e709d9ae --- /dev/null +++ b/tests/ui/traits/next-solver/object-soundness-requires-generalization.rs @@ -0,0 +1,20 @@ +// compile-flags: -Znext-solver +// ignore-test + +trait Trait { + type Gat<'lt>; +} +impl Trait for u8 { + type Gat<'lt> = u8; +} + +fn test<T: Trait, F: FnOnce(<T as Trait>::Gat<'_>) -> S + ?Sized, S>() {} + +fn main() { + // Proving `dyn FnOnce: FnOnce` requires making sure that all of the supertraits + // of the trait and associated type bounds hold. We check this in + // `predicates_for_object_candidate`, and eagerly replace projections using equality + // which may generalize a type and emit a nested AliasRelate goal. Make sure that + // we don't ICE in that case, and bubble that goal up to the caller. + test::<u8, dyn FnOnce(<u8 as Trait>::Gat<'_>) + 'static, _>(); +} diff --git a/tests/ui/traits/next-solver/object-unsafety.rs b/tests/ui/traits/next-solver/object-unsafety.rs new file mode 100644 index 000000000..cfa53948b --- /dev/null +++ b/tests/ui/traits/next-solver/object-unsafety.rs @@ -0,0 +1,27 @@ +// compile-flags: -Znext-solver + +trait Setup { + type From: Copy; +} + +fn copy<U: Setup + ?Sized>(from: &U::From) -> U::From { + *from +} + +pub fn copy_any<T>(t: &T) -> T { + copy::<dyn Setup<From=T>>(t) + //~^ ERROR the type `&<dyn Setup<From = T> as Setup>::From` is not well-formed + //~| ERROR the trait bound `dyn Setup<From = T>: Setup` is not satisfied + //~| ERROR mismatched types + //~| ERROR the type `<dyn Setup<From = T> as Setup>::From` is not well-formed + //~| ERROR the size for values of type `<dyn Setup<From = T> as Setup>::From` cannot be known at compilation time + + // FIXME(-Znext-solver): These error messages are horrible and some of them + // are even simple fallout from previous error. +} + +fn main() { + let x = String::from("Hello, world"); + let y = copy_any(&x); + println!("{y}"); +} diff --git a/tests/ui/traits/next-solver/object-unsafety.stderr b/tests/ui/traits/next-solver/object-unsafety.stderr new file mode 100644 index 000000000..ee38c256e --- /dev/null +++ b/tests/ui/traits/next-solver/object-unsafety.stderr @@ -0,0 +1,64 @@ +error[E0277]: the trait bound `dyn Setup<From = T>: Setup` is not satisfied + --> $DIR/object-unsafety.rs:12:12 + | +LL | copy::<dyn Setup<From=T>>(t) + | ^^^^^^^^^^^^^^^^^ the trait `Setup` is not implemented for `dyn Setup<From = T>` + | +note: required by a bound in `copy` + --> $DIR/object-unsafety.rs:7:12 + | +LL | fn copy<U: Setup + ?Sized>(from: &U::From) -> U::From { + | ^^^^^ required by this bound in `copy` +help: consider introducing a `where` clause, but there might be an alternative better way to express this requirement + | +LL | pub fn copy_any<T>(t: &T) -> T where dyn Setup<From = T>: Setup { + | ++++++++++++++++++++++++++++++++ + +error: the type `&<dyn Setup<From = T> as Setup>::From` is not well-formed + --> $DIR/object-unsafety.rs:12:31 + | +LL | copy::<dyn Setup<From=T>>(t) + | ^ + +error[E0308]: mismatched types + --> $DIR/object-unsafety.rs:12:31 + | +LL | copy::<dyn Setup<From=T>>(t) + | ------------------------- ^ types differ + | | + | arguments to this function are incorrect + | + = note: expected reference `&<dyn Setup<From = T> as Setup>::From` + found reference `&T` +note: function defined here + --> $DIR/object-unsafety.rs:7:4 + | +LL | fn copy<U: Setup + ?Sized>(from: &U::From) -> U::From { + | ^^^^ -------------- + +error: the type `<dyn Setup<From = T> as Setup>::From` is not well-formed + --> $DIR/object-unsafety.rs:12:5 + | +LL | copy::<dyn Setup<From=T>>(t) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error[E0277]: the size for values of type `<dyn Setup<From = T> as Setup>::From` cannot be known at compilation time + --> $DIR/object-unsafety.rs:12:5 + | +LL | copy::<dyn Setup<From=T>>(t) + | ^^^^^^^^^^^^^^^^^^^^^^^^^--- + | | + | doesn't have a size known at compile-time + | this returned value is of type `<dyn Setup<From = T> as Setup>::From` + | + = help: the trait `Sized` is not implemented for `<dyn Setup<From = T> as Setup>::From` + = note: the return type of a function must have a statically known size +help: consider further restricting the associated type + | +LL | pub fn copy_any<T>(t: &T) -> T where <dyn Setup<From = T> as Setup>::From: Sized { + | +++++++++++++++++++++++++++++++++++++++++++++++++ + +error: aborting due to 5 previous errors + +Some errors have detailed explanations: E0277, E0308. +For more information about an error, try `rustc --explain E0277`. diff --git a/tests/ui/traits/next-solver/opportunistic-region-resolve.rs b/tests/ui/traits/next-solver/opportunistic-region-resolve.rs new file mode 100644 index 000000000..d852332d0 --- /dev/null +++ b/tests/ui/traits/next-solver/opportunistic-region-resolve.rs @@ -0,0 +1,19 @@ +// compile-flags: -Znext-solver +// check-pass + +#![feature(rustc_attrs)] + +#[rustc_coinductive] +trait Trait {} + +#[rustc_coinductive] +trait Indirect {} +impl<T: Trait + ?Sized> Indirect for T {} + +impl<'a> Trait for &'a () where &'a (): Indirect {} + +fn impls_trait<T: Trait>() {} + +fn main() { + impls_trait::<&'static ()>(); +} diff --git a/tests/ui/traits/next-solver/overflow/exponential-trait-goals.rs b/tests/ui/traits/next-solver/overflow/exponential-trait-goals.rs new file mode 100644 index 000000000..a465bcecf --- /dev/null +++ b/tests/ui/traits/next-solver/overflow/exponential-trait-goals.rs @@ -0,0 +1,19 @@ +// compile-flags: -Znext-solver + +trait Trait {} + +struct W<T>(T); + +impl<T, U> Trait for W<(W<T>, W<U>)> +where + W<T>: Trait, + W<U>: Trait, +{ +} + +fn impls<T: Trait>() {} + +fn main() { + impls::<W<_>>(); + //~^ ERROR overflow evaluating the requirement `W<_>: Trait` +} diff --git a/tests/ui/traits/next-solver/overflow/exponential-trait-goals.stderr b/tests/ui/traits/next-solver/overflow/exponential-trait-goals.stderr new file mode 100644 index 000000000..90b54b1e7 --- /dev/null +++ b/tests/ui/traits/next-solver/overflow/exponential-trait-goals.stderr @@ -0,0 +1,16 @@ +error[E0275]: overflow evaluating the requirement `W<_>: Trait` + --> $DIR/exponential-trait-goals.rs:17:13 + | +LL | impls::<W<_>>(); + | ^^^^ + | + = help: consider increasing the recursion limit by adding a `#![recursion_limit = "256"]` attribute to your crate (`exponential_trait_goals`) +note: required by a bound in `impls` + --> $DIR/exponential-trait-goals.rs:14:13 + | +LL | fn impls<T: Trait>() {} + | ^^^^^ required by this bound in `impls` + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0275`. diff --git a/tests/ui/traits/next-solver/overflow/global-cache.rs b/tests/ui/traits/next-solver/overflow/global-cache.rs new file mode 100644 index 000000000..fe4032ca6 --- /dev/null +++ b/tests/ui/traits/next-solver/overflow/global-cache.rs @@ -0,0 +1,23 @@ +// compile-flags: -Znext-solver + +// Check that we consider the reached depth of global cache +// entries when detecting overflow. We would otherwise be unstable +// wrt to incremental compilation. +#![recursion_limit = "9"] + +trait Trait {} + +struct Inc<T>(T); + +impl<T: Trait> Trait for Inc<T> {} +impl Trait for () {} + +fn impls_trait<T: Trait>() {} + +type Four<T> = Inc<Inc<Inc<Inc<T>>>>; + +fn main() { + impls_trait::<Four<Four<()>>>(); + impls_trait::<Four<Four<Four<Four<()>>>>>(); + //~^ ERROR overflow evaluating the requirement +} diff --git a/tests/ui/traits/next-solver/overflow/global-cache.stderr b/tests/ui/traits/next-solver/overflow/global-cache.stderr new file mode 100644 index 000000000..676166193 --- /dev/null +++ b/tests/ui/traits/next-solver/overflow/global-cache.stderr @@ -0,0 +1,16 @@ +error[E0275]: overflow evaluating the requirement `Inc<Inc<Inc<Inc<Inc<Inc<Inc<...>>>>>>>: Trait` + --> $DIR/global-cache.rs:21:19 + | +LL | impls_trait::<Four<Four<Four<Four<()>>>>>(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: consider increasing the recursion limit by adding a `#![recursion_limit = "18"]` attribute to your crate (`global_cache`) +note: required by a bound in `impls_trait` + --> $DIR/global-cache.rs:15:19 + | +LL | fn impls_trait<T: Trait>() {} + | ^^^^^ required by this bound in `impls_trait` + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0275`. diff --git a/tests/ui/traits/next-solver/overflow/recursion-limit-normalizes-to-constraints.rs b/tests/ui/traits/next-solver/overflow/recursion-limit-normalizes-to-constraints.rs new file mode 100644 index 000000000..03ef93dc2 --- /dev/null +++ b/tests/ui/traits/next-solver/overflow/recursion-limit-normalizes-to-constraints.rs @@ -0,0 +1,25 @@ +// compile-flags: -Znext-solver=coherence +// check-pass + +// A regression test for trait-system-refactor-initiative#70. + +trait Trait { + type Assoc; +} + +struct W<T: ?Sized>(*mut T); +impl<T: ?Sized> Trait for W<W<T>> +where + W<T>: Trait, +{ + type Assoc = (); +} + +trait NoOverlap {} +impl<T: Trait<Assoc = u32>> NoOverlap for T {} +// `Projection(<W<_> as Trait>::Assoc, u32)` should result in error even +// though applying the impl results in overflow. This is necessary to match +// the behavior of the old solver. +impl<T: ?Sized> NoOverlap for W<T> {} + +fn main() {} diff --git a/tests/ui/traits/next-solver/overflow/recursion-limit-zero-issue-115351.rs b/tests/ui/traits/next-solver/overflow/recursion-limit-zero-issue-115351.rs new file mode 100644 index 000000000..52a17a142 --- /dev/null +++ b/tests/ui/traits/next-solver/overflow/recursion-limit-zero-issue-115351.rs @@ -0,0 +1,12 @@ +//~ ERROR overflow evaluating the requirement `Self well-formed` +//~| ERROR overflow evaluating the requirement `Self: Trait` + +// This is a non-regression test for issue #115351, where a recursion limit of 0 caused an ICE. +// compile-flags: -Znext-solver --crate-type=lib +// check-fail + +#![recursion_limit = "0"] +trait Trait {} +impl Trait for u32 {} +//~^ ERROR overflow evaluating the requirement `u32: Trait` +//~| ERROR overflow evaluating the requirement `u32 well-formed` diff --git a/tests/ui/traits/next-solver/overflow/recursion-limit-zero-issue-115351.stderr b/tests/ui/traits/next-solver/overflow/recursion-limit-zero-issue-115351.stderr new file mode 100644 index 000000000..16b25d90a --- /dev/null +++ b/tests/ui/traits/next-solver/overflow/recursion-limit-zero-issue-115351.stderr @@ -0,0 +1,27 @@ +error[E0275]: overflow evaluating the requirement `Self: Trait` + | + = help: consider increasing the recursion limit by adding a `#![recursion_limit = "2"]` attribute to your crate (`recursion_limit_zero_issue_115351`) + +error[E0275]: overflow evaluating the requirement `Self well-formed` + | + = help: consider increasing the recursion limit by adding a `#![recursion_limit = "2"]` attribute to your crate (`recursion_limit_zero_issue_115351`) + +error[E0275]: overflow evaluating the requirement `u32: Trait` + --> $DIR/recursion-limit-zero-issue-115351.rs:10:16 + | +LL | impl Trait for u32 {} + | ^^^ + | + = help: consider increasing the recursion limit by adding a `#![recursion_limit = "2"]` attribute to your crate (`recursion_limit_zero_issue_115351`) + +error[E0275]: overflow evaluating the requirement `u32 well-formed` + --> $DIR/recursion-limit-zero-issue-115351.rs:10:16 + | +LL | impl Trait for u32 {} + | ^^^ + | + = help: consider increasing the recursion limit by adding a `#![recursion_limit = "2"]` attribute to your crate (`recursion_limit_zero_issue_115351`) + +error: aborting due to 4 previous errors + +For more information about this error, try `rustc --explain E0275`. diff --git a/tests/ui/traits/next-solver/overflow/recursive-self-normalization-2.rs b/tests/ui/traits/next-solver/overflow/recursive-self-normalization-2.rs new file mode 100644 index 000000000..327ef865d --- /dev/null +++ b/tests/ui/traits/next-solver/overflow/recursive-self-normalization-2.rs @@ -0,0 +1,20 @@ +// compile-flags: -Znext-solver + +trait Foo1 { + type Assoc1; +} + +trait Foo2 { + type Assoc2; +} + +trait Bar {} +fn needs_bar<S: Bar>() {} + +fn test<T: Foo1<Assoc1 = <T as Foo2>::Assoc2> + Foo2<Assoc2 = <T as Foo1>::Assoc1>>() { + needs_bar::<T::Assoc1>(); + //~^ ERROR overflow evaluating the requirement `<T as Foo1>::Assoc1: Bar` + //~| ERROR overflow evaluating the requirement `<T as Foo2>::Assoc2` +} + +fn main() {} diff --git a/tests/ui/traits/next-solver/overflow/recursive-self-normalization-2.stderr b/tests/ui/traits/next-solver/overflow/recursive-self-normalization-2.stderr new file mode 100644 index 000000000..eda62b99c --- /dev/null +++ b/tests/ui/traits/next-solver/overflow/recursive-self-normalization-2.stderr @@ -0,0 +1,24 @@ +error[E0275]: overflow evaluating the requirement `<T as Foo1>::Assoc1: Bar` + --> $DIR/recursive-self-normalization-2.rs:15:17 + | +LL | needs_bar::<T::Assoc1>(); + | ^^^^^^^^^ + | + = help: consider increasing the recursion limit by adding a `#![recursion_limit = "256"]` attribute to your crate (`recursive_self_normalization_2`) +note: required by a bound in `needs_bar` + --> $DIR/recursive-self-normalization-2.rs:12:17 + | +LL | fn needs_bar<S: Bar>() {} + | ^^^ required by this bound in `needs_bar` + +error[E0275]: overflow evaluating the requirement `<T as Foo2>::Assoc2` + --> $DIR/recursive-self-normalization-2.rs:15:5 + | +LL | needs_bar::<T::Assoc1>(); + | ^^^^^^^^^^^^^^^^^^^^^^ + | + = help: consider increasing the recursion limit by adding a `#![recursion_limit = "256"]` attribute to your crate (`recursive_self_normalization_2`) + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0275`. diff --git a/tests/ui/traits/next-solver/overflow/recursive-self-normalization.rs b/tests/ui/traits/next-solver/overflow/recursive-self-normalization.rs new file mode 100644 index 000000000..f45d208e6 --- /dev/null +++ b/tests/ui/traits/next-solver/overflow/recursive-self-normalization.rs @@ -0,0 +1,16 @@ +// compile-flags: -Znext-solver + +trait Foo { + type Assoc; +} + +trait Bar {} +fn needs_bar<S: Bar>() {} + +fn test<T: Foo<Assoc = <T as Foo>::Assoc>>() { + needs_bar::<T::Assoc>(); + //~^ ERROR overflow evaluating the requirement `<T as Foo>::Assoc: Bar` + //~| ERROR overflow evaluating the requirement `<T as Foo>::Assoc` [E0275] +} + +fn main() {} diff --git a/tests/ui/traits/next-solver/overflow/recursive-self-normalization.stderr b/tests/ui/traits/next-solver/overflow/recursive-self-normalization.stderr new file mode 100644 index 000000000..b0a0a6976 --- /dev/null +++ b/tests/ui/traits/next-solver/overflow/recursive-self-normalization.stderr @@ -0,0 +1,24 @@ +error[E0275]: overflow evaluating the requirement `<T as Foo>::Assoc: Bar` + --> $DIR/recursive-self-normalization.rs:11:17 + | +LL | needs_bar::<T::Assoc>(); + | ^^^^^^^^ + | + = help: consider increasing the recursion limit by adding a `#![recursion_limit = "256"]` attribute to your crate (`recursive_self_normalization`) +note: required by a bound in `needs_bar` + --> $DIR/recursive-self-normalization.rs:8:17 + | +LL | fn needs_bar<S: Bar>() {} + | ^^^ required by this bound in `needs_bar` + +error[E0275]: overflow evaluating the requirement `<T as Foo>::Assoc` + --> $DIR/recursive-self-normalization.rs:11:5 + | +LL | needs_bar::<T::Assoc>(); + | ^^^^^^^^^^^^^^^^^^^^^ + | + = help: consider increasing the recursion limit by adding a `#![recursion_limit = "256"]` attribute to your crate (`recursive_self_normalization`) + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0275`. diff --git a/tests/ui/traits/next-solver/param-candidate-doesnt-shadow-project.rs b/tests/ui/traits/next-solver/param-candidate-doesnt-shadow-project.rs new file mode 100644 index 000000000..f67b073c5 --- /dev/null +++ b/tests/ui/traits/next-solver/param-candidate-doesnt-shadow-project.rs @@ -0,0 +1,25 @@ +// compile-flags: -Znext-solver +// check-pass + +trait Foo { + type Assoc; +} + +trait Bar {} + +impl<T> Foo for T { + type Assoc = i32; +} + +impl<T> Bar for T where T: Foo<Assoc = i32> {} + +fn require_bar<T: Bar>() {} + +fn foo<T: Foo>() { + // Unlike the classic solver, `<T as Foo>::Assoc = _` will still project + // down to `i32` even though there's a param-env candidate here, since we + // don't assemble any param-env projection candidates for `T: Foo` alone. + require_bar::<T>(); +} + +fn main() {} diff --git a/tests/ui/traits/next-solver/param-discr-kind.rs b/tests/ui/traits/next-solver/param-discr-kind.rs new file mode 100644 index 000000000..c66b0b9f4 --- /dev/null +++ b/tests/ui/traits/next-solver/param-discr-kind.rs @@ -0,0 +1,8 @@ +// compile-flags: -Znext-solver +// check-pass + +fn foo<T>(x: T) { + std::mem::discriminant(&x); +} + +fn main() {} diff --git a/tests/ui/traits/next-solver/pointee.rs b/tests/ui/traits/next-solver/pointee.rs new file mode 100644 index 000000000..a56df549a --- /dev/null +++ b/tests/ui/traits/next-solver/pointee.rs @@ -0,0 +1,21 @@ +// compile-flags: -Znext-solver +// check-pass +#![feature(ptr_metadata)] + +use std::ptr::{DynMetadata, Pointee}; + +trait Trait<U> {} +struct MyDst<T: ?Sized>(T); + +fn meta_is<T: Pointee<Metadata = U> + ?Sized, U>() {} + +fn works<T>() { + meta_is::<T, ()>(); + meta_is::<[T], usize>(); + meta_is::<str, usize>(); + meta_is::<dyn Trait<T>, DynMetadata<dyn Trait<T>>>(); + meta_is::<MyDst<T>, ()>(); + meta_is::<((((([u8],),),),),), usize>(); +} + +fn main() {} diff --git a/tests/ui/traits/next-solver/pointer-like.rs b/tests/ui/traits/next-solver/pointer-like.rs new file mode 100644 index 000000000..f6cc718c6 --- /dev/null +++ b/tests/ui/traits/next-solver/pointer-like.rs @@ -0,0 +1,14 @@ +// compile-flags: -Znext-solver + +#![feature(pointer_like_trait)] + +use std::marker::PointerLike; + +fn require_(_: impl PointerLike) {} + +fn main() { + require_(1usize); + require_(1u16); + //~^ ERROR `u16` needs to have the same ABI as a pointer + require_(&1i16); +} diff --git a/tests/ui/traits/next-solver/pointer-like.stderr b/tests/ui/traits/next-solver/pointer-like.stderr new file mode 100644 index 000000000..4b624fd0d --- /dev/null +++ b/tests/ui/traits/next-solver/pointer-like.stderr @@ -0,0 +1,24 @@ +error[E0277]: `u16` needs to have the same ABI as a pointer + --> $DIR/pointer-like.rs:11:14 + | +LL | require_(1u16); + | -------- ^^^^ the trait `PointerLike` is not implemented for `u16` + | | + | required by a bound introduced by this call + | + = note: the trait bound `u16: PointerLike` is not satisfied +note: required by a bound in `require_` + --> $DIR/pointer-like.rs:7:21 + | +LL | fn require_(_: impl PointerLike) {} + | ^^^^^^^^^^^ required by this bound in `require_` +help: consider borrowing here + | +LL | require_(&1u16); + | + +LL | require_(&mut 1u16); + | ++++ + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/traits/next-solver/prefer-candidate-no-constraints.rs b/tests/ui/traits/next-solver/prefer-candidate-no-constraints.rs new file mode 100644 index 000000000..a47f819f1 --- /dev/null +++ b/tests/ui/traits/next-solver/prefer-candidate-no-constraints.rs @@ -0,0 +1,22 @@ +// compile-flags: -Znext-solver +// check-pass + +trait Foo {} + +impl<T> Foo for T {} + +trait Bar {} + +struct Wrapper<'a, T>(&'a T); + +impl<'a, T> Bar for Wrapper<'a, T> where &'a T: Foo {} +// We need to satisfy `&'a T: Foo` when checking that this impl is WF +// that can either be satisfied via the param-env, or via an impl. +// +// When satisfied via the param-env, since each lifetime is canonicalized +// separately, we end up getting extra region constraints. +// +// However, when satisfied via the impl, there are no region constraints, +// and we can short-circuit a response with no external constraints. + +fn main() {} diff --git a/tests/ui/traits/next-solver/prefer-param-env-on-ambiguity.rs b/tests/ui/traits/next-solver/prefer-param-env-on-ambiguity.rs new file mode 100644 index 000000000..f8c0223e1 --- /dev/null +++ b/tests/ui/traits/next-solver/prefer-param-env-on-ambiguity.rs @@ -0,0 +1,10 @@ +// compile-flags: -Znext-solver +// check-pass + +trait Foo<'a> {} +trait Bar<'a> {} + +impl<'a, T: Bar<'a>> Foo<'a> for T {} +impl<T> Bar<'static> for T {} + +fn main() {} diff --git a/tests/ui/traits/next-solver/projection-discr-kind.rs b/tests/ui/traits/next-solver/projection-discr-kind.rs new file mode 100644 index 000000000..bf557f863 --- /dev/null +++ b/tests/ui/traits/next-solver/projection-discr-kind.rs @@ -0,0 +1,18 @@ +// compile-flags: -Znext-solver + +// Check that `<T::Assoc as DiscriminantKind>::Discriminant` doesn't normalize +// to itself and cause overflow/ambiguity. + +trait Foo { + type Assoc; +} + +trait Bar {} +fn needs_bar(_: impl Bar) {} + +fn foo<T: Foo>(x: T::Assoc) { + needs_bar(std::mem::discriminant(&x)); + //~^ ERROR the trait bound `Discriminant<<T as Foo>::Assoc>: Bar` is not satisfied +} + +fn main() {} diff --git a/tests/ui/traits/next-solver/projection-discr-kind.stderr b/tests/ui/traits/next-solver/projection-discr-kind.stderr new file mode 100644 index 000000000..69999c755 --- /dev/null +++ b/tests/ui/traits/next-solver/projection-discr-kind.stderr @@ -0,0 +1,22 @@ +error[E0277]: the trait bound `Discriminant<<T as Foo>::Assoc>: Bar` is not satisfied + --> $DIR/projection-discr-kind.rs:14:15 + | +LL | needs_bar(std::mem::discriminant(&x)); + | --------- ^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Bar` is not implemented for `Discriminant<<T as Foo>::Assoc>` + | | + | required by a bound introduced by this call + | +help: this trait has no implementations, consider adding one + --> $DIR/projection-discr-kind.rs:10:1 + | +LL | trait Bar {} + | ^^^^^^^^^ +note: required by a bound in `needs_bar` + --> $DIR/projection-discr-kind.rs:11:22 + | +LL | fn needs_bar(_: impl Bar) {} + | ^^^ required by this bound in `needs_bar` + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/traits/next-solver/projection/param-env-trait-candidate-1.rs b/tests/ui/traits/next-solver/projection/param-env-trait-candidate-1.rs new file mode 100644 index 000000000..b337c0673 --- /dev/null +++ b/tests/ui/traits/next-solver/projection/param-env-trait-candidate-1.rs @@ -0,0 +1,14 @@ +// check-pass +// compile-flags: -Znext-solver + +// See https://github.com/rust-lang/trait-system-refactor-initiative/issues/1 +// a minimization of a pattern in core. +fn next<T: Iterator<Item = U>, U>(t: &mut T) -> Option<U> { + t.next() +} + +fn foo<T: Iterator>(t: &mut T) { + let _: Option<T::Item> = next(t); +} + +fn main() {} diff --git a/tests/ui/traits/next-solver/projection/param-env-trait-candidate-2.rs b/tests/ui/traits/next-solver/projection/param-env-trait-candidate-2.rs new file mode 100644 index 000000000..db8dc1eb9 --- /dev/null +++ b/tests/ui/traits/next-solver/projection/param-env-trait-candidate-2.rs @@ -0,0 +1,29 @@ +// check-pass +// compile-flags: -Znext-solver + +// See https://github.com/rust-lang/trait-system-refactor-initiative/issues/1, +// a minimization of a pattern in core. + +trait Iterator { + type Item; +} + +struct Flatten<I>(I); + +impl<I, U> Iterator for Flatten<I> +where + I: Iterator<Item = U>, +{ + type Item = U; +} + +fn needs_iterator<I: Iterator>() {} + +fn environment<J>() +where + J: Iterator, +{ + needs_iterator::<Flatten<J>>(); +} + +fn main() {} diff --git a/tests/ui/traits/next-solver/slice-match-byte-lit.rs b/tests/ui/traits/next-solver/slice-match-byte-lit.rs new file mode 100644 index 000000000..1edc9f1e8 --- /dev/null +++ b/tests/ui/traits/next-solver/slice-match-byte-lit.rs @@ -0,0 +1,11 @@ +// compile-flags: -Znext-solver +// check-pass + +fn test(s: &[u8]) { + match &s[0..3] { + b"uwu" => {} + _ => {} + } +} + +fn main() {} diff --git a/tests/ui/traits/next-solver/specialization-transmute.rs b/tests/ui/traits/next-solver/specialization-transmute.rs new file mode 100644 index 000000000..58b62f52d --- /dev/null +++ b/tests/ui/traits/next-solver/specialization-transmute.rs @@ -0,0 +1,28 @@ +// compile-flags: -Znext-solver + +#![feature(specialization)] +//~^ WARN the feature `specialization` is incomplete + +trait Default { + type Id; + + fn intu(&self) -> &Self::Id; +} + +impl<T> Default for T { + default type Id = T; //~ ERROR type annotations needed + // This will be fixed by #111994 + fn intu(&self) -> &Self::Id { //~ ERROR type annotations needed + self + } +} + +fn transmute<T: Default<Id = U>, U: Copy>(t: T) -> U { + *t.intu() +} + +use std::num::NonZeroU8; +fn main() { + let s = transmute::<u8, Option<NonZeroU8>>(0); // this call should then error + assert_eq!(s, None); +} diff --git a/tests/ui/traits/next-solver/specialization-transmute.stderr b/tests/ui/traits/next-solver/specialization-transmute.stderr new file mode 100644 index 000000000..eaf32a475 --- /dev/null +++ b/tests/ui/traits/next-solver/specialization-transmute.stderr @@ -0,0 +1,26 @@ +warning: the feature `specialization` is incomplete and may not be safe to use and/or cause compiler crashes + --> $DIR/specialization-transmute.rs:3:12 + | +LL | #![feature(specialization)] + | ^^^^^^^^^^^^^^ + | + = note: see issue #31844 <https://github.com/rust-lang/rust/issues/31844> for more information + = help: consider using `min_specialization` instead, which is more stable and complete + = note: `#[warn(incomplete_features)]` on by default + +error[E0284]: type annotations needed: cannot satisfy `<T as Default>::Id normalizes-to _` + --> $DIR/specialization-transmute.rs:15:23 + | +LL | fn intu(&self) -> &Self::Id { + | ^^^^^^^^^ cannot satisfy `<T as Default>::Id normalizes-to _` + +error[E0282]: type annotations needed + --> $DIR/specialization-transmute.rs:13:23 + | +LL | default type Id = T; + | ^ cannot infer type for associated type `<T as Default>::Id` + +error: aborting due to 2 previous errors; 1 warning emitted + +Some errors have detailed explanations: E0282, E0284. +For more information about an error, try `rustc --explain E0282`. diff --git a/tests/ui/traits/next-solver/specialization-unconstrained.rs b/tests/ui/traits/next-solver/specialization-unconstrained.rs new file mode 100644 index 000000000..950fb1512 --- /dev/null +++ b/tests/ui/traits/next-solver/specialization-unconstrained.rs @@ -0,0 +1,22 @@ +// compile-flags: -Znext-solver + +#![feature(specialization)] +//~^ WARN the feature `specialization` is incomplete + +// Do not treat the RHS of a projection-goal as an unconstrained `Certainty::Yes` response +// if the impl is still further specializable. + +trait Default { + type Id; +} + +impl<T> Default for T { + default type Id = T; //~ ERROR type annotations needed +} + +fn test<T: Default<Id = U>, U>() {} + +fn main() { + test::<u32, ()>(); + //~^ ERROR cannot satisfy `<u32 as Default>::Id == ()` +} diff --git a/tests/ui/traits/next-solver/specialization-unconstrained.stderr b/tests/ui/traits/next-solver/specialization-unconstrained.stderr new file mode 100644 index 000000000..ed4dafa14 --- /dev/null +++ b/tests/ui/traits/next-solver/specialization-unconstrained.stderr @@ -0,0 +1,32 @@ +warning: the feature `specialization` is incomplete and may not be safe to use and/or cause compiler crashes + --> $DIR/specialization-unconstrained.rs:3:12 + | +LL | #![feature(specialization)] + | ^^^^^^^^^^^^^^ + | + = note: see issue #31844 <https://github.com/rust-lang/rust/issues/31844> for more information + = help: consider using `min_specialization` instead, which is more stable and complete + = note: `#[warn(incomplete_features)]` on by default + +error[E0284]: type annotations needed: cannot satisfy `<u32 as Default>::Id == ()` + --> $DIR/specialization-unconstrained.rs:20:5 + | +LL | test::<u32, ()>(); + | ^^^^^^^^^^^^^^^ cannot satisfy `<u32 as Default>::Id == ()` + | +note: required by a bound in `test` + --> $DIR/specialization-unconstrained.rs:17:20 + | +LL | fn test<T: Default<Id = U>, U>() {} + | ^^^^^^ required by this bound in `test` + +error[E0282]: type annotations needed + --> $DIR/specialization-unconstrained.rs:14:22 + | +LL | default type Id = T; + | ^ cannot infer type for associated type `<T as Default>::Id` + +error: aborting due to 2 previous errors; 1 warning emitted + +Some errors have detailed explanations: E0282, E0284. +For more information about an error, try `rustc --explain E0282`. diff --git a/tests/ui/traits/next-solver/stall-num-var-auto-trait.fallback.stderr b/tests/ui/traits/next-solver/stall-num-var-auto-trait.fallback.stderr new file mode 100644 index 000000000..2e3c22c8d --- /dev/null +++ b/tests/ui/traits/next-solver/stall-num-var-auto-trait.fallback.stderr @@ -0,0 +1,17 @@ +error[E0277]: the trait bound `i32: Foo` is not satisfied + --> $DIR/stall-num-var-auto-trait.rs:18:15 + | +LL | needs_foo(x); + | --------- ^ the trait `Foo` is not implemented for `i32` + | | + | required by a bound introduced by this call + | +note: required by a bound in `needs_foo` + --> $DIR/stall-num-var-auto-trait.rs:14:22 + | +LL | fn needs_foo(x: impl Foo) {} + | ^^^ required by this bound in `needs_foo` + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/traits/next-solver/stall-num-var-auto-trait.rs b/tests/ui/traits/next-solver/stall-num-var-auto-trait.rs new file mode 100644 index 000000000..f5bf985cd --- /dev/null +++ b/tests/ui/traits/next-solver/stall-num-var-auto-trait.rs @@ -0,0 +1,25 @@ +// compile-flags: -Znext-solver +// revisions: fallback constrain +//[constrain] check-pass + +// Tests that we stall the `{integer}: Foo` obligation until after we +// constrain the int type (or fallback occurs). + +#![feature(negative_impls, auto_traits)] + +auto trait Foo {} + +impl !Foo for i32 {} + +fn needs_foo(x: impl Foo) {} + +fn main() { + let mut x = 0; + needs_foo(x); + //[fallback]~^ ERROR the trait bound `i32: Foo` is not satisfied + + #[cfg(constrain)] + { + x = 1u64; + } +} diff --git a/tests/ui/traits/next-solver/structural-resolve-field.rs b/tests/ui/traits/next-solver/structural-resolve-field.rs new file mode 100644 index 000000000..b247e2375 --- /dev/null +++ b/tests/ui/traits/next-solver/structural-resolve-field.rs @@ -0,0 +1,13 @@ +// compile-flags: -Znext-solver +// check-pass + +#[derive(Default)] +struct Foo { + x: i32, +} + +fn main() { + let mut xs = <[Foo; 1]>::default(); + xs[0].x = 1; + (&mut xs[0]).x = 2; +} diff --git a/tests/ui/traits/next-solver/tait-eq-proj-2.rs b/tests/ui/traits/next-solver/tait-eq-proj-2.rs new file mode 100644 index 000000000..a3df053dd --- /dev/null +++ b/tests/ui/traits/next-solver/tait-eq-proj-2.rs @@ -0,0 +1,23 @@ +// compile-flags: -Znext-solver +// check-pass + +#![feature(type_alias_impl_trait)] + +// Similar to tests/ui/traits/next-solver/tait-eq-proj.rs +// but check the alias-sub relation in the other direction. + +type Tait = impl Iterator<Item = impl Sized>; + +fn mk<T>() -> T { + todo!() +} + +fn a(_: Tait) { + let x: Tait = mk(); + let mut array = mk(); + let mut z = IntoIterator::into_iter(array); + z = x; + array = [0i32; 32]; +} + +fn main() {} diff --git a/tests/ui/traits/next-solver/tait-eq-proj.rs b/tests/ui/traits/next-solver/tait-eq-proj.rs new file mode 100644 index 000000000..871e8e1e9 --- /dev/null +++ b/tests/ui/traits/next-solver/tait-eq-proj.rs @@ -0,0 +1,35 @@ +// compile-flags: -Znext-solver +// check-pass + +#![feature(type_alias_impl_trait)] + +type Tait = impl Iterator<Item = impl Sized>; + +/* + +Consider the goal - AliasRelate(Tait, <[i32; 32] as IntoIterator>::IntoIter) +which is registered on the line above. + +A. SubstRelate - fails (of course). + +B. NormalizesToRhs - Tait normalizes-to <[i32; 32] as IntoIterator>::IntoIter + * infer definition - Tait := <[i32; 32] as IntoIterator>::IntoIter + +C. NormalizesToLhs - <[i32; 32] as IntoIterator>::IntoIter normalizes-to Tait + * Find impl candidate, after substitute - std::array::IntoIter<i32, 32> + * Equate std::array::IntoIter<i32, 32> and Tait + * infer definition - Tait := std::array::IntoIter<i32, 32> + +B and C are not equal, but they are equivalent modulo normalization. + +We get around this by evaluating both the NormalizesToRhs and NormalizesToLhs +goals together. Essentially: + A alias-relate B if A normalizes-to B and B normalizes-to A. + +*/ + +fn a(_: Tait) { + let _: Tait = IntoIterator::into_iter([0i32; 32]); +} + +fn main() {} diff --git a/tests/ui/traits/next-solver/tait-eq-tait.rs b/tests/ui/traits/next-solver/tait-eq-tait.rs new file mode 100644 index 000000000..2629a124c --- /dev/null +++ b/tests/ui/traits/next-solver/tait-eq-tait.rs @@ -0,0 +1,18 @@ +// compile-flags: -Znext-solver +// check-pass + +// Not exactly sure if this is the inference behavior we *want*, +// but it is a side-effect of the lazy normalization of TAITs. + +#![feature(type_alias_impl_trait)] + +fn mk<T>() -> T { + todo!() +} + +fn main() { + type Tait = impl Sized; + type Tait2 = impl Sized; + let x: Tait = 1u32; + let y: Tait2 = x; +} diff --git a/tests/ui/traits/next-solver/temporary-ambiguity.rs b/tests/ui/traits/next-solver/temporary-ambiguity.rs new file mode 100644 index 000000000..6102de7e4 --- /dev/null +++ b/tests/ui/traits/next-solver/temporary-ambiguity.rs @@ -0,0 +1,22 @@ +// compile-flags: -Znext-solver +// check-pass + +// Checks that we don't explode when we assemble >1 candidate for a goal. + +struct Wrapper<T>(T); + +trait Foo {} + +impl Foo for Wrapper<i32> {} + +impl Foo for Wrapper<()> {} + +fn needs_foo(_: impl Foo) {} + +fn main() { + let mut x = Default::default(); + let w = Wrapper(x); + needs_foo(w); + x = 1; + let _ = x; +} diff --git a/tests/ui/traits/next-solver/trait-upcast-lhs-needs-normalization.rs b/tests/ui/traits/next-solver/trait-upcast-lhs-needs-normalization.rs new file mode 100644 index 000000000..8e0378e94 --- /dev/null +++ b/tests/ui/traits/next-solver/trait-upcast-lhs-needs-normalization.rs @@ -0,0 +1,19 @@ +// check-pass +// compile-flags: -Znext-solver +#![feature(trait_upcasting)] + +pub trait A {} +pub trait B: A {} + +pub trait Mirror { + type Assoc: ?Sized; +} +impl<T: ?Sized> Mirror for T { + type Assoc = T; +} + +pub fn foo<'a>(x: &'a <dyn B + 'static as Mirror>::Assoc) -> &'a (dyn A + 'static) { + x +} + +fn main() {} diff --git a/tests/ui/traits/next-solver/try-example.rs b/tests/ui/traits/next-solver/try-example.rs new file mode 100644 index 000000000..92b0b5978 --- /dev/null +++ b/tests/ui/traits/next-solver/try-example.rs @@ -0,0 +1,28 @@ +// check-pass +// compile-flags: -Znext-solver + +use std::error::Error; + +fn main() -> Result<(), Box<dyn Error>> { + let x: i32 = parse()?; + Ok(()) +} + +trait Parse {} + +impl Parse for i32 {} + +#[derive(Debug)] +struct ParseError; + +impl std::fmt::Display for ParseError { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!(f, "ParseError") + } +} + +impl Error for ParseError {} + +fn parse<T: Parse>() -> Result<T, ParseError> { + todo!() +} diff --git a/tests/ui/traits/next-solver/two-projection-param-candidates-are-ambiguous.rs b/tests/ui/traits/next-solver/two-projection-param-candidates-are-ambiguous.rs new file mode 100644 index 000000000..d25e372b5 --- /dev/null +++ b/tests/ui/traits/next-solver/two-projection-param-candidates-are-ambiguous.rs @@ -0,0 +1,30 @@ +// compile-flags: -Znext-solver + +// When we're solving `<T as Foo>::Assoc = i32`, we actually first solve +// `<T as Foo>::Assoc = ?1t`, then unify `?1t` with `i32`. That goal +// with the inference variable is ambiguous when there are >1 param-env +// candidates. + +// We don't unify the RHS of a projection goal eagerly when solving, both +// for caching reasons and partly to make sure that we don't make the new +// trait solver smarter than it should be. + +// This is (as far as I can tell) a forwards-compatible decision, but if you +// make this test go from fail to pass, be sure you understand the implications! + +trait Foo { + type Assoc; +} + +trait Bar {} + +impl<T> Bar for T where T: Foo<Assoc = i32> {} + +fn needs_bar<T: Bar>() {} + +fn foo<T: Foo<Assoc = i32> + Foo<Assoc = u32>>() { + needs_bar::<T>(); + //~^ ERROR type annotations needed: cannot satisfy `T: Bar` +} + +fn main() {} diff --git a/tests/ui/traits/next-solver/two-projection-param-candidates-are-ambiguous.stderr b/tests/ui/traits/next-solver/two-projection-param-candidates-are-ambiguous.stderr new file mode 100644 index 000000000..dfff9f11b --- /dev/null +++ b/tests/ui/traits/next-solver/two-projection-param-candidates-are-ambiguous.stderr @@ -0,0 +1,17 @@ +error[E0283]: type annotations needed: cannot satisfy `T: Bar` + --> $DIR/two-projection-param-candidates-are-ambiguous.rs:26:17 + | +LL | needs_bar::<T>(); + | ^ + | + = note: cannot satisfy `T: Bar` + = help: the trait `Bar` is implemented for `T` +note: required by a bound in `needs_bar` + --> $DIR/two-projection-param-candidates-are-ambiguous.rs:23:17 + | +LL | fn needs_bar<T: Bar>() {} + | ^^^ required by this bound in `needs_bar` + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0283`. diff --git a/tests/ui/traits/next-solver/unevaluated-const-impl-trait-ref.fails.stderr b/tests/ui/traits/next-solver/unevaluated-const-impl-trait-ref.fails.stderr new file mode 100644 index 000000000..4be90c702 --- /dev/null +++ b/tests/ui/traits/next-solver/unevaluated-const-impl-trait-ref.fails.stderr @@ -0,0 +1,18 @@ +error[E0277]: the trait bound `(): Trait<1>` is not satisfied + --> $DIR/unevaluated-const-impl-trait-ref.rs:20:13 + | +LL | needs::<1>(); + | ^ the trait `Trait<1>` is not implemented for `()` + | + = help: the following other types implement trait `Trait<N>`: + <() as Trait<0>> + <() as Trait<2>> +note: required by a bound in `needs` + --> $DIR/unevaluated-const-impl-trait-ref.rs:10:38 + | +LL | fn needs<const N: usize>() where (): Trait<N> {} + | ^^^^^^^^ required by this bound in `needs` + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/traits/next-solver/unevaluated-const-impl-trait-ref.rs b/tests/ui/traits/next-solver/unevaluated-const-impl-trait-ref.rs new file mode 100644 index 000000000..77a169d48 --- /dev/null +++ b/tests/ui/traits/next-solver/unevaluated-const-impl-trait-ref.rs @@ -0,0 +1,22 @@ +// compile-flags: -Znext-solver +// revisions: works fails +//[works] check-pass + +trait Trait<const N: usize> {} + +impl Trait<{ 1 - 1 }> for () {} +impl Trait<{ 1 + 1 }> for () {} + +fn needs<const N: usize>() where (): Trait<N> {} + +#[cfg(works)] +fn main() { + needs::<0>(); + needs::<2>(); +} + +#[cfg(fails)] +fn main() { + needs::<1>(); + //[fails]~^ ERROR the trait bound `(): Trait<1>` is not satisfied +} diff --git a/tests/ui/traits/next-solver/unsafe-auto-trait-impl.rs b/tests/ui/traits/next-solver/unsafe-auto-trait-impl.rs new file mode 100644 index 000000000..f66bf0b87 --- /dev/null +++ b/tests/ui/traits/next-solver/unsafe-auto-trait-impl.rs @@ -0,0 +1,8 @@ +// compile-flags: -Znext-solver +// check-pass + +struct Foo(*mut ()); + +unsafe impl Sync for Foo {} + +fn main() {} diff --git a/tests/ui/traits/next-solver/unsize-although-ambiguous.rs b/tests/ui/traits/next-solver/unsize-although-ambiguous.rs new file mode 100644 index 000000000..8217701b9 --- /dev/null +++ b/tests/ui/traits/next-solver/unsize-although-ambiguous.rs @@ -0,0 +1,13 @@ +// check-pass +// compile-flags: -Znext-solver + +use std::fmt::Display; + +fn box_dyn_display(_: Box<dyn Display>) {} + +fn main() { + // During coercion, we don't necessarily know whether `{integer}` implements + // `Display`. Before, that would cause us to bail out in the coercion loop when + // checking `{integer}: Unsize<dyn Display>`. + box_dyn_display(Box::new(1)); +} diff --git a/tests/ui/traits/next-solver/unsize-good.rs b/tests/ui/traits/next-solver/unsize-good.rs new file mode 100644 index 000000000..04ebe66f2 --- /dev/null +++ b/tests/ui/traits/next-solver/unsize-good.rs @@ -0,0 +1,25 @@ +// compile-flags: -Znext-solver +// check-pass + +#![feature(unsized_tuple_coercion)] + +trait Foo {} + +impl Foo for i32 {} + +fn main() { + // Unsizing via struct + let _: Box<dyn Foo> = Box::new(1i32); + + // Slice unsizing + let y = [1, 2, 3]; + let _: &[i32] = &y; + + // Tuple unsizing + let hi = (1i32,); + let _: &(dyn Foo,) = &hi; + + // Dropping auto traits + let a: &(dyn Foo + Send) = &1; + let _: &dyn Foo = a; +} diff --git a/tests/ui/traits/next-solver/upcast-right-substs.rs b/tests/ui/traits/next-solver/upcast-right-substs.rs new file mode 100644 index 000000000..5b4f6d4be --- /dev/null +++ b/tests/ui/traits/next-solver/upcast-right-substs.rs @@ -0,0 +1,13 @@ +// compile-flags: -Znext-solver +// check-pass +#![feature(trait_upcasting)] + +trait Foo: Bar<i32> + Bar<u32> {} + +trait Bar<T> {} + +fn main() { + let x: &dyn Foo = todo!(); + let y: &dyn Bar<i32> = x; + let z: &dyn Bar<u32> = x; +} diff --git a/tests/ui/traits/next-solver/upcast-wrong-substs.rs b/tests/ui/traits/next-solver/upcast-wrong-substs.rs new file mode 100644 index 000000000..0cd253007 --- /dev/null +++ b/tests/ui/traits/next-solver/upcast-wrong-substs.rs @@ -0,0 +1,11 @@ +// compile-flags: -Znext-solver + +trait Foo: Bar<i32> + Bar<u32> {} + +trait Bar<T> {} + +fn main() { + let x: &dyn Foo = todo!(); + let y: &dyn Bar<usize> = x; + //~^ ERROR mismatched types +} diff --git a/tests/ui/traits/next-solver/upcast-wrong-substs.stderr b/tests/ui/traits/next-solver/upcast-wrong-substs.stderr new file mode 100644 index 000000000..00ba1ef67 --- /dev/null +++ b/tests/ui/traits/next-solver/upcast-wrong-substs.stderr @@ -0,0 +1,14 @@ +error[E0308]: mismatched types + --> $DIR/upcast-wrong-substs.rs:9:30 + | +LL | let y: &dyn Bar<usize> = x; + | --------------- ^ expected trait `Bar`, found trait `Foo` + | | + | expected due to this + | + = note: expected reference `&dyn Bar<usize>` + found reference `&dyn Foo` + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0308`. diff --git a/tests/ui/traits/next-solver/winnow-specializing-impls.rs b/tests/ui/traits/next-solver/winnow-specializing-impls.rs new file mode 100644 index 000000000..d70a91596 --- /dev/null +++ b/tests/ui/traits/next-solver/winnow-specializing-impls.rs @@ -0,0 +1,22 @@ +// build-pass +// compile-flags: -Znext-solver + +// Tests that the specializing impl `<() as Foo>` holds during codegen. + +#![feature(min_specialization)] + +trait Foo { + fn bar(); +} + +impl<T> Foo for T { + default fn bar() {} +} + +impl Foo for () { + fn bar() {} +} + +fn main() { + <() as Foo>::bar(); +} |