//@ check-pass //@ compile-flags: -Znext-solver // Regression test for . // See comment below on `fn main`. trait Intersect { type Output; } impl Intersect> for T where T: Intersect, { type Output = T; } impl Intersect for Cuboid { type Output = Cuboid; } fn intersect(_: &T, _: &U) -> T::Output where T: Intersect, { todo!() } struct Cuboid; impl Cuboid { fn method(&self) {} } fn main() { let x = vec![]; // Here we end up trying to normalize `>>::Output` // for the return type of the function, to constrain `y`. The impl then requires // `Cuboid: Intersect`, which has two candidates. One that constrains // `?0 = Vec`, which itself has the same two candidates and ends up leading // to a recursion depth overflow. In the second impl, we constrain `?0 = Cuboid`. // // Floundering leads to us combining the overflow candidate and yes candidate to // overflow. Because the response was overflow, we used to bubble it up to the // parent normalizes-to goal, which caused us to drop its constraint that would // guide us to normalize the associated type mentioned before. // // After this PR, we implement a new floundering "algebra" such that `Overflow OR Maybe` // returns anew `Overflow { keep_constraints: true }`, which means that we don't // need to drop constraints in the parent normalizes-to goal. This allows us to // normalize `y` to `Cuboid`, and allows us to call the method successfully. We // then constrain the `?0` in `let x: Vec = x` below, so that we don't have // a left over ambiguous goal. let y = intersect(&Cuboid, &x); y.method(); let x: Vec = x; }