-
Notifications
You must be signed in to change notification settings - Fork 506
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Arbitrary self types v2: update reference. #1699
base: master
Are you sure you want to change the base?
Conversation
@rustbot label +S-waiting-on-author -S-waiting-on-review |
Wouldn't the point
for |
I agree, I'll remove that bit. |
This comment has been minimized.
This comment has been minimized.
c860df3
to
e138cf7
Compare
I've pushed a couple of extra commits here to respond to review feedback - I suspect I should probably squash them before this is merged (?) but for now it's easier for folks to see what I changed. |
d641699
to
84f896f
Compare
The first step is to build a list of types where we might find methods. | ||
Obtain these by repeatedly [dereferencing][dereference] 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`. | ||
Then, for each candidate `T`, add `&T` and `&mut T` to the list immediately after `T`. While dereferencing, we don't use the normal `Deref` trait, but instead the `Receiver` trait: there is a blanket implementation of `Receiver` for all `T: Deref` so in practice this is often the same. | ||
|
||
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]`. | ||
For instance, if the receiver has type `Box<[i32;2]>`, then the contributing 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: | ||
Some custom smart pointers may implement `Receiver` but not `Deref`. Imagine `MySmartPtr<T>: Receiver<Target=T>`: if the receiver type has `Box<MySmartPtr<SomeStruct>>` the contributing types will be `Box<MySmartPtr<SomeStruct>>`, `MySmartPtr<SomeStruct>` and `SomeStruct`. | ||
|
||
Even though we assemble this list by following the chain of `Receiver` implementations, we keep a note of which steps can be reached by following the regular `Deref` chain. In the above example, that would be all but the last step. The items in the list reachable by the `Deref` chain are termed the "candidate types"; the full list reachable by the `Receiver` chain is called the "contributing types". | ||
|
||
Then, for each _contributing_ type `T`, search for a [visible] method with a receiver of any _candidate_ type in the following places: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is better, but still some things we can improve:
- We're inconsistently using the word "candidate". Toward the top, we talk about assembling the list of candidates (i.e. "for each candidate
T
, add ... to the list"), but we don't mean the list of "candidate types" as defined later, we mean the list of "contributing types". The word "candidate" is also used further below in a seemingly-inconsistent way. - We separately define this notion of "candidate types" from "contributing types", but we don't say why or use the list of candidate types for anything as far as I can tell. It's a bit odd to define this separately if it has no semantic relevance to the language. If there is some semantic relevance, we should describe it. If it's only of implementation relevance, then it's probably a better fit for the dev guide.
- We're no longer stating our terms upfront. That's what the bit you removed about "The first step is to build a list of candidate receiver types" was doing -- it introduced that term, then described how we built that list. The text now says "the contributing types will be..." without first introducing that this is a special term and we're building a list of these things.
- Talking about repeated dereferencing and then saying, "well, really it's not dereferencing but this other thing" is a bit odd. It's probably better to just directly describe that we're following the chain of receiver targets.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Agreed with all your points other than this one:
We separately define this notion of "candidate types" from "contributing types", but we don't say why or use the list of candidate types for anything as far as I can tell. It's a bit odd to define this separately if it has no semantic relevance to the language. If there is some semantic relevance, we should describe it. If it's only of implementation relevance, then it's probably a better fit for the dev guide.
It is of semantic relevance - it says this, which you may have overlooked:
Then, for each contributing type
T
, search for a visible method with a receiver of any candidate type in the following places:
I'll have another crack at it.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Great, thanks. Did miss that bit.
so it's rare to implement `Receiver` directly: you'd only normally do this | ||
for smart pointer types which for some reason can't implement `Deref`. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'd probably remove this bit about it being rare and instead describe affirmatively why Receiver
can be implemented but Deref
cannot in some cases.
Part of rust-lang/rust#44874