@@ -2,10 +2,10 @@ use crate::consts::{constant, miri_to_const, Constant};
22use crate :: utils:: sugg:: Sugg ;
33use crate :: utils:: usage:: is_unused;
44use crate :: utils:: {
5- expr_block, get_arg_name, get_parent_expr, in_macro, indent_of, is_allowed, is_expn_of, is_refutable ,
6- is_type_diagnostic_item, is_wild, match_qpath, match_type, match_var, meets_msrv, multispan_sugg, remove_blocks ,
7- snippet, snippet_block, snippet_opt, snippet_with_applicability, span_lint_and_help, span_lint_and_note ,
8- span_lint_and_sugg, span_lint_and_then,
5+ expr_block, get_arg_name, get_parent_expr, implements_trait , in_macro, indent_of, is_allowed, is_expn_of,
6+ is_refutable , is_type_diagnostic_item, is_wild, match_qpath, match_type, match_var, meets_msrv, multispan_sugg,
7+ remove_blocks , snippet, snippet_block, snippet_opt, snippet_with_applicability, span_lint_and_help,
8+ span_lint_and_note , span_lint_and_sugg, span_lint_and_then,
99} ;
1010use crate :: utils:: { paths, search_same, SpanlessEq , SpanlessHash } ;
1111use if_chain:: if_chain;
@@ -717,6 +717,28 @@ fn check_single_match_single_pattern(
717717 }
718718}
719719
720+ fn peel_pat_refs ( pat : & ' a Pat < ' a > ) -> ( & ' a Pat < ' a > , usize ) {
721+ fn peel ( pat : & ' a Pat < ' a > , count : usize ) -> ( & ' a Pat < ' a > , usize ) {
722+ if let PatKind :: Ref ( pat, _) = pat. kind {
723+ peel ( pat, count + 1 )
724+ } else {
725+ ( pat, count)
726+ }
727+ }
728+ peel ( pat, 0 )
729+ }
730+
731+ fn peel_ty_refs ( ty : Ty < ' _ > ) -> ( Ty < ' _ > , usize ) {
732+ fn peel ( ty : Ty < ' _ > , count : usize ) -> ( Ty < ' _ > , usize ) {
733+ if let ty:: Ref ( _, ty, _) = ty. kind ( ) {
734+ peel ( ty, count + 1 )
735+ } else {
736+ ( ty, count)
737+ }
738+ }
739+ peel ( ty, 0 )
740+ }
741+
720742fn report_single_match_single_pattern (
721743 cx : & LateContext < ' _ > ,
722744 ex : & Expr < ' _ > ,
@@ -728,20 +750,51 @@ fn report_single_match_single_pattern(
728750 let els_str = els. map_or ( String :: new ( ) , |els| {
729751 format ! ( " else {}" , expr_block( cx, els, None , ".." , Some ( expr. span) ) )
730752 } ) ;
753+
754+ let ( msg, sugg) = if_chain ! {
755+ let ( pat, pat_ref_count) = peel_pat_refs( arms[ 0 ] . pat) ;
756+ if let PatKind :: Path ( _) | PatKind :: Lit ( _) = pat. kind;
757+ let ( ty, ty_ref_count) = peel_ty_refs( cx. typeck_results( ) . expr_ty( ex) ) ;
758+ if let Some ( trait_id) = cx. tcx. lang_items( ) . structural_peq_trait( ) ;
759+ if ty. is_integral( ) || ty. is_char( ) || ty. is_str( ) || implements_trait( cx, ty, trait_id, & [ ] ) ;
760+ then {
761+ // scrutinee derives PartialEq and the pattern is a constant.
762+ let pat_ref_count = match pat. kind {
763+ // string literals are already a reference.
764+ PatKind :: Lit ( Expr { kind: ExprKind :: Lit ( lit) , .. } ) if lit. node. is_str( ) => pat_ref_count + 1 ,
765+ _ => pat_ref_count,
766+ } ;
767+ let msg = "you seem to be trying to use match for an equality check. Consider using `if`" ;
768+ let sugg = format!(
769+ "if {} == {}{} {}{}" ,
770+ snippet( cx, ex. span, ".." ) ,
771+ // PartialEq for different reference counts may not exist.
772+ "&" . repeat( ty_ref_count - pat_ref_count) ,
773+ snippet( cx, arms[ 0 ] . pat. span, ".." ) ,
774+ expr_block( cx, & arms[ 0 ] . body, None , ".." , Some ( expr. span) ) ,
775+ els_str,
776+ ) ;
777+ ( msg, sugg)
778+ } else {
779+ let msg = "you seem to be trying to use match for destructuring a single pattern. Consider using `if let`" ;
780+ let sugg = format!(
781+ "if let {} = {} {}{}" ,
782+ snippet( cx, arms[ 0 ] . pat. span, ".." ) ,
783+ snippet( cx, ex. span, ".." ) ,
784+ expr_block( cx, & arms[ 0 ] . body, None , ".." , Some ( expr. span) ) ,
785+ els_str,
786+ ) ;
787+ ( msg, sugg)
788+ }
789+ } ;
790+
731791 span_lint_and_sugg (
732792 cx,
733793 lint,
734794 expr. span ,
735- "you seem to be trying to use match for destructuring a single pattern. Consider using `if \
736- let`",
795+ msg,
737796 "try this" ,
738- format ! (
739- "if let {} = {} {}{}" ,
740- snippet( cx, arms[ 0 ] . pat. span, ".." ) ,
741- snippet( cx, ex. span, ".." ) ,
742- expr_block( cx, & arms[ 0 ] . body, None , ".." , Some ( expr. span) ) ,
743- els_str,
744- ) ,
797+ sugg,
745798 Applicability :: HasPlaceholders ,
746799 ) ;
747800}
0 commit comments