Borrow confusion

#![allow(unused_variables, dead_code)]
use std::collections::HashMap;

struct Employee;

fn do_something(map: &mut HashMap<u32, Employee>, key: u32) -> &Employee {
    if let Some(emp) = map.get(&key) {
        return emp;
        //return map.get(&key).unwrap();
    }
    map.clear();
    &Employee {}
}

fn main() {}

the above code gives following error:

error[E0502]: cannot borrow `*map` as mutable because it is also borrowed as immutable
  --> src/main.rs:11:5
   |
6  | fn do_something(map: &mut HashMap<u32, Employee>, key: u32) -> &Employee {
   |                      - let's call the lifetime of this reference `'1`
7  |     if let Some(emp) = map.get(&key) {
   |                        ------------- immutable borrow occurs here
8  |         return emp;
   |                --- returning this value requires that `*map` is borrowed for `'1`
...
11 |     map.clear();
   |     ^^^^^^^^^^^ mutable borrow occurs here

For more information about this error, try `rustc --explain E0502`.

I am confused why the compiler says immutable borrow still exists.

after some trial and error, I noticed the following:

if I comment return emp; and uncomment the following line, then it compiles.

I am confused how does the error gone and why the error present in first place.

This is the typical reproducing case of known limitations of the current borrow checker. Eventually, developments like this will improve the situation - for now, you'll have to work around it.

See also this recent thread (with a workaround) and issue 51545.

Note that this is doing something entirely different: It's taking your Employee {}, promoting it to a static value, and returning a reference to that value in static memory. Your actual eventual Employee type probably doesn't have a reasonable and "const promotable" default value, so you would instead get an error about returning a borrow of a local variable that's going to drop.

1 Like

I'm having a hard time following this answer. Feel free to correct me, but all I can see is the typical borrow checking problem that polonius addresses, and the typical solution/workaround of re-creating the returned borrow from scratch once you are unconditionally on a returning oath. I don't see how static values or promotion would come into play.

Edit: Ah! Now, I'm seeing the &Employee {} return value at the end of the function, that's what got your attention. The specific choice of return value at the end of the function however seems completely irrelevant, both for the error message and for the solution/workaround that's being discussed.

Yeah, I'm just pointing out that the fact that it works in this minimization doesn't necessarily mean it's going to work with whatever they ultimately want to do. (What they do ultimately want to do in the else case is not clear to me from the example.)

@santhosh-tekuri if what I wrote is confusing, please ignore.

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.