Jonas Greitemann
Jonas Greitemann

Reputation: 1071

Why is it necessary to add redundant trait bounds even though my trait uses those same traits as bounds?

I have been trying to code a trait which requires a type to implement Add (and further down the line other operations for vector spaces) with itself as well as among its references. The following is a small example, illustrating the problem I ran into:

use std::ops::Add;

#[derive(Debug)]
struct MyVec<T>(Vec<T>);

impl<'a, 'b, T: Copy + Add> Add<&'a MyVec<T>> for &'b MyVec<T> {
    type Output = MyVec<T::Output>;
    fn add(self, other: &'a MyVec<T>) -> Self::Output {
        /* ... */
    }
}
impl<'a, T: Copy + Add> Add<MyVec<T>> for &'a MyVec<T> {
    /* ... */
}
impl<'a, T: Copy + Add> Add<&'a MyVec<T>> for MyVec<T> {
    /* ... */
}
impl<T: Copy + Add> Add<MyVec<T>> for MyVec<T> {
    /* ... */
}

trait Addable: Add<Self, Output = Self>
where
    Self: Sized,
    for<'a> &'a Self: Add<Self, Output = Self>,
    for<'b> Self: Add<&'b Self, Output = Self>,
    for<'a, 'b> &'a Self: Add<&'b Self, Output = Self>,
{
}

impl<T: Copy + Add<Output = T>> Addable for MyVec<T> {}

fn add_stuff<'a, 'b, T: Addable>(x: &'a T, y: &'b T) -> T {
    x + y
}

fn main() {
    let v = MyVec(vec![1, 2, 3]);
    let w = MyVec(vec![2, 4, 6]);
    println!("{:?}", add_stuff(&v, &w));
}

However, I get the following compiler errors:

error[E0277]: the trait bound `for<'a> &'a T: std::ops::Add<T>` is not satisfied
  --> src/main.rs:33:1
   |
33 | / fn add_stuff<'a, 'b, T: Addable>(x: &'a T, y: &'b T) -> T {
34 | |     x + y
35 | | }
   | |_^ no implementation for `&'a T + T`
   |
   = help: the trait `for<'a> std::ops::Add<T>` is not implemented for `&'a T`
   = help: consider adding a `where for<'a> &'a T: std::ops::Add<T>` bound
   = note: required by `Addable`

error[E0277]: the trait bound `for<'a, 'b> &'a T: std::ops::Add<&'b T>` is not satisfied
  --> src/main.rs:33:1
   |
33 | / fn add_stuff<'a, 'b, T: Addable>(x: &'a T, y: &'b T) -> T {
34 | |     x + y
35 | | }
   | |_^ no implementation for `&'a T + &'b T`
   |
   = help: the trait `for<'a, 'b> std::ops::Add<&'b T>` is not implemented for `&'a T`
   = help: consider adding a `where for<'a, 'b> &'a T: std::ops::Add<&'b T>` bound
   = note: required by `Addable`

This can be fixed by amending the add_stuff function with a where clause as suggested by the compiler:

where
    for<'c, 'd> &'c T: Add<&'d T, Output = T>,
    for<'c> &'c T: Add<T, Output = T>,

I do not understand why this is necessary. I thought by specifying a bound in the definition of the trait I could rely on that bound being met for any type that implements that trait? Having to add these where clauses every time sort of defies the whole point of my Addable trait.

Googling brought up this GitHub issue which I don't understand fully but which might be related? That would suggest this is indeed a bug in Rust (which hasn't been fixed for a very long time).

Upvotes: 6

Views: 822

Answers (1)

Sebastian Redl
Sebastian Redl

Reputation: 71899

You've hit a shortcoming of the Rust compiler as it currently is. RFC 2089 proposed to make it work as you expect, and was accepted in December 2017.

However, as of today, the feature isn't implemented. The tracking issue for the implementation hasn't seen much activity yet, so it appears implementation hasn't even started. It appears that some fundamental improvements to the compiler's trait bound handling are necessary before this particular feature can be efficiently implemented (search keyword: chalk).

Upvotes: 5

Related Questions