@@ -42,20 +42,39 @@ inference variables or other information.
4242The first thing that the probe phase does is to create a series of
4343* steps* . This is done by progressively dereferencing the receiver type
4444until 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
45+ "unsize" step. This "dereferencing" in fact uses the ` Receiver ` trait
46+ rather than the normal ` Deref ` trait. There's a blanket implementation
47+ of ` Receiver ` for ` T: Deref ` so the answer is often the same.
48+
49+ So if the receiver has type ` Rc<Box<[T; 3]>> ` , this
4650might yield:
4751
48- 1 . ` Rc<Box<[T; 3]>> `
49- 2 . ` Box<[T; 3]> `
50- 3 . ` [T; 3] `
51- 4 . ` [T] `
52+ 1 . ` Rc<Box<[T; 3]>> ` *
53+ 2 . ` Box<[T; 3]> ` *
54+ 3 . ` [T; 3] ` *
55+ 4 . ` [T] ` *
56+
57+ Some types might implement ` Receiver ` but not ` Deref ` . Imagine that
58+ ` SmartPtr<T> ` does this. If the receiver has type ` &Rc<SmartPtr<T>> `
59+ the steps would be:
60+
61+ 1 . ` &Rc<SmartPtr<T>> ` *
62+ 2 . ` Rc<SmartPtr<T>> ` *
63+ 3 . ` SmartPtr<T> ` *
64+ 4 . ` T `
65+
66+ The first three of those steps, marked with a * , can be reached using
67+ ` Deref ` as well as by ` Receiver ` . This fact is recorded against each step.
5268
5369### Candidate assembly
5470
55- We 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
57- invoked. For each candidate, we'll derive a "transformed self type"
58- that takes into account explicit self.
71+ We then search along these candidate steps to create a list of
72+ * candidates* . A ` Candidate ` is a method item that might plausibly be the
73+ method being invoked. For each candidate, we'll derive a "transformed self
74+ type" that takes into account explicit self.
75+
76+ At this point, we consider the whole list - all the steps reachable via
77+ ` Receiver ` , not just the shorter list reachable via ` Deref ` .
5978
6079Candidates are grouped into two kinds, inherent and extension.
6180
@@ -95,9 +114,14 @@ might have two candidates:
95114
96115### Candidate search
97116
98- Finally, to actually pick the method, we will search down the steps,
99- trying to match the receiver type against the candidate types. At
100- each step, we also consider an auto-ref and auto-mut-ref to see whether
117+ Finally, to actually pick the method, we will search down the steps again,
118+ trying to match the receiver type against the candidate types. This time,
119+ we consider only the steps which can be reached via ` Deref ` , since we
120+ actually need to convert the receiver type to match the ` self ` type.
121+ In the examples above, that means we consider only the steps marked with
122+ an asterisk.
123+
124+ At each step, we also consider an auto-ref and auto-mut-ref to see whether
101125that makes any of the candidates match. For each resulting receiver
102126type, we consider inherent candidates before extension candidates.
103127If there are multiple matching candidates in a group, we report an
@@ -111,3 +135,68 @@ recursively consider all where-clauses that appear on the impl: if
111135those match (or we cannot rule out that they do), then this is the
112136method we would pick. Otherwise, we would continue down the series of
113137steps.
138+
139+ ### ` Deref ` vs ` Receiver `
140+
141+ Why have longer and shorter lists here? The use-case is smart pointers.
142+ For example:
143+
144+ ```
145+ struct Inner;
146+
147+ // Assume this cannot implement Deref for some reason, e.g. because
148+ // we know other code may be accessing T and it's not safe to make
149+ // a reference to it
150+ struct Ptr<T>;
151+
152+ impl<T> Receiver for Ptr<T> {
153+ type Target = T;
154+ }
155+
156+ impl Inner {
157+ fn method1(self: &Ptr<Self>) {
158+ }
159+
160+ fn method2(&self) {}
161+ }
162+
163+ fn main() {
164+ let ptr = Ptr(Inner);
165+ ptr.method1();
166+ // ptr.method2();
167+ }
168+ ```
169+
170+ In this case, the step list for the ` method1 ` call would be:
171+
172+ 1 . ` Ptr<Inner> ` *
173+ 2 . ` Inner `
174+
175+ Because the list of types reached via ` Receiver ` includes ` Inner ` , we can
176+ look for methods in the ` impl Inner ` block during candidate search.
177+ But, we can't dereference a ` &Receiver ` to make a ` &Inner ` , so the picking
178+ process won't allow us to call ` method2 ` on a ` Ptr<Inner> ` .
179+
180+ ### Deshadowing
181+
182+ Once we've made a pick, code in ` pick_all_method ` also checks for a couple
183+ of cases where one method may shadow another. That is, in the code example
184+ above, imagine there also exists:
185+
186+ ```
187+ impl Inner {
188+ fn method3(self: &Ptr<Self>) {}
189+ }
190+
191+ impl<T> Ptr<T> {
192+ fn method3(self) {}
193+ }
194+ ```
195+
196+ These can both be called using ` ptr.method3() ` . Without special care, we'd
197+ automatically use ` Ptr::self ` because we pick by value before even looking
198+ at by-reference candidates. This could be a problem if the caller previously
199+ was using ` Inner::method3 ` : they'd get an unexpected behavior change.
200+ So, if we pick a by-value candidate we'll check to see if we might be
201+ shadowing a by-value candidate, and error if so. The same applies
202+ if a by-mut-ref candidate shadows a by-reference candidate.
0 commit comments