mirror of
https://github.com/rust-lang/rust-clippy
synced 2024-11-23 21:23:56 +00:00
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
|
@ -64,7 +64,7 @@ impl<'tcx> QuestionMark {
|
||||||
IfLetOrMatch::IfLet(if_let_expr, let_pat, if_then, if_else) => {
|
IfLetOrMatch::IfLet(if_let_expr, let_pat, if_then, if_else) => {
|
||||||
if let Some(ident_map) = expr_simple_identity_map(local.pat, let_pat, if_then)
|
if let Some(ident_map) = expr_simple_identity_map(local.pat, let_pat, if_then)
|
||||||
&& let Some(if_else) = if_else
|
&& let Some(if_else) = if_else
|
||||||
&& is_never_expr(cx, if_else)
|
&& is_never_expr(cx, if_else).is_some()
|
||||||
&& let qm_allowed = is_lint_allowed(cx, QUESTION_MARK, stmt.hir_id)
|
&& let qm_allowed = is_lint_allowed(cx, QUESTION_MARK, stmt.hir_id)
|
||||||
&& (qm_allowed || pat_and_expr_can_be_question_mark(cx, let_pat, if_else).is_none())
|
&& (qm_allowed || pat_and_expr_can_be_question_mark(cx, let_pat, if_else).is_none())
|
||||||
{
|
{
|
||||||
|
@ -88,10 +88,9 @@ impl<'tcx> QuestionMark {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
let check_types = self.matches_behaviour == MatchLintBehaviour::WellKnownTypes;
|
let check_types = self.matches_behaviour == MatchLintBehaviour::WellKnownTypes;
|
||||||
let diverging_arm_opt = arms
|
let diverging_arm_opt = arms.iter().enumerate().find(|(_, arm)| {
|
||||||
.iter()
|
is_never_expr(cx, arm.body).is_some() && pat_allowed_for_else(cx, arm.pat, check_types)
|
||||||
.enumerate()
|
});
|
||||||
.find(|(_, arm)| is_never_expr(cx, arm.body) && pat_allowed_for_else(cx, arm.pat, check_types));
|
|
||||||
let Some((idx, diverging_arm)) = diverging_arm_opt else {
|
let Some((idx, diverging_arm)) = diverging_arm_opt else {
|
||||||
return;
|
return;
|
||||||
};
|
};
|
||||||
|
|
|
@ -71,6 +71,7 @@ pub use self::hir_utils::{
|
||||||
both, count_eq, eq_expr_value, hash_expr, hash_stmt, is_bool, over, HirEqInterExpr, SpanlessEq, SpanlessHash,
|
both, count_eq, eq_expr_value, hash_expr, hash_stmt, is_bool, over, HirEqInterExpr, SpanlessEq, SpanlessHash,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
use core::mem;
|
||||||
use core::ops::ControlFlow;
|
use core::ops::ControlFlow;
|
||||||
use std::collections::hash_map::Entry;
|
use std::collections::hash_map::Entry;
|
||||||
use std::hash::BuildHasherDefault;
|
use std::hash::BuildHasherDefault;
|
||||||
|
@ -88,7 +89,7 @@ use rustc_hir::intravisit::{walk_expr, FnKind, Visitor};
|
||||||
use rustc_hir::LangItem::{OptionNone, OptionSome, ResultErr, ResultOk};
|
use rustc_hir::LangItem::{OptionNone, OptionSome, ResultErr, ResultOk};
|
||||||
use rustc_hir::{
|
use rustc_hir::{
|
||||||
self as hir, def, Arm, ArrayLen, BindingAnnotation, Block, BlockCheckMode, Body, Closure, Destination, Expr,
|
self as hir, def, Arm, ArrayLen, BindingAnnotation, Block, BlockCheckMode, Body, Closure, Destination, Expr,
|
||||||
ExprField, ExprKind, FnDecl, FnRetTy, GenericArgs, HirId, Impl, ImplItem, ImplItemKind, ImplItemRef, Item, ItemId,
|
ExprField, ExprKind, FnDecl, FnRetTy, GenericArgs, HirId, Impl, ImplItem, ImplItemKind, ImplItemRef, Item,
|
||||||
ItemKind, LangItem, Local, MatchSource, Mutability, Node, OwnerId, Param, Pat, PatKind, Path, PathSegment, PrimTy,
|
ItemKind, LangItem, Local, MatchSource, Mutability, Node, OwnerId, Param, Pat, PatKind, Path, PathSegment, PrimTy,
|
||||||
QPath, Stmt, StmtKind, TraitItem, TraitItemKind, TraitItemRef, TraitRef, TyKind, UnOp,
|
QPath, Stmt, StmtKind, TraitItem, TraitItemKind, TraitItemRef, TraitRef, TyKind, UnOp,
|
||||||
};
|
};
|
||||||
|
@ -117,7 +118,7 @@ use crate::ty::{
|
||||||
adt_and_variant_of_res, can_partially_move_ty, expr_sig, is_copy, is_recursively_primitive_type,
|
adt_and_variant_of_res, can_partially_move_ty, expr_sig, is_copy, is_recursively_primitive_type,
|
||||||
ty_is_fn_once_param,
|
ty_is_fn_once_param,
|
||||||
};
|
};
|
||||||
use crate::visitors::{for_each_expr, Descend};
|
use crate::visitors::for_each_expr;
|
||||||
|
|
||||||
use rustc_middle::hir::nested_filter;
|
use rustc_middle::hir::nested_filter;
|
||||||
|
|
||||||
|
@ -2975,100 +2976,247 @@ pub fn pat_is_wild<'tcx>(cx: &LateContext<'tcx>, pat: &'tcx PatKind<'_>, body: i
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Check if the expression either returns, or could be coerced into returning, `!`.
|
#[derive(Clone, Copy)]
|
||||||
pub fn is_never_expr(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {
|
pub enum RequiresSemi {
|
||||||
|
Yes,
|
||||||
|
No,
|
||||||
|
}
|
||||||
|
impl RequiresSemi {
|
||||||
|
pub fn requires_semi(self) -> bool {
|
||||||
|
matches!(self, Self::Yes)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Check if the expression return `!`, a type coerced from `!`, or could return `!` if the final
|
||||||
|
/// expression were turned into a statement.
|
||||||
|
#[expect(clippy::too_many_lines)]
|
||||||
|
pub fn is_never_expr<'tcx>(cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) -> Option<RequiresSemi> {
|
||||||
|
struct BreakTarget {
|
||||||
|
id: HirId,
|
||||||
|
unused: bool,
|
||||||
|
}
|
||||||
|
|
||||||
struct V<'cx, 'tcx> {
|
struct V<'cx, 'tcx> {
|
||||||
cx: &'cx LateContext<'tcx>,
|
cx: &'cx LateContext<'tcx>,
|
||||||
res: ControlFlow<(), Descend>,
|
break_targets: Vec<BreakTarget>,
|
||||||
|
break_targets_for_result_ty: u32,
|
||||||
|
in_final_expr: bool,
|
||||||
|
requires_semi: bool,
|
||||||
|
is_never: bool,
|
||||||
}
|
}
|
||||||
impl<'tcx> Visitor<'tcx> for V<'_, '_> {
|
|
||||||
fn visit_expr(&mut self, e: &'tcx Expr<'tcx>) {
|
|
||||||
fn is_never(cx: &LateContext<'_>, expr: &'_ Expr<'_>) -> bool {
|
|
||||||
if let Some(ty) = cx.typeck_results().expr_ty_opt(expr) {
|
|
||||||
return ty.is_never();
|
|
||||||
}
|
|
||||||
false
|
|
||||||
}
|
|
||||||
|
|
||||||
if self.res.is_break() {
|
impl<'tcx> V<'_, 'tcx> {
|
||||||
|
fn push_break_target(&mut self, id: HirId) {
|
||||||
|
self.break_targets.push(BreakTarget { id, unused: true });
|
||||||
|
self.break_targets_for_result_ty += u32::from(self.in_final_expr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'tcx> Visitor<'tcx> for V<'_, 'tcx> {
|
||||||
|
fn visit_expr(&mut self, e: &'tcx Expr<'_>) {
|
||||||
|
// Note: Part of the complexity here comes from the fact that
|
||||||
|
// coercions are applied to the innermost expression.
|
||||||
|
// e.g. In `let x: u32 = { break () };` the never-to-any coercion
|
||||||
|
// is applied to the break expression. This means we can't just
|
||||||
|
// check the block's type as it will be `u32` despite the fact
|
||||||
|
// that the block always diverges.
|
||||||
|
|
||||||
|
// The rest of the complexity comes from checking blocks which
|
||||||
|
// syntactically return a value, but will always diverge before
|
||||||
|
// reaching that point.
|
||||||
|
// e.g. In `let x = { foo(panic!()) };` the block's type will be the
|
||||||
|
// return type of `foo` even though it will never actually run. This
|
||||||
|
// can be trivially fixed by adding a semicolon after the call, but
|
||||||
|
// we must first detect that a semicolon is needed to make that
|
||||||
|
// suggestion.
|
||||||
|
|
||||||
|
if self.is_never && self.break_targets.is_empty() {
|
||||||
|
if self.in_final_expr && !self.requires_semi {
|
||||||
|
// This expression won't ever run, but we still need to check
|
||||||
|
// if it can affect the type of the final expression.
|
||||||
|
match e.kind {
|
||||||
|
ExprKind::DropTemps(e) => self.visit_expr(e),
|
||||||
|
ExprKind::If(_, then, Some(else_)) => {
|
||||||
|
self.visit_expr(then);
|
||||||
|
self.visit_expr(else_);
|
||||||
|
},
|
||||||
|
ExprKind::Match(_, arms, _) => {
|
||||||
|
for arm in arms {
|
||||||
|
self.visit_expr(arm.body);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
ExprKind::Loop(b, ..) => {
|
||||||
|
self.push_break_target(e.hir_id);
|
||||||
|
self.in_final_expr = false;
|
||||||
|
self.visit_block(b);
|
||||||
|
self.break_targets.pop();
|
||||||
|
},
|
||||||
|
ExprKind::Block(b, _) => {
|
||||||
|
if b.targeted_by_break {
|
||||||
|
self.push_break_target(b.hir_id);
|
||||||
|
self.visit_block(b);
|
||||||
|
self.break_targets.pop();
|
||||||
|
} else {
|
||||||
|
self.visit_block(b);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
_ => {
|
||||||
|
self.requires_semi = !self.cx.typeck_results().expr_ty(e).is_never();
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
match e.kind {
|
||||||
|
ExprKind::DropTemps(e) => self.visit_expr(e),
|
||||||
|
ExprKind::Ret(None) | ExprKind::Continue(_) => self.is_never = true,
|
||||||
|
ExprKind::Ret(Some(e)) | ExprKind::Become(e) => {
|
||||||
|
self.in_final_expr = false;
|
||||||
|
self.visit_expr(e);
|
||||||
|
self.is_never = true;
|
||||||
|
},
|
||||||
|
ExprKind::Break(dest, e) => {
|
||||||
|
if let Some(e) = e {
|
||||||
|
self.in_final_expr = false;
|
||||||
|
self.visit_expr(e);
|
||||||
|
}
|
||||||
|
if let Ok(id) = dest.target_id
|
||||||
|
&& let Some((i, target)) = self
|
||||||
|
.break_targets
|
||||||
|
.iter_mut()
|
||||||
|
.enumerate()
|
||||||
|
.find(|(_, target)| target.id == id)
|
||||||
|
{
|
||||||
|
target.unused &= self.is_never;
|
||||||
|
if i < self.break_targets_for_result_ty as usize {
|
||||||
|
self.requires_semi = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
self.is_never = true;
|
||||||
|
},
|
||||||
|
ExprKind::If(cond, then, else_) => {
|
||||||
|
let in_final_expr = mem::replace(&mut self.in_final_expr, false);
|
||||||
|
self.visit_expr(cond);
|
||||||
|
self.in_final_expr = in_final_expr;
|
||||||
|
|
||||||
// We can't just call is_never on expr and be done, because the type system
|
if self.is_never {
|
||||||
// sometimes coerces the ! type to something different before we can get
|
self.visit_expr(then);
|
||||||
// our hands on it. So instead, we do a manual search. We do fall back to
|
if let Some(else_) = else_ {
|
||||||
// is_never in some places when there is no better alternative.
|
self.visit_expr(else_);
|
||||||
self.res = match e.kind {
|
}
|
||||||
ExprKind::Continue(_) | ExprKind::Break(_, _) | ExprKind::Ret(_) => ControlFlow::Break(()),
|
|
||||||
ExprKind::Call(call, _) => {
|
|
||||||
if is_never(self.cx, e) || is_never(self.cx, call) {
|
|
||||||
ControlFlow::Break(())
|
|
||||||
} else {
|
} else {
|
||||||
ControlFlow::Continue(Descend::Yes)
|
self.visit_expr(then);
|
||||||
}
|
let is_never = mem::replace(&mut self.is_never, false);
|
||||||
},
|
if let Some(else_) = else_ {
|
||||||
ExprKind::MethodCall(..) => {
|
self.visit_expr(else_);
|
||||||
if is_never(self.cx, e) {
|
self.is_never &= is_never;
|
||||||
ControlFlow::Break(())
|
}
|
||||||
} else {
|
|
||||||
ControlFlow::Continue(Descend::Yes)
|
|
||||||
}
|
|
||||||
},
|
|
||||||
ExprKind::If(if_expr, if_then, if_else) => {
|
|
||||||
let else_diverges = if_else.map_or(false, |ex| is_never_expr(self.cx, ex));
|
|
||||||
let diverges =
|
|
||||||
is_never_expr(self.cx, if_expr) || (else_diverges && is_never_expr(self.cx, if_then));
|
|
||||||
if diverges {
|
|
||||||
ControlFlow::Break(())
|
|
||||||
} else {
|
|
||||||
ControlFlow::Continue(Descend::No)
|
|
||||||
}
|
|
||||||
},
|
|
||||||
ExprKind::Match(match_expr, match_arms, _) => {
|
|
||||||
let diverges = is_never_expr(self.cx, match_expr)
|
|
||||||
|| match_arms.iter().all(|arm| {
|
|
||||||
let guard_diverges = arm.guard.as_ref().map_or(false, |g| is_never_expr(self.cx, g.body()));
|
|
||||||
guard_diverges || is_never_expr(self.cx, arm.body)
|
|
||||||
});
|
|
||||||
if diverges {
|
|
||||||
ControlFlow::Break(())
|
|
||||||
} else {
|
|
||||||
ControlFlow::Continue(Descend::No)
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
ExprKind::Match(scrutinee, arms, _) => {
|
||||||
|
let in_final_expr = mem::replace(&mut self.in_final_expr, false);
|
||||||
|
self.visit_expr(scrutinee);
|
||||||
|
self.in_final_expr = in_final_expr;
|
||||||
|
|
||||||
// Don't continue into loops or labeled blocks, as they are breakable,
|
if self.is_never {
|
||||||
// and we'd have to start checking labels.
|
for arm in arms {
|
||||||
ExprKind::Block(_, Some(_)) | ExprKind::Loop(..) => ControlFlow::Continue(Descend::No),
|
self.visit_arm(arm);
|
||||||
|
}
|
||||||
// Default: descend
|
} else {
|
||||||
_ => ControlFlow::Continue(Descend::Yes),
|
let mut is_never = true;
|
||||||
};
|
for arm in arms {
|
||||||
if let ControlFlow::Continue(Descend::Yes) = self.res {
|
self.is_never = false;
|
||||||
walk_expr(self, e);
|
if let Some(guard) = arm.guard {
|
||||||
|
let in_final_expr = mem::replace(&mut self.in_final_expr, false);
|
||||||
|
self.visit_expr(guard.body());
|
||||||
|
self.in_final_expr = in_final_expr;
|
||||||
|
// The compiler doesn't consider diverging guards as causing the arm to diverge.
|
||||||
|
self.is_never = false;
|
||||||
|
}
|
||||||
|
self.visit_expr(arm.body);
|
||||||
|
is_never &= self.is_never;
|
||||||
|
}
|
||||||
|
self.is_never = is_never;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
ExprKind::Loop(b, _, _, _) => {
|
||||||
|
self.push_break_target(e.hir_id);
|
||||||
|
self.in_final_expr = false;
|
||||||
|
self.visit_block(b);
|
||||||
|
self.is_never = self.break_targets.pop().unwrap().unused;
|
||||||
|
},
|
||||||
|
ExprKind::Block(b, _) => {
|
||||||
|
if b.targeted_by_break {
|
||||||
|
self.push_break_target(b.hir_id);
|
||||||
|
self.visit_block(b);
|
||||||
|
self.is_never &= self.break_targets.pop().unwrap().unused;
|
||||||
|
} else {
|
||||||
|
self.visit_block(b);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
_ => {
|
||||||
|
self.in_final_expr = false;
|
||||||
|
walk_expr(self, e);
|
||||||
|
self.is_never |= self.cx.typeck_results().expr_ty(e).is_never();
|
||||||
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn visit_local(&mut self, local: &'tcx Local<'_>) {
|
fn visit_block(&mut self, b: &'tcx Block<'_>) {
|
||||||
// Don't visit the else block of a let/else statement as it will not make
|
let in_final_expr = mem::replace(&mut self.in_final_expr, false);
|
||||||
// the statement divergent even though the else block is divergent.
|
for s in b.stmts {
|
||||||
if let Some(init) = local.init {
|
self.visit_stmt(s);
|
||||||
self.visit_expr(init);
|
}
|
||||||
|
self.in_final_expr = in_final_expr;
|
||||||
|
if let Some(e) = b.expr {
|
||||||
|
self.visit_expr(e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Avoid unnecessary `walk_*` calls.
|
fn visit_local(&mut self, l: &'tcx Local<'_>) {
|
||||||
fn visit_ty(&mut self, _: &'tcx hir::Ty<'tcx>) {}
|
if let Some(e) = l.init {
|
||||||
fn visit_pat(&mut self, _: &'tcx Pat<'tcx>) {}
|
self.visit_expr(e);
|
||||||
fn visit_qpath(&mut self, _: &'tcx QPath<'tcx>, _: HirId, _: Span) {}
|
}
|
||||||
// Avoid monomorphising all `visit_*` functions.
|
if let Some(else_) = l.els {
|
||||||
fn visit_nested_item(&mut self, _: ItemId) {}
|
let is_never = self.is_never;
|
||||||
|
self.visit_block(else_);
|
||||||
|
self.is_never = is_never;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn visit_arm(&mut self, arm: &Arm<'tcx>) {
|
||||||
|
if let Some(guard) = arm.guard {
|
||||||
|
let in_final_expr = mem::replace(&mut self.in_final_expr, false);
|
||||||
|
self.visit_expr(guard.body());
|
||||||
|
self.in_final_expr = in_final_expr;
|
||||||
|
}
|
||||||
|
self.visit_expr(arm.body);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut v = V {
|
if cx.typeck_results().expr_ty(e).is_never() {
|
||||||
cx,
|
Some(RequiresSemi::No)
|
||||||
res: ControlFlow::Continue(Descend::Yes),
|
} else if let ExprKind::Block(b, _) = e.kind
|
||||||
};
|
&& !b.targeted_by_break
|
||||||
expr.visit(&mut v);
|
&& b.expr.is_none()
|
||||||
v.res.is_break()
|
{
|
||||||
|
// If a block diverges without a final expression then it's type is `!`.
|
||||||
|
None
|
||||||
|
} else {
|
||||||
|
let mut v = V {
|
||||||
|
cx,
|
||||||
|
break_targets: Vec::new(),
|
||||||
|
break_targets_for_result_ty: 0,
|
||||||
|
in_final_expr: true,
|
||||||
|
requires_semi: false,
|
||||||
|
is_never: false,
|
||||||
|
};
|
||||||
|
v.visit_expr(e);
|
||||||
|
v.is_never
|
||||||
|
.then_some(if v.requires_semi && matches!(e.kind, ExprKind::Block(..)) {
|
||||||
|
RequiresSemi::Yes
|
||||||
|
} else {
|
||||||
|
RequiresSemi::No
|
||||||
|
})
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,7 +5,9 @@
|
||||||
clippy::let_unit_value,
|
clippy::let_unit_value,
|
||||||
clippy::match_single_binding,
|
clippy::match_single_binding,
|
||||||
clippy::never_loop,
|
clippy::never_loop,
|
||||||
clippy::needless_if
|
clippy::needless_if,
|
||||||
|
clippy::diverging_sub_expression,
|
||||||
|
clippy::single_match
|
||||||
)]
|
)]
|
||||||
#![warn(clippy::manual_let_else)]
|
#![warn(clippy::manual_let_else)]
|
||||||
//@no-rustfix
|
//@no-rustfix
|
||||||
|
@ -24,7 +26,7 @@ fn main() {}
|
||||||
fn fire() {
|
fn fire() {
|
||||||
let v = if let Some(v_some) = g() { v_some } else { return };
|
let v = if let Some(v_some) = g() { v_some } else { return };
|
||||||
//~^ ERROR: this could be rewritten as `let...else`
|
//~^ 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() {
|
let v = if let Some(v_some) = g() {
|
||||||
//~^ ERROR: this could be rewritten as `let...else`
|
//~^ ERROR: this could be rewritten as `let...else`
|
||||||
v_some
|
v_some
|
||||||
|
@ -79,22 +81,76 @@ fn fire() {
|
||||||
panic!();
|
panic!();
|
||||||
};
|
};
|
||||||
|
|
||||||
// A match diverges if all branches diverge:
|
// The final expression will need to be turned into a statement.
|
||||||
// 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() {
|
let v = if let Some(v_some) = g() {
|
||||||
//~^ ERROR: this could be rewritten as `let...else`
|
//~^ ERROR: this could be rewritten as `let...else`
|
||||||
v_some
|
v_some
|
||||||
} else {
|
} else {
|
||||||
match () {
|
panic!();
|
||||||
_ if 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:
|
// An if's expression can cause divergence:
|
||||||
let v = if let Some(v_some) = g() { v_some } else { if panic!() {} };
|
let v = if let Some(v_some) = g() {
|
||||||
//~^ ERROR: this could be rewritten as `let...else`
|
//~^ ERROR: this could be rewritten as `let...else`
|
||||||
|
v_some
|
||||||
|
} else {
|
||||||
|
if panic!() {};
|
||||||
|
};
|
||||||
|
|
||||||
// An expression of a match can cause divergence:
|
// An expression of a match can cause divergence:
|
||||||
let v = if let Some(v_some) = g() {
|
let v = if let Some(v_some) = g() {
|
||||||
|
@ -103,7 +159,7 @@ fn fire() {
|
||||||
} else {
|
} else {
|
||||||
match panic!() {
|
match panic!() {
|
||||||
_ => {},
|
_ => {},
|
||||||
}
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
// Top level else if
|
// Top level else if
|
||||||
|
@ -342,6 +398,43 @@ fn not_fire() {
|
||||||
} else {
|
} else {
|
||||||
return;
|
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> {
|
struct S<T> {
|
||||||
|
|
|
@ -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:25:5
|
--> $DIR/manual_let_else.rs:27: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) = g() 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)]`
|
= help: to override `-D warnings` add `#[allow(clippy::manual_let_else)]`
|
||||||
|
|
||||||
error: this could be rewritten as `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 | / let v = if let Some(v_some) = g() {
|
||||||
LL | |
|
LL | |
|
||||||
|
@ -26,7 +26,7 @@ LL + };
|
||||||
|
|
|
|
||||||
|
|
||||||
error: this could be rewritten as `let...else`
|
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 | / let v = if let Some(v) = g() {
|
||||||
LL | |
|
LL | |
|
||||||
|
@ -47,25 +47,25 @@ LL + };
|
||||||
|
|
|
|
||||||
|
|
||||||
error: this could be rewritten as `let...else`
|
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 };
|
LL | let v = if let Some(v_some) = g() { v_some } else { continue };
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider writing: `let Some(v) = g() else { continue };`
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider writing: `let Some(v) = g() else { continue };`
|
||||||
|
|
||||||
error: this could be rewritten as `let...else`
|
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 };
|
LL | let v = if let Some(v_some) = g() { v_some } else { break };
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider writing: `let Some(v) = g() else { break };`
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider writing: `let Some(v) = g() else { break };`
|
||||||
|
|
||||||
error: this could be rewritten as `let...else`
|
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!() };
|
LL | let v = if let Some(v_some) = g() { v_some } else { panic!() };
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider writing: `let Some(v) = g() else { panic!() };`
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider writing: `let Some(v) = g() else { panic!() };`
|
||||||
|
|
||||||
error: this could be rewritten as `let...else`
|
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 | / let v = if let Some(v_some) = g() {
|
||||||
LL | |
|
LL | |
|
||||||
|
@ -83,7 +83,7 @@ LL + };
|
||||||
|
|
|
|
||||||
|
|
||||||
error: this could be rewritten as `let...else`
|
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 | / let v = if let Some(v_some) = g() {
|
||||||
LL | |
|
LL | |
|
||||||
|
@ -101,7 +101,7 @@ LL + };
|
||||||
|
|
|
|
||||||
|
|
||||||
error: this could be rewritten as `let...else`
|
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 | / let v = if let Some(v_some) = g() {
|
||||||
LL | |
|
LL | |
|
||||||
|
@ -127,29 +127,21 @@ LL | / let v = if let Some(v_some) = g() {
|
||||||
LL | |
|
LL | |
|
||||||
LL | | v_some
|
LL | | v_some
|
||||||
LL | | } else {
|
LL | | } else {
|
||||||
... |
|
LL | | panic!();
|
||||||
LL | | }
|
LL | | ()
|
||||||
LL | | };
|
LL | | };
|
||||||
| |______^
|
| |______^
|
||||||
|
|
|
|
||||||
help: consider writing
|
help: consider writing
|
||||||
|
|
|
|
||||||
LL ~ let Some(v) = g() else {
|
LL ~ let Some(v) = g() else {
|
||||||
LL + match () {
|
LL + panic!();
|
||||||
LL + _ if panic!() => {},
|
LL + ()
|
||||||
LL + _ => panic!(),
|
|
||||||
LL + }
|
|
||||||
LL + };
|
LL + };
|
||||||
|
|
|
|
||||||
|
|
||||||
error: this could be rewritten as `let...else`
|
error: this could be rewritten as `let...else`
|
||||||
--> $DIR/manual_let_else.rs:96:5
|
--> $DIR/manual_let_else.rs:94: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
|
|
||||||
|
|
|
|
||||||
LL | / let v = if let Some(v_some) = g() {
|
LL | / let v = if let Some(v_some) = g() {
|
||||||
LL | |
|
LL | |
|
||||||
|
@ -163,8 +155,14 @@ LL | | };
|
||||||
help: consider writing
|
help: consider writing
|
||||||
|
|
|
|
||||||
LL ~ let Some(v) = g() else {
|
LL ~ let Some(v) = g() else {
|
||||||
LL + match panic!() {
|
LL + panic!();
|
||||||
LL + _ => {},
|
LL + if true {
|
||||||
|
LL + match 0 {
|
||||||
|
LL + 0 => (),
|
||||||
|
LL + _ => (),
|
||||||
|
LL + }
|
||||||
|
LL + } else {
|
||||||
|
LL + panic!()
|
||||||
LL + }
|
LL + }
|
||||||
LL + };
|
LL + };
|
||||||
|
|
|
|
||||||
|
@ -175,6 +173,116 @@ error: this could be rewritten as `let...else`
|
||||||
LL | / let v = if let Some(v_some) = g() {
|
LL | / let v = if let Some(v_some) = g() {
|
||||||
LL | |
|
LL | |
|
||||||
LL | | v_some
|
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 | | } else if true {
|
||||||
... |
|
... |
|
||||||
LL | | panic!("diverge");
|
LL | | panic!("diverge");
|
||||||
|
@ -191,7 +299,7 @@ LL + } };
|
||||||
|
|
|
|
||||||
|
|
||||||
error: this could be rewritten as `let...else`
|
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 | / let v = if let Some(v_some) = g() {
|
||||||
LL | |
|
LL | |
|
||||||
|
@ -220,7 +328,7 @@ LL + };
|
||||||
|
|
|
|
||||||
|
|
||||||
error: this could be rewritten as `let...else`
|
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 | / let (v, w) = if let Some(v_some) = g().map(|v| (v, 42)) {
|
||||||
LL | |
|
LL | |
|
||||||
|
@ -238,7 +346,7 @@ LL + };
|
||||||
|
|
|
|
||||||
|
|
||||||
error: this could be rewritten as `let...else`
|
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 | / let (w, S { v }) = if let (Some(v_some), w_some) = (g().map(|_| S { v: 0 }), 0) {
|
||||||
LL | |
|
LL | |
|
||||||
|
@ -256,7 +364,7 @@ LL + };
|
||||||
|
|
|
|
||||||
|
|
||||||
error: this could be rewritten as `let...else`
|
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 };
|
LL | let $n = if let Some(v) = $e { v } else { return };
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider writing: `let Some($n) = g() 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)
|
= 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`
|
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 };
|
LL | let v = if let Variant::A(a, 0) = e() { a } else { return };
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider writing: `let Variant::A(v, 0) = e() else { return };`
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider writing: `let Variant::A(v, 0) = e() else { return };`
|
||||||
|
|
||||||
error: this could be rewritten as `let...else`
|
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 };
|
LL | let mut v = if let Variant::B(b) = e() { b } else { return };
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider writing: `let Variant::B(mut v) = e() else { return };`
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider writing: `let Variant::B(mut v) = e() else { return };`
|
||||||
|
|
||||||
error: this could be rewritten as `let...else`
|
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 | / let v = if let Ok(Some(Variant::B(b))) | Err(Some(Variant::A(b, _))) = nested {
|
||||||
LL | |
|
LL | |
|
||||||
|
@ -297,19 +405,19 @@ LL + };
|
||||||
|
|
|
|
||||||
|
|
||||||
error: this could be rewritten as `let...else`
|
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 };
|
LL | let v = if let Variant::A(.., a) = e() { a } else { return };
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider writing: `let Variant::A(.., v) = e() else { return };`
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider writing: `let Variant::A(.., v) = e() else { return };`
|
||||||
|
|
||||||
error: this could be rewritten as `let...else`
|
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 };
|
LL | let w = if let (Some(v), ()) = (g(), ()) { v } else { return };
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider writing: `let (Some(w), ()) = (g(), ()) else { return };`
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider writing: `let (Some(w), ()) = (g(), ()) else { return };`
|
||||||
|
|
||||||
error: this could be rewritten as `let...else`
|
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 | / let w = if let Some(S { v: x }) = Some(S { v: 0 }) {
|
||||||
LL | |
|
LL | |
|
||||||
|
@ -327,7 +435,7 @@ LL + };
|
||||||
|
|
|
|
||||||
|
|
||||||
error: this could be rewritten as `let...else`
|
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 | / let v = if let Some(S { v: x }) = Some(S { v: 0 }) {
|
||||||
LL | |
|
LL | |
|
||||||
|
@ -345,7 +453,7 @@ LL + };
|
||||||
|
|
|
|
||||||
|
|
||||||
error: this could be rewritten as `let...else`
|
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 | / let (x, S { v }, w) = if let Some(U { v, w, x }) = None::<U<S<()>>> {
|
||||||
LL | |
|
LL | |
|
||||||
|
@ -363,7 +471,7 @@ LL + };
|
||||||
|
|
|
|
||||||
|
|
||||||
error: this could be rewritten as `let...else`
|
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 | / let _ = match ff {
|
||||||
LL | |
|
LL | |
|
||||||
|
@ -372,5 +480,5 @@ LL | | _ => macro_call!(),
|
||||||
LL | | };
|
LL | | };
|
||||||
| |______^ help: consider writing: `let Some(_) = ff else { macro_call!() };`
|
| |______^ help: consider writing: `let Some(_) = ff else { macro_call!() };`
|
||||||
|
|
||||||
error: aborting due to 26 previous errors
|
error: aborting due to 30 previous errors
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue