Trait resolver and why does this work?

In the code in question trait MyTrait is not implemented for the struct MyStruct directly, only blanket implementation exist for references. However I'm still able to call a trait method on the object, not reference, of MyStruct.

Even though object is mut, implementation for &T is called, not &mut T.

Why does this work in the first place, why fn trait_test(self) is called for &T instead of &mut T and why am I able to call it more than once since method takes self and not &self?

#![allow(unused)]
trait MyTrait {
    fn trait_test(self);
}

struct MyStruct(u32);

impl<T> MyTrait for &T {
    fn trait_test(self) {
        println!("---------");
    }
}

impl<T> MyTrait for &mut T {
    fn trait_test(self) {
        println!("+++++++++");
    }
}

fn main() {
    let mut m = MyStruct(8);

    m.trait_test(); // Prints "---------".
    m.trait_test(); // Prints "---------".
}

basically, there's a well defined order when resolving a method call expression:

https://doc.rust-lang.org/reference/expressions/method-call-expr.html

to quote:

The first step is to build a list of candidate receiver types. [...]

Then, for each candidate type T, search for a visible method [...]

and candidate list is built with this algorithm (emphasis mine):

[...] repeatedly dereferencing the receiver expression’s type, adding each type encountered to the list, then finally attempting an unsized coercion at the end, and adding the result type if that is successful. Then, for each candidate T, add &T and &mut T to the list immediately after T.

the visible methods are looked up with this algorithm:

[...] with a receiver of that type in the following places:

  1. T’s inherent methods (methods implemented directly on T).
  2. Any of the methods provided by a visible trait implemented by T. [...]
4 Likes

fn main() {
let mut m = MyStruct(8);
m.trait_test(); // Prints "---------".
(&mut m).trait_test(); // Prints "++++++". you see,this works.
}