Cannot borrow `*self` as mutable more than once at a time


#1

Hi, I’m new to Rust and I love it, I’m currently learning about lifetimes but I can’t figure out what’s wrong with this snippet, can you please help me?

use std::result::Result as StdResult;

enum Error {
	Unknown,
	NoEventProviders,
}

type Result<T> = StdResult<T, Error>;

trait EventProvider {
	fn wait_event(&mut self) -> Result<Event>;
	fn poll_event(&mut self) -> Result<Option<Event>>;
}

trait Debuggee {}

enum EventInfo {}

enum Event<'a> {
	External {
		provider: &'a mut EventProvider,
	},
	
	Known {
		info: EventInfo,
		from: &'a Debuggee,
	},
}

struct EventQueue<'a> {
	providers: Vec<Box<EventProvider + 'a>>,
}

impl<'a> EventQueue<'a> {
	fn wait_event(&mut self) -> Result<Event> {
		match self.providers.len() {
			0 => Err(Error::NoEventProviders),
			1 => self.providers[0].wait_event(),
			_ => {
				loop {
					if let Some(e) = try!(self.poll_event()) {
						return Ok(e); // <-- if I change this line for unimplemented!() it compiles
					}
				}
			}
		}
	}
	
	fn poll_event(&mut self) -> Result<Option<Event>> {
		for p in &mut self.providers {
			if let Some(e) = try!(p.poll_event()) {
				return Ok(Some(e));
			}
		}
		Ok(None)
	}
}

What I try to do is moving the Event from the Result that is returned from poll_event(…), if there’s any. Thank you very much!


#2

Your code can be simplified to:

struct Foo;

impl Foo {
    fn bar(&mut self) -> Option<&str> {
        unimplemented!()
    }

    fn baz(&mut self) -> &str {
        loop {
            if let Some(e) = self.bar() {
                // unimplemented!() here compiles
                return e;
            }
        }
    }
}

and then loop just has the effect of executing the statement several times, so this fails in the same way:

fn baz(&mut self) -> &str {
    if let Some(e) = self.bar() {
        return e;
    }
    self.bar();
    ""
}

but with a more understandable error message:

rustc 1.14.0 (e8a012324 2016-12-16)
error[E0499]: cannot borrow `*self` as mutable more than once at a time
  --> <anon>:12:9
   |
9  |         if let Some(e) = self.bar() {
   |                          ---- first mutable borrow occurs here
...
12 |         self.bar();
   |         ^^^^ second mutable borrow occurs here
13 |         ""
14 |     }
   |     - first borrow ends here

So the first bar() call borrows self for the rest of the function. I have no idea why though.

Whatever the reason, the error message here could definitely be improved.


#3

This comes up every once in awhile.
Returning a borrowed value extends the borrowing until the end of the function body.
I must admit that I don’t fully understand why that is the case. But I believe the reason is that there might be destructors from “outer scopes” that are only run after returning.

This will probably just work once nonlexical borrowing is implemented.


#4

Thank you @bugaevc @troplin for your help!

I’d like to leave here this post as well, which really made me understand lifetimes, and also seems to explain why if I did return self.bar().unwrap(), things would just work: lifetimes span either a single expression or its enclosing block. [EDIT: Apparently, it’s not single-expression lifetimes but the borrow checker analysis of control-flow]

I can’t wait for nonlexical borrowing to be implemented. Definitely, I’m loving rust more day by day and can’t wait to see it take over the world. Thank you!