error[E0502]: cannot borrow `self.m2` as immutable because it is also borrowed as mutable
--> src\main.rs:23:17
|
19 | pub fn f1(&mut self) -> Result<&i32, String> {
| - let's call the lifetime of this reference `'1`
20 | if let Some(f1) = self.f2() {
| ---- mutable borrow occurs here
21 | Ok(f1)
| ------ returning this value requires that `*self` is borrowed for `'1`
22 | } else {
23 | Err(self.m2.some_expensive_computation())
| ^^^^^^^ immutable borrow occurs here
I'm confused about this error. I think in this case only one branch will actually got run, I don't understand why the self in if branch will affect the self in else.
And if I wrote like this:
pub fn f1(&mut self) -> Result<&i32, String> {
let err = Err(self.m2.some_expensive_computation());
if let Some(f1) = self.f2() {
Ok(f1)
} else {
err
}
}
It will compile. But as the function name suggests, it's expensive and should not do that out of "else" branch.
I appreciate it if someone could help to tell if this is a limitation of borrow checker or there's indeed a potential safety problem.
If it's a limitation, I'm curious what's the lifetime/borrow rules for a if let Some(v) = f() {...} else {...}
This is an unfortunate limitation of the current borrow checker, which will be solved in the next one. In the meantime there are workarounds you can use, like the polonius-the-crab crate.
If the actual f2 code only accesses m1 then you can avoid borrowing all of Self in f2 by changing its signature. I realize this may not work for your actual use case, it's just something to consider, if you don't want to use Polonius.
error: `mut` must be followed by a named binding
--> src\main.rs:22:9
|
22 | / polonius!(|self| -> &'polonius Result<&i32, String>{
23 | | if let Some(f1) = self.f2() {
24 | | polonius_return!(Ok(f1))
25 | | }
26 | | });
| |__________^
|
= note: `mut` may be followed by `variable` and `variable @ pattern`
= note: this error originates in the macro `polonius` (in Nightly builds, run with -Z macro-backtrace for more info)
help: remove the `mut` prefix
--> C:\Users\lleo\.cargo\registry\src\index.crates.io-1949cf8c6b5b557f\polonius-the-crab-0.4.2\src\macros.rs:89:14
|
89 - |mut $var: &mut _| {
89 + |$var: &mut _| {
|
Thanks, it works. I'm curious how safe it is. Can I consider that as long as the code compiles with polonius-the-crab, it is safe without any dangerous?
I trust that crate author with unsafe, whatever that's worth. They're also a Rust contributer, e.g. If you have any concerns they'd probably be responsive.
It is a small library with only one line of unsafe, and the soundness of the implementation is covered in the docs. Albeit the explanation is more handwavey than formal, and it relies on higher-order lifetime tricks, but it carries a lot of weight that a RustSec advisory has never been filed against it despite its popularity.