Why doesn't the compiler understand that x and !x can't be true at the same time?

I would like to only clone if necessary in this line:
c.src = if m.auto_resend { m.src.clone() } else { m.src };

But sadly using this logic, the compiler complains that I'm reusing a moved value below inside an if m.auto_resend block, so I have to clone all the time to make it compile. I guess the thinking is that m.auto_resend could have changed in between, but it's not even mutable and there's no async in between so I'm really annoyed by this...

Does anybody have any suggestions how to prevent unnecessary cloning here?

Ouside of things like divergence,[1] the compiler considers all branches to have been possibly executed.

You might be able to do something like cloning m.src into an Option and then unwrapping it later.


  1. returns, panics, .. ↩ī¸Ž

2 Likes

What you can do is put the m.src into an Option, which will be Some if and only if m.auto_resend is true. Then, pattern match that instead of testing m.auto_resend.

I guess the thinking is that m.auto_resend could have changed in between

In general, the compiler will never accept or reject a program based on reasoning about what an if condition or any other expression will evaluate at run time (except for certain "this is guaranteed to panic and you probably didn't mean that" diagnostics, if I remember correctly). Such reasoning is always necessarily incomplete, and "none of it" is a clear place to draw the line.

6 Likes

You can also branch the second if on the option

let to_resend = m.auto_resend.then(|| m.src.clone());
c.src = m.src;

// ...

if let Some(src) = to_resend {
    //...
}

Edit: which is what kpreid wrote...

4 Likes

Thank you for writing the clear example code!

3 Likes

I think std::mem::take might fit what you want here.

1 Like

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.