-
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
Closure tries to borrow &mut to entire struct, when only a field is required #19004
Comments
I'm pretty sure that it is fine to reference fn main() {
let mut f = Foo { b: 0, v: vec![1, 2, 3] };
let b = &mut f.b;
f.v.iter().map(|s| {
incr(b);
println!("{}: {}", b, s);
}).last();
} It would be nice if Rust was smarter about this though. |
I just ran into this one today, with 'f' being 'self'; that seems like a rather common case, which will come up any time you write self.somefield.method(|| { ... self.otherfield.method(...) ... }) (and at least one of the methods wants a &mut). Based on some discussion in the #rust IRC channel, this seems potentially feasible to fix. The closure desugaring just needs to recognize references to fields and capture the field in that case, rather than capturing the entire top-level label. |
Capturing the individual fields rather than "self" would significantly increase the size of the closure. It should be possible to internally capture just the "self" pointer, but make it appear for all intents and purposes that the fields were captured individually. |
Triage: no updates in almost two years. Personal note: this code still compiles with the original error today. Neat! Not too much pre-1.0 stuff left that does that... |
I don't think we should change this.
What should be done imo is to add a suggestion to the error that gives the solution of borrowing the field into a new binding and then using that binding inside the closure. |
@oli-obk That's fine if you're only borrowing one field, but it's a fair amount of boilerplate when you're borrowing say, all but one of the fields in the struct. It also produces a larger closure than necessary, which could be the difference between having to allocate the closure on the heap, vs being able to store it inline, if anyone writes a |
@Diggsey ah, so you are suggesting to store the pointer to the struct, but the borrowchecker will still forbid accessing already borrowed fields? |
Yep :) |
That's what I would like to see as well: this would entirely be a change to the borrow checker, with the implementation still just passing the struct pointer (commonly a |
This is fine: let _a = &mut foo.a;
&mut foo.b; // ok! So is this: let _a = &mut foo.a;
loop { &mut foo.b; } // ok! Why should closures be treated differently? It seems inconsistent with the rest of the language: let _a = &mut foo.a;
|| &mut foo.b; // cannot borrow `foo` as mutable more than once at a time Q: Does this require an RFC, or is it minimal and non-breaking enough to be fixed outright? |
Might have to be careful not to hint to LLVM that this is an exclusive reference? |
This is enough of a feature to require an RFC. |
Working on an RFC now... |
Offending code:
Error:
error: cannot borrow
fas mutable because
f.vis also borrowed as immutable
On playpen: http://is.gd/PTXhJq
Version info:
Thanks @bjz for helping me submit this.
The text was updated successfully, but these errors were encountered: