Why does match keep temporary values in scope through arms?

Why does a match on an inline value not act identically to declaring that value as a variable, when the cope of the arms is concerned?

let d = a.b().c();
match d {}

vs

match a.b().c() {}

I would expect there to be no difference in scope for the arms


Full example

Consider something like the below code. This runs without panic just fine, as would be expected.

use std::cell::RefCell;
use std::rc::Rc;

struct Node {
    regen_at: Option<u32>,
    energy: u32,
    max_energy: u32,
}

fn schedule(regen_at: u32, task: impl 'static + FnMut()) {
    // Save the task...
}

fn schedule_refresh(rc: Rc<RefCell<Node>>) {
    let regen_at = 300;
    rc.borrow_mut().regen_at = Some(regen_at);
    schedule(regen_at, move || {
        let mut cn = rc.borrow_mut();
        cn.energy = cn.max_energy;
    });
}

fn check_refresh(rc: Rc<RefCell<Node>>) {
    let regen_at = rc.borrow().regen_at;
    match regen_at {
        Some(_) => (),
        None => schedule_refresh(rc.clone()),
    };
}

fn main() {
    let node = Rc::new(RefCell::new(Node { regen_at: None, energy: 50, max_energy: 100 }));
    check_refresh(node.clone());
    let n = node.borrow();
    println!("{:?}, {}, {}", n.regen_at, n.energy, n.max_energy);
}

(Playground)

However, if we change that match in check_refresh to put the variable in-line, this panics when that RefCell is borrow_mut'd in schedule_refresh.

EDIT: I guess assignment does this too.

rc.borrow_mut().energy = rc.borrow().max_energy; panics, even though the right side should be able to fully resolve before the left side.

There has to be a reason for this, I'm just curious what it is.

The rules about temporary lifetimes, especially in conditional expressions, are a bit inconsistent, but can't be changed significantly without breaking existing code. See this thread for some details:

3 Likes

Thanks, that was an interesting rabbit hole to read down.

Perhaps this is one of those things that could be fixed with the introduction of a new edition?

Yandros adresses this in a link in that thread (source, emphasis not mine):

1 Like

The previous threads were helpful - stumbled across an even older PR on this! From 2013.

https://github.com/rust-lang/rust/issues/6393

This then tracks through not one, but two other issues! Crossing all the way up to an open one in the present. Quite a rabbit hole.

Well, strictly speaking the 2018 edition broke some code too. So it's not like it's unprecedented.
That said, the breakage was pretty limited in scope (<< 10% IIRC), and I'm not sure how much code such a change would break exactly.

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.