Borrow checker wrongly counts mutable references
Nobody has claimed this yet.
- Dominant language
- Rust
- Stars
- 119k
- Forks
- 16.1k
- PR merge metrics
- PR metrics pending
Description
I tried this code (playground):
pub struct MyCollection(Vec<(String, Record)>);
#[derive(Default)]
pub struct Record {}
impl MyCollection {
/// retrieves a record with given key, or creates a new one and appends it to
/// the list if it doesn't exist yet
pub fn get_or_push_default<'a>(&'a mut self, key: &str) -> &'a mut Record {
// try to find a record with given key
{
if let Some((_key, record)) = self.0.iter_mut().find(|(k, _)| k == key) {
return record;
}
} // `self.0` is no longer mutably referenced
// otherwise, create a default record and push it to the vec
let record = Record::default();
// ERROR: cannot borrow `self.0` as mutable more than once at a time
// (although it isn't borrowed)
self.0.push((key.to_owned(), record));
// with push_mut we wouldn't need unwrap, but that's not the issue here
&mut self.0.last_mut().unwrap().1
}
}
I expected this to compile. Not at any point in the code there is more than 1 mutable reference to self.0.
Instead, borrow checker detects that self.0 is mutably borrowed more than once when I call self.0.push(..) (or self.0.last_mut()). It identifies the first mutable reference in self.0.iter_mut(), although I surrounded it by braces which should have created an explicit scope in which self.0 is mutably borrowed.
Compiler error message:
Error message
Compiling playground v0.0.1 (/playground)
error[E0499]: cannot borrow `self.0` as mutable more than once at a time
--> src/lib.rs:20:9
|
8 | pub fn get_or_push_default<'a>(&'a mut self, key: &str) -> &'a mut Record {
| -- lifetime `'a` defined here
...
11 | if let Some((_key, record)) = self.0.iter_mut().find(|(k, _)| k == key) {
| ------ first mutable borrow occurs here
12 | return record;
| ------ returning this value requires that `self.0` is borrowed for `'a`
...
20 | self.0.push((key.to_owned(), record));
| ^^^^^^ second mutable borrow occurs here
error[E0499]: cannot borrow `self.0` as mutable more than once at a time
--> src/lib.rs:22:14
|
8 | pub fn get_or_push_default<'a>(&'a mut self, key: &str) -> &'a mut Record {
| -- lifetime `'a` defined here
...
11 | if let Some((_key, record)) = self.0.iter_mut().find(|(k, _)| k == key) {
| ------ first mutable borrow occurs here
12 | return record;
| ------ returning this value requires that `self.0` is borrowed for `'a`
...
22 | &mut self.0.last_mut().unwrap().1
| ^^^^^^ second mutable borrow occurs here
For more information about this error, try `rustc --explain E0499`.
error: could not compile `playground` (lib) due to 2 previous errors
Meta
rustc --version --verbose:
rustc 1.90.0 (1159e78c4 2025-09-14)
binary: rustc
commit-hash: 1159e78c4747b02ef996e55082b704c09b970588
commit-date: 2025-09-14
host: aarch64-unknown-linux-gnu
release: 1.90.0
LLVM version: 20.1.8
I also tested on latest stable, beta and nightly channels available on Rust playground.
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
Reproduce the supplied get_or_push_default example in the Rust Playground across stable, beta, and nightly, then trace borrow-checker handling of the explicit scope and returned mutable reference. A complete fix should accept this example without E0499 while preserving errors for genuinely overlapping mutable borrows; no repository file or test is named in the issue.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- rust
- Domain
- compilers
- Issue type
- Bug
- Difficulty
- 5/5
- Estimated time
- Over a week
- Activity status
- Stale
- Clarity
- Mostly clear
- Newbie friendliness
- 25/100