@@ -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
@@ -97,9 +116,14 @@ might have two candidates:
97116
98117### Candidate search
99118
100- Finally, to actually pick the method, we will search down the steps,
101- trying to match the receiver type against the candidate types. At
102- each step, we also consider an auto-ref and auto-mut-ref to see whether
119+ Finally, to actually pick the method, we will search down the steps again,
120+ trying to match the receiver type against the candidate types. This time,
121+ we consider only the steps which can be reached via ` Deref ` , since we
122+ actually need to convert the receiver type to match the ` self ` type.
123+ In the examples above, that means we consider only the steps marked with
124+ an asterisk.
125+
126+ At each step, we also consider an auto-ref and auto-mut-ref to see whether
103127that makes any of the candidates match. For each resulting receiver
104128type, we consider inherent candidates before extension candidates.
105129If there are multiple matching candidates in a group, we report an
@@ -113,3 +137,68 @@ recursively consider all where-clauses that appear on the impl: if
113137those match (or we cannot rule out that they do), then this is the
114138method we would pick. Otherwise, we would continue down the series of
115139steps.
140+
141+ ### ` Deref ` vs ` Receiver `
142+
143+ Why have longer and shorter lists here? The use-case is smart pointers.
144+ For example:
145+
146+ ```
147+ struct Inner;
148+
149+ // Assume this cannot implement Deref for some reason, e.g. because
150+ // we know other code may be accessing T and it's not safe to make
151+ // a reference to it
152+ struct Ptr<T>;
153+
154+ impl<T> Receiver for Ptr<T> {
155+ type Target = T;
156+ }
157+
158+ impl Inner {
159+ fn method1(self: &Ptr<Self>) {
160+ }
161+
162+ fn method2(&self) {}
163+ }
164+
165+ fn main() {
166+ let ptr = Ptr(Inner);
167+ ptr.method1();
168+ // ptr.method2();
169+ }
170+ ```
171+
172+ In this case, the step list for the ` method1 ` call would be:
173+
174+ 1 . ` Ptr<Inner> ` *
175+ 2 . ` Inner `
176+
177+ Because the list of types reached via ` Receiver ` includes ` Inner ` , we can
178+ look for methods in the ` impl Inner ` block during candidate search.
179+ But, we can't dereference a ` &Receiver ` to make a ` &Inner ` , so the picking
180+ process won't allow us to call ` method2 ` on a ` Ptr<Inner> ` .
181+
182+ ### Deshadowing
183+
184+ Once we've made a pick, code in ` pick_all_method ` also checks for a couple
185+ of cases where one method may shadow another. That is, in the code example
186+ above, imagine there also exists:
187+
188+ ```
189+ impl Inner {
190+ fn method3(self: &Ptr<Self>) {}
191+ }
192+
193+ impl<T> Ptr<T> {
194+ fn method3(self) {}
195+ }
196+ ```
197+
198+ These can both be called using ` ptr.method3() ` . Without special care, we'd
199+ automatically use ` Ptr::self ` because we pick by value before even looking
200+ at by-reference candidates. This could be a problem if the caller previously
201+ was using ` Inner::method3 ` : they'd get an unexpected behavior change.
202+ So, if we pick a by-value candidate we'll check to see if we might be
203+ shadowing a by-value candidate, and error if so. The same applies
204+ if a by-mut-ref candidate shadows a by-reference candidate.
0 commit comments