---
# System prepended metadata

title: '[Pre-RFC] Supertrait associated items in subtrait impl'

---

# [Pre-RFC] Supertrait associated items in subtrait impl

**RfL context**
This enables us to move `type Target` from `trait Deref` into `trait Receiver` without breaking existing `impl Deref` blocks in Rust ecosystem.

# Motivation

This RFC concerns itself with enabling subtrait `impl` blocks to supply associated items from one or several supertraits.

This RFC proposes an extension so that subtrait `impl` blocks may designate the associated types from supertraits so that the respective supertraits `impl` can be implied by collecting the required associated items, without resorting to individual, separate `impl`-supertrait blocks.

# Guide-level description

## Supertraits
Supertraits of a subtrait in this context is defined solely in the form of type bound list, as illustrated in [Listing 1](#Listing-1), as opposed to examples in [Listing 2](#Listing-2).

###### Listing 1
_Supertrait `Super1` and `Super2` registered with the subtrait `Sub` as type bounds_
```rust=
trait Super1 {}
trait Super2 {}
trait Sub : Super1 + Super2 {}
```
###### Listing 2
_Trait `Super1` and `Super2` are not registered as supertraits of trait `Sub` or `Sub2` in these examples_
```rust=
trait Super1 {}
trait Super2 {}
trait Id<T: ?Sized> { type T: ?Sized; }
impl<T: ?Sized> Id<T> for T { type T = T; }
trait Sub1 where Self: Super1 {}
// Fancy ways to say `Self`s
trait Sub2 where <Self as Id<Self>>::T: Super2 {}
```

## `impl` subtrait blocks today
The way to introduce `impl` of a subtrait now is rigid, in the sense that one `impl` block for the subtrait and additional one each for the involved supertrait.

###### Listing 3
```rust=
trait Super {
    type T;
    fn super_call(&self);
}
trait Sub: Super {
    fn method(&self) -> <Self as Super>::T;
}
enum MyType {}
// The disconnect between `impl Sub for MyType` manifests itself
// when `type T`, or `<Self as Super>` is literally located in another `impl` block
impl Sub for MyType {
    fn method(&self) -> <Self as Super>::T {
        self.super_call();
    }
}
impl Super for MyType {
    type T = ();
    
    fn super_call(&self) {}
}
```

There are two possible problems arising from this typical case.
- The disconnect between contexts, as subtrait `impl`s can refer to items from supertrait `impl`s, but the supertrait `impl`s can be located at other places, even in different modules of the crate. This can impact readability of the code, as readers need to jump extra loops to make the connections.
- The syntatical red-tape on subtrait `impl` blocks can become prohibitive as the type signature of `Self`, the `where` bounds and the list of generics grow.

## A new proposal: merge the super- and subtrait blocks into one

The proposal is to allow users to declare supertrait associated items directly in the subtrait `impl` blocks.

To build the intuition, [Listing 3](#Listing-3) could have been written into the following.

###### Listing 4
```rust=
impl Sub for MyType {
    // This is type from `Sub`
    fn method(&self) -> <Self as Super>::T {
        self.super_call();
    }

    // This is from `Super`
    type T = ();
    
    // This is also from `Super`
    fn super_call(&self) {}
}
```

Note that the associated items `type T` and `fn super_call` must be resolved to that from the trait `Super`.

However, this proposal also guarantee that [Listing 3](#Listing-3) on its own must continue to compile.

## One complete set of supertrait items, or none

Rust `impl`-trait blocks has always been self-containing today. With this proposal, this principle will remain upheld. For an `impl`-subtrait block to be valid, when it comes to completeness, the following rules must be observed.

- The subtrait associated items must be all fully defined.
- If one associated item from a **direct or indirect supertrait** `Super` is defined, so are all associated items from the trait `Super`.

Then in turn, the compiler should guarantee the following.

- If one associated item from a supertrait `Super<..>` is defined, it has the same effect as a standalone `impl<..> Super<..>` block, so that it can be considered that the type bound `Self: Super<..>` is satisfied.

#### Commentary
The primary reason that a clash between a subtrait item with a supertrait item is not considered for ambiguity and the item would be resolved to the subtrait item, is due to a property that we would like to uphold, which is to allow the user to easily cut out the supertrait `impl` block and add into the subtrait `impl` block without qualifying the subtrait item. The compiler, in this case, should have sufficiently erred about the name clash due to pasting in the supertrait items.

### Positive examples

Under this proposal, these are the notable valid examples.

###### Listing 5
```rust=
// == Prelude ==
trait Super1<T> {
    type Super1Type;
}
trait Super2 {
    type Super2Type;
}
trait Sub<T>: Super1<T> + Super2 {
    type Type;
}

// == Example 1 ==
enum MyType1 {}

impl<T> Sub<T> for MyType1 {
    type Type = u8;
    
    // .. implying an impl Super1<T>
    type Super1Type = u32;
    
    // .. implying an impl Super2
    type Super2Type = ();
}

// == Example 2 ==
enum MyType2 {}

impl<T> Sub<T> for MyType2 {
    type Type = u8;
    
    // .. implying an impl Super1<T>
    type Super1Type = u32;
    
    // Note that we have not declared anything
    // from Super2 yet
}

impl<T> Super2 for MyType2 {
    type Super2Type = ();
}
```

### Negative examples
Under this proposal, the following should not compile.

###### Listing 6
```rust=
// == Prelude ==
trait Super1<T> {
    type Super1Type;
    // Note that we have a second associated type
    type Super1Type2;
}
trait Super2 ..
trait Sub<T>: Super1<T> + Super2 ..

// == Example ==
enum MyType1 {}

impl<T> Sub<T> for MyType1 {
    type Type = u8;
    
    // .. implying an impl Super1<T>
    type Super1Type = u32;
    //   ^~~~~~~~~~
    // error[E0046]: not all trait items from `Super1` implemented, missing: `Super1Type2`
    
    // .. implying an impl Super2
    type Super2Type = ();
}
```
## Disambiguation

In case that there are clashes on associated item names among supertrait and subtrait items, attempting to declare one of them **from supertraits** without qualification must be rejected.

### Positive example, when the item can be resolved to a subtrait item

###### Listing 7
```rust=
trait Super1 {
    type Type;
}
trait Super2 {
    type Type;
}
trait Sub: Super1 + Super2 {
    type Type;
}
enum MyType1 {}

impl Sub for MyType1 {
    type Type = u8; // OK
}
```

### Negative example

###### Listing 8
```rust=
trait Super1 {
    type SuperType;
}
trait Super2 {
    type SuperType;
}
trait Sub: Super1 + Super2 {
    type Type;
}
enum MyType1 {}

impl Sub for MyType1 {
    type Type = u8; // OK
    type SuperType = u8;
    // error[???]: ambiguous associated item
    // could be `Super1::SuperType` or `Super2::SuperType`
}
```

### Positive example

To resolve the ambiguity, one must introduce path qualification of the targeted trait in front of the associated item identifier. If the targeted subtrait or supertrait has generics, the generics should be included in the path.

###### Listing 9
```rust=
trait Super1 {
    type Type;
    
    fn method();
    
    fn super_method1();
}
trait Super2<T> {
    type Type;
    
    fn method();
}
trait Sub<T>: Super1 + Super2<T> {
    type Type;
    
    fn method();
}
enum MyType1 {}

impl<T> Sub<T> for MyType1 {
    type Sub::<T>::Type = u8; // OK
    
    type Super::Type = u8; // OK
    
    type Super::<T>::Type = u8; // OK
    
    fn Sub::method() {} // OK
    
    fn Super1::method() {} // OK
    
    fn Super2::method() {} // OK
    
    fn super_method1() {} // OK, and this is for impl Super1 for MyType1
}
```

## Inductive Supertrait relation

Let us suppose `Sub` trait has a supertrait `Super1`, which in turn has a supertrait `Super2`.

###### Listing 10
```rust=
trait Super1: Super2 {
    type Type;
}
trait Super2 {
    type Type;
}
trait Sub: Super1 {
    type Type;
}
```

Then, this proposal enables the `impl` on subtrait with various depths of declaration.

###### Listing 11
```rust=
enum MyType1 {}
impl Sub for MyType1 {
    type Sub::Type = u8; // OK
    type Super1::Type = u32; // OK
    type Super2::Type = (); // OK
}

enum MyType2 {}
impl Sub for MyType2 {
    type Type = u8; // OK
}
impl Super1 for MyType2 {
    type Type = u32; // OK
    type Super2::Type = (); // OK
}
```

## "Marker" traits

Supertraits can have zero inherent associated items, which for the purpose of this RFC we name as marker traits. This may introduce ambiguity and raise the risk of mis-implementation of these traits, because there exist no user obligation to supply the implementation. To prevent mis-implementation, marker supertraits are not automatically backfill-implemented, unless the superbound prefixes the supertrait with the keywords `auto impl`.

Another notable recommendation is that users can signify that a marker trait with the attribute `#[auto_impl]` as opposed to .

###### Listing 12
```rust=
trait MarkerSuper1 {
}
trait MarkerSuper2 {
}
trait Sub: MarkerSuper1 + auto impl MarkerSuper2 {
    type Type;
}
enum MyType {}
impl Sub for MyType {
}

// We expect:
fn assert_sub()
where MyType: Sub //~ OK
{}

fn assert_marker_super1()
where MyType: MarkerSuper1 //~ ERROR: MarkerSuper1 is not implemented
{}

fn assert_marker_super2()
where MyType: MarkerSuper2 //~ OK
// .. because `MarkerSuper2` is a `auto impl` supertrait of `Sub`
{}
```

## Unsafety/Safety

Supertraits can be `unsafe`. As long as one supertrait is `unsafe` and its implementation is requested by a subtrait `impl` block, either through mentioning one of its applicable associated item or through the `auto impl` mechanism when this supertrait is a marker trait, it is obligatory for user to mark the whole subtrait `impl` as `unsafe`.

###### Listing 12

```rust=
unsafe trait MarkerSuper {}

trait Sub1: auto impl MarkerSuper {}

enum MyStruct {}
impl Sub1 for MyStruct {} //~ ERROR: `unsafe` is required on this subtrait impl

unsafe trait Super {
    type Type;
}

trait Sub2: MarkerSuper + Super {}
impl Sub2 for MyStruct {} //~ OK
unsafe impl Super for MyStruct { //~ OK
    type Type = ();
}

enum MyStruct2 {}
impl Sub2 for MyStruct2 { //~ ERROR: `unsafe` is required on this subtrait impl
    // .. due to supply of `Super::Type` and `Super` being `unsafe`
    type Type = ();
}
```

## `const`-ness

At the early stage of this proposal, we do not consider backfilling supertrait `const impl`s. Rather, supertrait `impl`s are not `const`.

This can be relaxed in a future iteration of the proposal which would involve more syntactical designs.

## Propagate full set of predicates by default

`impl` blocks may have their set of `where` bounds for various reasons. When supertrait `impl`s are "backfilled", the whole `where` bounds shall be propagated in full to these backfill `impl`s.

###### Listing 13

```rust=
trait Super {
    type Type: Send;
}
trait Sub: Super {}

struct MyStruct<T>(T)
impl<T: Send> Sub for MyStruct<T> {
    type Type = T; //~ OK
    // .. `T: Send` is propagated to the typing environment of `Super::Type`
}
```

# Reference-level description

The following is a suggestion on possible compiler implementation.

## AST extension

We will now allow path elements and generics in the associated item location. As far as it would look like, introduction of grammar ambiguity is unlikely.

## Name resolution

Given that identifiers can be foreign to the `impl`, and the associated item resolution is eager, we would like to one extra phase. The exact work requires a quick survey and prototyping.

The work here is to make sure that the respective `DefId`s of supertraits implied `impl`s shall be procured. In this way, no changes to trait solving are required, which is very critical to the success of implementation of this language extension.

We will defer the span information, which is critical to diagnostics, to a later phase of the prototyping.

# Drawback

## Introducing possible magic

Now unless the identifier names are very self-evident, the supertrait associated items may be seen too magical as they would appear very irrelevant to the `impl` block.

One could get confused if one is not very familiar with the trait definition and when subsequently encouter a supertrait item that has not logical connection to the rest of the subtrait `impl` block.

## Enablement of mis-organisation

One can foresee that given this option, users may elect to flood a subtrait `impl` block with all supertrait declaration. It has been a long appreciated tradition of Rust that code should be organised and partitioned by pragmatics and functions. There is a risk that the abuse of this language extension will break this nice property.

# Prior arts

The author has not been made aware of prior discussion.

# Unresolved questions

- If we want to proceed, how do we develop tools to help users contain unnecessary encroachment of supertrait items into subtrait `impl` blocks?