@@ -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+ peel_hir_pat_refs , peel_mid_ty_refs , peel_n_hir_expr_refs , remove_blocks , snippet , snippet_block , snippet_opt ,
8+ snippet_with_applicability , span_lint_and_help , 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;
@@ -728,20 +728,60 @@ fn report_single_match_single_pattern(
728728 let els_str = els. map_or ( String :: new ( ) , |els| {
729729 format ! ( " else {}" , expr_block( cx, els, None , ".." , Some ( expr. span) ) )
730730 } ) ;
731+
732+ let ( msg, sugg) = if_chain ! {
733+ let ( pat, pat_ref_count) = peel_hir_pat_refs( arms[ 0 ] . pat) ;
734+ if let PatKind :: Path ( _) | PatKind :: Lit ( _) = pat. kind;
735+ let ( ty, ty_ref_count) = peel_mid_ty_refs( cx. typeck_results( ) . expr_ty( ex) ) ;
736+ if let Some ( trait_id) = cx. tcx. lang_items( ) . structural_peq_trait( ) ;
737+ if ty. is_integral( ) || ty. is_char( ) || ty. is_str( ) || implements_trait( cx, ty, trait_id, & [ ] ) ;
738+ then {
739+ // scrutinee derives PartialEq and the pattern is a constant.
740+ let pat_ref_count = match pat. kind {
741+ // string literals are already a reference.
742+ PatKind :: Lit ( Expr { kind: ExprKind :: Lit ( lit) , .. } ) if lit. node. is_str( ) => pat_ref_count + 1 ,
743+ _ => pat_ref_count,
744+ } ;
745+ // References are only implicitly added to the pattern, so no overflow here.
746+ // e.g. will work: match &Some(_) { Some(_) => () }
747+ // will not: match Some(_) { &Some(_) => () }
748+ let ref_count_diff = ty_ref_count - pat_ref_count;
749+
750+ // Try to remove address of expressions first.
751+ let ( ex, removed) = peel_n_hir_expr_refs( ex, ref_count_diff) ;
752+ let ref_count_diff = ref_count_diff - removed;
753+
754+ let msg = "you seem to be trying to use `match` for an equality check. Consider using `if`" ;
755+ let sugg = format!(
756+ "if {} == {}{} {}{}" ,
757+ snippet( cx, ex. span, ".." ) ,
758+ // PartialEq for different reference counts may not exist.
759+ "&" . repeat( ref_count_diff) ,
760+ snippet( cx, arms[ 0 ] . pat. span, ".." ) ,
761+ expr_block( cx, & arms[ 0 ] . body, None , ".." , Some ( expr. span) ) ,
762+ els_str,
763+ ) ;
764+ ( msg, sugg)
765+ } else {
766+ let msg = "you seem to be trying to use `match` for destructuring a single pattern. Consider using `if let`" ;
767+ let sugg = format!(
768+ "if let {} = {} {}{}" ,
769+ snippet( cx, arms[ 0 ] . pat. span, ".." ) ,
770+ snippet( cx, ex. span, ".." ) ,
771+ expr_block( cx, & arms[ 0 ] . body, None , ".." , Some ( expr. span) ) ,
772+ els_str,
773+ ) ;
774+ ( msg, sugg)
775+ }
776+ } ;
777+
731778 span_lint_and_sugg (
732779 cx,
733780 lint,
734781 expr. span ,
735- "you seem to be trying to use match for destructuring a single pattern. Consider using `if \
736- let`",
782+ msg,
737783 "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- ) ,
784+ sugg,
745785 Applicability :: HasPlaceholders ,
746786 ) ;
747787}
0 commit comments