-
Notifications
You must be signed in to change notification settings - Fork 12.9k
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
MIR borrowck doesn't accept the example of iterating and updating a mutable reference #46589
Comments
It turns out the code for this was just never written. What we need to do is "kill" the relevant borrows in the rust/src/librustc_mir/dataflow/impls/borrows.rs Lines 265 to 268 in 707d070
We would need to handle this in the case of a general assignment, but there the |
So, if I understand correctly, we want to duplicate/share the logics from |
As discussed with @pnkfelix over gitter, I'll try to first write a patch that works only if we |
@Yoric great! that's a good starting point. |
…assign over this variable
Issue #46589 - Kill borrows on a local variable whenever we assign ov… …er this variable This is a first patch for the issue, handling the simple case while I figure out the data structures involved in the more complex cases.
I'm now trying to tackle down the next part, but I can't find anything useful in the RFC, so I'm a bit blind here. Looking at projections, I see the following cases:
I imagine that case 1. is basically the same thing as what I have done already and that cases for 3 and 5, there isn't anything we can do. What about cases 2, 4 and 6? |
needinfo @pnkfelix , @nikomatsakis ? |
@Yoric as I wrote in gitter, one way to approach this is to generalize the routine that is used to detect overlap between paths. This function is called rust/src/librustc_mir/borrow_check/mod.rs Lines 1769 to 1777 in 78f24d8
However, presently it is "biased" towards returning that yes, places overlap. This is because it is used to detect illegal assignments. Specifically, with indexing, we wind up approximating -- that is, if you borrow The part of the code that controls how we handle array accesses is here. Returning |
This is not as general as it could be, but I'm marking as deferred rather than complete because honestly I think handling local variables is "good enough" for now, and we can always come back to it. |
Here is an example (from #48001) of code that ought to pass when this is fully implemented: #![feature(nll)]
struct Foo;
impl Foo {
fn get_self(&mut self) -> Option<&mut Self> {
Some(self)
}
fn new_self(&mut self) -> &mut Self {
self
}
fn trigger_bug(&mut self) {
let other = &mut (&mut *self);
*other = match (*other).get_self() {
Some(s) => s,
None => (*other).new_self()
};
let c = other;
}
}
fn main() {} currently it fails with
|
I tried to write some code with an early-returned borrow inside a loop that I expected NLL would accept, but it didn’t. A reduced test case is below. Is this the same issue? #![feature(nll)]
fn main() {}
pub struct Decoder {
buf_read: BufRead,
}
impl Decoder {
pub fn next<'a>(&'a mut self) -> &'a str {
loop {
let buf = self.buf_read.fill_buf();
if let Some(s) = decode(buf) {
return s
}
// loop to get more input data
// At this point `buf` is not used anymore.
// With NLL I would expect the borrow to end here,
// such that `self.buf_read` is not borrowed anymore
// by the time we start the next loop iteration.
}
}
}
struct BufRead;
impl BufRead {
fn fill_buf(&mut self) -> &[u8] { unimplemented!() }
}
fn decode(_: &[u8]) -> Option<&str> { unimplemented!() } Errors: Compiling playground v0.0.1 (file:///playground)
error[E0499]: cannot borrow `self.buf_read` as mutable more than once at a time
--> src/main.rs:12:23
|
12 | let buf = self.buf_read.fill_buf();
| ^^^^^^^^^^^^^ mutable borrow starts here in previous iteration of loop
|
note: borrowed value must be valid for the lifetime 'a as defined on the method body at 10:17...
--> src/main.rs:10:17
|
10 | pub fn next<'a>(&'a mut self) -> &'a str {
| ^^
error: aborting due to previous error
For more information about this error, try `rustc --explain E0499`.
error: Could not compile `playground`.
To learn more, run the command again with --verbose. |
Interestingly, this a case where NLL is not "just" about making some code slightly nicer. As far as I can tell there is no way to write the algorithm without |
This commit adds the test for writing into a projection of a local to confirm there are no remaining borrows.
Re-triaging for #56754. Leaving assigned to @davidtwco. P-medium, NLL-complete. |
MIR borrowck doesn't accept the example of iterating and updating a mutable reference Fixes #46589. r? @pnkfelix or @nikomatsakis
@nikomatsakis's example still doesn't work, right?
|
@goffrie @nikomatsakis’s example is now missing the second error that this issue was intended to solve, namely:
|
I expected this example from the NLL RFC to pass the MIR borrow checker:
The idea here is that assigning to
list
is supposed to clear the existing borrows oflist.{value,next}
. However, it still gets errors for me:cc @pnkfelix @arielb1
The text was updated successfully, but these errors were encountered: