From edfd2b99097c6e0eb44790ff7c28b8cadf39cfeb Mon Sep 17 00:00:00 2001 From: hkalbasi <hamidrezakalbasi@protonmail.com> Date: Wed, 6 Oct 2021 16:35:31 +0330 Subject: [PATCH] upgrade equatable_if_let to style --- CHANGELOG.md | 1 + clippy_lints/src/casts/cast_lossless.rs | 6 +- .../src/casts/cast_possible_truncation.rs | 4 +- clippy_lints/src/equatable_if_let.rs | 229 ++++++++++++++---- clippy_lints/src/lib.register_all.rs | 1 + clippy_lints/src/lib.register_lints.rs | 1 + clippy_lints/src/lib.register_nursery.rs | 1 - clippy_lints/src/lib.register_pedantic.rs | 1 + clippy_lints/src/lib.register_style.rs | 1 + clippy_lints/src/manual_async_fn.rs | 2 +- clippy_lints/src/manual_map.rs | 2 +- clippy_lints/src/map_clone.rs | 2 +- .../src/methods/inefficient_to_string.rs | 2 +- clippy_lints/src/methods/mod.rs | 2 +- clippy_lints/src/methods/or_fun_call.rs | 4 +- clippy_lints/src/multiple_crate_versions.rs | 10 +- clippy_lints/src/needless_borrow.rs | 2 +- clippy_lints/src/redundant_clone.rs | 4 +- clippy_lints/src/same_name_method.rs | 4 +- .../src/transmute/transmute_ref_to_ref.rs | 2 +- clippy_lints/src/unused_async.rs | 2 +- clippy_lints/src/utils/internal_lints.rs | 2 +- clippy_lints/src/write.rs | 6 +- clippy_utils/src/ast_utils.rs | 12 +- clippy_utils/src/higher.rs | 36 +++ tests/lint_message_convention.rs | 2 +- tests/ui-internal/if_chain_style.rs | 2 +- tests/ui/equatable_if_let.fixed | 69 +++++- tests/ui/equatable_if_let.rs | 71 +++++- tests/ui/equatable_if_let.stderr | 117 +++++++-- 30 files changed, 487 insertions(+), 113 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 7fdb300c9774..b0b21343dc75 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2696,6 +2696,7 @@ Released 2018-09-13 [`enum_variant_names`]: https://rust-lang.github.io/rust-clippy/master/index.html#enum_variant_names [`eq_op`]: https://rust-lang.github.io/rust-clippy/master/index.html#eq_op [`equatable_if_let`]: https://rust-lang.github.io/rust-clippy/master/index.html#equatable_if_let +[`equatable_matches`]: https://rust-lang.github.io/rust-clippy/master/index.html#equatable_matches [`erasing_op`]: https://rust-lang.github.io/rust-clippy/master/index.html#erasing_op [`eval_order_dependence`]: https://rust-lang.github.io/rust-clippy/master/index.html#eval_order_dependence [`excessive_precision`]: https://rust-lang.github.io/rust-clippy/master/index.html#excessive_precision diff --git a/clippy_lints/src/casts/cast_lossless.rs b/clippy_lints/src/casts/cast_lossless.rs index 869deecfbd53..7b3322741fa7 100644 --- a/clippy_lints/src/casts/cast_lossless.rs +++ b/clippy_lints/src/casts/cast_lossless.rs @@ -65,7 +65,7 @@ fn should_lint(cx: &LateContext<'_>, expr: &Expr<'_>, cast_from: Ty<'_>, cast_to (true, false) => { let from_nbits = utils::int_ty_to_nbits(cast_from, cx.tcx); - let to_nbits = if let ty::Float(FloatTy::F32) = cast_to.kind() { + let to_nbits = if cast_to.kind() == &ty::Float(FloatTy::F32) { 32 } else { 64 @@ -73,9 +73,7 @@ fn should_lint(cx: &LateContext<'_>, expr: &Expr<'_>, cast_from: Ty<'_>, cast_to from_nbits < to_nbits }, - (_, _) => { - matches!(cast_from.kind(), ty::Float(FloatTy::F32)) && matches!(cast_to.kind(), ty::Float(FloatTy::F64)) - }, + (_, _) => cast_from.kind() == &ty::Float(FloatTy::F32) && cast_to.kind() == &ty::Float(FloatTy::F64), } } diff --git a/clippy_lints/src/casts/cast_possible_truncation.rs b/clippy_lints/src/casts/cast_possible_truncation.rs index 833ad122e0d4..b24f206ab0c8 100644 --- a/clippy_lints/src/casts/cast_possible_truncation.rs +++ b/clippy_lints/src/casts/cast_possible_truncation.rs @@ -40,9 +40,7 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, cast_from: Ty<'_>, ca }, (_, _) => { - if matches!(cast_from.kind(), &ty::Float(FloatTy::F64)) - && matches!(cast_to.kind(), &ty::Float(FloatTy::F32)) - { + if cast_from.kind() == &ty::Float(FloatTy::F64) && cast_to.kind() == &ty::Float(FloatTy::F32) { "casting `f64` to `f32` may truncate the value".to_string() } else { return; diff --git a/clippy_lints/src/equatable_if_let.rs b/clippy_lints/src/equatable_if_let.rs index 0c6ba91c9430..0cbaee9cc83e 100644 --- a/clippy_lints/src/equatable_if_let.rs +++ b/clippy_lints/src/equatable_if_let.rs @@ -1,16 +1,21 @@ -use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::source::snippet_with_applicability; use clippy_utils::ty::implements_trait; +use clippy_utils::{diagnostics::span_lint_and_sugg, higher::MatchesExpn}; use if_chain::if_chain; use rustc_errors::Applicability; -use rustc_hir::{Expr, ExprKind, Pat, PatKind}; -use rustc_lint::{LateContext, LateLintPass}; -use rustc_middle::ty::Ty; +use rustc_hir::{ + def::{DefKind, Res}, + Arm, Expr, ExprKind, Pat, PatKind, QPath, +}; +use rustc_lint::{LateContext, LateLintPass, Lint}; +use rustc_middle::ty::{Adt, Ty}; use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_span::Span; declare_clippy_lint! { /// ### What it does - /// Checks for pattern matchings that can be expressed using equality. + /// Checks for `if let <pat> = <expr>` (and `while let` and similars) that can be expressed + /// using `if <expr> == <pat>`. /// /// ### Why is this bad? /// @@ -33,68 +38,192 @@ declare_clippy_lint! { /// } /// ``` pub EQUATABLE_IF_LET, - nursery, - "using pattern matching instead of equality" + style, + "using if let instead of if with a equality condition" } -declare_lint_pass!(PatternEquality => [EQUATABLE_IF_LET]); +declare_clippy_lint! { + /// ### What it does + /// Checks for `matches!(<expr>, <pat>)` that can be expressed + /// using `<expr> == <pat>`. + /// + /// ### Why is this bad? + /// + /// It is less concise and less clear. + /// + /// ### Example + /// ```rust,ignore + /// let condition = matches!(x, Some(2)); + /// ``` + /// Should be written + /// ```rust,ignore + /// let condition = x == Some(2); + /// ``` + pub EQUATABLE_MATCHES, + pedantic, + "using `matches!` instead of equality" +} + +declare_lint_pass!(PatternEquality => [EQUATABLE_IF_LET, EQUATABLE_MATCHES]); -/// detects if pattern matches just one thing -fn unary_pattern(pat: &Pat<'_>) -> bool { - fn array_rec(pats: &[Pat<'_>]) -> bool { - pats.iter().all(unary_pattern) +fn equatable_pattern(cx: &LateContext<'_>, pat: &Pat<'_>) -> bool { + fn array_rec(cx: &LateContext<'_>, pats: &[Pat<'_>]) -> bool { + pats.iter().all(|x| equatable_pattern(cx, x)) } - match &pat.kind { - PatKind::Slice(_, _, _) | PatKind::Range(_, _, _) | PatKind::Binding(..) | PatKind::Wild | PatKind::Or(_) => { + fn is_derived(cx: &LateContext<'_>, pat: &Pat<'_>) -> bool { + let ty = cx.typeck_results().pat_ty(pat); + if let Some(def_id) = cx.tcx.lang_items().structural_peq_trait() { + implements_trait(cx, ty, def_id, &[ty.into()]) + } else { false + } + } + match &pat.kind { + PatKind::Slice(a, None, []) => array_rec(cx, a), + PatKind::Struct(_, a, etc) => !etc && is_derived(cx, pat) && a.iter().all(|x| equatable_pattern(cx, x.pat)), + PatKind::Tuple(a, etc) => !etc.is_some() && array_rec(cx, a), + PatKind::TupleStruct(_, a, etc) => !etc.is_some() && is_derived(cx, pat) && array_rec(cx, a), + PatKind::Ref(x, _) | PatKind::Box(x) => equatable_pattern(cx, x), + PatKind::Path(QPath::Resolved(_, b)) => match b.res { + Res::Def(DefKind::Const, _) => true, + _ => is_derived(cx, pat), }, - PatKind::Struct(_, a, etc) => !etc && a.iter().all(|x| unary_pattern(x.pat)), - PatKind::Tuple(a, etc) | PatKind::TupleStruct(_, a, etc) => !etc.is_some() && array_rec(a), - PatKind::Ref(x, _) | PatKind::Box(x) => unary_pattern(x), - PatKind::Path(_) | PatKind::Lit(_) => true, + PatKind::Path(_) => is_derived(cx, pat), + PatKind::Lit(_) => true, + PatKind::Slice(..) | PatKind::Range(..) | PatKind::Binding(..) | PatKind::Wild | PatKind::Or(_) => false, } } -fn is_structural_partial_eq(cx: &LateContext<'tcx>, ty: Ty<'tcx>, other: Ty<'tcx>) -> bool { +fn is_partial_eq(cx: &LateContext<'tcx>, t1: Ty<'tcx>, t2: Ty<'tcx>) -> bool { if let Some(def_id) = cx.tcx.lang_items().eq_trait() { - implements_trait(cx, ty, def_id, &[other.into()]) + implements_trait(cx, t1, def_id, &[t2.into()]) } else { false } } +fn pat_to_string(cx: &LateContext<'tcx>, app: &mut Applicability, pat: &Pat<'_>, goal: Ty<'_>) -> Option<String> { + fn inner(cx: &LateContext<'tcx>, app: &mut Applicability, pat: &Pat<'_>, goal: Ty<'_>, r: &mut String) -> bool { + let ty = cx.typeck_results().pat_ty(pat); + if ty == goal { + match &pat.kind { + PatKind::TupleStruct(q, ..) | PatKind::Struct(q, ..) => { + let (adt_def, generic_args) = if let Adt(x, y) = ty.kind() { + (x, y) + } else { + return false; // shouldn't happen + }; + let path = if let QPath::Resolved(.., p) = q { + p + } else { + return false; // give up + }; + let var = adt_def.variant_of_res(path.res); + match &pat.kind { + PatKind::TupleStruct(_, params, _) => { + *r += &*snippet_with_applicability(cx, path.span, "..", app); + *r += "("; + for (i, (p, f)) in params.iter().zip(var.fields.iter()).enumerate() { + if i != 0 { + *r += ", "; + } + inner(cx, app, p, f.ty(cx.tcx, generic_args), r); + } + *r += ")"; + }, + PatKind::Struct(_, fields, _) => { + *r += &*snippet_with_applicability(cx, path.span, "..", app); + *r += " { "; + for (i, p) in fields.iter().enumerate() { + if i != 0 { + *r += ", "; + } + *r += &*snippet_with_applicability(cx, p.ident.span, "..", app); + *r += ": "; + if let Some(x) = var.fields.iter().find(|f| f.ident == p.ident) { + inner(cx, app, p.pat, x.ty(cx.tcx, generic_args), r); + } else { + return false; // won't happen + } + } + *r += " }"; + }, + _ => return false, // won't happen + } + }, + _ => { + *r += &*snippet_with_applicability(cx, pat.span, "..", app); + }, + } + return true; + } + if goal.is_ref() { + if let Some(tam) = goal.builtin_deref(true) { + *r += "&"; + return inner(cx, app, pat, tam.ty, r); + } + } + false + } + let mut r = "".to_string(); + if let PatKind::Struct(..) = pat.kind { + r += "("; + } + let success = inner(cx, app, pat, goal, &mut r); + if let PatKind::Struct(..) = pat.kind { + r += ")"; + } + if !success { + return None; + } + Some(r) +} + +fn emit_lint(cx: &LateContext<'tcx>, pat: &Pat<'_>, exp: &Expr<'_>, span: Span, lint: &'static Lint) { + if_chain! { + if equatable_pattern(cx, pat); + let exp_ty = cx.typeck_results().expr_ty(exp); + if is_partial_eq(cx, exp_ty, exp_ty); + let mut app = Applicability::MachineApplicable; + if let Some(pat_str) = pat_to_string(cx, &mut app, pat, exp_ty); + then { + /*let pat_str = match pat.kind { + PatKind::Struct(..) => format!( + "({})", + snippet_with_applicability(cx, pat.span, "..", &mut applicability), + ), + _ => snippet_with_applicability(cx, pat.span, "..", &mut applicability).to_string(), + };*/ + let exp_str = snippet_with_applicability(cx, exp.span, "..", &mut app); + span_lint_and_sugg( + cx, + lint, + span, + "this pattern matching can be expressed using equality", + "try", + format!( + "{} == {}", + exp_str, + pat_str, + ), + app, + ); + } + } +} + impl<'tcx> LateLintPass<'tcx> for PatternEquality { fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) { - if_chain! { - if let ExprKind::Let(pat, exp, _) = expr.kind; - if unary_pattern(pat); - let exp_ty = cx.typeck_results().expr_ty(exp); - let pat_ty = cx.typeck_results().pat_ty(pat); - if is_structural_partial_eq(cx, exp_ty, pat_ty); - then { - - let mut applicability = Applicability::MachineApplicable; - let pat_str = match pat.kind { - PatKind::Struct(..) => format!( - "({})", - snippet_with_applicability(cx, pat.span, "..", &mut applicability), - ), - _ => snippet_with_applicability(cx, pat.span, "..", &mut applicability).to_string(), - }; - span_lint_and_sugg( - cx, - EQUATABLE_IF_LET, - expr.span, - "this pattern matching can be expressed using equality", - "try", - format!( - "{} == {}", - snippet_with_applicability(cx, exp.span, "..", &mut applicability), - pat_str, - ), - applicability, - ); - } + if let ExprKind::Let(pat, exp, _) = expr.kind { + emit_lint(cx, pat, exp, expr.span, EQUATABLE_IF_LET); + } + if let Some(MatchesExpn { + call_site, + arm: Arm { pat, guard: None, .. }, + exp, + }) = MatchesExpn::parse(expr) + { + emit_lint(cx, pat, exp, call_site, EQUATABLE_MATCHES); } } } diff --git a/clippy_lints/src/lib.register_all.rs b/clippy_lints/src/lib.register_all.rs index 3e6e0244754f..e0b58469b6b6 100644 --- a/clippy_lints/src/lib.register_all.rs +++ b/clippy_lints/src/lib.register_all.rs @@ -51,6 +51,7 @@ store.register_group(true, "clippy::all", Some("clippy_all"), vec![ LintId::of(enum_variants::MODULE_INCEPTION), LintId::of(eq_op::EQ_OP), LintId::of(eq_op::OP_REF), + LintId::of(equatable_if_let::EQUATABLE_IF_LET), LintId::of(erasing_op::ERASING_OP), LintId::of(escape::BOXED_LOCAL), LintId::of(eta_reduction::REDUNDANT_CLOSURE), diff --git a/clippy_lints/src/lib.register_lints.rs b/clippy_lints/src/lib.register_lints.rs index 2ba2b3da55cd..e7e12fc9d7cc 100644 --- a/clippy_lints/src/lib.register_lints.rs +++ b/clippy_lints/src/lib.register_lints.rs @@ -117,6 +117,7 @@ store.register_lints(&[ eq_op::EQ_OP, eq_op::OP_REF, equatable_if_let::EQUATABLE_IF_LET, + equatable_if_let::EQUATABLE_MATCHES, erasing_op::ERASING_OP, escape::BOXED_LOCAL, eta_reduction::REDUNDANT_CLOSURE, diff --git a/clippy_lints/src/lib.register_nursery.rs b/clippy_lints/src/lib.register_nursery.rs index 96e0b421094d..32606e570d8c 100644 --- a/clippy_lints/src/lib.register_nursery.rs +++ b/clippy_lints/src/lib.register_nursery.rs @@ -8,7 +8,6 @@ store.register_group(true, "clippy::nursery", Some("clippy_nursery"), vec![ LintId::of(copies::BRANCHES_SHARING_CODE), LintId::of(disallowed_method::DISALLOWED_METHOD), LintId::of(disallowed_type::DISALLOWED_TYPE), - LintId::of(equatable_if_let::EQUATABLE_IF_LET), LintId::of(fallible_impl_from::FALLIBLE_IMPL_FROM), LintId::of(floating_point_arithmetic::IMPRECISE_FLOPS), LintId::of(floating_point_arithmetic::SUBOPTIMAL_FLOPS), diff --git a/clippy_lints/src/lib.register_pedantic.rs b/clippy_lints/src/lib.register_pedantic.rs index 6533b94e82bd..7274efcd492e 100644 --- a/clippy_lints/src/lib.register_pedantic.rs +++ b/clippy_lints/src/lib.register_pedantic.rs @@ -28,6 +28,7 @@ store.register_group(true, "clippy::pedantic", Some("clippy_pedantic"), vec![ LintId::of(doc::MISSING_PANICS_DOC), LintId::of(empty_enum::EMPTY_ENUM), LintId::of(enum_variants::MODULE_NAME_REPETITIONS), + LintId::of(equatable_if_let::EQUATABLE_MATCHES), LintId::of(eta_reduction::REDUNDANT_CLOSURE_FOR_METHOD_CALLS), LintId::of(excessive_bools::FN_PARAMS_EXCESSIVE_BOOLS), LintId::of(excessive_bools::STRUCT_EXCESSIVE_BOOLS), diff --git a/clippy_lints/src/lib.register_style.rs b/clippy_lints/src/lib.register_style.rs index a39c111c5742..3ae1fb829593 100644 --- a/clippy_lints/src/lib.register_style.rs +++ b/clippy_lints/src/lib.register_style.rs @@ -20,6 +20,7 @@ store.register_group(true, "clippy::style", Some("clippy_style"), vec![ LintId::of(enum_variants::ENUM_VARIANT_NAMES), LintId::of(enum_variants::MODULE_INCEPTION), LintId::of(eq_op::OP_REF), + LintId::of(equatable_if_let::EQUATABLE_IF_LET), LintId::of(eta_reduction::REDUNDANT_CLOSURE), LintId::of(float_literal::EXCESSIVE_PRECISION), LintId::of(from_over_into::FROM_OVER_INTO), diff --git a/clippy_lints/src/manual_async_fn.rs b/clippy_lints/src/manual_async_fn.rs index b632af455f85..14b6c36627e7 100644 --- a/clippy_lints/src/manual_async_fn.rs +++ b/clippy_lints/src/manual_async_fn.rs @@ -165,7 +165,7 @@ fn captures_all_lifetimes(inputs: &[Ty<'_>], output_lifetimes: &[LifetimeName]) // - There's only one output lifetime bound using `+ '_` // - All input lifetimes are explicitly bound to the output input_lifetimes.is_empty() - || (output_lifetimes.len() == 1 && matches!(output_lifetimes[0], LifetimeName::Underscore)) + || (output_lifetimes.len() == 1 && output_lifetimes[0] == LifetimeName::Underscore) || input_lifetimes .iter() .all(|in_lt| output_lifetimes.iter().any(|out_lt| in_lt == out_lt)) diff --git a/clippy_lints/src/manual_map.rs b/clippy_lints/src/manual_map.rs index b5f573cb104e..2c26ab02a4fe 100644 --- a/clippy_lints/src/manual_map.rs +++ b/clippy_lints/src/manual_map.rs @@ -170,7 +170,7 @@ impl LateLintPass<'_> for ManualMap { } // `ref` and `ref mut` annotations were handled earlier. - let annotation = if matches!(annotation, BindingAnnotation::Mutable) { + let annotation = if annotation == BindingAnnotation::Mutable { "mut " } else { "" diff --git a/clippy_lints/src/map_clone.rs b/clippy_lints/src/map_clone.rs index 394606200bb0..f246817ab414 100644 --- a/clippy_lints/src/map_clone.rs +++ b/clippy_lints/src/map_clone.rs @@ -88,7 +88,7 @@ impl<'tcx> LateLintPass<'tcx> for MapClone { then { let obj_ty = cx.typeck_results().expr_ty(obj); if let ty::Ref(_, ty, mutability) = obj_ty.kind() { - if matches!(mutability, Mutability::Not) { + if mutability == &Mutability::Not { let copy = is_copy(cx, ty); lint(cx, e.span, args[0].span, copy); } diff --git a/clippy_lints/src/methods/inefficient_to_string.rs b/clippy_lints/src/methods/inefficient_to_string.rs index 950ec62c9fe4..10e377cddee6 100644 --- a/clippy_lints/src/methods/inefficient_to_string.rs +++ b/clippy_lints/src/methods/inefficient_to_string.rs @@ -51,7 +51,7 @@ pub fn check<'tcx>(cx: &LateContext<'tcx>, expr: &hir::Expr<'_>, method_name: Sy /// Returns whether `ty` specializes `ToString`. /// Currently, these are `str`, `String`, and `Cow<'_, str>`. fn specializes_tostring(cx: &LateContext<'_>, ty: Ty<'_>) -> bool { - if let ty::Str = ty.kind() { + if ty.kind() == &ty::Str { return true; } diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index b26d11c0d6b0..d980777bd44c 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -2456,7 +2456,7 @@ impl OutType { fn is_bool(ty: &hir::Ty<'_>) -> bool { if let hir::TyKind::Path(QPath::Resolved(_, path)) = ty.kind { - matches!(path.res, Res::PrimTy(PrimTy::Bool)) + path.res == Res::PrimTy(PrimTy::Bool) } else { false } diff --git a/clippy_lints/src/methods/or_fun_call.rs b/clippy_lints/src/methods/or_fun_call.rs index a4d3f0bfb6c1..8b0220664ef1 100644 --- a/clippy_lints/src/methods/or_fun_call.rs +++ b/clippy_lints/src/methods/or_fun_call.rs @@ -51,8 +51,8 @@ pub(super) fn check<'tcx>( let path = last_path_segment(qpath).ident.name; // needs to target Default::default in particular or be *::new and have a Default impl // available - if (matches!(path, kw::Default) && is_default_default()) - || (matches!(path, sym::new) && implements_default(arg, default_trait_id)); + if (path == kw::Default && is_default_default()) + || (path == sym::new && implements_default(arg, default_trait_id)); then { let mut applicability = Applicability::MachineApplicable; diff --git a/clippy_lints/src/multiple_crate_versions.rs b/clippy_lints/src/multiple_crate_versions.rs index 1c61970fdc8b..bb94a3096fc5 100644 --- a/clippy_lints/src/multiple_crate_versions.rs +++ b/clippy_lints/src/multiple_crate_versions.rs @@ -84,13 +84,9 @@ impl LateLintPass<'_> for MultipleCrateVersions { fn is_normal_dep(nodes: &[Node], local_id: &PackageId, dep_id: &PackageId) -> bool { fn depends_on(node: &Node, dep_id: &PackageId) -> bool { - node.deps.iter().any(|dep| { - dep.pkg == *dep_id - && dep - .dep_kinds - .iter() - .any(|info| matches!(info.kind, DependencyKind::Normal)) - }) + node.deps + .iter() + .any(|dep| dep.pkg == *dep_id && dep.dep_kinds.iter().any(|info| info.kind == DependencyKind::Normal)) } nodes diff --git a/clippy_lints/src/needless_borrow.rs b/clippy_lints/src/needless_borrow.rs index 1b2495d764d2..d10deeb568e0 100644 --- a/clippy_lints/src/needless_borrow.rs +++ b/clippy_lints/src/needless_borrow.rs @@ -116,7 +116,7 @@ impl<'tcx> LateLintPass<'tcx> for NeedlessBorrow { .. }] = *adj3 { - let help_msg_ty = if matches!(mutability, Mutability::Not) { + let help_msg_ty = if mutability == Mutability::Not { format!("&{}", ty) } else { format!("&mut {}", ty) diff --git a/clippy_lints/src/redundant_clone.rs b/clippy_lints/src/redundant_clone.rs index 7041e4f980ef..bc9d1c911bbd 100644 --- a/clippy_lints/src/redundant_clone.rs +++ b/clippy_lints/src/redundant_clone.rs @@ -323,7 +323,7 @@ fn find_stmt_assigns_to<'tcx>( Some(base_local_and_movability(cx, mir, *place)) }, (false, mir::Rvalue::Ref(_, _, place)) => { - if let [mir::ProjectionElem::Deref] = place.as_ref().projection { + if place.as_ref().projection == [mir::ProjectionElem::Deref] { Some(base_local_and_movability(cx, mir, *place)) } else { None @@ -355,7 +355,7 @@ fn base_local_and_movability<'tcx>( let PlaceRef { local, mut projection } = place.as_ref(); while let [base @ .., elem] = projection { projection = base; - deref |= matches!(elem, mir::ProjectionElem::Deref); + deref |= elem == &mir::ProjectionElem::Deref; field |= matches!(elem, mir::ProjectionElem::Field(..)) && has_drop(cx, mir::Place::ty_from(local, projection, &mir.local_decls, cx.tcx).ty); slice |= matches!(elem, mir::ProjectionElem::Index(..)) diff --git a/clippy_lints/src/same_name_method.rs b/clippy_lints/src/same_name_method.rs index 014898e6dab1..2cd2999474d2 100644 --- a/clippy_lints/src/same_name_method.rs +++ b/clippy_lints/src/same_name_method.rs @@ -83,9 +83,7 @@ impl<'tcx> LateLintPass<'tcx> for SameNameMethod { cx.tcx .associated_items(did) .in_definition_order() - .filter(|assoc_item| { - matches!(assoc_item.kind, AssocKind::Fn) - }) + .filter(|assoc_item| assoc_item.kind == AssocKind::Fn) .map(|assoc_item| assoc_item.ident.name) .collect() }else{ diff --git a/clippy_lints/src/transmute/transmute_ref_to_ref.rs b/clippy_lints/src/transmute/transmute_ref_to_ref.rs index d105e37abf9c..50eca0a9cc21 100644 --- a/clippy_lints/src/transmute/transmute_ref_to_ref.rs +++ b/clippy_lints/src/transmute/transmute_ref_to_ref.rs @@ -23,7 +23,7 @@ pub(super) fn check<'tcx>( if let (ty::Ref(_, ty_from, from_mutbl), ty::Ref(_, ty_to, to_mutbl)) = (&from_ty.kind(), &to_ty.kind()) { if_chain! { if let (&ty::Slice(slice_ty), &ty::Str) = (&ty_from.kind(), &ty_to.kind()); - if let ty::Uint(ty::UintTy::U8) = slice_ty.kind(); + if slice_ty.kind() == &ty::Uint(ty::UintTy::U8); if from_mutbl == to_mutbl; then { let postfix = if *from_mutbl == Mutability::Mut { diff --git a/clippy_lints/src/unused_async.rs b/clippy_lints/src/unused_async.rs index f4808682b692..fe16217b8099 100644 --- a/clippy_lints/src/unused_async.rs +++ b/clippy_lints/src/unused_async.rs @@ -67,7 +67,7 @@ impl<'tcx> LateLintPass<'tcx> for UnusedAsync { hir_id: HirId, ) { if let FnKind::ItemFn(_, _, FnHeader { asyncness, .. }, _) = &fn_kind { - if matches!(asyncness, IsAsync::Async) { + if asyncness == &IsAsync::Async { let mut visitor = AsyncFnVisitor { cx, found_await: false }; walk_fn(&mut visitor, fn_kind, fn_decl, body.id(), span, hir_id); if !visitor.found_await { diff --git a/clippy_lints/src/utils/internal_lints.rs b/clippy_lints/src/utils/internal_lints.rs index 3e2a4e9748db..aa42630b0a6b 100644 --- a/clippy_lints/src/utils/internal_lints.rs +++ b/clippy_lints/src/utils/internal_lints.rs @@ -536,7 +536,7 @@ impl<'tcx> LateLintPass<'tcx> for OuterExpnDataPass { let method_names: Vec<SymbolStr> = method_names.iter().map(|s| s.as_str()).collect(); let method_names: Vec<&str> = method_names.iter().map(|s| &**s).collect(); if_chain! { - if let ["expn_data", "outer_expn"] = method_names.as_slice(); + if method_names.as_slice() == ["expn_data", "outer_expn"]; let args = arg_lists[1]; if args.len() == 1; let self_arg = &args[0]; diff --git a/clippy_lints/src/write.rs b/clippy_lints/src/write.rs index 85d1f65c51f0..890ff0e6d506 100644 --- a/clippy_lints/src/write.rs +++ b/clippy_lints/src/write.rs @@ -564,13 +564,13 @@ impl Write { LitKind::StrRaw(_) | LitKind::ByteStrRaw(_) if matches!(fmtstr.style, StrStyle::Raw(_)) => { lit.token.symbol.as_str().replace("{", "{{").replace("}", "}}") }, - LitKind::Str | LitKind::ByteStr if matches!(fmtstr.style, StrStyle::Cooked) => { + LitKind::Str | LitKind::ByteStr if fmtstr.style == StrStyle::Cooked => { lit.token.symbol.as_str().replace("{", "{{").replace("}", "}}") }, LitKind::StrRaw(_) | LitKind::Str | LitKind::ByteStrRaw(_) | LitKind::ByteStr => continue, LitKind::Byte | LitKind::Char => match &*lit.token.symbol.as_str() { - "\"" if matches!(fmtstr.style, StrStyle::Cooked) => "\\\"", - "\"" if matches!(fmtstr.style, StrStyle::Raw(0)) => continue, + "\"" if fmtstr.style == StrStyle::Cooked => "\\\"", + "\"" if fmtstr.style == StrStyle::Raw(0) => continue, "\\\\" if matches!(fmtstr.style, StrStyle::Raw(_)) => "\\", "\\'" => "'", "{" => "{{", diff --git a/clippy_utils/src/ast_utils.rs b/clippy_utils/src/ast_utils.rs index 2fa98831c774..e536f2a90a89 100644 --- a/clippy_utils/src/ast_utils.rs +++ b/clippy_utils/src/ast_utils.rs @@ -278,7 +278,7 @@ pub fn eq_item_kind(l: &ItemKind, r: &ItemKind) -> bool { }, (Trait(box TraitKind(la, lu, lg, lb, li)), Trait(box TraitKind(ra, ru, rg, rb, ri))) => { la == ra - && matches!(lu, Unsafe::No) == matches!(ru, Unsafe::No) + && matches!(lu, Unsafe::Yes(_)) == matches!(ru, Unsafe::Yes(_)) && eq_generics(lg, rg) && over(lb, rb, eq_generic_bound) && over(li, ri, |l, r| eq_item(l, r, eq_assoc_item_kind)) @@ -306,10 +306,10 @@ pub fn eq_item_kind(l: &ItemKind, r: &ItemKind) -> bool { items: ri, }), ) => { - matches!(lu, Unsafe::No) == matches!(ru, Unsafe::No) - && matches!(lp, ImplPolarity::Positive) == matches!(rp, ImplPolarity::Positive) + matches!(lu, Unsafe::Yes(_)) == matches!(ru, Unsafe::Yes(_)) + && matches!(lp, ImplPolarity::Negative(_)) == matches!(rp, ImplPolarity::Negative(_)) && eq_defaultness(*ld, *rd) - && matches!(lc, ast::Const::No) == matches!(rc, ast::Const::No) + && matches!(lc, ast::Const::Yes(_)) == matches!(rc, ast::Const::Yes(_)) && eq_generics(lg, rg) && both(lot, rot, |l, r| eq_path(&l.path, &r.path)) && eq_ty(lst, rst) @@ -388,9 +388,9 @@ pub fn eq_fn_sig(l: &FnSig, r: &FnSig) -> bool { } pub fn eq_fn_header(l: &FnHeader, r: &FnHeader) -> bool { - matches!(l.unsafety, Unsafe::No) == matches!(r.unsafety, Unsafe::No) + matches!(l.unsafety, Unsafe::Yes(_)) == matches!(r.unsafety, Unsafe::Yes(_)) && l.asyncness.is_async() == r.asyncness.is_async() - && matches!(l.constness, Const::No) == matches!(r.constness, Const::No) + && matches!(l.constness, Const::Yes(_)) == matches!(r.constness, Const::Yes(_)) && eq_ext(&l.ext, &r.ext) } diff --git a/clippy_utils/src/higher.rs b/clippy_utils/src/higher.rs index ba4d50bf7446..e3d88b1f2d4e 100644 --- a/clippy_utils/src/higher.rs +++ b/clippy_utils/src/higher.rs @@ -467,6 +467,42 @@ pub fn extract_assert_macro_args<'tcx>(e: &'tcx Expr<'tcx>) -> Option<Vec<&'tcx None } +/// A parsed `matches!` expansion +#[derive(Debug)] +pub struct MatchesExpn<'tcx> { + /// Span of `matches!(..)` + pub call_site: Span, + /// Second parameter of `matches!` + pub arm: &'tcx Arm<'tcx>, + /// First parameter of `matches!` + pub exp: &'tcx Expr<'tcx>, +} + +impl MatchesExpn<'tcx> { + /// Parses an expanded `matches!` invocation + pub fn parse(expr: &'tcx Expr<'tcx>) -> Option<Self> { + if_chain! { + if let ExprKind::Match(exp, [arm_true, arm_false], _) = expr.kind; + if let ExprKind::Lit(lit_true) = &arm_true.body.kind; + if lit_true.node == LitKind::Bool(true); + if let ExprKind::Lit(lit_false) = &arm_false.body.kind; + if lit_false.node == LitKind::Bool(false); + // there is no sym::matches ?! + //if let ExpnKind::Macro(_, sym::matches) = expn_data.kind; + then { + let expn_data = expr.span.ctxt().outer_expn_data(); + Some(MatchesExpn { + call_site: expn_data.call_site, + arm: arm_true, + exp, + }) + } else { + None + } + } + } +} + /// A parsed `format!` expansion pub struct FormatExpn<'tcx> { /// Span of `format!(..)` diff --git a/tests/lint_message_convention.rs b/tests/lint_message_convention.rs index b4d94dc983fe..c17d73acc35e 100644 --- a/tests/lint_message_convention.rs +++ b/tests/lint_message_convention.rs @@ -84,7 +84,7 @@ fn lint_message_convention() { .expect("failed to read dir") .map(|direntry| direntry.unwrap().path()) }) - .filter(|file| matches!(file.extension().map(OsStr::to_str), Some(Some("stderr")))); + .filter(|file| file.extension().map(OsStr::to_str) == Some(Some("stderr"))); // get all files that have any "bad lines" in them let bad_tests: Vec<Message> = tests diff --git a/tests/ui-internal/if_chain_style.rs b/tests/ui-internal/if_chain_style.rs index 8e871707aa8f..1bd8c4d61a10 100644 --- a/tests/ui-internal/if_chain_style.rs +++ b/tests/ui-internal/if_chain_style.rs @@ -1,5 +1,5 @@ #![warn(clippy::if_chain_style)] -#![allow(clippy::no_effect)] +#![allow(clippy::no_effect, clippy::equatable_if_let)] extern crate if_chain; diff --git a/tests/ui/equatable_if_let.fixed b/tests/ui/equatable_if_let.fixed index ba72cc237b4a..053667e82133 100644 --- a/tests/ui/equatable_if_let.fixed +++ b/tests/ui/equatable_if_let.fixed @@ -1,7 +1,7 @@ // run-rustfix -#![allow(unused_variables, dead_code)] -#![warn(clippy::equatable_if_let)] +#![allow(unused_variables, dead_code, clippy::redundant_pattern_matching, clippy::op_ref)] +#![warn(clippy::equatable_if_let, clippy::equatable_matches)] use std::cmp::Ordering; @@ -19,11 +19,13 @@ struct Struct { b: bool, } +#[derive(Clone, Copy)] enum NotPartialEq { A, B, } +#[derive(Clone, Copy)] enum NotStructuralEq { A, B, @@ -35,6 +37,19 @@ impl PartialEq for NotStructuralEq { } } +#[derive(PartialEq)] +enum Generic<A, B> { + VA(A), + VB(B), + VC, +} + +#[derive(PartialEq)] +struct Generic2<A, B> { + a: A, + b: B, +} + fn main() { let a = 2; let b = 3; @@ -43,6 +58,20 @@ fn main() { let e = Enum::UnitVariant; let f = NotPartialEq::A; let g = NotStructuralEq::A; + let h: Generic<Enum, NotPartialEq> = Generic::VC; + let i: Generic<Enum, NotStructuralEq> = Generic::VC; + let j = vec![1, 2, 3, 4]; + let k = Some(&false); + let l = Generic2 { + a: Generic2 { a: "xxxx", b: 3 }, + b: Generic2 { + a: &Enum::UnitVariant, + b: false, + }, + }; + let m = Generic2 { a: 3, b: 5 }; + let n = Some("xxxx"); + let mut o = j.iter(); // true @@ -54,6 +83,24 @@ fn main() { if e == (Enum::RecordVariant { a: 64, b: 32 }) {} if e == Enum::UnitVariant {} if (e, &d) == (Enum::UnitVariant, &Struct { a: 2, b: false }) {} + if Some(g) == None {} + if i == Generic::VA(Enum::UnitVariant) {} + if i == Generic::VC {} + if j[1..3] == [7, 5] {} + if j[..] == [1, 2, 3, 4] {} + if k == Some(&true) {} + if k == Some(&false) {} + if &k == &Some(&true) {} + if &&k == &&Some(&false) {} + if k == None {} + if l == (Generic2 { a: Generic2 { a: "yyy", b: 3 }, b: Generic2 { a: &Enum::UnitVariant, b: false } }) + {} + if m == (Generic2 { a: 3, b: 5 }) {} + if n == Some("yyy") {} + + let _ = c == Some(2); + + while o.next() == Some(&2) {} // false @@ -63,7 +110,21 @@ fn main() { if let Struct { a, b: false } = d {} if let Struct { a: 2, b: x } = d {} if let NotPartialEq::A = f {} - if g == NotStructuralEq::A {} + if let NotStructuralEq::A = g {} if let Some(NotPartialEq::A) = Some(f) {} - if Some(g) == Some(NotStructuralEq::A) {} + if let None = Some(f) {} + if let Some(NotStructuralEq::A) = Some(g) {} + if let Generic::VA(Enum::UnitVariant) = h {} + if let Generic::VB(NotPartialEq::A) = h {} + if let Generic::VC = h {} + if let Generic::VB(NotStructuralEq::A) = i {} + if let [7, _] = j[2..] {} + if let [1, 2 | 5, 3, 4] = j[..] {} + if let [2, ..] = j[..] {} + + let _ = matches!(c, Some(x)); + let _ = matches!(c, Some(x) if x == 2); + let _ = matches!(c, Some(2) if 3 > 5); + + while let Some(4 | 7) = o.next() {} } diff --git a/tests/ui/equatable_if_let.rs b/tests/ui/equatable_if_let.rs index 12526ca193db..7c2d8cf9d919 100644 --- a/tests/ui/equatable_if_let.rs +++ b/tests/ui/equatable_if_let.rs @@ -1,7 +1,7 @@ // run-rustfix -#![allow(unused_variables, dead_code)] -#![warn(clippy::equatable_if_let)] +#![allow(unused_variables, dead_code, clippy::redundant_pattern_matching, clippy::op_ref)] +#![warn(clippy::equatable_if_let, clippy::equatable_matches)] use std::cmp::Ordering; @@ -19,11 +19,13 @@ struct Struct { b: bool, } +#[derive(Clone, Copy)] enum NotPartialEq { A, B, } +#[derive(Clone, Copy)] enum NotStructuralEq { A, B, @@ -35,6 +37,19 @@ impl PartialEq for NotStructuralEq { } } +#[derive(PartialEq)] +enum Generic<A, B> { + VA(A), + VB(B), + VC, +} + +#[derive(PartialEq)] +struct Generic2<A, B> { + a: A, + b: B, +} + fn main() { let a = 2; let b = 3; @@ -43,6 +58,20 @@ fn main() { let e = Enum::UnitVariant; let f = NotPartialEq::A; let g = NotStructuralEq::A; + let h: Generic<Enum, NotPartialEq> = Generic::VC; + let i: Generic<Enum, NotStructuralEq> = Generic::VC; + let j = vec![1, 2, 3, 4]; + let k = Some(&false); + let l = Generic2 { + a: Generic2 { a: "xxxx", b: 3 }, + b: Generic2 { + a: &Enum::UnitVariant, + b: false, + }, + }; + let m = Generic2 { a: 3, b: 5 }; + let n = Some("xxxx"); + let mut o = j.iter(); // true @@ -54,6 +83,30 @@ fn main() { if let Enum::RecordVariant { a: 64, b: 32 } = e {} if let Enum::UnitVariant = e {} if let (Enum::UnitVariant, &Struct { a: 2, b: false }) = (e, &d) {} + if let None = Some(g) {} + if let Generic::VA(Enum::UnitVariant) = i {} + if let Generic::VC = i {} + if let [7, 5] = j[1..3] {} + if let [1, 2, 3, 4] = j[..] {} + if let Some(true) = k {} + if let Some(&false) = k {} + if let Some(true) = &k {} + if let Some(false) = &&k {} + if let None = k {} + if let Generic2 { + a: Generic2 { a: "yyy", b: 3 }, + b: Generic2 { + a: Enum::UnitVariant, + b: false, + }, + } = l + {} + if let Generic2 { a: 3, b: 5 } = m {} + if let Some("yyy") = n {} + + let _ = matches!(c, Some(2)); + + while let Some(2) = o.next() {} // false @@ -65,5 +118,19 @@ fn main() { if let NotPartialEq::A = f {} if let NotStructuralEq::A = g {} if let Some(NotPartialEq::A) = Some(f) {} + if let None = Some(f) {} if let Some(NotStructuralEq::A) = Some(g) {} + if let Generic::VA(Enum::UnitVariant) = h {} + if let Generic::VB(NotPartialEq::A) = h {} + if let Generic::VC = h {} + if let Generic::VB(NotStructuralEq::A) = i {} + if let [7, _] = j[2..] {} + if let [1, 2 | 5, 3, 4] = j[..] {} + if let [2, ..] = j[..] {} + + let _ = matches!(c, Some(x)); + let _ = matches!(c, Some(x) if x == 2); + let _ = matches!(c, Some(2) if 3 > 5); + + while let Some(4 | 7) = o.next() {} } diff --git a/tests/ui/equatable_if_let.stderr b/tests/ui/equatable_if_let.stderr index 79ef919384df..993974906df7 100644 --- a/tests/ui/equatable_if_let.stderr +++ b/tests/ui/equatable_if_let.stderr @@ -1,5 +1,5 @@ error: this pattern matching can be expressed using equality - --> $DIR/equatable_if_let.rs:49:8 + --> $DIR/equatable_if_let.rs:78:8 | LL | if let 2 = a {} | ^^^^^^^^^ help: try: `a == 2` @@ -7,58 +7,145 @@ LL | if let 2 = a {} = note: `-D clippy::equatable-if-let` implied by `-D warnings` error: this pattern matching can be expressed using equality - --> $DIR/equatable_if_let.rs:50:8 + --> $DIR/equatable_if_let.rs:79:8 | LL | if let Ordering::Greater = a.cmp(&b) {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `a.cmp(&b) == Ordering::Greater` error: this pattern matching can be expressed using equality - --> $DIR/equatable_if_let.rs:51:8 + --> $DIR/equatable_if_let.rs:80:8 | LL | if let Some(2) = c {} | ^^^^^^^^^^^^^^^ help: try: `c == Some(2)` error: this pattern matching can be expressed using equality - --> $DIR/equatable_if_let.rs:52:8 + --> $DIR/equatable_if_let.rs:81:8 | LL | if let Struct { a: 2, b: false } = d {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `d == (Struct { a: 2, b: false })` error: this pattern matching can be expressed using equality - --> $DIR/equatable_if_let.rs:53:8 + --> $DIR/equatable_if_let.rs:82:8 | LL | if let Enum::TupleVariant(32, 64) = e {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `e == Enum::TupleVariant(32, 64)` error: this pattern matching can be expressed using equality - --> $DIR/equatable_if_let.rs:54:8 + --> $DIR/equatable_if_let.rs:83:8 | LL | if let Enum::RecordVariant { a: 64, b: 32 } = e {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `e == (Enum::RecordVariant { a: 64, b: 32 })` error: this pattern matching can be expressed using equality - --> $DIR/equatable_if_let.rs:55:8 + --> $DIR/equatable_if_let.rs:84:8 | LL | if let Enum::UnitVariant = e {} | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `e == Enum::UnitVariant` error: this pattern matching can be expressed using equality - --> $DIR/equatable_if_let.rs:56:8 + --> $DIR/equatable_if_let.rs:85:8 | LL | if let (Enum::UnitVariant, &Struct { a: 2, b: false }) = (e, &d) {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `(e, &d) == (Enum::UnitVariant, &Struct { a: 2, b: false })` error: this pattern matching can be expressed using equality - --> $DIR/equatable_if_let.rs:66:8 + --> $DIR/equatable_if_let.rs:86:8 | -LL | if let NotStructuralEq::A = g {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `g == NotStructuralEq::A` +LL | if let None = Some(g) {} + | ^^^^^^^^^^^^^^^^^^ help: try: `Some(g) == None` error: this pattern matching can be expressed using equality - --> $DIR/equatable_if_let.rs:68:8 + --> $DIR/equatable_if_let.rs:87:8 | -LL | if let Some(NotStructuralEq::A) = Some(g) {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `Some(g) == Some(NotStructuralEq::A)` +LL | if let Generic::VA(Enum::UnitVariant) = i {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `i == Generic::VA(Enum::UnitVariant)` -error: aborting due to 10 previous errors +error: this pattern matching can be expressed using equality + --> $DIR/equatable_if_let.rs:88:8 + | +LL | if let Generic::VC = i {} + | ^^^^^^^^^^^^^^^^^^^ help: try: `i == Generic::VC` + +error: this pattern matching can be expressed using equality + --> $DIR/equatable_if_let.rs:89:8 + | +LL | if let [7, 5] = j[1..3] {} + | ^^^^^^^^^^^^^^^^^^^^ help: try: `j[1..3] == [7, 5]` + +error: this pattern matching can be expressed using equality + --> $DIR/equatable_if_let.rs:90:8 + | +LL | if let [1, 2, 3, 4] = j[..] {} + | ^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `j[..] == [1, 2, 3, 4]` + +error: this pattern matching can be expressed using equality + --> $DIR/equatable_if_let.rs:91:8 + | +LL | if let Some(true) = k {} + | ^^^^^^^^^^^^^^^^^^ help: try: `k == Some(&true)` + +error: this pattern matching can be expressed using equality + --> $DIR/equatable_if_let.rs:92:8 + | +LL | if let Some(&false) = k {} + | ^^^^^^^^^^^^^^^^^^^^ help: try: `k == Some(&false)` + +error: this pattern matching can be expressed using equality + --> $DIR/equatable_if_let.rs:93:8 + | +LL | if let Some(true) = &k {} + | ^^^^^^^^^^^^^^^^^^^ help: try: `&k == &Some(&true)` + +error: this pattern matching can be expressed using equality + --> $DIR/equatable_if_let.rs:94:8 + | +LL | if let Some(false) = &&k {} + | ^^^^^^^^^^^^^^^^^^^^^ help: try: `&&k == &&Some(&false)` + +error: this pattern matching can be expressed using equality + --> $DIR/equatable_if_let.rs:95:8 + | +LL | if let None = k {} + | ^^^^^^^^^^^^ help: try: `k == None` + +error: this pattern matching can be expressed using equality + --> $DIR/equatable_if_let.rs:96:8 + | +LL | if let Generic2 { + | ________^ +LL | | a: Generic2 { a: "yyy", b: 3 }, +LL | | b: Generic2 { +LL | | a: Enum::UnitVariant, +LL | | b: false, +LL | | }, +LL | | } = l + | |_________^ help: try: `l == (Generic2 { a: Generic2 { a: "yyy", b: 3 }, b: Generic2 { a: &Enum::UnitVariant, b: false } })` + +error: this pattern matching can be expressed using equality + --> $DIR/equatable_if_let.rs:104:8 + | +LL | if let Generic2 { a: 3, b: 5 } = m {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `m == (Generic2 { a: 3, b: 5 })` + +error: this pattern matching can be expressed using equality + --> $DIR/equatable_if_let.rs:105:8 + | +LL | if let Some("yyy") = n {} + | ^^^^^^^^^^^^^^^^^^^ help: try: `n == Some("yyy")` + +error: this pattern matching can be expressed using equality + --> $DIR/equatable_if_let.rs:107:13 + | +LL | let _ = matches!(c, Some(2)); + | ^^^^^^^^^^^^^^^^^^^^ help: try: `c == Some(2)` + | + = note: `-D clippy::equatable-matches` implied by `-D warnings` + +error: this pattern matching can be expressed using equality + --> $DIR/equatable_if_let.rs:109:11 + | +LL | while let Some(2) = o.next() {} + | ^^^^^^^^^^^^^^^^^^^^^^ help: try: `o.next() == Some(&2)` + +error: aborting due to 23 previous errors