1

The following program is not allowed due to a violation of the borrow checking rules:

struct Foo;

impl Foo {
    fn bar(&mut self, i: u8) { }
    fn baz(&mut self) -> u8 { 0 }
}

fn main() {
    let mut foo = Foo;
    
    foo.bar(foo.baz())
//  --------^^^^^^^^^-
//  |   |   |
//  |   |   second mutable borrow occurs here
//  |   first borrow later used by call
//  first mutable borrow occurs here
}

But you can work around this by binding to a temporary variable, like:

fn main() {
    let mut foo = Foo;

    let t = foo.baz();
    foo.bar(t);
}

Why does the borrow checker start at the outer most function call? Shouldn't it be the other way around?

kalkronline
  • 459
  • 2
  • 12
  • im voting to reopen this, it is absolutely not at all related to any of the linked "duplicates" – kalkronline Jun 21 '23 at 17:43
  • I feel that [this](https://stackoverflow.com/a/59146116/442760) expains the same thing Chayim said with other words, take a close look at the desugared version and compare it to the desugared version of this problem. That the rightmost borrow of `self` is immutable in the linked question is of no consequence. – cafce25 Jun 21 '23 at 17:55
  • @cafce25 I don't understand, you can close a question when the answers are similar to others? – kalkronline Jun 21 '23 at 19:25
  • Yes, closure as duplicateis a way to direct people to an answer, since that answer applies here this question is a duplicate of the other. Having duplicates is fine, too, they serve as signposts so other people can find an answer more easily. – cafce25 Jun 21 '23 at 19:34

1 Answers1

5

It's because Rust has a strictly defined evaluation order, by which method arguments are evaluated left-to-right, and the receiver (self) is evaluated first. Evaluating the receiver includes evaluating any autoref/deref borrow for it, so the code is as if written:

let receiver = &mut foo;
let arg0 = foo.baz();
receiver.bar(arg0);

Here we can clearly see that foo is already borrowed when we call baz().

Chayim Friedman
  • 47,971
  • 5
  • 48
  • 77
  • 4
    ah, when you write it as `Foo::bar(&mut foo, Foo::baz(&mut foo))`, it makes perfect sense why the left-to-right eval order would get in the way of the borrows. – kalkronline Jun 20 '23 at 21:43