Polonius fails to infer lifetimes of borrows
Open
Nobody has claimed this yet.
C-bug
NLL-polonius
T-types
- Dominant language
- Rust
- Stars
- 119k
- Forks
- 16.1k
- PR merge metrics
- PR metrics pending
Description
I tried this code:
struct Foo([u8; 10]);
impl Foo {
fn read_non_empty<'c, P>(&'c mut self) -> P
where
P: serde::Deserialize<'c> + std::string::ToString,
{
loop {
let b: P = self.read();
if !b.to_string().is_empty() {
return b;
}
}
}
fn read<'c, P>(&'c mut self) -> P
where
P: serde::Deserialize<'c>,
{
unimplemented!();
}
}
I expected to see this happen: Compilation to succeed.
Instead, this happened: Got an error:
❯ RUSTFLAGS='-Zpolonius' cargo +nightly c --tests
Checking tmp-scdnga v0.1.0 (/home/zeenix/.cache/cargo-temp/tmp-sCDnga)
error[E0499]: cannot borrow `*self` as mutable more than once at a time
--> src/main.rs:9:24
|
4 | fn read_non_empty<'c, P>(&'c mut self) -> P
| -- lifetime `'c` defined here
...
9 | let b: P = self.read();
| ^^^^-------
| |
| `*self` was mutably borrowed here in the previous iteration of the loop
| argument requires that `*self` is borrowed for `'c`
For more information about this error, try `rustc --explain E0499`.
error: could not compile `tmp-scdnga` (bin "tmp-scdnga" test) due to 1 previous error
If I modify the code to not use a loop, I still get the same:
fn read_non_empty<'c, P>(&'c mut self) -> P
where
P: serde::Deserialize<'c> + std::string::ToString,
{
{
let b: P = self.read();
if !b.to_string().is_empty() {
return b;
}
}
{
let b: P = self.read();
if !b.to_string().is_empty() {
return b;
}
}
unimplemented!();
}
Meta
rustc --version --verbose:
rustc 1.85.0-nightly (9e136a30a 2024-12-19)
binary: rustc
commit-hash: 9e136a30a965bf4e63f03095c57df7257bf96fd6
commit-date: 2024-12-19
host: x86_64-unknown-linux-gnu
release: 1.85.0-nightly
LLVM version: 19.1.6
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 reproducing the report's example from src/main.rs with the shown nightly compiler and RUSTFLAGS='-Zpolonius'. Read the borrow-checking and Polonius implementation areas to determine why repeated mutable borrows retain the deserialization lifetime. Done means the reproducer compiles and a regression test covers the loop and non-loop cases.
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
- Quiet
- Clarity
- Needs clarification
- Newbie friendliness
- 35/100