rust-lang / trait-system-refactor-initiative

The Rustc Trait System Refactor Initiative
22 stars 0 forks source link

old trait solver provisional cache does not handle changes in the cycle kind #119

Open lcnr opened 4 months ago

lcnr commented 4 months ago
struct A<T: ?Sized>(*const T);
struct B<T: ?Sized>(*const T);
struct C<T: ?Sized>(*const T);

impl<T: ?Sized> Unpin for A<T>
where
    B<T>: Unpin,
    B<T>: Inductive,
{}

impl<T: ?Sized> Unpin for B<T>
where
    A<T>: Unpin,
{}

trait Inductive {}
impl<T: ?Sized + Unpin> Inductive for T {}

fn is_unpin<T: Unpin>() {}

fn main() {
    is_unpin::<A<()>>();
}

This test should fail as A: Unpin -> B: Inductive -> B: Unpin -> A: Unpin is an inductive cycle. However, the old solver reuses the provisional cache entry of the coinductive A: Unpin -> B: Unpin -> A: Unpin cycle for B: Unpin. Changing the order of where clauses on the A<T>: Unpin impl causes this test to correctly The only place we remove provisional entries is fn on_failure or when completely done with this cycle. Idk if and how you'd get an unsoundness from that, but this explains why the old solver is fast when handling complex auto trait cycles.

It does hang during coherence when computing intercrate ambiguity causes. It recursively evaluates nested goals, but still returns Ok(None), clearing the provisional cache.