use typenum::*;
use std::ops::Add;
struct A<T> {}
impl<L: Unsigned> Add<A<L>> for A<L> {
type Output = i32;
fn add(self, _rhs: A<L>) > Self::Output {
5
}
}
impl<L: Unsigned> Add<A<Add1<L>>> for A<L> {
type Output = i32;
fn add(self, _rhs: A<Add1<L>>) > Self::Output {
500
}
}
fn main() {
let a1 = A::<P1>{};
let a2 = A::<P2>{};
assert_eq!(a1 + a1, 5);
assert_eq!(a1 + a2, 500);
assert_eq!(a2 + a2, 5);
}
The Error:
Compiling playground v0.0.1 (/playground)
error[E0119]: conflicting implementations of trait `Add` for type `A<_>`
> src/main.rs:13:1

6  impl<L: Unsigned> Add<A<L>> for A<L> {
  first implementation here
...
13  impl<L: Unsigned> Add<A<Add1<L>>> for A<L> {
 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `A<_>`
For more information about this error, try `rustc explain E0119`.
error: could not compile `playground` (bin "playground") due to 1 previous error
Aren’t Add<SomeStruct<P1>> and Add<SomeStruct<P2>> different traits?
Sure, they are, but your case of P1 = L and P2 = Add1<L> doesn’t seem to rule out overlap in a way that can convince the compiler.
While indeed the (sealed) implementors of Unsigned from typenum never have L and Add1<L> be the same type, that’s “just a convention” that typenum follows. In principle, the compiler
cannot tell this property anyways, and
would need to account for futurecompatibility, so upstream could add new implementors of Unsigned and Add<B1> so that Add1<L>is the same as L for those.
I suppose this is a downside of working with a binary representation of the typelevel numbers. If it was a unary system, where each successor was just Successor<Previous> and Successor is a simple struct Successor<T>(T) type constructor, then the compiler could know that Successor<L> and L are never the same.
I came up with a second alternative approach. While the first above relied on more finegrained manual impls (and the fact that the last bit is always different for successors), this one just calculates R  L, and then uses the difference to avoid overlap. This still needs a 2step process, as Rust’s overlap protection isn’t all that smart, so we use a helper trait and pass it the calculated difference as parameter:
use typenum::*;
use std::ops::Add;
use core::ops::Sub;
#[derive(Copy, Clone)]
struct A<T>(T);
impl<L: Unsigned, R: Unsigned, D> Add<A<R>> for A<L>
where
R: Sub<L, Output = D>,
L: AddAWithDiff<D>
{
type Output = i32;
fn add(self, _rhs: A<R>) > Self::Output {
L::add_impl()
}
}
trait AddAWithDiff<D> {
fn add_impl() > i32;
}
impl<L> AddAWithDiff<U0> for L {
fn add_impl() > i32 {
5
}
}
impl<L> AddAWithDiff<U1> for L {
fn add_impl() > i32 {
500
}
}
fn main() {
let a1 = A(U1::new());
let a2 = A(U2::new());
assert_eq!(a1 + a1, 5);
assert_eq!(a1 + a2, 500);
assert_eq!(a2 + a2, 5);
}