You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Borrows in patterns are kept during the whole if let expression, including the else branch, which is counterintuitive and annoying.
For example, this doesn't compile.
letmut x = Some(1);ifletSome(&ref p) = x.as_ref(){// do something with p}else{
x = Some(2);// error: x is still borrowed}
To pass the borrow check, you have to write ugly code like this.
letmut x = Some(1);letmut flag = false;ifletSome(&ref p) = x.as_ref(){// do something with p}else{
flag = true;}if flag {
x = Some(2);}
Unlike match mentioned in #35132, if let with else has two braces and seems to have two different lexical scope naturally, and borrows should only live the first scope.
On the other hand, although non-lexical lifetimes do fix both issues, I think this one is easier to resolve by simply desugering code like the latter I've shown.
So you meant to change desugaring of if let, the current behavior of which leads to the very NLL example?
To me it looks a bit difficult to apply your desugaring in general, since if let can have types other than ().
I don't think desugaring will be an issue. At least handling a return value works with the example below (using fake macro-like syntax, and likely in need of some NoDrop to avoid issues where the expression is Drop)
if let $p:pattern = $ei:expr {
$em:expr
} else {
$ef:expr
}
Transformed to:
{
let mut flag = false;
let mut v = if let $p = $ei {
$em
} else {
flag = true;
unsafe { uninitialized() }
};
if flag {
v = $ef;
}
v
}
let mut x = Some(1);
let res = {
let mut flag = false;
let mut v = if let Some(&ref p) = x.as_ref() {
// do something with p
println!("{}", p);
p * 3
} else {
flag = true;
unsafe { std::mem::uninitialized() }
};
if flag {
x = Some(2);
v = 7;
}
v
};
Triage: OP's example now compiles on 2018.
2015 errors:
error[E0506]: cannot assign to `x` because it is borrowed
--> src/main.rs:6:9
|
3 | if let Some(&ref p) = x.as_ref() {
| - borrow of `x` occurs here
...
6 | x = Some(2); // error: x is still borrowed
| ^^^^^^^^^^^ assignment to borrowed `x` occurs here
Activity
qnighy commentedon Jul 22, 2017
This seems to be the known limitation of the current borrow checker. #35132 is one of the similar issues.
oxalica commentedon Jul 22, 2017
Unlike
matchmentioned in #35132,if letwithelsehas two braces and seems to have two different lexical scope naturally, and borrows should only live the first scope.On the other hand, although non-lexical lifetimes do fix both issues, I think this one is easier to resolve by simply desugering code like the latter I've shown.
qnighy commentedon Jul 22, 2017
So you meant to change desugaring of
if let, the current behavior of which leads to the very NLL example?To me it looks a bit difficult to apply your desugaring in general, since
if letcan have types other than().Perhaps rust-lang/rfcs#2068 is also related?
codyps commentedon Jul 23, 2017
I don't think desugaring will be an issue. At least handling a return value works with the example below (using fake macro-like syntax, and likely in need of some
NoDropto avoid issues where the expression isDrop)Transformed to:
A specific example (https://play.rust-lang.org/?gist=205359c0924e50efa8974f1f73250419&version=stable)
scottmcm commentedon Jul 31, 2017
There are flagless desugars too, like
(Or the nicer version with labeled blocks, if inside the compiler or if that RFC is accepted)
memoryruins commentedon Jan 30, 2019
Triage: OP's example now compiles on 2018.
2015 errors:
rustc: 1.32.0Auto merge of #59114 - matthewjasper:enable-migate-2015, r=<try>
Auto merge of #59114 - matthewjasper:enable-migate-2015, r=pnkfelix
Auto merge of #59114 - matthewjasper:enable-migate-2015, r=pnkfelix