6

Consider the following code:

use std::ops::Add;

trait Trait
    where Self::Assoc: Add<Self::Assoc, Output=Self::Assoc>
                     + for <'a> Add<&'a Self::Assoc, Output=Self::Assoc>
{
    type Assoc;
    fn get(&self) -> Self::Assoc;
}

fn add1<T: Trait>(x: T, y: T) -> T::Assoc {
    x.get() + y.get()
}

This fails to compile with:

error[E0308]: mismatched types
  --> src/lib.rs:12:15
   |
12 |     x.get() + y.get()
   |               ^^^^^^^
   |               |
   |               expected reference, found associated type
   |               help: consider borrowing here: `&y.get()`
   |
   = note:    expected reference `&<T as Trait>::Assoc`
           found associated type `<T as Trait>::Assoc`

I'm able to work around the issue by explicitly specifying what trait I want to use:

fn add2<T: Trait>(x: T, y: T) -> T::Assoc {
    <T::Assoc as Add<T::Assoc>>::add(x.get(), y.get())
}

But I'm wondering: why is this happening? Also, is there any more compact work around?

Note that the order of the trait bounds matters. If I change them to:

    where Self::Assoc: for <'a> Add<&'a Self::Assoc, Output=Self::Assoc>
                     + Add<Self::Assoc, Output=Self::Assoc>

... then add1 compiles fine, but this fails:

fn add3<T: Trait>(x: T, y: T) -> T::Assoc {
    x.get() + &y.get()
}

Link to playground

Peter Hall
  • 53,120
  • 14
  • 139
  • 204
prosc
  • 327
  • 2
  • 5
  • Seems like [this](https://github.com/rust-lang/rust/issues/54296) issue. I believe it is not a high priority to fix this, as it can in the majority of cases easily be worked around. Annoying though. – L. Riemer Mar 19 '20 at 10:13
  • _"Also, is there any more compact work around?"_ -- You will need to be a bit clearer about exactly you want to achieve. A workaround could be to just dereference `y` when adding. I guess that's not what you want, but I can't deduce your abstraction requirements. – Peter Hall Mar 19 '20 at 10:34
  • @L.Riemer: you're probably right – prosc Mar 19 '20 at 21:58
  • @PeterHall: ideally I would like to write the `+` operator, avoid any verbose `<... as ...>` forms, and still use the correct trait (referencing/dereferencing would switch to another trait, which will execute different code and might have a performance impact) – prosc Mar 19 '20 at 22:01
  • I believe all these inference problems have been deferred until the new constraint solver engine [chalk](https://github.com/rust-lang/chalk) lands in the Rust compiler. – Sven Marnach Mar 20 '20 at 08:41

0 Answers0