Traits with &Self bounds


#1

I’m trying to create a supertrait with a few convenient bounds, including requirements on &Self. So for example, say I want an AddAny trait which allows all of these: x + y, x + &y, &x + y, &x + &y.

Implementing the first two variations is easy, and works fine: http://is.gd/QmW61x

use std::ops::Add;

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

impl<T> AddAny for T
where T: Add<T, Output=T>,
for<'b> T: Add<&'b T, Output=T>,
{}

fn add_val_val<T: AddAny>(x: T, y: T) -> T { x + y }
fn add_val_ref<T: AddAny>(x: T, y: &T) -> T { x + y }

fn main() {
    println!("{}", add_val_val(2, 3));
    println!("{}", add_val_ref(2, &3));
}

That’s pared down from my attempt at a full solution, which doesn’t work: http://is.gd/19Opn1

use std::ops::Add;

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

impl<T> AddAny for T
where T: Add<T, Output=T>,
for<'b> T: Add<&'b T, Output=T>,
for<'a> &'a T: Add<T, Output=T>,
for<'a, 'b> &'a T: Add<&'b T, Output=T>
{}

fn add_val_val<T: AddAny>(x: T, y: T) -> T { x + y }
fn add_val_ref<T: AddAny>(x: T, y: &T) -> T { x + y }
fn add_ref_val<T: AddAny>(x: &T, y: T) -> T { x + y }
fn add_ref_ref<T: AddAny>(x: &T, y: &T) -> T { x + y }

fn main() {
    println!("{}", add_val_val(2, 3));
    println!("{}", add_val_ref(2, &3));
    println!("{}", add_ref_val(&2, 3));
    println!("{}", add_ref_ref(&2, &3));
}

errors:

<anon>:17:1: 17:53 error: the trait `for<'a> core::ops::Add<T>` is not implemented for the type `&'a T` [E0277]
<anon>:17 fn add_val_val<T: AddAny>(x: T, y: T) -> T { x + y }
          ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
<anon>:17:1: 17:53 help: see the detailed explanation for E0277
<anon>:17:1: 17:53 note: required by `AddAny`
<anon>:17:1: 17:53 error: the trait `for<'b, 'a> core::ops::Add<&'b T>` is not implemented for the type `&'a T` [E0277]
<anon>:17 fn add_val_val<T: AddAny>(x: T, y: T) -> T { x + y }
          ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
<anon>:17:1: 17:53 help: see the detailed explanation for E0277
<anon>:17:1: 17:53 note: required by `AddAny`

(repeated for each of those generic functions)

So T, which I’m constraining to types that have implemented AddAny, is somehow failing to actually have AddAny implemented? Huh?

I thought maybe I was writing the impl wrong, but even removing all that errors the same way. http://is.gd/iB8akI

use std::ops::Add;

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

fn add_val_val<T: AddAny>(x: T, y: T) -> T { x + y }
fn add_val_ref<T: AddAny>(x: T, y: &T) -> T { x + y }
fn add_ref_val<T: AddAny>(x: &T, y: T) -> T { x + y }
fn add_ref_ref<T: AddAny>(x: &T, y: &T) -> T { x + y }

fn main() { }

So it seems like the &Self bounds make this impossible to be satisfied. Is there any way to express this?


#2

Last I ran into this, where clauses on traits aren’t considered when working out what you can and can’t do with a type that implements said trait.

The only solutions I could find were to duplicate the bounds everywhere you need them, or to somehow wrangle the constraint on to an associated type with its own trait that you use instead.


#3

Probably


#4

OK, darn, that does look like the same issue. Subscribed, thanks.