Borrow checker unhelpful diagnostic
Open
Nobody has claimed this yet.
A-diagnostics
T-compiler
- Dominant language
- Rust
- Stars
- 119k
- Forks
- 16.1k
- PR merge metrics
- PR metrics pending
Description
Code
fn confusing_diagnostic() {
let r0_members = std::collections::BTreeSet::from(["m0", "m1", "m2", "m3"]);
let mut rooms = std::collections::BTreeMap::from([(0, ("m0", r0_members))]);
let for_removal = vec!["m1", "m3"];
let room = rooms.get_mut(&0).unwrap();
for_removal
.iter()
.filter(|&member| *member != (*room).0)
.for_each(|member| {
rooms.get_mut(&0).unwrap().1.remove(member);
});
}
Current output
error[E0499]: cannot borrow `rooms` as mutable more than once at a time
--> src/main.rs:24:19
|
20 | let room = rooms.get_mut(&0).unwrap();
| ----- first mutable borrow occurs here
...
24 | .for_each(|member| {
| -------- ^^^^^^^^ second mutable borrow occurs here
| |
| first borrow later used by call
25 | rooms.get_mut(&0).unwrap().1.remove(member);
| ----- second borrow occurs due to use of `rooms` in closure
Desired output
error[E0499]: cannot borrow `rooms` as mutable more than once at a time
--> src/main.rs:24:19
|
20 | let room = rooms.get_mut(&0).unwrap();
| ----- first mutable borrow occurs here
...
23 | .filter(|&member| *member != (*room).0)
| ------ ^^^^ first borrow used here
| |
| first borrow later used by call
...
24 | .for_each(|member| {
| ^^^^^^^^ second mutable borrow occurs here
25 | rooms.get_mut(&0).unwrap().1.remove(member);
| ----- second borrow occurs due to use of `rooms` in closure
Rationale and extra context
The mention "first borrow later used by call" to for_each is misleading. It would be more helpful to point to the filter closure, as a fix consists in using a reference to the field of room we need in filter instead:
fn fixed() {
let r0_members = std::collections::BTreeSet::from(["m0", "m1", "m2", "m3"]);
let mut rooms = std::collections::BTreeMap::from([(0, ("m0", r0_members))]);
let for_removal = vec!["m1", "m3"];
let room = rooms.get_mut(&0).unwrap();
let owner = (*room).0;
for_removal
.iter()
.filter(|&member| *member != owner)
.for_each(|member| {
rooms.get_mut(&0).unwrap().1.remove(member);
});
}
@nirbheek
@sdroege
Other cases
No response
Anything else?
No response
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start by compiling the reproducer in src/main.rs and inspect the E0499 borrow-checker diagnostic shown in the issue. Compare the reported spans with the desired output, especially the filter closure; the work is done when the diagnostic points to the first borrow's use there and the existing example is covered by an appropriate compiler test.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- rust
- Domain
- compilers
- Issue type
- Bug
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Stale
- Clarity
- Mostly clear
- Newbie friendliness
- 45/100