@@ -2,10 +2,10 @@ use crate::consts::{constant, miri_to_const, Constant};
2
2
use crate :: utils:: sugg:: Sugg ;
3
3
use crate :: utils:: usage:: is_unused;
4
4
use 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,
9
9
} ;
10
10
use crate :: utils:: { paths, search_same, SpanlessEq , SpanlessHash } ;
11
11
use if_chain:: if_chain;
@@ -728,20 +728,60 @@ fn report_single_match_single_pattern(
728
728
let els_str = els. map_or ( String :: new ( ) , |els| {
729
729
format ! ( " else {}" , expr_block( cx, els, None , ".." , Some ( expr. span) ) )
730
730
} ) ;
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
+
731
778
span_lint_and_sugg (
732
779
cx,
733
780
lint,
734
781
expr. span ,
735
- "you seem to be trying to use match for destructuring a single pattern. Consider using `if \
736
- let`",
782
+ msg,
737
783
"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,
745
785
Applicability :: HasPlaceholders ,
746
786
) ;
747
787
}
0 commit comments