Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Return Result After Mutable Borrow in Loop #68117

Closed
Tloru opened this issue Jan 11, 2020 · 2 comments
Closed

Return Result After Mutable Borrow in Loop #68117

Tloru opened this issue Jan 11, 2020 · 2 comments

Comments

@Tloru
Copy link

Tloru commented Jan 11, 2020

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
#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.

@cwaldren
Copy link

cwaldren commented Jan 11, 2020

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.

@jonas-schievink
Copy link
Contributor

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

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants