@@ -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
+ 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,
9
9
} ;
10
10
use crate :: utils:: { paths, search_same, SpanlessEq , SpanlessHash } ;
11
11
use if_chain:: if_chain;
@@ -717,6 +717,28 @@ fn check_single_match_single_pattern(
717
717
}
718
718
}
719
719
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
+
720
742
fn report_single_match_single_pattern (
721
743
cx : & LateContext < ' _ > ,
722
744
ex : & Expr < ' _ > ,
@@ -728,20 +750,51 @@ fn report_single_match_single_pattern(
728
750
let els_str = els. map_or ( String :: new ( ) , |els| {
729
751
format ! ( " else {}" , expr_block( cx, els, None , ".." , Some ( expr. span) ) )
730
752
} ) ;
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
+
731
791
span_lint_and_sugg (
732
792
cx,
733
793
lint,
734
794
expr. span ,
735
- "you seem to be trying to use match for destructuring a single pattern. Consider using `if \
736
- let`",
795
+ msg,
737
796
"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,
745
798
Applicability :: HasPlaceholders ,
746
799
) ;
747
800
}
0 commit comments