From 5d403c0b859259499886d3ee3d4b4b4dfaab6ae2 Mon Sep 17 00:00:00 2001 From: J-ZhengLi Date: Sat, 16 Apr 2022 16:57:06 +0800 Subject: [PATCH 1/3] allow check for `match` in lint [`option_if_let_else`] and add test case for `Result` --- clippy_lints/src/option_if_let_else.rs | 170 ++++++++++++++++++------- tests/ui/option_if_let_else.fixed | 15 +++ tests/ui/option_if_let_else.rs | 21 +++ tests/ui/option_if_let_else.stderr | 22 +++- 4 files changed, 183 insertions(+), 45 deletions(-) diff --git a/clippy_lints/src/option_if_let_else.rs b/clippy_lints/src/option_if_let_else.rs index 44f153cffac5..b99966c5a5df 100644 --- a/clippy_lints/src/option_if_let_else.rs +++ b/clippy_lints/src/option_if_let_else.rs @@ -7,15 +7,18 @@ use clippy_utils::{ }; use if_chain::if_chain; use rustc_errors::Applicability; -use rustc_hir::LangItem::OptionSome; -use rustc_hir::{def::Res, BindingAnnotation, Expr, ExprKind, Mutability, PatKind, Path, QPath, UnOp}; +use rustc_hir::LangItem::{OptionNone, OptionSome}; +use rustc_hir::{ + def::Res, Arm, BindingAnnotation, Expr, ExprKind, MatchSource, Mutability, Pat, PatKind, Path, QPath, UnOp, +}; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::{declare_lint_pass, declare_tool_lint}; use rustc_span::sym; declare_clippy_lint! { /// ### What it does - /// Lints usage of `if let Some(v) = ... { y } else { x }` which is more + /// Lints usage of `if let Some(v) = ... { y } else { x }` and + /// `match .. { Some(v) => y, None/_ => x }` which are more /// idiomatically done with `Option::map_or` (if the else bit is a pure /// expression) or `Option::map_or_else` (if the else bit is an impure /// expression). @@ -39,6 +42,10 @@ declare_clippy_lint! { /// } else { /// 5 /// }; + /// let _ = match optional { + /// Some(val) => val + 1, + /// None => 5 + /// }; /// let _ = if let Some(foo) = optional { /// foo /// } else { @@ -53,6 +60,7 @@ declare_clippy_lint! { /// # let optional: Option = Some(0); /// # fn do_complicated_function() -> u32 { 5 }; /// let _ = optional.map_or(5, |foo| foo); + /// let _ = optional.map_or(5, |val| val + 1); /// let _ = optional.map_or_else(||{ /// let y = do_complicated_function(); /// y*y @@ -76,9 +84,21 @@ fn is_result_ok(cx: &LateContext<'_>, expr: &'_ Expr<'_>) -> bool { } } -/// A struct containing information about occurrences of the -/// `if let Some(..) = .. else` construct that this lint detects. -struct OptionIfLetElseOccurrence { +/// A struct containing information about occurrences of construct that this lint detects +/// +/// Such as: +/// +/// ```ignore +/// if let Some(..) = {..} else {..} +/// ``` +/// or +/// ```ignore +/// match x { +/// Some(..) => {..}, +/// None/_ => {..} +/// } +/// ``` +struct OptionOccurence { option: String, method_sugg: String, some_expr: String, @@ -99,43 +119,39 @@ fn format_option_in_sugg(cx: &LateContext<'_>, cond_expr: &Expr<'_>, as_ref: boo ) } -/// If this expression is the option if let/else construct we're detecting, then -/// this function returns an `OptionIfLetElseOccurrence` struct with details if -/// this construct is found, or None if this construct is not found. -fn detect_option_if_let_else<'tcx>(cx: &LateContext<'tcx>, expr: &Expr<'tcx>) -> Option { +fn try_get_option_occurence<'tcx>( + cx: &LateContext<'tcx>, + pat: &Pat<'tcx>, + expr: &Expr<'_>, + if_then: &'tcx Expr<'_>, + if_else: &'tcx Expr<'_>, +) -> Option { + let cond_expr = match expr.kind { + ExprKind::Unary(UnOp::Deref, inner_expr) | ExprKind::AddrOf(_, _, inner_expr) => inner_expr, + _ => expr, + }; if_chain! { - if !expr.span.from_expansion(); // Don't lint macros, because it behaves weirdly - if !in_constant(cx, expr.hir_id); - if let Some(higher::IfLet { let_pat, let_expr, if_then, if_else: Some(if_else) }) - = higher::IfLet::hir(cx, expr); - if !is_else_clause(cx.tcx, expr); - if !is_result_ok(cx, let_expr); // Don't lint on Result::ok because a different lint does it already - if let PatKind::TupleStruct(struct_qpath, [inner_pat], _) = &let_pat.kind; - if is_lang_ctor(cx, struct_qpath, OptionSome); - if let PatKind::Binding(bind_annotation, _, id, None) = &inner_pat.kind; + if !is_result_ok(cx, cond_expr); // Don't lint on Result::ok because a different lint does it already + let inner_pat = try_get_inner_pat(cx, pat)?; + if let PatKind::Binding(bind_annotation, _, id, None) = inner_pat.kind; if let Some(some_captures) = can_move_expr_to_closure(cx, if_then); if let Some(none_captures) = can_move_expr_to_closure(cx, if_else); if some_captures .iter() .filter_map(|(id, &c)| none_captures.get(id).map(|&c2| (c, c2))) .all(|(x, y)| x.is_imm_ref() && y.is_imm_ref()); - then { - let capture_mut = if bind_annotation == &BindingAnnotation::Mutable { "mut " } else { "" }; + let capture_mut = if bind_annotation == BindingAnnotation::Mutable { "mut " } else { "" }; let some_body = peel_blocks(if_then); let none_body = peel_blocks(if_else); let method_sugg = if eager_or_lazy::switch_to_eager_eval(cx, none_body) { "map_or" } else { "map_or_else" }; let capture_name = id.name.to_ident_string(); - let (as_ref, as_mut) = match &let_expr.kind { + let (as_ref, as_mut) = match &expr.kind { ExprKind::AddrOf(_, Mutability::Not, _) => (true, false), ExprKind::AddrOf(_, Mutability::Mut, _) => (false, true), - _ => (bind_annotation == &BindingAnnotation::Ref, bind_annotation == &BindingAnnotation::RefMut), - }; - let cond_expr = match let_expr.kind { - // Pointer dereferencing happens automatically, so we can omit it in the suggestion - ExprKind::Unary(UnOp::Deref, expr) | ExprKind::AddrOf(_, _, expr) => expr, - _ => let_expr, + _ => (bind_annotation == BindingAnnotation::Ref, bind_annotation == BindingAnnotation::RefMut), }; + // Check if captures the closure will need conflict with borrows made in the scrutinee. // TODO: check all the references made in the scrutinee expression. This will require interacting // with the borrow checker. Currently only `[.]*` is checked for. @@ -154,33 +170,99 @@ fn detect_option_if_let_else<'tcx>(cx: &LateContext<'tcx>, expr: &Expr<'tcx>) -> } } } - Some(OptionIfLetElseOccurrence { + + return Some(OptionOccurence { option: format_option_in_sugg(cx, cond_expr, as_ref, as_mut), method_sugg: method_sugg.to_string(), some_expr: format!("|{}{}| {}", capture_mut, capture_name, Sugg::hir_with_macro_callsite(cx, some_body, "..")), none_expr: format!("{}{}", if method_sugg == "map_or" { "" } else { "|| " }, Sugg::hir_with_macro_callsite(cx, none_body, "..")), - }) + }); + } + } + + None +} + +fn try_get_inner_pat<'tcx>(cx: &LateContext<'tcx>, pat: &Pat<'tcx>) -> Option<&'tcx Pat<'tcx>> { + if let PatKind::TupleStruct(ref qpath, [inner_pat], ..) = pat.kind { + if is_lang_ctor(cx, qpath, OptionSome) { + return Some(inner_pat); + } + } + None +} + +/// If this expression is the option if let/else construct we're detecting, then +/// this function returns an `OptionOccurence` struct with details if +/// this construct is found, or None if this construct is not found. +fn detect_option_if_let_else<'tcx>(cx: &LateContext<'tcx>, expr: &Expr<'tcx>) -> Option { + if let Some(higher::IfLet { + let_pat, + let_expr, + if_then, + if_else: Some(if_else), + }) = higher::IfLet::hir(cx, expr) + { + if !is_else_clause(cx.tcx, expr) { + return try_get_option_occurence(cx, let_pat, let_expr, if_then, if_else); + } + } + None +} + +fn detect_option_match<'tcx>(cx: &LateContext<'tcx>, expr: &Expr<'tcx>) -> Option { + if let ExprKind::Match(ex, arms, MatchSource::Normal) = expr.kind { + if let Some((let_pat, if_then, if_else)) = try_convert_match(cx, arms) { + return try_get_option_occurence(cx, let_pat, ex, if_then, if_else); + } + } + None +} + +fn try_convert_match<'tcx>( + cx: &LateContext<'tcx>, + arms: &[Arm<'tcx>], +) -> Option<(&'tcx Pat<'tcx>, &'tcx Expr<'tcx>, &'tcx Expr<'tcx>)> { + if arms.len() == 2 { + return if is_none_arm(cx, &arms[1]) { + Some((arms[0].pat, arms[0].body, arms[1].body)) + } else if is_none_arm(cx, &arms[0]) { + Some((arms[1].pat, arms[1].body, arms[0].body)) } else { None - } + }; + } + None +} + +fn is_none_arm(cx: &LateContext<'_>, arm: &Arm<'_>) -> bool { + match arm.pat.kind { + PatKind::Path(ref qpath) => is_lang_ctor(cx, qpath, OptionNone), + PatKind::Wild => true, + _ => false, } } impl<'tcx> LateLintPass<'tcx> for OptionIfLetElse { fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &Expr<'tcx>) { - if let Some(detection) = detect_option_if_let_else(cx, expr) { - span_lint_and_sugg( - cx, - OPTION_IF_LET_ELSE, - expr.span, - format!("use Option::{} instead of an if let/else", detection.method_sugg).as_str(), - "try", - format!( - "{}.{}({}, {})", - detection.option, detection.method_sugg, detection.none_expr, detection.some_expr, - ), - Applicability::MaybeIncorrect, - ); + // Don't lint macros, because it behaves weirdly + // and don't lint constant as well + if !expr.span.from_expansion() && !in_constant(cx, expr.hir_id) { + let detection = detect_option_if_let_else(cx, expr).or_else(|| detect_option_match(cx, expr)); + if let Some(det) = detection { + span_lint_and_sugg( + cx, + OPTION_IF_LET_ELSE, + expr.span, + format!("use Option::{} instead of an if let/else", det.method_sugg).as_str(), + "try", + format!( + "{}.{}({}, {})", + det.option, det.method_sugg, det.none_expr, det.some_expr + ), + Applicability::MaybeIncorrect, + ); + } } } } diff --git a/tests/ui/option_if_let_else.fixed b/tests/ui/option_if_let_else.fixed index b6d5e106f057..79610a0ea349 100644 --- a/tests/ui/option_if_let_else.fixed +++ b/tests/ui/option_if_let_else.fixed @@ -179,4 +179,19 @@ fn main() { let _ = pattern_to_vec("hello world"); let _ = complex_subpat(); + + // issue #8492 + let _ = s.map_or(1, |string| string.len()); + let _ = Some(10).map_or(5, |a| a + 1); + + let res: Result = Ok(5); + let _ = match res { + Ok(a) => a + 1, + _ => 1, + }; + let _ = match res { + Err(_) => 1, + Ok(a) => a + 1, + }; + let _ = if let Ok(a) = res { a + 1 } else { 5 }; } diff --git a/tests/ui/option_if_let_else.rs b/tests/ui/option_if_let_else.rs index 35bae1593435..9eeaea12d3bc 100644 --- a/tests/ui/option_if_let_else.rs +++ b/tests/ui/option_if_let_else.rs @@ -208,4 +208,25 @@ fn main() { let _ = pattern_to_vec("hello world"); let _ = complex_subpat(); + + // issue #8492 + let _ = match s { + Some(string) => string.len(), + None => 1, + }; + let _ = match Some(10) { + Some(a) => a + 1, + None => 5, + }; + + let res: Result = Ok(5); + let _ = match res { + Ok(a) => a + 1, + _ => 1, + }; + let _ = match res { + Err(_) => 1, + Ok(a) => a + 1, + }; + let _ = if let Ok(a) = res { a + 1 } else { 5 }; } diff --git a/tests/ui/option_if_let_else.stderr b/tests/ui/option_if_let_else.stderr index daba606004e1..4086b45b7c0c 100644 --- a/tests/ui/option_if_let_else.stderr +++ b/tests/ui/option_if_let_else.stderr @@ -206,5 +206,25 @@ LL + s.len() + x LL ~ }); | -error: aborting due to 15 previous errors +error: use Option::map_or instead of an if let/else + --> $DIR/option_if_let_else.rs:212:13 + | +LL | let _ = match s { + | _____________^ +LL | | Some(string) => string.len(), +LL | | None => 1, +LL | | }; + | |_____^ help: try: `s.map_or(1, |string| string.len())` + +error: use Option::map_or instead of an if let/else + --> $DIR/option_if_let_else.rs:216:13 + | +LL | let _ = match Some(10) { + | _____________^ +LL | | Some(a) => a + 1, +LL | | None => 5, +LL | | }; + | |_____^ help: try: `Some(10).map_or(5, |a| a + 1)` + +error: aborting due to 17 previous errors From ffe71251638d8f1c19de61905ff56a423132a692 Mon Sep 17 00:00:00 2001 From: J-ZhengLi Date: Sat, 16 Apr 2022 17:40:28 +0800 Subject: [PATCH 2/3] and check for `Result` --- clippy_lints/src/option_if_let_else.rs | 28 +++++++++----------------- tests/ui/option_if_let_else.fixed | 12 +++-------- tests/ui/option_if_let_else.stderr | 28 +++++++++++++++++++++++++- 3 files changed, 39 insertions(+), 29 deletions(-) diff --git a/clippy_lints/src/option_if_let_else.rs b/clippy_lints/src/option_if_let_else.rs index b99966c5a5df..93388e785913 100644 --- a/clippy_lints/src/option_if_let_else.rs +++ b/clippy_lints/src/option_if_let_else.rs @@ -1,19 +1,17 @@ use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::sugg::Sugg; -use clippy_utils::ty::is_type_diagnostic_item; use clippy_utils::{ can_move_expr_to_closure, eager_or_lazy, higher, in_constant, is_else_clause, is_lang_ctor, peel_blocks, peel_hir_expr_while, CaptureKind, }; use if_chain::if_chain; use rustc_errors::Applicability; -use rustc_hir::LangItem::{OptionNone, OptionSome}; +use rustc_hir::LangItem::{OptionNone, OptionSome, ResultErr, ResultOk}; use rustc_hir::{ def::Res, Arm, BindingAnnotation, Expr, ExprKind, MatchSource, Mutability, Pat, PatKind, Path, QPath, UnOp, }; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::{declare_lint_pass, declare_tool_lint}; -use rustc_span::sym; declare_clippy_lint! { /// ### What it does @@ -74,16 +72,6 @@ declare_clippy_lint! { declare_lint_pass!(OptionIfLetElse => [OPTION_IF_LET_ELSE]); -/// Returns true iff the given expression is the result of calling `Result::ok` -fn is_result_ok(cx: &LateContext<'_>, expr: &'_ Expr<'_>) -> bool { - if let ExprKind::MethodCall(path, &[ref receiver], _) = &expr.kind { - path.ident.name.as_str() == "ok" - && is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(receiver), sym::Result) - } else { - false - } -} - /// A struct containing information about occurrences of construct that this lint detects /// /// Such as: @@ -130,9 +118,8 @@ fn try_get_option_occurence<'tcx>( ExprKind::Unary(UnOp::Deref, inner_expr) | ExprKind::AddrOf(_, _, inner_expr) => inner_expr, _ => expr, }; + let inner_pat = try_get_inner_pat(cx, pat)?; if_chain! { - if !is_result_ok(cx, cond_expr); // Don't lint on Result::ok because a different lint does it already - let inner_pat = try_get_inner_pat(cx, pat)?; if let PatKind::Binding(bind_annotation, _, id, None) = inner_pat.kind; if let Some(some_captures) = can_move_expr_to_closure(cx, if_then); if let Some(none_captures) = can_move_expr_to_closure(cx, if_else); @@ -185,7 +172,7 @@ fn try_get_option_occurence<'tcx>( fn try_get_inner_pat<'tcx>(cx: &LateContext<'tcx>, pat: &Pat<'tcx>) -> Option<&'tcx Pat<'tcx>> { if let PatKind::TupleStruct(ref qpath, [inner_pat], ..) = pat.kind { - if is_lang_ctor(cx, qpath, OptionSome) { + if is_lang_ctor(cx, qpath, OptionSome) || is_lang_ctor(cx, qpath, ResultOk) { return Some(inner_pat); } } @@ -224,9 +211,9 @@ fn try_convert_match<'tcx>( arms: &[Arm<'tcx>], ) -> Option<(&'tcx Pat<'tcx>, &'tcx Expr<'tcx>, &'tcx Expr<'tcx>)> { if arms.len() == 2 { - return if is_none_arm(cx, &arms[1]) { + return if is_none_or_err_arm(cx, &arms[1]) { Some((arms[0].pat, arms[0].body, arms[1].body)) - } else if is_none_arm(cx, &arms[0]) { + } else if is_none_or_err_arm(cx, &arms[0]) { Some((arms[1].pat, arms[1].body, arms[0].body)) } else { None @@ -235,9 +222,12 @@ fn try_convert_match<'tcx>( None } -fn is_none_arm(cx: &LateContext<'_>, arm: &Arm<'_>) -> bool { +fn is_none_or_err_arm(cx: &LateContext<'_>, arm: &Arm<'_>) -> bool { match arm.pat.kind { PatKind::Path(ref qpath) => is_lang_ctor(cx, qpath, OptionNone), + PatKind::TupleStruct(ref qpath, [first_pat], _) => { + is_lang_ctor(cx, qpath, ResultErr) && matches!(first_pat.kind, PatKind::Wild) + }, PatKind::Wild => true, _ => false, } diff --git a/tests/ui/option_if_let_else.fixed b/tests/ui/option_if_let_else.fixed index 79610a0ea349..f15ac551bb3c 100644 --- a/tests/ui/option_if_let_else.fixed +++ b/tests/ui/option_if_let_else.fixed @@ -185,13 +185,7 @@ fn main() { let _ = Some(10).map_or(5, |a| a + 1); let res: Result = Ok(5); - let _ = match res { - Ok(a) => a + 1, - _ => 1, - }; - let _ = match res { - Err(_) => 1, - Ok(a) => a + 1, - }; - let _ = if let Ok(a) = res { a + 1 } else { 5 }; + let _ = res.map_or(1, |a| a + 1); + let _ = res.map_or(1, |a| a + 1); + let _ = res.map_or(5, |a| a + 1); } diff --git a/tests/ui/option_if_let_else.stderr b/tests/ui/option_if_let_else.stderr index 4086b45b7c0c..1bf513e08724 100644 --- a/tests/ui/option_if_let_else.stderr +++ b/tests/ui/option_if_let_else.stderr @@ -226,5 +226,31 @@ LL | | None => 5, LL | | }; | |_____^ help: try: `Some(10).map_or(5, |a| a + 1)` -error: aborting due to 17 previous errors +error: use Option::map_or instead of an if let/else + --> $DIR/option_if_let_else.rs:222:13 + | +LL | let _ = match res { + | _____________^ +LL | | Ok(a) => a + 1, +LL | | _ => 1, +LL | | }; + | |_____^ help: try: `res.map_or(1, |a| a + 1)` + +error: use Option::map_or instead of an if let/else + --> $DIR/option_if_let_else.rs:226:13 + | +LL | let _ = match res { + | _____________^ +LL | | Err(_) => 1, +LL | | Ok(a) => a + 1, +LL | | }; + | |_____^ help: try: `res.map_or(1, |a| a + 1)` + +error: use Option::map_or instead of an if let/else + --> $DIR/option_if_let_else.rs:230:13 + | +LL | let _ = if let Ok(a) = res { a + 1 } else { 5 }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `res.map_or(5, |a| a + 1)` + +error: aborting due to 20 previous errors From 1f75845a8f3318fba32aeb2f443f37aabdcc86f0 Mon Sep 17 00:00:00 2001 From: Philipp Krones Date: Sun, 21 Aug 2022 10:29:07 +0200 Subject: [PATCH 3/3] Reduce indentation and add comment about lint name --- clippy_lints/src/option_if_let_else.rs | 39 ++++++++++++++------------ tests/ui/option_if_let_else.stderr | 10 +++---- 2 files changed, 26 insertions(+), 23 deletions(-) diff --git a/clippy_lints/src/option_if_let_else.rs b/clippy_lints/src/option_if_let_else.rs index 93388e785913..9602d0d1d2ea 100644 --- a/clippy_lints/src/option_if_let_else.rs +++ b/clippy_lints/src/option_if_let_else.rs @@ -64,6 +64,8 @@ declare_clippy_lint! { /// y*y /// }, |foo| foo); /// ``` + // FIXME: Before moving this lint out of nursery, the lint name needs to be updated. It now also + // covers matches and `Result`. #[clippy::version = "1.47.0"] pub OPTION_IF_LET_ELSE, nursery, @@ -235,24 +237,25 @@ fn is_none_or_err_arm(cx: &LateContext<'_>, arm: &Arm<'_>) -> bool { impl<'tcx> LateLintPass<'tcx> for OptionIfLetElse { fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &Expr<'tcx>) { - // Don't lint macros, because it behaves weirdly - // and don't lint constant as well - if !expr.span.from_expansion() && !in_constant(cx, expr.hir_id) { - let detection = detect_option_if_let_else(cx, expr).or_else(|| detect_option_match(cx, expr)); - if let Some(det) = detection { - span_lint_and_sugg( - cx, - OPTION_IF_LET_ELSE, - expr.span, - format!("use Option::{} instead of an if let/else", det.method_sugg).as_str(), - "try", - format!( - "{}.{}({}, {})", - det.option, det.method_sugg, det.none_expr, det.some_expr - ), - Applicability::MaybeIncorrect, - ); - } + // Don't lint macros and constants + if expr.span.from_expansion() || in_constant(cx, expr.hir_id) { + return; + } + + let detection = detect_option_if_let_else(cx, expr).or_else(|| detect_option_match(cx, expr)); + if let Some(det) = detection { + span_lint_and_sugg( + cx, + OPTION_IF_LET_ELSE, + expr.span, + format!("use Option::{} instead of an if let/else", det.method_sugg).as_str(), + "try", + format!( + "{}.{}({}, {})", + det.option, det.method_sugg, det.none_expr, det.some_expr + ), + Applicability::MaybeIncorrect, + ); } } } diff --git a/tests/ui/option_if_let_else.stderr b/tests/ui/option_if_let_else.stderr index 1bf513e08724..a5dbf6e1f221 100644 --- a/tests/ui/option_if_let_else.stderr +++ b/tests/ui/option_if_let_else.stderr @@ -207,7 +207,7 @@ LL ~ }); | error: use Option::map_or instead of an if let/else - --> $DIR/option_if_let_else.rs:212:13 + --> $DIR/option_if_let_else.rs:213:13 | LL | let _ = match s { | _____________^ @@ -217,7 +217,7 @@ LL | | }; | |_____^ help: try: `s.map_or(1, |string| string.len())` error: use Option::map_or instead of an if let/else - --> $DIR/option_if_let_else.rs:216:13 + --> $DIR/option_if_let_else.rs:217:13 | LL | let _ = match Some(10) { | _____________^ @@ -227,7 +227,7 @@ LL | | }; | |_____^ help: try: `Some(10).map_or(5, |a| a + 1)` error: use Option::map_or instead of an if let/else - --> $DIR/option_if_let_else.rs:222:13 + --> $DIR/option_if_let_else.rs:223:13 | LL | let _ = match res { | _____________^ @@ -237,7 +237,7 @@ LL | | }; | |_____^ help: try: `res.map_or(1, |a| a + 1)` error: use Option::map_or instead of an if let/else - --> $DIR/option_if_let_else.rs:226:13 + --> $DIR/option_if_let_else.rs:227:13 | LL | let _ = match res { | _____________^ @@ -247,7 +247,7 @@ LL | | }; | |_____^ help: try: `res.map_or(1, |a| a + 1)` error: use Option::map_or instead of an if let/else - --> $DIR/option_if_let_else.rs:230:13 + --> $DIR/option_if_let_else.rs:231:13 | LL | let _ = if let Ok(a) = res { a + 1 } else { 5 }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `res.map_or(5, |a| a + 1)`