Change divergence checking to match the compiler's type system based definition of divergence.
This commit is contained in:
parent
16d58a2982
commit
a44bb07900
4 changed files with 481 additions and 133 deletions
|
|
@ -5,7 +5,9 @@
|
|||
clippy::let_unit_value,
|
||||
clippy::match_single_binding,
|
||||
clippy::never_loop,
|
||||
clippy::needless_if
|
||||
clippy::needless_if,
|
||||
clippy::diverging_sub_expression,
|
||||
clippy::single_match
|
||||
)]
|
||||
#![warn(clippy::manual_let_else)]
|
||||
//@no-rustfix
|
||||
|
|
@ -24,7 +26,7 @@ fn main() {}
|
|||
fn fire() {
|
||||
let v = if let Some(v_some) = g() { v_some } else { return };
|
||||
//~^ ERROR: this could be rewritten as `let...else`
|
||||
//~| NOTE: `-D clippy::manual-let-else` implied by `-D warnings`
|
||||
|
||||
let v = if let Some(v_some) = g() {
|
||||
//~^ ERROR: this could be rewritten as `let...else`
|
||||
v_some
|
||||
|
|
@ -79,22 +81,76 @@ fn fire() {
|
|||
panic!();
|
||||
};
|
||||
|
||||
// A match diverges if all branches diverge:
|
||||
// Note: the corresponding let-else requires a ; at the end of the match
|
||||
// as otherwise the type checker does not turn it into a ! type.
|
||||
// The final expression will need to be turned into a statement.
|
||||
let v = if let Some(v_some) = g() {
|
||||
//~^ ERROR: this could be rewritten as `let...else`
|
||||
v_some
|
||||
} else {
|
||||
match () {
|
||||
_ if panic!() => {},
|
||||
_ => panic!(),
|
||||
panic!();
|
||||
()
|
||||
};
|
||||
|
||||
// Even if the result is buried multiple expressions deep.
|
||||
let v = if let Some(v_some) = g() {
|
||||
//~^ ERROR: this could be rewritten as `let...else`
|
||||
v_some
|
||||
} else {
|
||||
panic!();
|
||||
if true {
|
||||
match 0 {
|
||||
0 => (),
|
||||
_ => (),
|
||||
}
|
||||
} else {
|
||||
panic!()
|
||||
}
|
||||
};
|
||||
|
||||
// Or if a break gives the value.
|
||||
let v = if let Some(v_some) = g() {
|
||||
//~^ ERROR: this could be rewritten as `let...else`
|
||||
v_some
|
||||
} else {
|
||||
loop {
|
||||
panic!();
|
||||
break ();
|
||||
}
|
||||
};
|
||||
|
||||
// Even if the break is in a weird position.
|
||||
let v = if let Some(v_some) = g() {
|
||||
//~^ ERROR: this could be rewritten as `let...else`
|
||||
v_some
|
||||
} else {
|
||||
'a: loop {
|
||||
panic!();
|
||||
loop {
|
||||
match 0 {
|
||||
0 if (return break 'a ()) => {},
|
||||
_ => {},
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// A match diverges if all branches diverge:
|
||||
let v = if let Some(v_some) = g() {
|
||||
//~^ ERROR: this could be rewritten as `let...else`
|
||||
v_some
|
||||
} else {
|
||||
match 0 {
|
||||
0 if true => panic!(),
|
||||
_ => panic!(),
|
||||
};
|
||||
};
|
||||
|
||||
// An if's expression can cause divergence:
|
||||
let v = if let Some(v_some) = g() { v_some } else { if panic!() {} };
|
||||
//~^ ERROR: this could be rewritten as `let...else`
|
||||
let v = if let Some(v_some) = g() {
|
||||
//~^ ERROR: this could be rewritten as `let...else`
|
||||
v_some
|
||||
} else {
|
||||
if panic!() {};
|
||||
};
|
||||
|
||||
// An expression of a match can cause divergence:
|
||||
let v = if let Some(v_some) = g() {
|
||||
|
|
@ -103,7 +159,7 @@ fn fire() {
|
|||
} else {
|
||||
match panic!() {
|
||||
_ => {},
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
// Top level else if
|
||||
|
|
@ -342,6 +398,43 @@ fn not_fire() {
|
|||
} else {
|
||||
return;
|
||||
};
|
||||
|
||||
// A break that skips the divergent statement will cause the expression to be non-divergent.
|
||||
let _x = if let Some(x) = Some(0) {
|
||||
x
|
||||
} else {
|
||||
'foo: loop {
|
||||
break 'foo 0;
|
||||
panic!();
|
||||
}
|
||||
};
|
||||
|
||||
// Even in inner loops.
|
||||
let _x = if let Some(x) = Some(0) {
|
||||
x
|
||||
} else {
|
||||
'foo: {
|
||||
loop {
|
||||
break 'foo 0;
|
||||
}
|
||||
panic!();
|
||||
}
|
||||
};
|
||||
|
||||
// But a break that can't ever be reached still affects divergence checking.
|
||||
let _x = if let Some(x) = g() {
|
||||
x
|
||||
} else {
|
||||
'foo: {
|
||||
'bar: loop {
|
||||
loop {
|
||||
break 'bar ();
|
||||
}
|
||||
break 'foo ();
|
||||
}
|
||||
panic!();
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
struct S<T> {
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
error: this could be rewritten as `let...else`
|
||||
--> $DIR/manual_let_else.rs:25:5
|
||||
--> $DIR/manual_let_else.rs:27:5
|
||||
|
|
||||
LL | let v = if let Some(v_some) = g() { v_some } else { return };
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider writing: `let Some(v) = g() else { return };`
|
||||
|
|
@ -8,7 +8,7 @@ LL | let v = if let Some(v_some) = g() { v_some } else { return };
|
|||
= help: to override `-D warnings` add `#[allow(clippy::manual_let_else)]`
|
||||
|
||||
error: this could be rewritten as `let...else`
|
||||
--> $DIR/manual_let_else.rs:28:5
|
||||
--> $DIR/manual_let_else.rs:30:5
|
||||
|
|
||||
LL | / let v = if let Some(v_some) = g() {
|
||||
LL | |
|
||||
|
|
@ -26,7 +26,7 @@ LL + };
|
|||
|
|
||||
|
||||
error: this could be rewritten as `let...else`
|
||||
--> $DIR/manual_let_else.rs:35:5
|
||||
--> $DIR/manual_let_else.rs:37:5
|
||||
|
|
||||
LL | / let v = if let Some(v) = g() {
|
||||
LL | |
|
||||
|
|
@ -47,25 +47,25 @@ LL + };
|
|||
|
|
||||
|
||||
error: this could be rewritten as `let...else`
|
||||
--> $DIR/manual_let_else.rs:47:9
|
||||
--> $DIR/manual_let_else.rs:49:9
|
||||
|
|
||||
LL | let v = if let Some(v_some) = g() { v_some } else { continue };
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider writing: `let Some(v) = g() else { continue };`
|
||||
|
||||
error: this could be rewritten as `let...else`
|
||||
--> $DIR/manual_let_else.rs:49:9
|
||||
--> $DIR/manual_let_else.rs:51:9
|
||||
|
|
||||
LL | let v = if let Some(v_some) = g() { v_some } else { break };
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider writing: `let Some(v) = g() else { break };`
|
||||
|
||||
error: this could be rewritten as `let...else`
|
||||
--> $DIR/manual_let_else.rs:54:5
|
||||
--> $DIR/manual_let_else.rs:56:5
|
||||
|
|
||||
LL | let v = if let Some(v_some) = g() { v_some } else { panic!() };
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider writing: `let Some(v) = g() else { panic!() };`
|
||||
|
||||
error: this could be rewritten as `let...else`
|
||||
--> $DIR/manual_let_else.rs:58:5
|
||||
--> $DIR/manual_let_else.rs:60:5
|
||||
|
|
||||
LL | / let v = if let Some(v_some) = g() {
|
||||
LL | |
|
||||
|
|
@ -83,7 +83,7 @@ LL + };
|
|||
|
|
||||
|
||||
error: this could be rewritten as `let...else`
|
||||
--> $DIR/manual_let_else.rs:66:5
|
||||
--> $DIR/manual_let_else.rs:68:5
|
||||
|
|
||||
LL | / let v = if let Some(v_some) = g() {
|
||||
LL | |
|
||||
|
|
@ -101,7 +101,7 @@ LL + };
|
|||
|
|
||||
|
||||
error: this could be rewritten as `let...else`
|
||||
--> $DIR/manual_let_else.rs:74:5
|
||||
--> $DIR/manual_let_else.rs:76:5
|
||||
|
|
||||
LL | / let v = if let Some(v_some) = g() {
|
||||
LL | |
|
||||
|
|
@ -127,29 +127,21 @@ LL | / let v = if let Some(v_some) = g() {
|
|||
LL | |
|
||||
LL | | v_some
|
||||
LL | | } else {
|
||||
... |
|
||||
LL | | }
|
||||
LL | | panic!();
|
||||
LL | | ()
|
||||
LL | | };
|
||||
| |______^
|
||||
|
|
||||
help: consider writing
|
||||
|
|
||||
LL ~ let Some(v) = g() else {
|
||||
LL + match () {
|
||||
LL + _ if panic!() => {},
|
||||
LL + _ => panic!(),
|
||||
LL + }
|
||||
LL + panic!();
|
||||
LL + ()
|
||||
LL + };
|
||||
|
|
||||
|
||||
error: this could be rewritten as `let...else`
|
||||
--> $DIR/manual_let_else.rs:96:5
|
||||
|
|
||||
LL | let v = if let Some(v_some) = g() { v_some } else { if panic!() {} };
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider writing: `let Some(v) = g() else { if panic!() {} };`
|
||||
|
||||
error: this could be rewritten as `let...else`
|
||||
--> $DIR/manual_let_else.rs:100:5
|
||||
--> $DIR/manual_let_else.rs:94:5
|
||||
|
|
||||
LL | / let v = if let Some(v_some) = g() {
|
||||
LL | |
|
||||
|
|
@ -163,8 +155,14 @@ LL | | };
|
|||
help: consider writing
|
||||
|
|
||||
LL ~ let Some(v) = g() else {
|
||||
LL + match panic!() {
|
||||
LL + _ => {},
|
||||
LL + panic!();
|
||||
LL + if true {
|
||||
LL + match 0 {
|
||||
LL + 0 => (),
|
||||
LL + _ => (),
|
||||
LL + }
|
||||
LL + } else {
|
||||
LL + panic!()
|
||||
LL + }
|
||||
LL + };
|
||||
|
|
||||
|
|
@ -175,6 +173,116 @@ error: this could be rewritten as `let...else`
|
|||
LL | / let v = if let Some(v_some) = g() {
|
||||
LL | |
|
||||
LL | | v_some
|
||||
LL | | } else {
|
||||
... |
|
||||
LL | | }
|
||||
LL | | };
|
||||
| |______^
|
||||
|
|
||||
help: consider writing
|
||||
|
|
||||
LL ~ let Some(v) = g() else {
|
||||
LL + loop {
|
||||
LL + panic!();
|
||||
LL + break ();
|
||||
LL + }
|
||||
LL + };
|
||||
|
|
||||
|
||||
error: this could be rewritten as `let...else`
|
||||
--> $DIR/manual_let_else.rs:121:5
|
||||
|
|
||||
LL | / let v = if let Some(v_some) = g() {
|
||||
LL | |
|
||||
LL | | v_some
|
||||
LL | | } else {
|
||||
... |
|
||||
LL | | }
|
||||
LL | | };
|
||||
| |______^
|
||||
|
|
||||
help: consider writing
|
||||
|
|
||||
LL ~ let Some(v) = g() else {
|
||||
LL + 'a: loop {
|
||||
LL + panic!();
|
||||
LL + loop {
|
||||
LL + match 0 {
|
||||
LL + 0 if (return break 'a ()) => {},
|
||||
LL + _ => {},
|
||||
LL + }
|
||||
LL + }
|
||||
LL + }
|
||||
LL + };
|
||||
|
|
||||
|
||||
error: this could be rewritten as `let...else`
|
||||
--> $DIR/manual_let_else.rs:137:5
|
||||
|
|
||||
LL | / let v = if let Some(v_some) = g() {
|
||||
LL | |
|
||||
LL | | v_some
|
||||
LL | | } else {
|
||||
... |
|
||||
LL | | };
|
||||
LL | | };
|
||||
| |______^
|
||||
|
|
||||
help: consider writing
|
||||
|
|
||||
LL ~ let Some(v) = g() else {
|
||||
LL + match 0 {
|
||||
LL + 0 if true => panic!(),
|
||||
LL + _ => panic!(),
|
||||
LL + };
|
||||
LL + };
|
||||
|
|
||||
|
||||
error: this could be rewritten as `let...else`
|
||||
--> $DIR/manual_let_else.rs:148:5
|
||||
|
|
||||
LL | / let v = if let Some(v_some) = g() {
|
||||
LL | |
|
||||
LL | | v_some
|
||||
LL | | } else {
|
||||
LL | | if panic!() {};
|
||||
LL | | };
|
||||
| |______^
|
||||
|
|
||||
help: consider writing
|
||||
|
|
||||
LL ~ let Some(v) = g() else {
|
||||
LL + if panic!() {};
|
||||
LL + };
|
||||
|
|
||||
|
||||
error: this could be rewritten as `let...else`
|
||||
--> $DIR/manual_let_else.rs:156:5
|
||||
|
|
||||
LL | / let v = if let Some(v_some) = g() {
|
||||
LL | |
|
||||
LL | | v_some
|
||||
LL | | } else {
|
||||
... |
|
||||
LL | | };
|
||||
LL | | };
|
||||
| |______^
|
||||
|
|
||||
help: consider writing
|
||||
|
|
||||
LL ~ let Some(v) = g() else {
|
||||
LL + match panic!() {
|
||||
LL + _ => {},
|
||||
LL + };
|
||||
LL + };
|
||||
|
|
||||
|
||||
error: this could be rewritten as `let...else`
|
||||
--> $DIR/manual_let_else.rs:166:5
|
||||
|
|
||||
LL | / let v = if let Some(v_some) = g() {
|
||||
LL | |
|
||||
LL | | v_some
|
||||
LL | | } else if true {
|
||||
... |
|
||||
LL | | panic!("diverge");
|
||||
|
|
@ -191,7 +299,7 @@ LL + } };
|
|||
|
|
||||
|
||||
error: this could be rewritten as `let...else`
|
||||
--> $DIR/manual_let_else.rs:120:5
|
||||
--> $DIR/manual_let_else.rs:176:5
|
||||
|
|
||||
LL | / let v = if let Some(v_some) = g() {
|
||||
LL | |
|
||||
|
|
@ -220,7 +328,7 @@ LL + };
|
|||
|
|
||||
|
||||
error: this could be rewritten as `let...else`
|
||||
--> $DIR/manual_let_else.rs:138:5
|
||||
--> $DIR/manual_let_else.rs:194:5
|
||||
|
|
||||
LL | / let (v, w) = if let Some(v_some) = g().map(|v| (v, 42)) {
|
||||
LL | |
|
||||
|
|
@ -238,7 +346,7 @@ LL + };
|
|||
|
|
||||
|
||||
error: this could be rewritten as `let...else`
|
||||
--> $DIR/manual_let_else.rs:146:5
|
||||
--> $DIR/manual_let_else.rs:202:5
|
||||
|
|
||||
LL | / let (w, S { v }) = if let (Some(v_some), w_some) = (g().map(|_| S { v: 0 }), 0) {
|
||||
LL | |
|
||||
|
|
@ -256,7 +364,7 @@ LL + };
|
|||
|
|
||||
|
||||
error: this could be rewritten as `let...else`
|
||||
--> $DIR/manual_let_else.rs:156:13
|
||||
--> $DIR/manual_let_else.rs:212:13
|
||||
|
|
||||
LL | let $n = if let Some(v) = $e { v } else { return };
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider writing: `let Some($n) = g() else { return };`
|
||||
|
|
@ -267,19 +375,19 @@ LL | create_binding_if_some!(w, g());
|
|||
= note: this error originates in the macro `create_binding_if_some` (in Nightly builds, run with -Z macro-backtrace for more info)
|
||||
|
||||
error: this could be rewritten as `let...else`
|
||||
--> $DIR/manual_let_else.rs:165:5
|
||||
--> $DIR/manual_let_else.rs:221:5
|
||||
|
|
||||
LL | let v = if let Variant::A(a, 0) = e() { a } else { return };
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider writing: `let Variant::A(v, 0) = e() else { return };`
|
||||
|
||||
error: this could be rewritten as `let...else`
|
||||
--> $DIR/manual_let_else.rs:169:5
|
||||
--> $DIR/manual_let_else.rs:225:5
|
||||
|
|
||||
LL | let mut v = if let Variant::B(b) = e() { b } else { return };
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider writing: `let Variant::B(mut v) = e() else { return };`
|
||||
|
||||
error: this could be rewritten as `let...else`
|
||||
--> $DIR/manual_let_else.rs:174:5
|
||||
--> $DIR/manual_let_else.rs:230:5
|
||||
|
|
||||
LL | / let v = if let Ok(Some(Variant::B(b))) | Err(Some(Variant::A(b, _))) = nested {
|
||||
LL | |
|
||||
|
|
@ -297,19 +405,19 @@ LL + };
|
|||
|
|
||||
|
||||
error: this could be rewritten as `let...else`
|
||||
--> $DIR/manual_let_else.rs:181:5
|
||||
--> $DIR/manual_let_else.rs:237:5
|
||||
|
|
||||
LL | let v = if let Variant::A(.., a) = e() { a } else { return };
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider writing: `let Variant::A(.., v) = e() else { return };`
|
||||
|
||||
error: this could be rewritten as `let...else`
|
||||
--> $DIR/manual_let_else.rs:185:5
|
||||
--> $DIR/manual_let_else.rs:241:5
|
||||
|
|
||||
LL | let w = if let (Some(v), ()) = (g(), ()) { v } else { return };
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider writing: `let (Some(w), ()) = (g(), ()) else { return };`
|
||||
|
||||
error: this could be rewritten as `let...else`
|
||||
--> $DIR/manual_let_else.rs:189:5
|
||||
--> $DIR/manual_let_else.rs:245:5
|
||||
|
|
||||
LL | / let w = if let Some(S { v: x }) = Some(S { v: 0 }) {
|
||||
LL | |
|
||||
|
|
@ -327,7 +435,7 @@ LL + };
|
|||
|
|
||||
|
||||
error: this could be rewritten as `let...else`
|
||||
--> $DIR/manual_let_else.rs:197:5
|
||||
--> $DIR/manual_let_else.rs:253:5
|
||||
|
|
||||
LL | / let v = if let Some(S { v: x }) = Some(S { v: 0 }) {
|
||||
LL | |
|
||||
|
|
@ -345,7 +453,7 @@ LL + };
|
|||
|
|
||||
|
||||
error: this could be rewritten as `let...else`
|
||||
--> $DIR/manual_let_else.rs:205:5
|
||||
--> $DIR/manual_let_else.rs:261:5
|
||||
|
|
||||
LL | / let (x, S { v }, w) = if let Some(U { v, w, x }) = None::<U<S<()>>> {
|
||||
LL | |
|
||||
|
|
@ -363,7 +471,7 @@ LL + };
|
|||
|
|
||||
|
||||
error: this could be rewritten as `let...else`
|
||||
--> $DIR/manual_let_else.rs:322:5
|
||||
--> $DIR/manual_let_else.rs:378:5
|
||||
|
|
||||
LL | / let _ = match ff {
|
||||
LL | |
|
||||
|
|
@ -372,5 +480,5 @@ LL | | _ => macro_call!(),
|
|||
LL | | };
|
||||
| |______^ help: consider writing: `let Some(_) = ff else { macro_call!() };`
|
||||
|
||||
error: aborting due to 26 previous errors
|
||||
error: aborting due to 30 previous errors
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue