Polonius: Either Borrower or Lender Be, but Responsibly - Niko Matsakis
Why Stack Overflow recommends it
Stack Overflow users link it when explaining why the Rust borrow checker rejects code that looks valid, such as conditional returns of mutable borrows, and to show that Polonius would accept it.
Recommended by 2 people across 2 different months, 2021 to 2022.
What it is
Niko Matsakis, a Rust core team member, explains Polonius, a reformulation of Rust's borrow checker that tracks where each reference may have come from (its origin) instead of how long it lives. It accepts programs that the current non-lexical lifetimes (NLL) checker rejects, and the talk walks through the idea with worked examples. Recorded at Rust Belt Rust, with slides re-recorded after the fact.
What people said
Strong rec Maksim Gayduk · 2022-02 · Stack Overflow · on “Rust mutable references working in some cases but not in other cases”
Seems like this thread Returning a reference from a HashMap or Vec causes a borrow to last beyond the scope it's in? [LINK] that refers to a known issue [LINK] answers my question. Running my program with Polonius borrow checker also seems to work: RUSTFLAGS="-Z polonius" cargo +nightly test And here is the perfect video explaining just the thing: [this video] How to properly reason about this to determine why does insert function compile, and find_node_mut doesn't: In both functions, node and node_ptr are used interchangeably, so their scope sort of "overlaps". In insert function, the compiler is able to properly determine the "liveness" of the loans: the variable is "dead" if it is about to get
Recommends rubixibuc · 2021-08 · Stack Overflow · on “How can we coerce a mutable reference into an immutable when we can never have both at the same time?”
I can’t tell if this is officially re-borrowing or a side effect of liveness - or both concepts are entangled. Liveness being that a borrows is only invalid in case where the violation involves live references. I learned about that here [this video] afterwards.
Cites user4815162342 · 2021-11 · Stack Overflow · on “Taming Lifetime Contagion with Rust Structs”
TL;DR If you don't need the executor's futures to refer to local data in the executor's surroundings, you should just use 'static : #[cfg(test)] struct MockThing { executor: LocalExecutor<'static> } Both Executor and LocalExecutor have a lifetime in order to allow the futures they run to borrow data from an outside environment. For example, this compiles and runs as expected: // local data let greeting = "foo".to_owned(); // executor let local_ex = LocalExecutor::new(); // spawn a future that references local data let handle = local_ex.spawn(async { println!("Hello {}", greeting); }); future::block_on(local_ex.run(handle)); // data still alive println!("done {}", greeting); LocalExecutor (li
Cites Max Heiber · 2022-01 · Stack Overflow · on “Borrow checker complains about multiple borrowing, when only one will ever occur”
According to The Polonius Talk [this video] rustc currently treats lifetimes in function signatures as if they are live for the entirety of the function body. So, if I understand currectly, it doesn't matter to rustc that the borrows are on different match arms. The code type-checks with cargo +nightly rustc -- -Zpolonius which means that when Polonius features are fully integrated the code should type-check without any changes. I couldn't find a better workaround than using unsafe like in the example in question and adding a comment saying the unsafe can be removed at some point.
Cites Max Heiber · 2022-01 · Stack Overflow · on “How to access mutable iterables inside a nested loop”
The behavior you want is possible if you: make fresh mutable borrows in each nested loop And wait for rustc to integrate more Polonius capabilities. (Can experiment now with cargo +nightly rustc -- -Z polonius ). While you wait, you could use unsafe like in this post: Borrow checker complains about multiple borrowing, when only one will ever occur [LINK] Keeping the rest of your code the same and focussing on this part, but with the return commented out: fn find_unused<'a>(data: &'a mut Vec<Association>) -> Option<&'a String> { for k in 0.. { for a in data { // Error - but rustc says what to do here if a.key == k && !a.used { a.used = true; // return Some(&a.value); } } } None } The error me