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.