// 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` impl and required // inference from an `Impl` candidate in the `B` impl. // // To make global cache accesses stronger than the guidance from the where-bounds, we add // another coinductive cycle from `A: Trait` to `A: Trait` 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 {} struct A(*const T); struct B(*const T); trait IncompleteGuidance {} impl IncompleteGuidance for T {} impl IncompleteGuidance for T {} impl IncompleteGuidance for T {} trait ImplGuidance {} impl ImplGuidance for T {} impl ImplGuidance for T {} impl Trait for A where T: IncompleteGuidance, A: Trait, B: Trait, (): ToU8, { } trait ToU8 {} impl ToU8 for () {} impl Trait for B where T: ImplGuidance, A: Trait, { } fn impls_trait, U: ?Sized, V: ?Sized, D: ?Sized>() {} fn with_bound() where X: IncompleteGuidance, X: IncompleteGuidance, X: IncompleteGuidance, { impls_trait::, _, _, _>(); // 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`. impls_trait::, _, _, _>(); //~^ ERROR the trait bound `A: Trait<_, _, _>` is not satisfied } fn main() { with_bound::(); }