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/new-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/new-solver/cycles')
16 files changed, 0 insertions, 546 deletions
diff --git a/tests/ui/traits/new-solver/cycles/coinduction/fixpoint-exponential-growth.rs b/tests/ui/traits/new-solver/cycles/coinduction/fixpoint-exponential-growth.rs deleted file mode 100644 index 44e763ef9..000000000 --- a/tests/ui/traits/new-solver/cycles/coinduction/fixpoint-exponential-growth.rs +++ /dev/null @@ -1,31 +0,0 @@ -// compile-flags: -Ztrait-solver=next - -// 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. This fixpoint is -// never reached here and each step doubles the amount of nested obligations. -// -// 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/new-solver/cycles/coinduction/fixpoint-exponential-growth.stderr b/tests/ui/traits/new-solver/cycles/coinduction/fixpoint-exponential-growth.stderr deleted file mode 100644 index 1ac0e2977..000000000 --- a/tests/ui/traits/new-solver/cycles/coinduction/fixpoint-exponential-growth.stderr +++ /dev/null @@ -1,16 +0,0 @@ -error[E0275]: overflow evaluating the requirement `W<_>: Trait` - --> $DIR/fixpoint-exponential-growth.rs:29: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:26:13 - | -LL | fn impls<T: Trait>() {} - | ^^^^^ required by this bound in `impls` - -error: aborting due to previous error - -For more information about this error, try `rustc --explain E0275`. diff --git a/tests/ui/traits/new-solver/cycles/coinduction/incompleteness-unstable-result.rs b/tests/ui/traits/new-solver/cycles/coinduction/incompleteness-unstable-result.rs deleted file mode 100644 index 0cd14f05c..000000000 --- a/tests/ui/traits/new-solver/cycles/coinduction/incompleteness-unstable-result.rs +++ /dev/null @@ -1,69 +0,0 @@ -// compile-flags: -Ztrait-solver=next -#![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/new-solver/cycles/coinduction/incompleteness-unstable-result.stderr b/tests/ui/traits/new-solver/cycles/coinduction/incompleteness-unstable-result.stderr deleted file mode 100644 index f1871ff05..000000000 --- a/tests/ui/traits/new-solver/cycles/coinduction/incompleteness-unstable-result.stderr +++ /dev/null @@ -1,16 +0,0 @@ -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 previous error - -For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/traits/new-solver/cycles/double-cycle-inductive-coinductive.rs b/tests/ui/traits/new-solver/cycles/double-cycle-inductive-coinductive.rs deleted file mode 100644 index 5617e45ad..000000000 --- a/tests/ui/traits/new-solver/cycles/double-cycle-inductive-coinductive.rs +++ /dev/null @@ -1,37 +0,0 @@ -// compile-flags: -Ztrait-solver=next -#![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/new-solver/cycles/double-cycle-inductive-coinductive.stderr b/tests/ui/traits/new-solver/cycles/double-cycle-inductive-coinductive.stderr deleted file mode 100644 index a3404da51..000000000 --- a/tests/ui/traits/new-solver/cycles/double-cycle-inductive-coinductive.stderr +++ /dev/null @@ -1,29 +0,0 @@ -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/new-solver/cycles/fixpoint-rerun-all-cycle-heads.rs b/tests/ui/traits/new-solver/cycles/fixpoint-rerun-all-cycle-heads.rs deleted file mode 100644 index 279063923..000000000 --- a/tests/ui/traits/new-solver/cycles/fixpoint-rerun-all-cycle-heads.rs +++ /dev/null @@ -1,53 +0,0 @@ -// compile-flags: -Ztrait-solver=next -#![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/new-solver/cycles/fixpoint-rerun-all-cycle-heads.stderr b/tests/ui/traits/new-solver/cycles/fixpoint-rerun-all-cycle-heads.stderr deleted file mode 100644 index 4cbd08981..000000000 --- a/tests/ui/traits/new-solver/cycles/fixpoint-rerun-all-cycle-heads.stderr +++ /dev/null @@ -1,10 +0,0 @@ -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 previous error - diff --git a/tests/ui/traits/new-solver/cycles/inductive-cycle-but-err.rs b/tests/ui/traits/new-solver/cycles/inductive-cycle-but-err.rs deleted file mode 100644 index cda987898..000000000 --- a/tests/ui/traits/new-solver/cycles/inductive-cycle-but-err.rs +++ /dev/null @@ -1,48 +0,0 @@ -// compile-flags: -Ztrait-solver=next -#![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/new-solver/cycles/inductive-cycle-but-err.stderr b/tests/ui/traits/new-solver/cycles/inductive-cycle-but-err.stderr deleted file mode 100644 index 57227321a..000000000 --- a/tests/ui/traits/new-solver/cycles/inductive-cycle-but-err.stderr +++ /dev/null @@ -1,16 +0,0 @@ -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 previous error - -For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/traits/new-solver/cycles/inductive-cycle-but-ok.rs b/tests/ui/traits/new-solver/cycles/inductive-cycle-but-ok.rs deleted file mode 100644 index d4851eb69..000000000 --- a/tests/ui/traits/new-solver/cycles/inductive-cycle-but-ok.rs +++ /dev/null @@ -1,44 +0,0 @@ -// compile-flags: -Ztrait-solver=next -// 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/new-solver/cycles/inductive-cycle-discarded-coinductive-constraints.rs b/tests/ui/traits/new-solver/cycles/inductive-cycle-discarded-coinductive-constraints.rs deleted file mode 100644 index 530e6d0ec..000000000 --- a/tests/ui/traits/new-solver/cycles/inductive-cycle-discarded-coinductive-constraints.rs +++ /dev/null @@ -1,36 +0,0 @@ -// check-pass -// compile-flags: -Ztrait-solver=next -#![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/new-solver/cycles/inductive-not-on-stack.rs b/tests/ui/traits/new-solver/cycles/inductive-not-on-stack.rs deleted file mode 100644 index f06b98a79..000000000 --- a/tests/ui/traits/new-solver/cycles/inductive-not-on-stack.rs +++ /dev/null @@ -1,46 +0,0 @@ -// compile-flags: -Ztrait-solver=next -#![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/new-solver/cycles/inductive-not-on-stack.stderr b/tests/ui/traits/new-solver/cycles/inductive-not-on-stack.stderr deleted file mode 100644 index 859b3f3f1..000000000 --- a/tests/ui/traits/new-solver/cycles/inductive-not-on-stack.stderr +++ /dev/null @@ -1,29 +0,0 @@ -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/new-solver/cycles/leak-check-coinductive-cycle.rs b/tests/ui/traits/new-solver/cycles/leak-check-coinductive-cycle.rs deleted file mode 100644 index a6d318726..000000000 --- a/tests/ui/traits/new-solver/cycles/leak-check-coinductive-cycle.rs +++ /dev/null @@ -1,33 +0,0 @@ -// compile-flags: -Ztrait-solver=next -// 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/new-solver/cycles/provisional-result-done.rs b/tests/ui/traits/new-solver/cycles/provisional-result-done.rs deleted file mode 100644 index 589d34dd7..000000000 --- a/tests/ui/traits/new-solver/cycles/provisional-result-done.rs +++ /dev/null @@ -1,33 +0,0 @@ -// compile-flags: -Ztrait-solver=next -// 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<_>>(); -} |