core::ops::Receiver (arbitrary self types) doesn't play well with associated trait bounds

[first time poster here]

I've noticed that two language features that work nicely independently don't play well together. I have a trait, and I'd like implementations to be able to specify a handle type which is anything that acts as Receiver<Target=Self>, via an associated type.

The problem is that Receiver isn't transitive when used as a trait bound, even though it is transitive in "normal" use. See the three different cases in the sample code below.

#![feature(arbitrary_self_types)]

struct MySmartPtr<T>(T);

impl<T> core::ops::Receiver for MySmartPtr<T> {
  type Target = T;
}

struct Content;

impl Content {
  // Case 1: nested arbitrary self type works with concrete types
  fn method(self: MySmartPtr<MySmartPtr<Self>>) {}
}

trait Foo {
    type SelfHandle: core::ops::Receiver<Target=Self>;
    fn method(self: Self::SelfHandle) {}
}
impl Foo for Content {
    // Case 2: (unnested) arbitrary self type works via associated type in trait
    type SelfHandle = MySmartPtr<Self>;
}

// exactly the same as Foo, but the impl for Content is different
trait Bar {
    type SelfHandle: core::ops::Receiver<Target=Self>;
    fn method(self: Self::SelfHandle) {}
}

impl Bar for Content {
    // Case 3: nesting in combination with associated type in trait DOES NOT work
    type SelfHandle = MySmartPtr<MySmartPtr<Self>>;
}

Here's an analogous scenario on stable. This was also noted in the RFC.

Given how Receiver and Deref are defined, the compilation errors are the correct results. A trait bound for "eventually auto-derefs to &Self" or "is a valid receiver inside an impl Self" would require new language features.

1 Like