Type recursion when trait bound is added on reference type

I ran into this issue when I'm trying to create a wrapper type on several numeric types, here is a minimized example to reproduce this problem

use std::ops::Add;

struct Wrapper<T>(pub T);

impl<T: Add<Output = T>> Add for Wrapper<T> {
    type Output = Self;
    fn add(self, rhs: Self) -> Self::Output {
        Self(self.0.add(rhs.0))
    }
}

impl<T: for<'r> Add<&'r T, Output = T>> Add<&Wrapper<T>> for Wrapper<T> {
    type Output = Self;
    fn add(self, rhs: &Self) -> Self::Output {
        Self(self.0.add(&rhs.0))
    }
}

impl<T> Add<Wrapper<T>> for &Wrapper<T>
where for<'r> &'r T: Add<T, Output = T> {
    type Output = Wrapper<T>;
    fn add(self, rhs: Wrapper<T>) -> Self::Output {
        Wrapper((&self.0).add(rhs.0))
    }
}

// this function works
fn sum1<T: Add<Output = T> + for<'r> Add<&'r T, Output = T>>(a: T, b: T) -> T {
    (a + &b) + b
}
// this doesn't
fn sum2<T: Add<Output = T>>(a: T, b: T) -> T
where for<'r> &'r T: Add<T, Output = T> {
    (&a + b) + a
}

fn main() {
    assert_eq!(sum1(Wrapper(0), Wrapper(0)).0, 0);
    assert_eq!(sum2(Wrapper(0), Wrapper(0)).0, 0);
}

(playground)

I don't understand why the sum1 works but sum2 will lead to type expansion recursion:

   Compiling test_ref v0.1.0 (/home/jacobz/test_ref)
error[E0275]: overflow evaluating the requirement `for<'r> &'r Wrapper<_>: Add<Wrapper<_>>`
  --> src/main.rs:43:16
   |
43 |     assert_eq!(sum2(Wrapper(0), Wrapper(0)).0, 0);
   |                ^^^^
   |
   = help: consider increasing the recursion limit by adding a `#![recursion_limit = "256"]` attribute to your crate (`test_ref`)
   = note: required because of the requirements on the impl of `for<'r> Add<Wrapper<Wrapper<_>>>` for `&'r Wrapper<Wrapper<_>>`
   = note: 127 redundant requirements hidden
   = note: required because of the requirements on the impl of `for<'r> Add<Wrapper<Wrapper<Wrapper<Wrapper<Wrapper<Wrapper<Wrapper<Wrapper<Wrapper<Wrapper<Wrapper<Wrapper<Wrapper<Wrapper<Wrapper<Wrapper<Wrapper<Wrapper<Wrapper<Wrapper<Wrapper<Wrapper<Wrapper<Wrapper<Wrapper<Wrapper<Wrapper<Wrapper<Wrapper<Wrapper<Wrapper<Wrapper<Wrapper<Wrapper<Wrapper<Wrapper<Wrapper<Wrapper<Wrapper<Wrapper<Wrapper<Wrapper<Wrapper<Wrapper<Wrapper<Wrapper<Wrapper<Wrapper<Wrapper<Wrapper<Wrapper<Wrapper<Wrapper<Wrapper<Wrapper<Wrapper<Wrapper<Wrapper<Wrapper<Wrapper<Wrapper<Wrapper<Wrapper<Wrapper<Wrapper<Wrapper<Wrapper<Wrapper<Wrapper<Wrapper<Wrapper<Wrapper<Wrapper<Wrapper<Wrapper<Wrapper<Wrapper<Wrapper<Wrapper<Wrapper<Wrapper<Wrapper<Wrapper<Wrapper<Wrapper<Wrapper<Wrapper<Wrapper<Wrapper<Wrapper<Wrapper<Wrapper<Wrapper<Wrapper<Wrapper<Wrapper<Wrapper<Wrapper<Wrapper<Wrapper<Wrapper<Wrapper<Wrapper<Wrapper<Wrapper<Wrapper<Wrapper<Wrapper<Wrapper<Wrapper<Wrapper<Wrapper<Wrapper<Wrapper<Wrapper<Wrapper<Wrapper<Wrapper<Wrapper<Wrapper<Wrapper<Wrapper<Wrapper<Wrapper<Wrapper<Wrapper<Wrapper<Wrapper<Wrapper<_>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` for `&'r Wrapper<Wrapper<Wrapper<Wrapper<Wrapper<Wrapper<Wrapper<Wrapper<Wrapper<Wrapper<Wrapper<Wrapper<Wrapper<Wrapper<Wrapper<Wrapper<Wrapper<Wrapper<Wrapper<Wrapper<Wrapper<Wrapper<Wrapper<Wrapper<Wrapper<Wrapper<Wrapper<Wrapper<Wrapper<Wrapper<Wrapper<Wrapper<Wrapper<Wrapper<Wrapper<Wrapper<Wrapper<Wrapper<Wrapper<Wrapper<Wrapper<Wrapper<Wrapper<Wrapper<Wrapper<Wrapper<Wrapper<Wrapper<Wrapper<Wrapper<Wrapper<Wrapper<Wrapper<Wrapper<Wrapper<Wrapper<Wrapper<Wrapper<Wrapper<Wrapper<Wrapper<Wrapper<Wrapper<Wrapper<Wrapper<Wrapper<Wrapper<Wrapper<Wrapper<Wrapper<Wrapper<Wrapper<Wrapper<Wrapper<Wrapper<Wrapper<Wrapper<Wrapper<Wrapper<Wrapper<Wrapper<Wrapper<Wrapper<Wrapper<Wrapper<Wrapper<Wrapper<Wrapper<Wrapper<Wrapper<Wrapper<Wrapper<Wrapper<Wrapper<Wrapper<Wrapper<Wrapper<Wrapper<Wrapper<Wrapper<Wrapper<Wrapper<Wrapper<Wrapper<Wrapper<Wrapper<Wrapper<Wrapper<Wrapper<Wrapper<Wrapper<Wrapper<Wrapper<Wrapper<Wrapper<Wrapper<Wrapper<Wrapper<Wrapper<Wrapper<Wrapper<Wrapper<Wrapper<Wrapper<Wrapper<Wrapper<Wrapper<Wrapper<Wrapper<_>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>`
note: required by a bound in `sum2`
  --> src/main.rs:32:22
   |
31 | fn sum2<T: Add<Output = T>>(a: T, b: T) -> T
   |    ---- required by a bound in this
32 | where for<'r> &'r T: Add<T, Output = T> {
   |                      ^^^^^^^^^^^^^^^^^^ required by this bound in `sum2`

For more information about this error, try `rustc --explain E0275`.

Is there any solution to workaround this? Thanks in advance!

It looks like it's getting lost looking for types it could possibly coerce to for some reason. Simd showing up in the error is odd. Probably worth filing an issue over.

You can be explicit about T to avoid inference:

    assert_eq!(sum2::<Wrapper<i32>>(Wrapper(0), Wrapper(0)).0, 0);

But this may not be ergonomically viable elsewhere.

1 Like

Thanks for the reply! The fix doesn't work for me tho, since I would like to expose this method as public API. I will report this issue.

Well I found a lot of similar issues on Github: #85063, #39959, it's basically a compiler bug (which have been around since beta!).

1 Like