Also consider match guards for divergence check
Plus, add some tests for the divergence check.
This commit is contained in:
parent
96ea5b2cd6
commit
dcde480a66
@ -194,8 +194,11 @@ fn is_never(cx: &LateContext<'_>, expr: &'_ Expr<'_>) -> bool {
|
|||||||
ControlFlow::Continue(Descend::No)
|
ControlFlow::Continue(Descend::No)
|
||||||
},
|
},
|
||||||
ExprKind::Match(match_expr, match_arms, _) => {
|
ExprKind::Match(match_expr, match_arms, _) => {
|
||||||
let diverges =
|
let diverges = expr_diverges(cx, match_expr)
|
||||||
expr_diverges(cx, match_expr) || match_arms.iter().all(|arm| expr_diverges(cx, arm.body));
|
|| match_arms.iter().all(|arm| {
|
||||||
|
let guard_diverges = arm.guard.as_ref().map_or(false, |g| expr_diverges(cx, g.body()));
|
||||||
|
guard_diverges || expr_diverges(cx, arm.body)
|
||||||
|
});
|
||||||
if diverges {
|
if diverges {
|
||||||
return ControlFlow::Break(());
|
return ControlFlow::Break(());
|
||||||
}
|
}
|
||||||
|
@ -3,6 +3,7 @@
|
|||||||
clippy::collapsible_else_if,
|
clippy::collapsible_else_if,
|
||||||
clippy::unused_unit,
|
clippy::unused_unit,
|
||||||
clippy::let_unit_value,
|
clippy::let_unit_value,
|
||||||
|
clippy::match_single_binding,
|
||||||
clippy::never_loop
|
clippy::never_loop
|
||||||
)]
|
)]
|
||||||
#![warn(clippy::manual_let_else)]
|
#![warn(clippy::manual_let_else)]
|
||||||
@ -55,6 +56,38 @@ fn fire() {
|
|||||||
if true { return } else { panic!() }
|
if true { return } else { panic!() }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Diverging after an if still makes the block diverge:
|
||||||
|
let v = if let Some(v_some) = g() {
|
||||||
|
v_some
|
||||||
|
} else {
|
||||||
|
if true {}
|
||||||
|
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.
|
||||||
|
let v = if let Some(v_some) = g() {
|
||||||
|
v_some
|
||||||
|
} else {
|
||||||
|
match () {
|
||||||
|
_ if panic!() => {},
|
||||||
|
_ => panic!(),
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// An if's expression can cause divergence:
|
||||||
|
let v = if let Some(v_some) = g() { v_some } else { if panic!() {} };
|
||||||
|
|
||||||
|
// An expression of a match can cause divergence:
|
||||||
|
let v = if let Some(v_some) = g() {
|
||||||
|
v_some
|
||||||
|
} else {
|
||||||
|
match panic!() {
|
||||||
|
_ => {},
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
// Top level else if
|
// Top level else if
|
||||||
let v = if let Some(v_some) = g() {
|
let v = if let Some(v_some) = g() {
|
||||||
v_some
|
v_some
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
error: this could be rewritten as `let...else`
|
error: this could be rewritten as `let...else`
|
||||||
--> $DIR/manual_let_else.rs:17:5
|
--> $DIR/manual_let_else.rs:18:5
|
||||||
|
|
|
|
||||||
LL | let v = if let Some(v_some) = g() { v_some } else { return };
|
LL | let v = if let Some(v_some) = g() { v_some } else { return };
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider writing: `let Some(v_some) = g() else { return };`
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider writing: `let Some(v_some) = g() else { return };`
|
||||||
@ -7,7 +7,7 @@ LL | let v = if let Some(v_some) = g() { v_some } else { return };
|
|||||||
= note: `-D clippy::manual-let-else` implied by `-D warnings`
|
= note: `-D clippy::manual-let-else` implied by `-D warnings`
|
||||||
|
|
||||||
error: this could be rewritten as `let...else`
|
error: this could be rewritten as `let...else`
|
||||||
--> $DIR/manual_let_else.rs:18:5
|
--> $DIR/manual_let_else.rs:19:5
|
||||||
|
|
|
|
||||||
LL | / let v = if let Some(v_some) = g() {
|
LL | / let v = if let Some(v_some) = g() {
|
||||||
LL | | v_some
|
LL | | v_some
|
||||||
@ -24,7 +24,7 @@ LL + };
|
|||||||
|
|
|
|
||||||
|
|
||||||
error: this could be rewritten as `let...else`
|
error: this could be rewritten as `let...else`
|
||||||
--> $DIR/manual_let_else.rs:24:5
|
--> $DIR/manual_let_else.rs:25:5
|
||||||
|
|
|
|
||||||
LL | / let v = if let Some(v) = g() {
|
LL | / let v = if let Some(v) = g() {
|
||||||
LL | | // Blocks around the identity should have no impact
|
LL | | // Blocks around the identity should have no impact
|
||||||
@ -45,25 +45,25 @@ LL + };
|
|||||||
|
|
|
|
||||||
|
|
||||||
error: this could be rewritten as `let...else`
|
error: this could be rewritten as `let...else`
|
||||||
--> $DIR/manual_let_else.rs:37:9
|
--> $DIR/manual_let_else.rs:38:9
|
||||||
|
|
|
|
||||||
LL | let v = if let Some(v_some) = g() { v_some } else { continue };
|
LL | let v = if let Some(v_some) = g() { v_some } else { continue };
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider writing: `let Some(v_some) = g() else { continue };`
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider writing: `let Some(v_some) = g() else { continue };`
|
||||||
|
|
||||||
error: this could be rewritten as `let...else`
|
error: this could be rewritten as `let...else`
|
||||||
--> $DIR/manual_let_else.rs:38:9
|
--> $DIR/manual_let_else.rs:39:9
|
||||||
|
|
|
|
||||||
LL | let v = if let Some(v_some) = g() { v_some } else { break };
|
LL | let v = if let Some(v_some) = g() { v_some } else { break };
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider writing: `let Some(v_some) = g() else { break };`
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider writing: `let Some(v_some) = g() else { break };`
|
||||||
|
|
||||||
error: this could be rewritten as `let...else`
|
error: this could be rewritten as `let...else`
|
||||||
--> $DIR/manual_let_else.rs:42:5
|
--> $DIR/manual_let_else.rs:43:5
|
||||||
|
|
|
|
||||||
LL | let v = if let Some(v_some) = g() { v_some } else { panic!() };
|
LL | let v = if let Some(v_some) = g() { v_some } else { panic!() };
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider writing: `let Some(v_some) = g() else { panic!() };`
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider writing: `let Some(v_some) = g() else { panic!() };`
|
||||||
|
|
||||||
error: this could be rewritten as `let...else`
|
error: this could be rewritten as `let...else`
|
||||||
--> $DIR/manual_let_else.rs:45:5
|
--> $DIR/manual_let_else.rs:46:5
|
||||||
|
|
|
|
||||||
LL | / let v = if let Some(v_some) = g() {
|
LL | / let v = if let Some(v_some) = g() {
|
||||||
LL | | v_some
|
LL | | v_some
|
||||||
@ -80,7 +80,7 @@ LL + };
|
|||||||
|
|
|
|
||||||
|
|
||||||
error: this could be rewritten as `let...else`
|
error: this could be rewritten as `let...else`
|
||||||
--> $DIR/manual_let_else.rs:52:5
|
--> $DIR/manual_let_else.rs:53:5
|
||||||
|
|
|
|
||||||
LL | / let v = if let Some(v_some) = g() {
|
LL | / let v = if let Some(v_some) = g() {
|
||||||
LL | | v_some
|
LL | | v_some
|
||||||
@ -97,7 +97,75 @@ LL + };
|
|||||||
|
|
|
|
||||||
|
|
||||||
error: this could be rewritten as `let...else`
|
error: this could be rewritten as `let...else`
|
||||||
--> $DIR/manual_let_else.rs:59:5
|
--> $DIR/manual_let_else.rs:60:5
|
||||||
|
|
|
||||||
|
LL | / let v = if let Some(v_some) = g() {
|
||||||
|
LL | | v_some
|
||||||
|
LL | | } else {
|
||||||
|
LL | | if true {}
|
||||||
|
LL | | panic!();
|
||||||
|
LL | | };
|
||||||
|
| |______^
|
||||||
|
|
|
||||||
|
help: consider writing
|
||||||
|
|
|
||||||
|
LL ~ let Some(v_some) = g() else {
|
||||||
|
LL + if true {}
|
||||||
|
LL + panic!();
|
||||||
|
LL + };
|
||||||
|
|
|
||||||
|
|
||||||
|
error: this could be rewritten as `let...else`
|
||||||
|
--> $DIR/manual_let_else.rs:70:5
|
||||||
|
|
|
||||||
|
LL | / let v = if let Some(v_some) = g() {
|
||||||
|
LL | | v_some
|
||||||
|
LL | | } else {
|
||||||
|
LL | | match () {
|
||||||
|
... |
|
||||||
|
LL | | }
|
||||||
|
LL | | };
|
||||||
|
| |______^
|
||||||
|
|
|
||||||
|
help: consider writing
|
||||||
|
|
|
||||||
|
LL ~ let Some(v_some) = g() else {
|
||||||
|
LL + match () {
|
||||||
|
LL + _ if panic!() => {},
|
||||||
|
LL + _ => panic!(),
|
||||||
|
LL + }
|
||||||
|
LL + };
|
||||||
|
|
|
||||||
|
|
||||||
|
error: this could be rewritten as `let...else`
|
||||||
|
--> $DIR/manual_let_else.rs:80:5
|
||||||
|
|
|
||||||
|
LL | let v = if let Some(v_some) = g() { v_some } else { if panic!() {} };
|
||||||
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider writing: `let Some(v_some) = g() else { if panic!() {} };`
|
||||||
|
|
||||||
|
error: this could be rewritten as `let...else`
|
||||||
|
--> $DIR/manual_let_else.rs:83:5
|
||||||
|
|
|
||||||
|
LL | / let v = if let Some(v_some) = g() {
|
||||||
|
LL | | v_some
|
||||||
|
LL | | } else {
|
||||||
|
LL | | match panic!() {
|
||||||
|
LL | | _ => {},
|
||||||
|
LL | | }
|
||||||
|
LL | | };
|
||||||
|
| |______^
|
||||||
|
|
|
||||||
|
help: consider writing
|
||||||
|
|
|
||||||
|
LL ~ let Some(v_some) = g() else {
|
||||||
|
LL + match panic!() {
|
||||||
|
LL + _ => {},
|
||||||
|
LL + }
|
||||||
|
LL + };
|
||||||
|
|
|
||||||
|
|
||||||
|
error: this could be rewritten as `let...else`
|
||||||
|
--> $DIR/manual_let_else.rs:92:5
|
||||||
|
|
|
|
||||||
LL | / let v = if let Some(v_some) = g() {
|
LL | / let v = if let Some(v_some) = g() {
|
||||||
LL | | v_some
|
LL | | v_some
|
||||||
@ -118,7 +186,7 @@ LL + } };
|
|||||||
|
|
|
|
||||||
|
|
||||||
error: this could be rewritten as `let...else`
|
error: this could be rewritten as `let...else`
|
||||||
--> $DIR/manual_let_else.rs:68:5
|
--> $DIR/manual_let_else.rs:101:5
|
||||||
|
|
|
|
||||||
LL | / let v = if let Some(v_some) = g() {
|
LL | / let v = if let Some(v_some) = g() {
|
||||||
LL | | v_some
|
LL | | v_some
|
||||||
@ -147,7 +215,7 @@ LL + };
|
|||||||
|
|
|
|
||||||
|
|
||||||
error: this could be rewritten as `let...else`
|
error: this could be rewritten as `let...else`
|
||||||
--> $DIR/manual_let_else.rs:85:5
|
--> $DIR/manual_let_else.rs:118:5
|
||||||
|
|
|
|
||||||
LL | / let (v, w) = if let Some(v_some) = g().map(|v| (v, 42)) {
|
LL | / let (v, w) = if let Some(v_some) = g().map(|v| (v, 42)) {
|
||||||
LL | | v_some
|
LL | | v_some
|
||||||
@ -164,7 +232,7 @@ LL + };
|
|||||||
|
|
|
|
||||||
|
|
||||||
error: this could be rewritten as `let...else`
|
error: this could be rewritten as `let...else`
|
||||||
--> $DIR/manual_let_else.rs:92:5
|
--> $DIR/manual_let_else.rs:125:5
|
||||||
|
|
|
|
||||||
LL | / let v = if let (Some(v_some), w_some) = (g(), 0) {
|
LL | / let v = if let (Some(v_some), w_some) = (g(), 0) {
|
||||||
LL | | (w_some, v_some)
|
LL | | (w_some, v_some)
|
||||||
@ -181,7 +249,7 @@ LL + };
|
|||||||
|
|
|
|
||||||
|
|
||||||
error: this could be rewritten as `let...else`
|
error: this could be rewritten as `let...else`
|
||||||
--> $DIR/manual_let_else.rs:101:13
|
--> $DIR/manual_let_else.rs:134:13
|
||||||
|
|
|
|
||||||
LL | let $n = if let Some(v) = $e { v } else { return };
|
LL | let $n = if let Some(v) = $e { v } else { return };
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider writing: `let Some(v) = g() else { return };`
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider writing: `let Some(v) = g() else { return };`
|
||||||
@ -191,5 +259,5 @@ 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)
|
= note: this error originates in the macro `create_binding_if_some` (in Nightly builds, run with -Z macro-backtrace for more info)
|
||||||
|
|
||||||
error: aborting due to 13 previous errors
|
error: aborting due to 17 previous errors
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user