Explicit lifetime on &'a mut self extends borrow in caller?

If I put an explicit lifetime on the receiver of a method, like &'a mut self, then calls to that method extend the mutable borrow for the lifetime of self:

The larger problem I'm trying to solve is implementing a doubly-linked list with typed_arena::Arena. Here's a slightly more detailed example:

https://replit.com/join/kkjnmevntl-ahupp

Without the explicit lifetime on &mut self I get an error like this:

"cannot infer an appropriate lifetime for autoref due to conflicting requirements"

Based on this writeup of arenas in rust, I tried using a non-mut &self + RefCell:

https://replit.com/join/tnwdeovmyr-ahupp

This does work, but now the type signatures don't accurately reflect that's going on w/r/t mutability. And I don't really grok why its necessary. Any suggestions here?

these replit links only give me a login screen. Is it possible to provide the code directly and/or in the Rust playground instead?

Your first Playground link has:

struct A<'t> {
    value: &'t i32,
}

impl<'t> A<'t> {
    fn test(&'t mut self) {}

If we substitute in the type of Self, we get that the parameter to test is of type &'t mut A<'t>. It is nearly always incorrect to use the same lifetime parameter for an &mut and what the &mut refers to — it produces exactly the effect you're seeing, because of the simultaneous constraints:

  • &'t mut requires the thing being referred to is guaranteed to exist for lifetime 't.
  • A<'t> requires that the A<'t> does not outlive 't.

Putting these two constraints together in the form &'t mut A<'t> causes the borrow checker to conclude that the A is borrowed for the rest of its existence.

More generally, using the same lifetime for an &mut reference and something else will usually be over-constraining. They should get their own independent lifetimes.

3 Likes

Notably, constructing recursive types in an arena is an exception where coming across such a reference type can make sense. It has got to be treated almost like the owner of the data though, as you cannot share/duplicate such mutable references.

Doubly linked list would mean shared references are needed and then interior mutability e. g. via RefCell seems unavoidable. I cannot see the code examples of OP though because they appear to be on a website that forces you to create an account in order to see the linked contents.

Rust uses lifetimes to statically prove that no exclusive borrow (&mut) to some memory is alive at the same point as any other access (among other things). We have the terms "mutable borrow" and "interior mutability", but probably would be better off with the terms "exclusive borrow" and "shared mutability".

A doubly-linked list made out of &mut references would have multiple live &mut to the same memory, which is instant UB in Rust.

RefCell uses runtime checks to achieve the same exclusivity guarantees.

2 Likes

I've made copies of the second two examples on the playground. This is the first replit link, and this is the second one.

Note that the rust playground doesn't support arbitrary crates (typed_arena in this case) so you can't run them, that's why I used replit.

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.