arbitrary_self_types: Split the Autoderef chain by dingxiangfei2009 · Pull Request #146095 · rust-lang/rust (original) (raw)
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 andprivacy statement. We’ll occasionally send you account related emails.
Already on GitHub?Sign in to your account
Conversation
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.Learn more about bidirectional Unicode characters
[ Show hidden characters]({{ revealButtonHref }})
Receiver chain has been an extension of Deref chain, but the consequence has been questioned as this would admit method signatures that are deemed dubious.
It is also debatable that Receiver trait which determines applicable Self type should have anything to do with dereference operation in general.
This patch separate the two traits and isolate their use in the language. This means that in method probing, we will chase down a Deref chain for an applicable type for the variable self, from which we additionally chase down a Receiver chain for an applicable Self type from a list of methods that accepts one of these possible types of self.
To facilitate discussion, we can use the Zulip thread #t-lang > Consequences of making Deref a subtrait of Receiver.
Pending items
- First, gather feedback on the proposed change and assess the impact on the overall feature.
- Stomp out UI test changes due to lost diagnostics, by enabling search through Receiver side-chains, so that we can suggest enabling
arbitrary_self_typesgate again.
r? @jackh726
rustbot has assigned @jackh726.
They will have a look at your PR within the next two weeks and either review your PR or reassign to another reviewer.
Use r? to explicitly pick a reviewer
rustbot added S-waiting-on-review
Status: Awaiting review from the assignee but also interested parties.
Relevant to the compiler team, which will review and decide on the PR/issue.
Relevant to the library team, which will review and decide on the PR/issue.
labels
This PR changes a file inside tests/crashes. If a crash was fixed, please move into the corresponding ui subdir and add 'Fixes #' to the PR description to autoclose the issue upon merge.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
The Miri subtree was changed
cc @rust-lang/miri
Some changes occurred in compiler/rustc_codegen_gcc
This comment has been minimized.
This comment has been minimized.
Is this waiting on discussion and a decision from the lang team?
ojeda mentioned this pull request
@jackh726 Sorry I was not very clear. Indeed it would need a lang team discussion.
To support the discussion, I am writing a report to describe what changes this would bring to the feature.
traviscross added S-waiting-on-author
Status: This is awaiting some action (such as code changes or more information) from the author.
DEPRECATED: Use the team-based variants `S-waiting-on-t-lang`, `S-waiting-on-t-compiler`, ...
Items that are on lang's radar and will need eventual work or consideration.
Relevant to the language team
and removed T-libs
Relevant to the library team, which will review and decide on the PR/issue.
labels
The report is a bit overdue. I would like to just publish a partial text while I need more time to restore some diagnostics.
Acceptable receivers
Landing #146095 means that types implementing Deref are not automatically acceptable receiver types anymore.
| Before #146095 | After #146095 |
|---|---|
| struct A; struct B; impl Deref for A { type Target = B; fn deref(&self) -> &B { &B } } impl B { fn recv(self: &A); } A.recv(); // resolves to B::recv | struct A; struct B; impl Deref for A { type Target = B; fn deref(&self) -> &B { &B } } // This is needed ... impl Receiver for A { type Target = B; } impl B { fn recv(self: &A); } A.recv(); // ^ ... in order to resolve this to B::recv |
| // The following passes checking in our surprises impl Trait for str { fn recv(self: &String) {} } "hello".to_string().recv(); impl Trait for MyType { fn recv(self: MutexGuard<'_, Self>) {} } let my_mutex = Mutex::new(MyType); my_mutex.lock().recv(); | // The following stops to compile for good reasons impl Trait for str { fn recv(self: &String) {} // `String: Deref<Target = str>` but without `Receiver<Target = str>` } "hello".to_string().recv(); //~ ERROR impl Trait for MyType { fn recv(self: MutexGuard<'_, Self>) {} // `MutexGuard<'_, MyType>: Deref<Target = MyType>` but without `Receiver<Target = MyType>` } let my_mutex = Mutex::new(MyType); my_mutex.lock().recv(); //~ ERROR |
Library changes
This patch demonstrates that we now explicitly mark types like Rc, Arc, Box, Pin as valid receivers regardless of whether a Deref is applicable.
This is particularly important for Pin as we want to conditionally make it Derefable but unconditionally a valid method receiver just like the stable Rust.
Shadowing
After careful consideration and testing, I believe that splitting the two traits do not change the fundamental reasoning behind method shadowing diagnostics. Before this change, concerns about shadowing items through Deref, and by extension Receiver, are reported by the compiler by picking up inherent methods with the same name on some self receiver down the Receiver chain. Those shadowed items will continue to be reported as they will appear in the same Receiver sub-chain after this PR lands.
traviscross added I-lang-nominated
Nominated for discussion during a lang team meeting.
Lang team prioritization drag level 1. https://rust-lang.zulipchat.com/#narrow/channel/410516-t-lang
labels
I'm going to go ahead and nominate. This is just a vibe check. We're not making a binding decision at this time. The question on the table is only whether we might have such opposition to this direction that we'd block or discourage its exploration.
For my part, I want to see this explored so we can fully consider it.
This comment has been minimized.
This comment has been minimized.
Some changes occurred in compiler/rustc_codegen_cranelift
cc @bjorn3
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
traviscross removed I-lang-nominated
Nominated for discussion during a lang team meeting.
Lang team prioritization drag level 1. https://rust-lang.zulipchat.com/#narrow/channel/410516-t-lang
labels
We talked about this, for a vibe check, in the lang meeting this past week. People certainly aren't yet sold on this approach -- I'm not yet sold myself. However, I feel that the way to work out whether this approach is viable and desirable is to let @dingxiangfei2009 land this and explore it further -- experimentation will hopefully help to answer the kind of questions this approach raises and support the writing of comprehensive design documents for this -- and that went without objection.
Putting on the hat of the lang champion here, then, this PR is OK to land as far as lang is concerned.
We'll want to be careful, in how we do this experimentation, that we still support experimentation of and the ability to answer important design questions for the other model, e.g. to support work on evolving trait hierarchies, reborrowing, autoref, projection, etc., where we might want to compare how the complete solution would look either in the Deref::Target == Receiver::Target world or in the other one. I'm hopeful that we can add additional feature flags as necessary in order to support whatever turns out to be needed here.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
| hir_analysis_invalid_receiver_ty_help_no_arbitrary_self_types = |
| consider changing to `self`, `&self`, `&mut self`, `self: Box`, `self: Rc`, `self: Arc`, or `self: Pin ` (where P is one of the previous types except `Self`) |
| consider changing to `self`, `&self`, `&mut self`, `self: Box`, `self: Rc`, `self: Arc`, or `self: Pin ` (where P is one of the previous types except `Self`); |
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm surprised by this change. I would expect to only change the diagnostic when the feature is not enabled hir_analysis_invalid_receiver_ty_help
Comment on lines 367 to 368
| A(A, PhantomData<fn() -> C>), |
|---|
| B(B, PhantomData<fn() -> C>), |
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why the extra PhantomData<fn() -> C> here? I assume it was to ensure that C is used constrained in the impl below, but it's unnecessary.
| } |
|---|
| } |
| if follow_receiver_chain { |
| EitherIter::A(fcx.autoderef(span, ty).follow_receiver_chain(), PhantomData) |
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Okay, so if I'm understanding this correctly, for each step in Deref chain, we then try a Receiver chain? That's pretty crazy, and is very likely going to have an effect on perf.
I would really like to evaluate perf before and after this PR (when enabling arbitrary self types).
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think we are already performing quadratic time probing with how Receiver is set up on main branch.
FnCtxt::probe_opwalks theDerefchain followed byReceiverextension chain for candidateSelftype. They are collected intosteps.ProbeContext::assemble_*collects all methods with applicableSelftype, for eachSelffromsteps.ProbeContext::pick_all_methoddoes the following. For each type fromsteps, only when it is a member of theDerefchain which corresponds to a possibleselfvalue, this function calls out toProbeContext::pick_methodamong all candidate method items. It will try to unify the type ofselfwith that ofselfargument in the method signature. That is how we find a method match with oneselfand oneSelfin a rightimpl.
I am thinking of sorting the candidates into bins for each candidate Self type. With this structure we save some search effort. Let me work on a patch on this idea.
Comment on lines +1825 to +1827
| // We are in the wf check, so we would like to deref the references in the type head. |
|---|
| // However, we do not want to walk `Deref` chain. |
| autoderef = autoderef.follow_receiver_chain(); |
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm curious why that is here? But in confirm we do?
| &*self.0 |
|---|
| } |
| } |
| impl<T: ?Sized> Receiver for Ptr<T> { |
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Are these impls required? I imagine this might be a consequence of my comment in wfcheck?
This comment has been minimized.
Receiver chain has been an extension of Deref chain, but the consequence has been questioned as this would admit method signatures that are deemed dubious.
It is also debatable that Receiver trait which determines applicable
Self type should have anything to do with dereference operation
in general.
This patch separate the two traits and isolate their use in the language.
This means that in method probing, we will chase down a Deref chain for
an applicable type for the variable self, from which we additionally
chase down a Receiver chain for an applicable Self type from a list of
methods that accepts one of these possible types of self.
This patch includes rewording of diagnostics.
This PR was rebased onto a different master commit. Here's a range-diff highlighting what actually changed.
Rebasing is a normal part of keeping PRs up to date, so no action is needed—this note is just to help reviewers.
Labels
`#![feature(arbitrary_self_types)]`
Items that are on lang's radar and will need eventual work or consideration.
Status: This is awaiting some action (such as code changes or more information) from the author.
Status: Awaiting review from the assignee but also interested parties.
Relevant to the compiler team, which will review and decide on the PR/issue.
Relevant to the language team