rust-lang / rust-lang/rust

Polonius fails to infer lifetimes of borrows

Open
#134,554 22 comments 2 reactions 0 assignees View on GitHub

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

View all comments

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

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. 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

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.