Conflicting implementations not overlapping

pub trait Cond {
    type Output;
}
pub struct S;
impl<T> From<T> for S where T: Cond<Output = i32> {}
impl<T> From<T> for S where T: Cond<Output = u32> {}

The implementations cannot overlap, because <T as Cond>::Output cannot be both i32 and u32. The code as far as I know does not use negative bounds which are problematic. That is because the second constraint isn't T: !Cond<Output = i32> or T: Cond<Output != i32>. Is there any reason I'm missing which would make accepting this a problem?

The workaround for this is a private trait

pub trait Cond {
    type Output;
}
pub struct S;

impl<T> From<T> for S where T: IntoS<T::Output> + Cond {
    fn from(value: T) -> Self { value.into_s() }
}

pub IntoS<C> {
    fn into_s(self) -> S;
}

impl<T: Cond<Output=u32>> IntoS<u32> for T {
    fn into_s(self) -> S { ... }
}

impl<T: Cond<Output=i32>> IntoS<i32> for T {
    fn into_s(self) -> S { ... }
}

But it would be nice if this workaround wasn't necessary.

3 Likes

I believe this is issue#20400. RFC#1672 was proposed to fix this, but postponed for two main reasons. The first is that it's effectively blocked on chalk anyway, and the second is

that this isn't quite clear-cut, actually. As boats writes,

2 Likes

Thanks for the workaround. Though in my case what I really wanted was From for the first condition and TryFrom for the second; so I created another trait instead of using TryFrom.