]> git.proxmox.com Git - rustc.git/blame - src/doc/rustc-dev-guide/src/method-lookup.md
New upstream version 1.69.0+dfsg1
[rustc.git] / src / doc / rustc-dev-guide / src / method-lookup.md
CommitLineData
a1dfa0c6
XL
1# Method lookup
2
3Method lookup can be rather complex due to the interaction of a number
4of factors, such as self types, autoderef, trait lookup, etc. This
5file provides an overview of the process. More detailed notes are in
6the code itself, naturally.
7
8One way to think of method lookup is that we convert an expression of
cdc7bbd5
XL
9the form `receiver.method(...)` into a more explicit [fully-qualified syntax][]
10(formerly called [UFCS][]):
a1dfa0c6 11
cdc7bbd5
XL
12- `Trait::method(ADJ(receiver), ...)` for a trait call
13- `ReceiverType::method(ADJ(receiver), ...)` for an inherent method call
a1dfa0c6
XL
14
15Here `ADJ` is some kind of adjustment, which is typically a series of
16autoderefs and then possibly an autoref (e.g., `&**receiver`). However
17we sometimes do other adjustments and coercions along the way, in
18particular unsizing (e.g., converting from `[T; n]` to `[T]`).
19
20Method lookup is divided into two major phases:
21
221. Probing ([`probe.rs`][probe]). The probe phase is when we decide what method
23 to call and how to adjust the receiver.
242. Confirmation ([`confirm.rs`][confirm]). The confirmation phase "applies"
25 this selection, updating the side-tables, unifying type variables, and
26 otherwise doing side-effectful things.
27
28One reason for this division is to be more amenable to caching. The
29probe phase produces a "pick" (`probe::Pick`), which is designed to be
30cacheable across method-call sites. Therefore, it does not include
31inference variables or other information.
32
cdc7bbd5 33[fully-qualified syntax]: https://doc.rust-lang.org/nightly/book/ch19-03-advanced-traits.html#fully-qualified-syntax-for-disambiguation-calling-methods-with-the-same-name
a1dfa0c6 34[UFCS]: https://github.com/rust-lang/rfcs/blob/master/text/0132-ufcs.md
2b03887a
FG
35[probe]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_hir_typeck/method/probe/
36[confirm]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_hir_typeck/method/confirm/
a1dfa0c6
XL
37
38## The Probe phase
39
40### Steps
41
42The first thing that the probe phase does is to create a series of
43*steps*. This is done by progressively dereferencing the receiver type
44until it cannot be deref'd anymore, as well as applying an optional
45"unsize" step. So if the receiver has type `Rc<Box<[T; 3]>>`, this
46might yield:
47
cdc7bbd5
XL
481. `Rc<Box<[T; 3]>>`
492. `Box<[T; 3]>`
503. `[T; 3]`
514. `[T]`
a1dfa0c6
XL
52
53### Candidate assembly
54
55We then search along those steps to create a list of *candidates*. A
56`Candidate` is a method item that might plausibly be the method being
57invoked. For each candidate, we'll derive a "transformed self type"
58that takes into account explicit self.
59
60Candidates are grouped into two kinds, inherent and extension.
61
62**Inherent candidates** are those that are derived from the
63type of the receiver itself. So, if you have a receiver of some
64nominal type `Foo` (e.g., a struct), any methods defined within an
65impl like `impl Foo` are inherent methods. Nothing needs to be
66imported to use an inherent method, they are associated with the type
67itself (note that inherent impls can only be defined in the same
cdc7bbd5 68crate as the type itself).
a1dfa0c6
XL
69
70FIXME: Inherent candidates are not always derived from impls. If you
71have a trait object, such as a value of type `Box<ToString>`, then the
72trait methods (`to_string()`, in this case) are inherently associated
73with it. Another case is type parameters, in which case the methods of
74their bounds are inherent. However, this part of the rules is subject
75to change: when DST's "impl Trait for Trait" is complete, trait object
76dispatch could be subsumed into trait matching, and the type parameter
77behavior should be reconsidered in light of where clauses.
78
79TODO: Is this FIXME still accurate?
80
81**Extension candidates** are derived from imported traits. If I have
04454e1e
FG
82the trait `ToString` imported, and I call `to_string()` as a method,
83then we will list the `to_string()` definition in each impl of
84`ToString` as a candidate. These kinds of method calls are called
85"extension methods".
a1dfa0c6
XL
86
87So, let's continue our example. Imagine that we were calling a method
88`foo` with the receiver `Rc<Box<[T; 3]>>` and there is a trait `Foo`
89that defines it with `&self` for the type `Rc<U>` as well as a method
04454e1e 90on the type `Box` that defines `foo` but with `&mut self`. Then we
a1dfa0c6 91might have two candidates:
cdc7bbd5 92
04454e1e
FG
93- `&Rc<U>` as an extension candidate
94- `&mut Box<U>` as an inherent candidate
a1dfa0c6
XL
95
96### Candidate search
97
98Finally, to actually pick the method, we will search down the steps,
99trying to match the receiver type against the candidate types. At
100each step, we also consider an auto-ref and auto-mut-ref to see whether
04454e1e
FG
101that makes any of the candidates match. For each resulting receiver
102type, we consider inherent candidates before extension candidates.
103If there are multiple matching candidates in a group, we report an
104error, except that multiple impls of the same trait are treated as a
105single match. Otherwise we pick the first match we find.
a1dfa0c6
XL
106
107In the case of our example, the first step is `Rc<Box<[T; 3]>>`,
108which does not itself match any candidate. But when we autoref it, we
04454e1e 109get the type `&Rc<Box<[T; 3]>>` which matches `&Rc<U>`. We would then
a1dfa0c6
XL
110recursively consider all where-clauses that appear on the impl: if
111those match (or we cannot rule out that they do), then this is the
112method we would pick. Otherwise, we would continue down the series of
113steps.