@@ -3,11 +3,11 @@ use rustc_ast::ast::LitKind;
33use  rustc_errors:: Applicability ; 
44use  rustc_hir:: intravisit:: FnKind ; 
55use  rustc_hir:: { 
6-     def,  BinOpKind ,  BindingAnnotation ,  Body ,  Expr ,  ExprKind ,  FnDecl ,  HirId ,  Mutability ,  PatKind ,  Stmt ,   StmtKind ,   Ty , 
7-     TyKind ,  UnOp , 
6+     self   as  hir ,   def,  BinOpKind ,  BindingAnnotation ,  Body ,  Expr ,  ExprKind ,  FnDecl ,  HirId ,  Mutability ,  PatKind ,  Stmt , 
7+     StmtKind ,   TyKind ,  UnOp , 
88} ; 
99use  rustc_lint:: { LateContext ,  LateLintPass } ; 
10- use  rustc_middle:: ty; 
10+ use  rustc_middle:: ty:: { self ,   Ty } ; 
1111use  rustc_session:: { declare_lint_pass,  declare_tool_lint} ; 
1212use  rustc_span:: hygiene:: DesugaringKind ; 
1313use  rustc_span:: source_map:: { ExpnKind ,  Span } ; 
@@ -371,8 +371,8 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for MiscLints {
371371                if  op. is_comparison ( )  { 
372372                    check_nan ( cx,  left,  expr) ; 
373373                    check_nan ( cx,  right,  expr) ; 
374-                     check_to_owned ( cx,  left,  right) ; 
375-                     check_to_owned ( cx,  right,  left) ; 
374+                     check_to_owned ( cx,  left,  right,   true ) ; 
375+                     check_to_owned ( cx,  right,  left,   false ) ; 
376376                } 
377377                if  ( op == BinOpKind :: Eq  || op == BinOpKind :: Ne )  && ( is_float ( cx,  left)  || is_float ( cx,  right) )  { 
378378                    if  is_allowed ( cx,  left)  || is_allowed ( cx,  right)  { 
@@ -570,19 +570,38 @@ fn is_array(cx: &LateContext<'_, '_>, expr: &Expr<'_>) -> bool {
570570    matches ! ( & walk_ptrs_ty( cx. tables. expr_ty( expr) ) . kind,  ty:: Array ( _,  _) ) 
571571} 
572572
573- fn  check_to_owned ( cx :  & LateContext < ' _ ,  ' _ > ,  expr :  & Expr < ' _ > ,  other :  & Expr < ' _ > )  { 
573+ fn  check_to_owned ( cx :  & LateContext < ' _ ,  ' _ > ,  expr :  & Expr < ' _ > ,  other :  & Expr < ' _ > ,  left :  bool )  { 
574+     #[ derive( Default ) ]  
575+     struct  EqImpl  { 
576+         ty_eq_other :  bool , 
577+         other_eq_ty :  bool , 
578+     } 
579+ 
580+     impl  EqImpl  { 
581+         fn  is_implemented ( & self )  -> bool  { 
582+             self . ty_eq_other  || self . other_eq_ty 
583+         } 
584+     } 
585+ 
586+     fn  symmetric_partial_eq < ' tcx > ( cx :  & LateContext < ' _ ,  ' tcx > ,  ty :  Ty < ' tcx > ,  other :  Ty < ' tcx > )  -> Option < EqImpl >  { 
587+         cx. tcx . lang_items ( ) . eq_trait ( ) . map ( |def_id| EqImpl  { 
588+             ty_eq_other :  implements_trait ( cx,  ty,  def_id,  & [ other. into ( ) ] ) , 
589+             other_eq_ty :  implements_trait ( cx,  other,  def_id,  & [ ty. into ( ) ] ) , 
590+         } ) 
591+     } 
592+ 
574593    let  ( arg_ty,  snip)  = match  expr. kind  { 
575594        ExprKind :: MethodCall ( ..,  ref  args,  _)  if  args. len ( )  == 1  => { 
576595            if  match_trait_method ( cx,  expr,  & paths:: TO_STRING )  || match_trait_method ( cx,  expr,  & paths:: TO_OWNED )  { 
577-                 ( cx. tables . expr_ty_adjusted ( & args[ 0 ] ) ,  snippet ( cx,  args[ 0 ] . span ,  ".." ) ) 
596+                 ( cx. tables . expr_ty ( & args[ 0 ] ) ,  snippet ( cx,  args[ 0 ] . span ,  ".." ) ) 
578597            }  else  { 
579598                return ; 
580599            } 
581600        } , 
582601        ExprKind :: Call ( ref  path,  ref  v)  if  v. len ( )  == 1  => { 
583602            if  let  ExprKind :: Path ( ref  path)  = path. kind  { 
584603                if  match_qpath ( path,  & [ "String" ,  "from_str" ] )  || match_qpath ( path,  & [ "String" ,  "from" ] )  { 
585-                     ( cx. tables . expr_ty_adjusted ( & v[ 0 ] ) ,  snippet ( cx,  v[ 0 ] . span ,  ".." ) ) 
604+                     ( cx. tables . expr_ty ( & v[ 0 ] ) ,  snippet ( cx,  v[ 0 ] . span ,  ".." ) ) 
586605                }  else  { 
587606                    return ; 
588607                } 
@@ -593,28 +612,19 @@ fn check_to_owned(cx: &LateContext<'_, '_>, expr: &Expr<'_>, other: &Expr<'_>) {
593612        _ => return , 
594613    } ; 
595614
596-     let  other_ty = cx. tables . expr_ty_adjusted ( other) ; 
597-     let  partial_eq_trait_id = match  cx. tcx . lang_items ( ) . eq_trait ( )  { 
598-         Some ( id)  => id, 
599-         None  => return , 
600-     } ; 
615+     let  other_ty = cx. tables . expr_ty ( other) ; 
601616
602-     let  deref_arg_impl_partial_eq_other = arg_ty. builtin_deref ( true ) . map_or ( false ,  |tam| { 
603-         implements_trait ( cx,  tam. ty ,  partial_eq_trait_id,  & [ other_ty. into ( ) ] ) 
604-     } ) ; 
605-     let  arg_impl_partial_eq_deref_other = other_ty. builtin_deref ( true ) . map_or ( false ,  |tam| { 
606-         implements_trait ( cx,  arg_ty,  partial_eq_trait_id,  & [ tam. ty . into ( ) ] ) 
607-     } ) ; 
608-     let  arg_impl_partial_eq_other = implements_trait ( cx,  arg_ty,  partial_eq_trait_id,  & [ other_ty. into ( ) ] ) ; 
617+     let  without_deref = symmetric_partial_eq ( cx,  arg_ty,  other_ty) . unwrap_or_default ( ) ; 
618+     let  with_deref = arg_ty
619+         . builtin_deref ( true ) 
620+         . and_then ( |tam| symmetric_partial_eq ( cx,  tam. ty ,  other_ty) ) 
621+         . unwrap_or_default ( ) ; 
609622
610-     if  !deref_arg_impl_partial_eq_other  && !arg_impl_partial_eq_deref_other && !arg_impl_partial_eq_other  { 
623+     if  !with_deref . is_implemented ( )  && !without_deref . is_implemented ( )  { 
611624        return ; 
612625    } 
613626
614-     let  other_gets_derefed = match  other. kind  { 
615-         ExprKind :: Unary ( UnOp :: UnDeref ,  _)  => true , 
616-         _ => false , 
617-     } ; 
627+     let  other_gets_derefed = matches ! ( other. kind,  ExprKind :: Unary ( UnOp :: UnDeref ,  _) ) ; 
618628
619629    let  lint_span = if  other_gets_derefed { 
620630        expr. span . to ( other. span ) 
@@ -634,18 +644,34 @@ fn check_to_owned(cx: &LateContext<'_, '_>, expr: &Expr<'_>, other: &Expr<'_>) {
634644                return ; 
635645            } 
636646
637-             let  try_hint = if  deref_arg_impl_partial_eq_other { 
638-                 // suggest deref on the left 
639-                 format ! ( "*{}" ,  snip) 
647+             let  expr_snip; 
648+             let  eq_impl; 
649+             if  with_deref. is_implemented ( )  { 
650+                 expr_snip = format ! ( "*{}" ,  snip) ; 
651+                 eq_impl = with_deref; 
640652            }  else  { 
641-                 // suggest dropping the to_owned on the left 
642-                 snip . to_string ( ) 
653+                 expr_snip = snip . to_string ( ) ; 
654+                 eq_impl = without_deref ; 
643655            } ; 
644656
657+             let  span; 
658+             let  hint; 
659+             if  ( eq_impl. ty_eq_other  && left)  || ( eq_impl. other_eq_ty  && !left)  { 
660+                 span = expr. span ; 
661+                 hint = expr_snip; 
662+             }  else  { 
663+                 span = expr. span . to ( other. span ) ; 
664+                 if  eq_impl. ty_eq_other  { 
665+                     hint = format ! ( "{} == {}" ,  expr_snip,  snippet( cx,  other. span,  ".." ) ) ; 
666+                 }  else  { 
667+                     hint = format ! ( "{} == {}" ,  snippet( cx,  other. span,  ".." ) ,  expr_snip) ; 
668+                 } 
669+             } 
670+ 
645671            diag. span_suggestion ( 
646-                 lint_span , 
672+                 span , 
647673                "try" , 
648-                 try_hint , 
674+                 hint , 
649675                Applicability :: MachineApplicable ,  // snippet 
650676            ) ; 
651677        } , 
@@ -694,7 +720,7 @@ fn non_macro_local(cx: &LateContext<'_, '_>, res: def::Res) -> bool {
694720    } 
695721} 
696722
697- fn  check_cast ( cx :  & LateContext < ' _ ,  ' _ > ,  span :  Span ,  e :  & Expr < ' _ > ,  ty :  & Ty < ' _ > )  { 
723+ fn  check_cast ( cx :  & LateContext < ' _ ,  ' _ > ,  span :  Span ,  e :  & Expr < ' _ > ,  ty :  & hir :: Ty < ' _ > )  { 
698724    if_chain !  { 
699725        if  let  TyKind :: Ptr ( ref mut_ty)  = ty. kind; 
700726        if  let  ExprKind :: Lit ( ref lit)  = e. kind; 
0 commit comments