1
votes

Inside a function, I am trying to push a value into a vector and afterwards return a reference to that value, which is inside the vector. Sadly, it doesn't work and I get the following error:

error[E0502]: cannot borrow `vector` as immutable because it is also borrowed as mutable
  --> src\lib.rs:19:19
   |
18 |     let _unit_0 = push_and_get(&mut vector);
   |                                ----------- mutable borrow occurs here
19 |     let _unit_1 = vector.last().unwrap();
   |                   ^^^^^^ immutable borrow occurs here
20 |     drop(_unit_0);
   |          ------- mutable borrow later used here

Here's my code with two functions (this_works, this_does_not_work) which, to my understanding, do the same thing, but only one of them works.

fn this_works() {
    let mut vector = Vec::new();
    vector.push(());
    let _unit_0 = vector.last().unwrap();
    let _unit_1 = vector.last().unwrap();
}

fn this_does_not_work() {
    let mut vector = Vec::new();
    let _unit_0 = push_and_get(&mut vector);
    let _unit_1 = vector.last().unwrap();
    drop(_unit_0); // Added, to make the error reappear
}

fn push_and_get(vector: &mut Vec<()>) -> &() {
    vector.push(());
    vector.last().unwrap()
}

Is there any way to get the push_and_get function to work or is it impossible, because of a limitation of Rust? If it's the first, how can I get it to work and if it's the latter, are there any plans to fix this particular issue or are there any good reasons why this shouldn't be fixed?

1
do the same thingWhy doesn't the lifetime of a mutable borrow end when the function call is complete?; Is there any way to get [it] to workWhat are the options to end a mutable borrow in Rust?; are there any plans to fix this particular issueWhat are non-lexical lifetimes?Shepmaster
@Shepmaster This issue is not solvable by non-lexical lifetimes. While the current code would work, now, as soon as I add a manual drop, i.e. I don't allow the compiler to reorder the statements, so that _unit_1 gets dropped before _unit_0 is created, the error appears, again.Phlopsi

1 Answers

0
votes

After more testing, I think I can answer my own question, now. The provided example can be reduced even further to show the core problem. Here's the actual minimum amount of code required to reproduce the error:

// I have embedded the error message as comments
fn main() {
    let mut owned: () = ();
    let ref0: &() = &mut owned;
    //              ---------- mutable borrow occurs here
    let ref1: &() = &owned;
    //              ^^^^^^ immutable borrow occurs here
    drop(ref0);
    //   ---- mutable borrow later used here
}

What this boils down to is, that Rust allows the conversion of &mut to &, but only in theory. Practically, as soon as you use that borrow created from the mutable borrow, while having another regular borrow, the compiler suddenly realizes, that the converted borrow is still a mutable borrow. The type checker is lying.

In conclusion, it's impossible to combine push() and last() into a single function.

P.S. It'd be nice if Rust would support true conversion from &mut to &, that doesn't produce the above error, in the future.