generalize: handle occurs check failure in aliases by lcnr · Pull Request #117088 · rust-lang/rust (original) (raw)
This PR mostly fixes generalization for aliases, fixing #105787. It is therefore a (theoretical) breaking change.
Equating ?x == Alias<?x>
previously failed. This is incomplete (and therefore allows overlaps via the implicit negative overlap check in coherence). This PR instead delays equality in this case, emitting a Projection
goal. This projection goal then stalls until the projection can be normalized to a rigid type, in which case the occurs check is correct, or the projection cannot be normalized and stays rigid (due to a ParamEnv
candidate).
It is non-trivial whether we can get trait solver overflow (in the old solver) for rigid projections, e.g.
trait Unnormalizable { type Assoc; }
struct Inv(*mut T);
fn unconstrained() -> T { todo!() }
fn create<T, U: Unnormalizable>( x: &U, ) -> (Inv, Inv<<U as Unnormalizable>::Assoc>) { todo!() }
fn foo<T: Unnormalizable + Unnormalizable, U, V>() {
let q = unconstrained();
let (mut x, y) = create::<_, _>(&q);
x = y; // equate ?x
with <T as Unnormalizable<?x>>::Assoc
drop::(q);
}
However, projection goals only constrain the term to the projection itself if we were able to select a ParamEnv
candidate. As we do not have non-lifetime binders, this only happens if the projection does not contain type inference variables.
I believe that you can get solver overflow with specialization and default associated items, but idc 😁
This only fixes problem case 2 of rust-lang/trait-system-refactor-initiative#8. However, this is by far the easiest way to get an incorrect occurs check failure (and the only one I bothered to write a coherence unsoundness test for). This only impacts the old solver for projections containing bound variables (as we otherwise eagerly normalize and replace the projection with an inference variable).
I consider this to 1) be a step in the right direction and 2) necessary for future work on the new trait solver.