Traits with &Self bounds

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: Rust Playground

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: Rust Playground

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. Rust Playground

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?

1 Like

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.

Probably

https://github.com/rust-lang/rust/issues/20671

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

Has this changed in any way in the past 6 years?
Is it still not possible to require &Self to implement some trait without specifying that clause on every function that uses it?