-
Notifications
You must be signed in to change notification settings - Fork 12.8k
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
Use normal mutable borrows in matches #57609
Conversation
@bors try |
⌛ Trying commit 34f7a41485e00806e7b82ec5b439972a53033e9c with merge 26f8d250bb3c8a85e812cf663c730ef9e0df9315... |
☀️ Test successful - checks-travis |
@rust-lang/infra please can this have a crater run? |
@craterbot run start=master#03acbd71c977cd63ce5f39ba9b6fe9ffd578785a end=try#26f8d250bb3c8a85e812cf663c730ef9e0df9315 mode=check-only |
👌 Experiment ℹ️ Crater is a tool to run experiments across parts of the Rust ecosystem. Learn more |
🚧 Experiment ℹ️ Crater is a tool to run experiments across parts of the Rust ecosystem. Learn more |
🎉 Experiment
|
A bit of a longer write up on the two options here then. CFG construction changesFor reference, the generated CFG for a match with 3 arms where the first one has a guard now looks something like this: The Fake borrows changesFake borrows are now added not only to the start block, but also to the end of any binding block that are proceeded by a guard. This means that the fake borrows are not live for the binding block and so do not conflict with any Option A (commit 1)At this point using minimal two-phase borrows is compatible with the match lowering. Some notes:
Option B (commit 3)This uses real borrows. See OP for some details. Some note:
|
@matthewjasper ok, I read your comment, but I still feel like I don't fully understand what is being proposed. Probably I'm just missing a certain amount of context. Let me just pepper out a few questions I guess:
When you say "fake borrows", you mean that we put dummy borrows like
Why does it mean that? Because the "fake borrows" we inserted at the start block never wind up being used? Are they live only during the matching code that we generate, which inspects the discriminants and so forth, or are they ever live for "user code" (i.e., guards)? If they are only live for code we generate, then it doesn't seem like they play much of a role, do they? (Since we trust that code not to mutate things.) Maybe they are needed for initialization checks or something?
What is a "minimal" 2PB? And which borrows are becoming 2PB exactly? Do you mean for the I feel like what I might like to see is some kind "representative desugaring" of a match in both styles. |
A simple example of the generated MIR for nightly and for this branch is here https://gist.github.com/matthewjasper/fb0f4bfb9d3a6d179ed0c2eb7a5b0da5 I've marked the 2-phase borrow that's created on nightly.
Yes. In the example above, all of the shallow/guard borrows are "fake borrows". See
They're live in all guards (and while we're branching). They're not live outside of the match expression, in the arm expressions or after we've selected a pattern and are creating bindings for it - either the bindings for the guard or the bindings for the arm.
I mean the version of 2 phase borrows discussed in #56254. The two-phase borrows are the ones that are already two phase: the borrows associated to |
34f7a41
to
be15224
Compare
Sorry @matthewjasper been very distracted. I've added a calendar event to review and ponder this for Mon Jan 28, so hopefully that will help. |
OK, I read the desugared example in your gist. Allow me to attempt to re-summarize what is going on. First off, the match process looks vaguely like this:
Does this sound right? |
To redraw my flow graph with fake borrows inserted, it looks something like this:
|
If that is the case, I am wondering what the role of the fake borrows being live during "discriminant testing" is. I don't think they're harmful per se, just trying to create an accurate model of what the "threats" are. I think there are a few things that users can do that are problematic:
|
So, first a couple of my own versions of the diagram:
In the case of no guard
No, there's no read here at the moment (you link to a fake read at (***)). It would certainly be nicer to have them there instead of where they currently are if it's not too annoying to implement. Currently we rely on the
As well as the above I think you're asking why |
So after some discussion on Zulip, I think that me and @nikomatsakis are agreed that we want the match CFG to look like this
If there's no guard then |
Too big to rollup, @bors p=1 |
⌛ Testing commit 5ffc919 with merge 8972b60cf5f62fd21799a1609065a1eba92da65b... |
💔 Test failed - checks-travis |
The job Click to expand the log.
I'm a bot! I can only do what humans tell me to, so if this was not helpful or you have suggestions for improvements, please ping or otherwise contact |
Broken the miri test |
@bors retry |
Use normal mutable borrows in matches `ref mut` borrows are currently two-phase with NLL enabled. This changes them to be proper mutable borrows. To accommodate this, first the position of fake borrows is changed: ```text [ 1. Pre-match ] | [ (old create fake borrows) ] [ 2. Discriminant testing -- check discriminants ] <-+ | | | (once a specific arm is chosen) | | | [ (old read fake borrows) ] | [ 3. Create "guard bindings" for arm ] | [ (create fake borrows) ] | | | [ 4. Execute guard code ] | [ (read fake borrows) ] --(guard is false)-----------+ | | (guard results in true) | [ 5. Create real bindings and execute arm ] | [ Exit match ] ``` The following additional changes are made to accommodate `ref mut` bindings: * We no longer create fake `Shared` borrows. These borrows are no longer needed for soundness, just to avoid some arguably strange cases. * `Shallow` borrows no longer conflict with existing borrows, avoiding conflicting access between the guard borrow access and the `ref mut` borrow. There is some further clean up done in this PR: * Avoid the "later used here" note for Shallow borrows (since it's not relevant with the message provided) * Make any use of a two-phase borrow activate it. * Simplify the cleanup_post_borrowck passes into a single pass. cc #56254 r? @nikomatsakis
☀️ Test successful - checks-travis, status-appveyor |
☀️ Test successful - checks-travis, status-appveyor |
ref mut
borrows are currently two-phase with NLL enabled. This changes them to be proper mutable borrows. To accommodate this, first the position of fake borrows is changed:The following additional changes are made to accommodate
ref mut
bindings:Shared
borrows. These borrows are no longer needed for soundness, just to avoid some arguably strange cases.Shallow
borrows no longer conflict with existing borrows, avoiding conflicting access between the guard borrow access and theref mut
borrow.There is some further clean up done in this PR:
cc #56254
r? @nikomatsakis