relating projection substs is unsound during coherence · Issue #102048 · rust-lang/rust (original) (raw)

// This must fail coherence. // // Getting this to pass was fairly difficult, so here's an explanation // of what's happening: // // Normalizing projections currently tries to replace them with inference variables // while emitting a nested Projection obligation. This cannot be done if the projection // has bound variables which is the case here. // // So the projections stay until after normalization. When unifying two projections we // currently treat them as if they are injective, so we incorrectly unify their // substs. This means that coherence for the two impls ends up unifying ?T and ?U // as it tries to unify <?T as WithAssoc1<'a>>::Assoc with <?U as WithAssoc1<'a>>::Assoc. // // impl1 therefore has the projection <?T as WithAssoc2<'a>>::Assoc and we have the // assumption ?T: for<'a> WithAssoc2<'a, Assoc = i32> in the param_env, so we normalize // that to i32. We then try to unify i32 from impl1 with u32 from impl2 which fails, // causing coherence to consider these two impls distinct. pub trait Trait {}

pub trait WithAssoc1<'a> { type Assoc; } pub trait WithAssoc2<'a> { type Assoc; }

// impl 1 impl<T, U> Trait<for<'a> fn(<T as WithAssoc1<'a>>::Assoc, <U as WithAssoc2<'a>>::Assoc)> for (T, U) where T: for<'a> WithAssoc1<'a> + for<'a> WithAssoc2<'a, Assoc = i32>, U: for<'a> WithAssoc2<'a>, { }

// impl 2 impl<T, U> Trait<for<'a> fn(<U as WithAssoc1<'a>>::Assoc, u32)> for (T, U) where U: for<'a> WithAssoc1<'a> { }

this currently compiles even though the following crate would mean that both impls overlap:

extern crate test1; use test1::*;

struct Ty1; struct Ty2;

impl WithAssoc1<'_> for Ty1 { type Assoc = (); } impl WithAssoc2<'_> for Ty1 { type Assoc = i32; } impl WithAssoc1<'_> for Ty2 { type Assoc = (); } impl WithAssoc2<'_> for Ty2 { type Assoc = u32; }

fn foo<T, U>() where (T, U): Trait<for<'a> fn((), u32)>, { }

fn main() { foo::<Ty1, Ty2>(); }

however, it seems like rustc generally has issues with both of these impls, so it actually believes that none of these impls apply 😁 see also #102047 where the first impl results in an ICE.