Description
I am looking at the algorithm for method call resolution.
The first step is to build a list of candidate receiver types. Obtain these by 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.
For instance, if the receiver has type Box<[i32;2]>, then the candidate types will be Box<[i32;2]>, &Box<[i32;2]>, &mut Box<[i32;2]>, [i32; 2] (by dereferencing), &[i32; 2], &mut [i32; 2], [i32] (by unsized coercion), &[i32], and finally &mut [i32].
Then, for each candidate type T, search for a visible method with a receiver of that type in the following places:
- T's inherent methods (methods implemented directly on T).
- Any of the methods provided by a visible trait implemented by T. If T is a type parameter, methods provided by trait bounds on T are looked up first. Then all remaining methods in scope are looked up.
Let's follow this algorithm for this method call:
struct Foo;
impl Foo {
fn foo(&self) {}
}
fn main() {
let a = Foo;
a.foo();
}
First, build the list of candidate types:
Foo
&Foo
&mut Foo
Then for each candidate type, search for methods with a receiver of that type in the places listed:
Foo
: There are no methods with receiver type ofFoo
&Foo
:
2.1. Search&Foo
's inherent methods (methods implemented directly on&Foo
). There are none because there is noimpl &Foo
.
2.2. Search methods provided by traits implemented by&Foo
. There are none.&mut Foo
: no methods with receiver type of&mut Foo
So according to the reference, the a.foo()
method call shouldn't work.
Another example is with a trait:
struct Foo;
trait Trait {
fn foo(&self);
}
impl Trait for Foo {
fn foo(&self) {}
}
fn main() {
let a = Foo;
a.foo();
}
The reference says to look for methods with the receiver type of &Foo
in traits implemented by &Foo
, but Trait
is not implemented by &Foo
.