"Multiple mutable references" error doesn't make sense here

Hi,
I'm getting the classic cannot borrow `*self` as mutable more than once at a time error and I'm not sure exactly why.

I'm trying to replicate the code on this page, and I'm getting a bunch of these errors. For example, on this function:

    fn comparison(&'s mut self) -> Expression<'s> {
        let mut lhs = self.equality();

        while self.match_current(TokenKind::Greater) || self.match_current(TokenKind::GreaterEqual) 
            || self.match_current(TokenKind::Less) || self.match_current(TokenKind::LessEqual) {
                let operator = self.previous();
                let rhs = self.equality();

                lhs = Expression::Binary {
                    lhs: Box::new(lhs),
                    operator: operator.kind,
                    rhs: Box::new(rhs),
                };
        }

        lhs
    }

I'm getting that self.equality() is the first mutable borrow, and every other self.* function call is another mutable borrow. Here's the relevant function signatures:

fn equality(&'s mut self) -> Expression<'s>
fn match_current(&'s mut self, t: TokenKind<'s>) -> bool
fn previous(&'s self) -> &'s Token

Of course, all of these use a &mut self, but my understanding was that those references go out of scope when the function is done?

Also, it may be relevant to note that the struct uses 't and 's, where 's: `t

Any help would be appreciated!

Let's start with the signature:

    fn comparison(&'s mut self) -> Expression<'s> {

If this is an implementation for Expression<'s>:

impl<'s> Expression<'s> {
    fn comparison(&'s mut self) -> Expression<'s> {

Then you're uniquely (mutably) borrowing the Expression for the entirety of its lifetime. This (&'a mut SomeType<'a>) is a red flag, because once you've uniquely borrowed something for its entire lifetime, nothing else can use it ever again (except perhaps indirectly via a returned value). This is almost never what you want.

Here's an example. The fix for this one is usually to borrow for some arbitrarily short lifetime. Depending on the rest of your struct, it may or may not make sense to retain the returned lifetime.


Unfortunately, there are other problems with the approach. You're taking multiple borrows from within yourself and then trying to return them:

                lhs = Expression::Binary {
                    lhs: Box::new(lhs),
                    operator: operator.kind,
                    rhs: Box::new(rhs),
                };

lhs and rhs both borrow from self, so as far as the language is concerned, they could point to the same data; or to use some jargon, they could alias. But guaranteeing that unique borrows to not alias is a core tenant of Rust's design. There is also currently no way to declare a method that only mutably borrows parts of self.

To make it more concrete, consider here:

    // n.b. same meaning as:
    // fn comparison(&mut self) -> Expression<'_> {
    fn comparison<'e>(&'e mut self) -> Expression<'e> {
        let foo = self.part_of_self(); // Has to borrow for 'e (or longer)
        let bar = self.part_of_self(); // Has to borrow for 'e (or longer)
        Expression { foo, bar }
    }

How to fix this one? Well, if it's possible (depending on how the rest of your code works), you need some way to specify that the borrow of &mut self doesn't actually "flow into" the return value. This means that they must have unrelated lifetimes. So if it is possible to write your methods like so:

    // Note: Borrows `self` for some arbitrarily short lifetime,
    // but can always return `&'s str` or `Expression<'s>`
    fn part_of_self(&mut self) -> &'s str { /* ... */ }
    fn comparison(&mut self) -> Expression<'s> { /* ... */

Then you might be able to make it work.

If you can't, some sort of interior mutability may be in order.

2 Likes

Hey, thanks for the reply! I've spent a good part of the day trying to get it to work, but I keep getting the same errors over again.

I should have been more clear in my original post, but all of these functions are actually in a Parser struct, defined like this:

pub struct Parser<'t, 's: 't> { //Source should last at least as long as Vec<Token>
    tokens: &'t Vec<Token<'s>>,
    current: usize,
}

My idea was that, if the struct didn't actually own the Vec<Token>, there shouldn't be any mutability issues since it can't mutate the data it's creating references to. I still think this (should?) work in theory, since the entire struct is essentially just a reference with a usize to act as a dumb-pointer.

But now that I'm juggling two lifetimes, it's led to a bunch of other problems. For example, this function gives me an error:

fn match_current(&mut self, t: TokenKind) -> bool {
        if self.check_current(t) {
            self.advance(); //E0495 here
            return true
        }

        false
    }

The relevant function signature is:
fn advance(&mut self) -> &'s Token

The error says that Autoref can't determine a lifetime for &mut self. I can fix it by changing this to:
fn match_current(&'s mut self, t: TokenKind) -> bool
But then, like you said, this means I can't ever use that reference again.

I'm thinking I need to change how the data is stored, but I'm not sure how I would do that. The parser struct didn't work any better when it looked like:

pub struct Parser<'s> {
    tokens: Vec<Token<'s>>,
    current: usize,
}

Do you have any suggestions here?

The problem there seems to be in your advance() signature. Currently, it is equivalent to this, once the elided lifetime is expanded:

impl<'t, 's: 't> Parser<'t, 's> {
    fn advance<'r>(&'r mut self) -> &'s Token<'r> { ... }
}

However, assuming that the returned &Token comes from tokens, this is not really what you need. Since tokens is a &'t Vec<Token<'s>>, each of its elements is a &'t Token<'s>. Thus, changing the function signature accordingly would prevent you from needing &'s mut self:

impl<'t, 's: 't> Parser<'t, 's> {
    fn advance(&mut self) -> &'t Token<'s> { ... }
}
3 Likes

So, something like this?

impl<'t, 's> Parser<'t, 's> /* Implied: 's: 't */ {
    fn match_current(&mut self, t: ()) -> bool {
        self.advance();
        true
    }
    fn advance(&mut self) -> &'s Token {
        todo!()
    }
}

If we follow the requirements of that elided_lifetimes_in_paths lint I enabled, we end up with a signature of:

fn advance(&mut self) -> &'s Token<'_> { /* ... */ }

Which is short for

fn advance<'x>(&'x mut self /* Parser<'t, 's> */) -> &'s Token<'x> { /* ... */ }

Perhaps the easiest way to understand the problem at this point is to step back and ask, how can you get a &'s Token<'_> out of a &'t Vec<Token<'s>>? You've only borrowed the Tokens for 't.

But forging ahead with trying to understand the error, one may interpret it as something like:

  • Your Parser is only valid for 't
  • So 'x can't be longer than that ('t: 'x)
  • And based on the return, we also need 'x: 's
  • But we also know that 's: 't
  • In summary,
    • 's >= 't => 'x >= 's
    • Which implies they're all equal
    • But that's not what your signatures declared

And you can "fix" it by changing what your signatures declare and using &'s mut ..., and everything ends up equal. But that's not really what you want, and not actually a fix.

Instead what you probably meant to do is return a Token<'s> (or maybe a &Token<'s>, if they're costly to clone).

2 Likes

Thank you @LegionMammal978 and @quinedot ! My code just compiled and I've never been this happy in my life. Y'all are awesome.

1 Like

You're welcome! In general, when writing methods for a struct with a lifetime parameter, you have to pay close attention to which lifetime you use. This is because there's two lifetimes involved: the lifetime of what your struct is borrowing (the 'a in MyStruct<'a>), and the lifetime of the receiver (the 'b in &'b self or &'b mut self).

Which lifetime you should use in your output type depends on who owns the output data. If the output data is borrowing from your struct's fields, it should have the shorter lifetime 'b. But if the output data is borrowing what your struct is borrowing, it should have the longer lifetime 'a. For example:

pub struct NamedSlice<'a> {
    name: String,
    slice: &'a [i32],
}

impl<'a> NamedSlice<'a> {
    pub fn new(name: String, slice: &'a [i32]) -> NamedSlice<'a> {
        NamedSlice { name, slice }
    }

    // We own the name, so we return it with lifetime `'b`.
    // This can also be written `fn name(&self) -> &str`.
    pub fn name<'b>(&'b self) -> &'b str {
        &self.name
    }

    // We're borrowing the slice, so we return it with lifetime `'a`.
    // This can also be written `fn slice(&self) -> &'a [i32]`.
    pub fn slice<'b>(&'b self) -> &'a [i32] {
        self.slice
    }
}
4 Likes