@@ -14,38 +14,68 @@ let log_pi = pi.unwrap_or(1.0).log(2.72);
14
14
# assert! (1.14 < log_pi && log_pi < 1.15 )
15
15
```
16
16
17
- When resolving method calls on an expression of type ` A ` , Rust will use the
18
- following order, only looking at methods that are [ visible] . If the type of ` A `
19
- is a type parameter or ` Self ` in a trait definitition then steps 2-4 first
20
- consider traits from bounds on the type paramter, then the traits that are in
21
- scope. For other types, only the traits that are in scope are considered.
22
-
23
- 1 . Inherent methods, with receiver of type ` A ` , ` &A ` , ` &mut A ` .
24
- 1 . Trait methods with receiver of type ` A ` .
25
- 1 . Trait methods with receiver of type ` &A ` .
26
- 1 . Trait methods with receiver of type ` &mut A ` .
27
- 1 . If it's possible, Rust will then repeat steps 1-5 with
28
- ` <A as std::ops::Deref>::Target ` , and insert a dereference operator.
29
- 1 . If ` A ` is now an [ array] type, then repeat steps 1-4 with the corresponding
30
- slice type.
31
-
32
- Note: In steps 1-4, the receiver is used, not the type of ` Self ` nor the
33
- type of ` A ` . For example:
34
-
35
- ``` rust,ignore
36
- // `Self` is `&A`, receiver is `&A`.
37
- impl<'a> Trait for &'a A {
38
- fn method(self) {}
17
+ When resolving method calls on an expression of type ` A ` , Rust looks up methods
18
+ both on the type itself and the traits in implements. Additionally, unlike with
19
+ non-method function calls, the ` self ` parameter is special and may be
20
+ automatically dereferenced in order to resolve it. Rust uses the following
21
+ process to resolve method calls.
22
+
23
+ First, Rust will attempt to build a list of candidate receiver types. It obtains
24
+ these by repeatedly [ dereferencing] [ dereference ] the type, adding each type
25
+ encountered to the list, then finally attempting an [ unsized coercion] at the
26
+ end, and adding the result type if that is successful. Then, for each candidate
27
+ ` T ` , Rust adds ` &T ` and ` &mut T ` to the list immediately afterward.
28
+
29
+ So, for instance, if ` A ` is ` Box<[i32;2]> ` , then the candidate types will be
30
+ ` Box<[i32;2]> ` , ` &Box<[i32;2]> ` , ` &mut Box<[i32;2]> ` , ` [i32; 2] ` (by
31
+ dereferencing), ` &[i32; 2] ` , ` &mut [i32; 2] ` , ` [i32] ` (by unsized coercion),
32
+ ` &[i32] ` , and finally ` &mut [i32] ` .
33
+
34
+ Then, for each candidate type ` T ` , Rust will search for a [ visible] method with
35
+ a receiver of that type in the following places:
36
+
37
+ 1 . ` T ` 's inherent methods (methods implemented directly on ` T ` ).
38
+ 1 . Any of the methods provided by a trait implemented by ` T ` . If ` T ` is
39
+ a type parameter (including the ` Self ` parameter of a trait), then only
40
+ methods from the trait constraints on ` T ` are available for lookup. If ` T ` is
41
+ not, then methods from any in-scope trait are available.
42
+
43
+ Note that the lookup is done for each type in order, which can occasionally lead
44
+ to surprising results. The below code will print "In trait impl!", because
45
+ ` &self ` methods are looked up first, the trait method is found before the
46
+ struct's ` &mut self ` method is found.
47
+
48
+ ``` rust
49
+ struct Foo {}
50
+
51
+ trait Bar {
52
+ fn bar (& self );
53
+ }
54
+
55
+ impl Foo {
56
+ fn bar (& mut self ) {
57
+ println! (" In struct impl!" )
58
+ }
39
59
}
40
- // If `A` is `&B`, then `Self` is `B` and the receiver is `A`.
41
- impl B {
42
- fn method(&self) {}
60
+
61
+ impl Bar for Foo {
62
+ fn bar (& self ) {
63
+ println! (" In trait impl!" )
64
+ }
65
+ }
66
+
67
+ fn main () {
68
+ let mut f = Foo {};
69
+ f . bar ();
43
70
}
44
71
```
45
72
46
- Another note: this process does not use the mutability or lifetime of the
47
- receiver, or whether ` unsafe ` methods can currently be called to resolve
48
- methods. These constraints instead lead to compiler errors.
73
+ If this results in multiple possible candidates, then it is an error, and the
74
+ receiver must be [ converted] [ disambiguate call ] to an appropriate receiver type
75
+ to make the method call.
76
+
77
+ The lookup process does not take into account the mutability or lifetime of the
78
+ receiver, or whether a method is ` unsafe ` . Once a method is looked up.
49
79
50
80
If a step is reached where there is more than one possible method, such as where
51
81
generic methods or traits are considered the same, then it is a compiler
@@ -64,4 +94,5 @@ and function invocation.
64
94
[ visible ] : visibility-and-privacy.html
65
95
[ array ] : types.html#array-and-slice-types
66
96
[ trait objects ] : types.html#trait-objects
67
- [ disambiguating function call syntax ] : expressions/call-expr.html#disambiguating-function-calls
97
+ [ disambiguate call ] : expressions/call-expr.html#disambiguating-function-calls
98
+ [ dereference ] : expressions/operator-expr.html#the-dereference-operator
0 commit comments