I've come across a lifetime issue that should compile according to my internal model of how lifetimes work.
I tried to minimize the code so that it's hopefully easier to understand.
enum Enum {
A(usize),
B,
// ^^ 1
}
impl Enum {
fn get<'this>(&'this mut self) -> Option<&'this usize> {
// ^^^ 2
if let Self::A(val) = self {
if val.is_power_of_two() {
// ^^^^^^^^^^^^^^^^^^^^^^^^^^---------+
return Some(val); // +-- 3
}// ^^^^^^^^^^^^^^^^^ 4 |
// ^----------------------------------+
}
match self {
Self::A(_) => None,
// ^^^^^^^^^^^^^^^^^^^ 5
_ => None,
}
}
}
This code (playground) fails with the error message:
error[E0503]: cannot use `*self` because it was mutably borrowed
--> src/main.rs:18:15
|
8 | fn get<'this>(&'this mut self) -> Option<&'this usize> {
| ----- lifetime `'this` defined here
9 | // ^^^ 2
10 | if let Self::A(val) = self {
| --- `self.0` is borrowed here
...
13 | return Some(val); // +-- 3
| --------- returning this value requires that `self.0` is borrowed for `'this`
...
18 | match self {
| ^^^^ use of borrowed `self.0`
My intuition here is that the borrow created in the if let
should not extend beyond it, since it is not used beyond it (except if the function returns, but that should be independent of the code path in which it doesn't return).
If I remove any of the code section 1-5
, the code compiles again.
Any insight into why this code cannot compile is appreciated.
While my main goal asking this is to understand why this doesn't work, some hints on how the code could be fixed while keeping the semantics (the idea is that self
should be updated in the match
, before returning None
, but that made the error message more complicated) are also appreciated.