-
Notifications
You must be signed in to change notification settings - Fork 1.6k
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
Non-lexical borrow scopes and better treatment of nested method calls #811
Comments
Most of these are old, but some specific messages for specific tests: * trait-contravariant-self.rs: failed due to a soundess hole: rust-lang@05e3248 * process-detatch: rust-lang@15966c3 says "this test is being ignored until signals are implemented" That's not happening for a long time, and when it is, we'll write tests for it. * deep-vector{,2}.rs: "too big for our poor macro infrastructure", and has been ignored over a year. * borrowck-nested-calls.rs's FIXME rust-lang#6268 was closed in favor of rust-lang/rfcs#811 * issue-15167.rs works properly now * issue-9737.rs works properly now * match-var-hygiene.rs works properly now Addresses a chunk of rust-lang#3965
@mike-marcacci pointed out that the if let Some(val) = map.get_mut(&id) {
/* ... */
} else {
map.insert(id, new_val);
} seems "innocent", it is actually just a syntax sugar for the |
What's the state of this feature? Any new plans and/or changes with this? |
@flavius basically, the HIR/MIR work needs to be completed first. |
I would like to see this implemented. I believe I ran into this with the following code which is descending a prefix tree and inserting new nodes:
The problematic line is this one:
This causes the Rust compiler to spew a page of errors:
This can be "fixed" by replacing the line with this:
In my opinion this adds no value and simply serves as a means of appeasing the borrow checker. The program is correct either way; it seems to be purely a limitation of the borrow checker that it cannot determine this and the programmer has to explicitly add a temporary variable. I understand there may be concern about making the borrow checker more complicated. However, I feel that usability takes precedence here. It's no secret that writing code the Rust compiler can prove is "safe" is one of the largest barriers to using Rust. Any change that makes the compiler smarter and able to correctly recognize more safe code as safe is, in my opinion, an improvement (at least, provided that it continues to follow well-defined rules). |
Your issue here is reborrow vs. move, which is distinct from non-lexical borrows. You can also move |
Is this related to places where matching an option won't compile using e.g. code like this can fail because match foo.as_mut() {
Some(x) => x.bar(), // fn bar(&mut self)
None => foo = Some(Foo::new(7))
} It can be worked around like match foo {
Some(ref mut x) => x.bar(),
None => foo = Some(Foo::new(7))
} |
That's a different issue - non-lexical borrows. |
@arielb1 The title of this issue is "Non-lexical borrow scopes and"... |
@ehiggs I wouldn't call that a work around, it's the idiomatic solution. |
Oops wrong RFC - I thought this was copy-vs-move. |
Think this is related:
|
@aidanhs no, I think that is correct. If you visualize the implicit scopes: fn main() {
let mut a = 1;
{
let c;
{
let b = &mut a;
{
c = &*b;
}
}
let d = &a;
}
} ...then you can see that you're trying to borrow While borrowing a mutable reference to a value, that refrence is the only way to access that value at all. |
Just curious, what is the current status of this issue? Will work on non-lexical borrows resume now that MIR has landed on Nightly? |
Not sure if that was intentional or not, but beta and nightly allow the following piece of code to work (not panic at runtime): use std::cell::RefCell;
fn main() {
let mut data = RefCell::new(None);
let inner = if data.borrow().is_none() {
let d = 1337;
*data.borrow_mut() = Some(d);
d
} else {
data.borrow().unwrap()
};
} (found here: http://stackoverflow.com/questions/40482981/if-condition-remains-borrowed-in-body ) |
It was intentional, the previous behavior was a long-standing bug that was only partially fixed before. |
Can this ticket be closed? I see that all three of the linked issues in the description are closed. If it still needs to be open, is it also still appropriate to have the "postponed" label? |
@radix The issue #29775 was linked to this one and closed at some point, however, I've just checked and it is still relevant. So if this one is to be closed, I suggest to reopen #29775 since it is stil relevant and represents a very basic use case. |
Why would we close it?
That's because they're duplicates of this one.
Yes, as generally this means "we considered it but decided that it's not the right time yet." This is still true, as porting the borrowck to MIR is still a blocker. |
@steveklabnik I apologize. I was just unclear on the status since recent comments seemed to indicate it, or some parts of it, had been fixed. I also didn't realize that the links in the description were duplicates, I assumed they were dependents. My error. I should have worded my message more carefully. I didn't mean to say that I think it should be closed, just that I was curious about its status. Thank you for the information. @istankovic I'm not sure which #29775 you are referring to, as I can't find a reference to that number on this page. |
@radix sorry, I meant rust-lang/rust#29975 |
@radix it's all good! This is a very long-running and complicated issue, it's very easy to have done that. 😄 |
A rather long write-up about nested method calls specifically: https://internals.rust-lang.org/t/accepting-nested-method-calls-with-an-mut-self-receiver/4588 |
What’s the status on this? As far as I can tell, borrows being lexical means not only that some programs need to be more verbose, but also that some programs are impossible (at least with the desired API/characteristics). For example, I just tried to write something like this (reduced here): pub enum Token {
Whitespace,
Ident(String),
Number(i32),
}
pub struct Parser {
/* ... */
}
impl Parser {
pub fn advance_without_skipping_whitespace(&mut self) -> &Token {
unimplemented!()
}
pub fn advance(&mut self) -> &Token {
loop {
match self.advance_without_skipping_whitespace() {
&Token::Whitespace => {}
result => return result
}
}
}
} … and got this error message: error[E0499]: cannot borrow `*self` as mutable more than once at a time
--> <anon>:18:19
|
18 | match self.advance_without_skipping_whitespace() {
| ^^^^
| |
| second mutable borrow occurs here
| first mutable borrow occurs here
...
23 | }
| - first borrow ends here
error: aborting due to previous error The problem is the "first" borrow lasting for the whole function rather than just one iteration of the loop. I think that’s because the borrowed value is (in some code paths) returned, and borrow are lexical? I can’t find a way to rewrite this that compiles in today’s Rust, even tail recursion has the same problem as a loop. |
That may have been a bit over-dramatic, I found a work-around. (Not returning the result of But the same kind of issues happen all the time when porting existing parsing code to this new API. Enough that this approach is not viable, I may have to do somewhat-expensive cloning everywhere. |
It is in-progress. Some steps have recently landed, but its not 100% working yet. |
I think we can basically close this in favor of rust-lang/rust#43234 |
In general, it can be useful to have support for borrows that aren't tied to lexical scopes.
Related links:
&mut
receivers result in borrowck errors (Nested method calls with&mut
receivers result in borrowck errors rust#6268)&mut self
receiver"UPDATE: The relevant RFCs have been accepted. See rust-lang/rust#43234 to track implementation progress here.
The text was updated successfully, but these errors were encountered: