Return value borrowed even in exclusive code paths

Hello,

Consider this code:

fn borrow_one_or_another<'a>(vec : &'a mut Vec<String>, index : usize) -> &'a mut String {

    if let Some(value_a) = vec.get_mut(index) {
        return value_a
    } else {
        if let Some(value_b) = vec.get_mut(index+1) {
            return value_b
        } else {
            panic!("")
        }
    }    
}

fn main() {
    let mut myvec = vec!["one".to_string(), "two".to_string(), "three".to_string()];
    println!("{}", borrow_one_or_another(&mut myvec, 0))
}    

So I imagine the compiler complains about double-borrowing because the result from the first get_mut isn't dropped until after the whole conditional, including the else clause. So it's perfectly reasonable to complain about the double-borrow here.

But what about this?

fn borrow_one_or_another<'a>(vec : &'a mut Vec<String>, index : usize) -> &'a mut String {

    let returned_option = vec.get_mut(index);
    if let Some(value_a) = returned_option {
        return value_a
    }
    drop(returned_option);

    if let Some(value_b) = vec.get_mut(index+1) {
        return value_b
    } else {
        panic!("")
    }
}

It seems that the return value has the effect of borrowing the argument until the end of the function, even though that code path is exclusive with the continuation of the function. What's going in here? Or more interestingly, what is the most elegant work-around**?

**For this case, I know I could use a non-borrowing function like contains() so I only needed to make one call to get_mut() in this particular case, but my use of a Vec was to illustrate the compiler's behavior and the "check in advance with non-borrowing functions" strategy isn't a generalizable solution.

Thanks in advance for any insight.

Ah, it's good old Problem Case #3 again. tl;dr: intended to work, not currently supported.

On nightly you can switch to an experimental borrow checker which ought to support it correctly (add -Z polonius to rustc flags).

Here's a previous discussion on the topic. I've mostly given up on understanding the workarounds because I consistently fail at it, but there are workarounds at least in some cases -- maybe one of them will work for you.

4 Likes

Thanks for that! I suspected that might be the case so I spent some time reading the language dev forum but I didn't search for the right terms.

On the upside, there are some work-arounds for my case.

Thanks again!