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/cycles | |
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/cycles')
18 files changed, 599 insertions, 0 deletions
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<_>>(); +} |