@@ -12,7 +12,6 @@ use rustc_hir::def::{DefKind, Res};
1212use  rustc_hir:: intravisit:: { walk_block,  walk_expr,  Visitor } ; 
1313use  rustc_hir:: { CoroutineDesugaring ,  PatField } ; 
1414use  rustc_hir:: { CoroutineKind ,  CoroutineSource ,  LangItem } ; 
15- use  rustc_infer:: traits:: ObligationCause ; 
1615use  rustc_middle:: hir:: nested_filter:: OnlyBodies ; 
1716use  rustc_middle:: mir:: tcx:: PlaceTy ; 
1817use  rustc_middle:: mir:: { 
@@ -21,16 +20,21 @@ use rustc_middle::mir::{
2120    PlaceRef ,  ProjectionElem ,  Rvalue ,  Statement ,  StatementKind ,  Terminator ,  TerminatorKind , 
2221    VarBindingForm , 
2322} ; 
24- use  rustc_middle:: ty:: { self ,  suggest_constraining_type_params,  PredicateKind ,  Ty ,  TyCtxt } ; 
23+ use  rustc_middle:: ty:: { 
24+     self ,  suggest_constraining_type_params,  PredicateKind ,  ToPredicate ,  Ty ,  TyCtxt , 
25+     TypeSuperVisitable ,  TypeVisitor , 
26+ } ; 
2527use  rustc_middle:: util:: CallKind ; 
2628use  rustc_mir_dataflow:: move_paths:: { InitKind ,  MoveOutIndex ,  MovePathIndex } ; 
29+ use  rustc_span:: def_id:: DefId ; 
2730use  rustc_span:: def_id:: LocalDefId ; 
2831use  rustc_span:: hygiene:: DesugaringKind ; 
2932use  rustc_span:: symbol:: { kw,  sym,  Ident } ; 
3033use  rustc_span:: { BytePos ,  Span ,  Symbol } ; 
3134use  rustc_trait_selection:: infer:: InferCtxtExt ; 
35+ use  rustc_trait_selection:: traits:: error_reporting:: suggestions:: TypeErrCtxtExt ; 
3236use  rustc_trait_selection:: traits:: error_reporting:: FindExprBySpan ; 
33- use  rustc_trait_selection:: traits:: ObligationCtxt ; 
37+ use  rustc_trait_selection:: traits:: { Obligation ,   ObligationCause ,   ObligationCtxt } ; 
3438use  std:: iter; 
3539
3640use  crate :: borrow_set:: TwoPhaseActivation ; 
@@ -283,7 +287,8 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
283287                // something that already has `Fn`-like bounds (or is a closure), so we can't 
284288                // restrict anyways. 
285289            }  else  { 
286-                 self . suggest_adding_copy_bounds ( & mut  err,  ty,  span) ; 
290+                 let  copy_did = self . infcx . tcx . require_lang_item ( LangItem :: Copy ,  Some ( span) ) ; 
291+                 self . suggest_adding_bounds ( & mut  err,  ty,  copy_did,  span) ; 
287292            } 
288293
289294            if  needs_note { 
@@ -774,7 +779,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
774779        } 
775780    } 
776781
777-     fn  suggest_adding_copy_bounds ( & self ,  err :  & mut  Diag < ' _ > ,  ty :  Ty < ' tcx > ,  span :  Span )  { 
782+     fn  suggest_adding_bounds ( & self ,  err :  & mut  Diag < ' _ > ,  ty :  Ty < ' tcx > ,   def_id :   DefId ,  span :  Span )  { 
778783        let  tcx = self . infcx . tcx ; 
779784        let  generics = tcx. generics_of ( self . mir_def_id ( ) ) ; 
780785
@@ -787,10 +792,9 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
787792        } ; 
788793        // Try to find predicates on *generic params* that would allow copying `ty` 
789794        let  ocx = ObligationCtxt :: new ( self . infcx ) ; 
790-         let  copy_did = tcx. require_lang_item ( LangItem :: Copy ,  Some ( span) ) ; 
791795        let  cause = ObligationCause :: misc ( span,  self . mir_def_id ( ) ) ; 
792796
793-         ocx. register_bound ( cause,  self . param_env ,  ty,  copy_did ) ; 
797+         ocx. register_bound ( cause,  self . param_env ,  ty,  def_id ) ; 
794798        let  errors = ocx. select_all_or_error ( ) ; 
795799
796800        // Only emit suggestion if all required predicates are on generic 
@@ -876,6 +880,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
876880                Some ( borrow_span) , 
877881                None , 
878882            ) ; 
883+         self . suggest_copy_for_type_in_cloned_ref ( & mut  err,  place) ; 
879884        self . buffer_error ( err) ; 
880885    } 
881886
@@ -1214,10 +1219,104 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
12141219        ) ; 
12151220
12161221        self . suggest_using_local_if_applicable ( & mut  err,  location,  issued_borrow,  explanation) ; 
1222+         self . suggest_copy_for_type_in_cloned_ref ( & mut  err,  place) ; 
12171223
12181224        err
12191225    } 
12201226
1227+     fn  suggest_copy_for_type_in_cloned_ref ( & self ,  err :  & mut  Diag < ' tcx > ,  place :  Place < ' tcx > )  { 
1228+         let  tcx = self . infcx . tcx ; 
1229+         let  hir = tcx. hir ( ) ; 
1230+         let  Some ( body_id)  = tcx. hir_node ( self . mir_hir_id ( ) ) . body_id ( )  else  {  return  } ; 
1231+         struct  FindUselessClone < ' hir >  { 
1232+             pub  clones :  Vec < & ' hir  hir:: Expr < ' hir > > , 
1233+         } 
1234+         impl < ' hir >  FindUselessClone < ' hir >  { 
1235+             pub  fn  new ( )  -> Self  { 
1236+                 Self  {  clones :  vec ! [ ]  } 
1237+             } 
1238+         } 
1239+ 
1240+         impl < ' v >  Visitor < ' v >  for  FindUselessClone < ' v >  { 
1241+             fn  visit_expr ( & mut  self ,  ex :  & ' v  hir:: Expr < ' v > )  { 
1242+                 // FIXME: use `lookup_method_for_diagnostic`? 
1243+                 if  let  hir:: ExprKind :: MethodCall ( segment,  _rcvr,  args,  _span)  = ex. kind 
1244+                     && segment. ident . name  == sym:: clone
1245+                     && args. len ( )  == 0 
1246+                 { 
1247+                     self . clones . push ( ex) ; 
1248+                 } 
1249+                 hir:: intravisit:: walk_expr ( self ,  ex) ; 
1250+             } 
1251+         } 
1252+         let  mut  expr_finder = FindUselessClone :: new ( ) ; 
1253+ 
1254+         let  body = hir. body ( body_id) . value ; 
1255+         expr_finder. visit_expr ( body) ; 
1256+ 
1257+         pub  struct  Holds < ' tcx >  { 
1258+             ty :  Ty < ' tcx > , 
1259+             holds :  bool , 
1260+         } 
1261+ 
1262+         impl < ' tcx >  TypeVisitor < TyCtxt < ' tcx > >  for  Holds < ' tcx >  { 
1263+             type  Result  = std:: ops:: ControlFlow < ( ) > ; 
1264+ 
1265+             fn  visit_ty ( & mut  self ,  t :  Ty < ' tcx > )  -> Self :: Result  { 
1266+                 if  t == self . ty  { 
1267+                     self . holds  = true ; 
1268+                 } 
1269+                 t. super_visit_with ( self ) 
1270+             } 
1271+         } 
1272+ 
1273+         let  mut  types_to_constrain = FxIndexSet :: default ( ) ; 
1274+ 
1275+         let  local_ty = self . body . local_decls [ place. local ] . ty ; 
1276+         let  typeck_results = tcx. typeck ( self . mir_def_id ( ) ) ; 
1277+         let  clone = tcx. require_lang_item ( LangItem :: Clone ,  Some ( body. span ) ) ; 
1278+         for  expr in  expr_finder. clones  { 
1279+             if  let  hir:: ExprKind :: MethodCall ( _,  rcvr,  _,  span)  = expr. kind 
1280+                 && let  Some ( rcvr_ty)  = typeck_results. node_type_opt ( rcvr. hir_id ) 
1281+                 && let  Some ( ty)  = typeck_results. node_type_opt ( expr. hir_id ) 
1282+                 && rcvr_ty == ty
1283+                 && let  ty:: Ref ( _,  inner,  _)  = rcvr_ty. kind ( ) 
1284+                 && let  inner = inner. peel_refs ( ) 
1285+                 && let  mut  v = ( Holds  {  ty :  inner,  holds :  false  } ) 
1286+                 && let  _ = v. visit_ty ( local_ty) 
1287+                 && v. holds 
1288+                 && let  None  = self . infcx . type_implements_trait_shallow ( clone,  inner,  self . param_env ) 
1289+             { 
1290+                 err. span_label ( 
1291+                     span, 
1292+                     format ! ( 
1293+                         "this call doesn't do anything, the result is still `{rcvr_ty}` \  
1294+                               because `{inner}` doesn't implement `Clone`", 
1295+                     ) , 
1296+                 ) ; 
1297+                 types_to_constrain. insert ( inner) ; 
1298+             } 
1299+         } 
1300+         for  ty in  types_to_constrain { 
1301+             self . suggest_adding_bounds ( err,  ty,  clone,  body. span ) ; 
1302+             if  let  ty:: Adt ( ..)  = ty. kind ( )  { 
1303+                 // The type doesn't implement Clone. 
1304+                 let  trait_ref = ty:: Binder :: dummy ( ty:: TraitRef :: new ( self . infcx . tcx ,  clone,  [ ty] ) ) ; 
1305+                 let  obligation = Obligation :: new ( 
1306+                     self . infcx . tcx , 
1307+                     ObligationCause :: dummy ( ) , 
1308+                     self . param_env , 
1309+                     trait_ref, 
1310+                 ) ; 
1311+                 self . infcx . err_ctxt ( ) . suggest_derive ( 
1312+                     & obligation, 
1313+                     err, 
1314+                     trait_ref. to_predicate ( self . infcx . tcx ) , 
1315+                 ) ; 
1316+             } 
1317+         } 
1318+     } 
1319+ 
12211320    #[ instrument( level = "debug" ,  skip( self ,  err) ) ]  
12221321    fn  suggest_using_local_if_applicable ( 
12231322        & self , 
0 commit comments