0

I am writing a parser in Rust. It is a structure owning a vector of tokens (with a lifetime 'a) with methods mutating its start-end indices and state.

A common pattern among the parsing methods is the following:

fn eat_item(&mut self) -> ParseResult {
    let elim = self.eat_item_eliminator()?;

    self.eat_token(TT::Colon)?;

    // ...

    Ok(/*AST Node*/)
}

fn eat_item_eliminator(&mut self) -> ParseResult { ... }
fn eat_token(&mut self, tt: TT) -> Result<(), ParseError> { ... }

Token borrows a slice of source string, and thus requires a lifetime and cannot be Copyed.

I've reduced my code to:

struct A {}

impl A {
    pub fn mut1(&mut self) -> Result<usize, &str> {
        let foo = self.mut2()?;

        self.mut3()?;

        Ok(foo)
    }

    fn mut2(&mut self) -> Result<usize, &str> {
        Ok(1)
    }

    fn mut3(&mut self) -> Result<(), &str> {
        Ok(())
    }
}

fn main() {
    let mut a = A {};

    let _ = a.mut1();
}

playground

The error is:

error[E0499]: cannot borrow `*self` as mutable more than once at a time
 --> src/main.rs:7:9
  |
4 |     pub fn mut1(&mut self) -> Result<usize, &str> {
  |                 - let's call the lifetime of this reference `'1`
5 |         let foo = self.mut2()?;
  |                   ----       - returning this value requires that `*self` is borrowed for `'1`
  |                   |
  |                   first mutable borrow occurs here
6 | 
7 |         self.mut3()?;
  |         ^^^^ second mutable borrow occurs here

Is there a clean way of changing the structure of my parser so that no such conflicts arise?

Shepmaster
  • 388,571
  • 95
  • 1,107
  • 1,366
DrunkCoder
  • 379
  • 2
  • 9
  • 2
    TL;DR the duplicate: you need to differentiate the lifetime of the returned reference from `self`. This may be `'static` or a generic lifetime of the type. Anything so long as it's not tied to `self`. [Applied to your example code](https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&gist=2accd355d9f770cc3fb2ff289d39e7e4) – Shepmaster Jan 07 '20 at 20:24
  • Actually, the MRE I've provided isn't accurate, the result shouldn't return anything copyable, but rather a `B<'a>`, where `'a` is the lifetime of `self` - `self` owns some data of type `&'a str` which will be passed to the return type `ParseResult<'a>`. [playground](https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&gist=fbcaadea8364ac22c432dfb23dbf041d) So in this case, it is not possible to use a structure of code similar to the problematic one? Do I need to either clone the data of `self` or completely reorganize my code? – DrunkCoder Jan 07 '20 at 20:35
  • 1
    `Copy` isn't relevant here. For that example, the returned `B` needs to have a lifetime that's not `self`, [like this](https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&gist=40afc0dc096eb043d50d0c4b04a49499). If it's for a member of `A`, then [use that lifetime](https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&gist=0f8247663685119ae945a3a60b8542cc). – Shepmaster Jan 07 '20 at 20:46
  • Thank you, the solution was more subtle, however, and actually had its source in another file (which I hadn't expected; basically, the anonymous lifetime of `self` was being assigned to a part of return data of a method, which created conflicting requirements) in the declaration of `ParseError` - some of its variants used unnecessary references. The code worked after adding explicit lifetimes to the method signatures, removing the need for references in `ParseError` and implementing `Clone` for `Token` (the data owned by the parser). – DrunkCoder Jan 07 '20 at 21:13
  • I recommend enabling `#![deny(rust_2018_idioms)]` in your crate to prevent this. See also [Why does returning a mutable reference from a method prevent calling any other methods, even when the reference goes out of scope?](https://stackoverflow.com/q/54887383/155423) – Shepmaster Jan 07 '20 at 21:30

0 Answers0