Rust: Return Result After Mutable Borrow in Loop

Created on 11 Jan 2020  Â·  2Comments  Â·  Source: rust-lang/rust

I'm writing a fairly standard bytecode interpreter in Rust. The core VM loop looks something like this:

// contains mutable program state
struct VM { /* ip, stack, etc. */ }

impl VM {
    fn step(&mut self) -> Result<(), &str> {
        // decode and execute a single potentially fallible bytecode op
        // oh, an error occured:
        return Err("(•_• ?)")
    }

    pub fn run(&mut self) -> Result<(), &str> {
        // stepping through the program
        loop {
            // stop running if something goes wrong
            self.step()?
        }
    }
}

However, this code fails to compile, throwingE0499:

error[E0499]: cannot borrow `*self` as mutable more than once at a time
  --> src/lib.rs:15:13
   |
11 |     pub fn run(&mut self) -> Result<(), &str> {
   |                - let's call the lifetime of this reference `'1`
...
15 |             self.step()?
   |             ^^^^       - returning this value requires that `*self` is borrowed for `'1`
   |             |
   |             mutable borrow starts here in previous iteration of loop

I think I understand why this error is occurring - self.step()? mutably borrows self, and upon the next iteration of the loop, another mutable reference to self can not be taken out. Is there any way to restructure the above code while still maintaining the same behaviour without encountering an error?

I'm not sure how to proceed - I've refactored the code many times, following suggestions from:
https://stackoverflow.com/questions/39622783/how-can-i-do-a-mutable-borrow-in-a-for-loop
https://stackoverflow.com/questions/36667723/can-i-reset-a-borrow-of-a-local-in-a-loop
https://users.rust-lang.org/t/single-threaded-code-mutable-borrow-in-loop/20879/7
https://github.com/rust-lang/rust/issues/21906
... And a few other sources I've left out for brevity.

One question is particular is very similar to the above situation, however the answers offered were less than satisfactory, as I don't mind changing the structure / signatures of my program to achieve satisfactory results:
https://stackoverflow.com/questions/46393890/mutable-borrow-in-loop

That's all :)
Any help or pointers in the right direction are appreciated.

Most helpful comment

This is a known limitation of current NLL. It will be fixed by the Polonius borrow checker.

All 2 comments

I believe the issue is with the return value of step: Result<(), &str>.

If you change it to return a newly allocated String, it should compile: https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&gist=3697e762756b593929bb3ef6273df1fe

I don't yet fully understand why this doesn't compile in the first place, so I can't help with that (see here).

I believe the issue tracking this general problem is non-lexical lifetimes.

This is a known limitation of current NLL. It will be fixed by the Polonius borrow checker.

Was this page helpful?
0 / 5 - 0 ratings