Which rule does it regulate that `dyn Trait + AutoTrait` can be coerced to `dyn Trait`?

Consider this example:

use std::error::Error;
fn invoke()->Box<dyn Error + Send + Sync>{
   todo!()
}

fn main(){
  let b:Box<dyn Error> = invoke();
}

I tried to find the relevant rules in Type coercions - The Rust Reference

The rules I think it might be relevant are two parts

Coercion is allowed between the following types:

  • [...]
  • TyCtor(T) to TyCtor(U), where TyCtor(T) is one of
  • [...]
  • Box<T>

Unsized coercions

  • [...]
  • dyn T to dyn U, when U is one of T’s supertraits.

However, I doubt that, can a trait be called as super trait of itself?

If the rule that permits the coercion is not my cited rules, where is the correct rule?

A type is a sub- and super-type of itself, so why not.

That said, even with that interpretation the documentation is incomplete I think; you can also drop the principle trait and just have a dyn Send for example.

(I think that was just an FCP during the trait upcasting development, but I'm on mobile so it would be a pain to dig up.)

Even before trait upcasting, you could use unsizing dyn coercion to shorten the dyn lifetime (even in Invariant position). I don't think that was ever in the reference. Dropping auto traits probably was before trait upcasting, you could look up the old phrasing.

This documents says

It is an error for a trait to be its own supertrait.

I can't read the mind of the author of the quote in the OP. But I would not at all be surprised if the phrasing was less than mathematically formal (i.e. based on a more human language level).

You could post a PR or request issue to clarify the OP quoted section.

You have the right rules. That it doesn't clearly permit T = U is an oversight in the wording of this rule.

It looks like this case was perhaps never particularly well-documented. Look at the reference in 1.85 release or earlier for instance.

(The ability to cast away + Send + Sync like this on the other hand is at least as old as Rust 1.0.)

Edit: Up to 1.47 it spoke of “subtrait” here (whatever that was supposed to mean, exactly, at the time)..

Edit2: If you're going to improve this, also take a look at the library docs of Unsize in std::marker - Rust which are similarly not getting some of these details right.

Full context from the documentation:

Supertraits are declared by trait bounds on the Self type of a trait and transitively the supertraits of the traits declared in those trait bounds. It is an error for a trait to be its own supertrait.

Given the context, I think they meant "It is an error for a trait to be transitively declared as its own supertrait". The compiler does indeed give an error for this:

i think that essentially a group of trait is it's own thing and so every trait of the group is a supertrait of the group

What's meant with that quote is the following:

error[E0391]: cycle detected when computing the super clauses of `Tone`
 --> src/main.rs:1:17
  |
1 | pub trait Tone: Tone {}
  |                 ^^^^
  |
  = note: ...which immediately requires computing the super clauses of `Tone` again
note: cycle used when checking that `Tone` is well-formed
 --> src/main.rs:1:1
  |
1 | pub trait Tone: Tone {}
  | ^^^^^^^^^^^^^^^^^^^^
  = note: for more information, see <https://rustc-dev-guide.rust-lang.org/overview.html#queries> and <https://rustc-dev-guide.rust-lang.org/query.html>

For more information about this error, try `rustc --explain E0391`.
error: could not compile `trait_test` (bin "trait_test") due to 1 previous error

So in fact, you can't use a Trait as a supertrait of itself but you can do:

pub trait Tone {
    fn tone(self) -> String;
}

pub trait Meow: Tone {}

#[derive(Default)]
struct Foo(String);
impl Tone for Foo {
    fn tone(self) -> String {
        self.0
    }
}
impl Meow for Foo {}

fn barking<T>(bark: T)
where
    T: Meow + Tone,
{
    println!("meow {}", bark.tone())
}

fn main() {
    let foo = Foo("Meeeee!".to_string());
    barking(foo);
}

In this case, the where clause does not test whether Meow and Tone are related to each other. It only tests whether your chosen type has both implemented. The function barking does not recognise that Meow depends on Tone.

You need to think more in terms of graphs! When you implement a trait, it can depend on any trait you want, except itself. It doesn't matter if the traits your trait uses as dependencies are related to each other.

  • Trait Tone is a dependency of Meow and AngryMeow
  • Trait Meow is a dependency of AngryMeow