@@ -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+ , 
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