Finomnis
Finomnis

Reputation: 22738

Why does impl overloading work with `for &T where T: MyTrait` but not with `for &dyn MyTrait`?

Why does this compile:

trait MyTrait {}

trait MyTraitFrom<'a, T> {
    fn mytrait_from(value: &'a mut T) -> Self;
}

impl<'a, T: MyTrait> MyTraitFrom<'a, T> for &'a mut T {
    fn mytrait_from(value: &'a mut T) -> Self {
        value
    }
}

impl<'a, T: MyTrait> MyTraitFrom<'a, &'a mut T> for &'a mut T {
    fn mytrait_from(value: &'a mut &'a mut T) -> Self {
        let value: &'a mut T = value;
        value
    }
}

but this doesn't:

trait MyTrait {}

trait MyTraitFrom<'a, T> {
    fn mytrait_from(value: &'a mut T) -> Self;
}

impl<'a, T: MyTrait> MyTraitFrom<'a, T> for &'a mut dyn MyTrait {
    fn mytrait_from(value: &'a mut T) -> Self {
        value
    }
}

impl<'a, T: MyTrait> MyTraitFrom<'a, &'a mut T> for &'a mut dyn MyTrait {
    fn mytrait_from(value: &'a mut &'a mut T) -> Self {
        let value: &'a mut T = value;
        value
    }
}
error[E0119]: conflicting implementations of trait `MyTraitFrom<'_, &mut _>` for type `&mut dyn MyTrait`
  --> src/lib.rs:13:1
   |
7  | impl<'a, T: MyTrait> MyTraitFrom<'a, T> for &'a mut dyn MyTrait {
   | --------------------------------------------------------------- first implementation here
...
13 | impl<'a, T: MyTrait> MyTraitFrom<'a, &'a mut T> for &'a mut dyn MyTrait {
   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `&mut dyn MyTrait`
   |
   = note: downstream crates may implement trait `MyTrait` for type `&mut _`

Isn't &'a mut T more general than &'a mut dyn MyTrait?

Upvotes: 1

Views: 51

Answers (1)

Chayim Friedman
Chayim Friedman

Reputation: 71350

&'a mut T is indeed more general than &'a mut dyn MyTrait...

...if T is not constrained somewhere else. Which it is here - the T is the same for the generic parameter and the Self type.

The more general code, which does not compile either, is:

impl<'a, T: MyTrait, U> MyTraitFrom<'a, T> for &'a mut U {
    fn mytrait_from(value: &'a mut T) -> Self {
        value
    }
}

impl<'a, T: MyTrait, U> MyTraitFrom<'a, &'a mut T> for &'a mut U {
    fn mytrait_from(value: &'a mut &'a mut T) -> Self {
        let value: &'a mut T = value;
        value
    }
}

Think about it: we can list all generic parameters and Self to obtain a unique identity for this implementation. If two identities conflict, their impls also do. For the dyn MyTrait case, the identities (ignoring lifetimes) are (&'a mut dyn MyTrait, T) and (&'a mut dyn MyTrait, &'a mut T). As &'a mut T is itself a T, this clearly conflicts. The same also applies to the abovementioned example with U. However, in your first case, the identitiers are (&'a mut T, T) and (&'a mut T, &'a mut T). These do not conflict, as when T is &'a mut T &'a mut T becomes &'a mut &'a mut T, and it is not the same as &'a mut T anymore.

Upvotes: 1

Related Questions