@@ -987,17 +987,46 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
987987 else {
988988 return false ;
989989 } ;
990- let arg_node = self . tcx . hir_node ( * arg_hir_id) ;
991- let Node :: Expr ( Expr { kind : hir:: ExprKind :: Path ( _) , .. } ) = arg_node else {
992- return false ;
993- } ;
994990
995991 let clone_trait = self . tcx . require_lang_item ( LangItem :: Clone , None ) ;
996992 let has_clone = |ty| {
997993 self . type_implements_trait ( clone_trait, [ ty] , obligation. param_env )
998994 . must_apply_modulo_regions ( )
999995 } ;
1000996
997+ let existing_clone_call = match self . tcx . hir_node ( * arg_hir_id) {
998+ // It's just a variable. Propose cloning it.
999+ Node :: Expr ( Expr { kind : hir:: ExprKind :: Path ( _) , .. } ) => None ,
1000+ // It's already a call to `clone()`. We might be able to suggest
1001+ // adding a `+ Clone` bound, though.
1002+ Node :: Expr ( Expr {
1003+ kind :
1004+ hir:: ExprKind :: MethodCall (
1005+ hir:: PathSegment { ident, .. } ,
1006+ _receiver,
1007+ & [ ] ,
1008+ call_span,
1009+ ) ,
1010+ hir_id,
1011+ ..
1012+ } ) if ident. name == sym:: clone
1013+ && !call_span. from_expansion ( )
1014+ && !has_clone ( * inner_ty) =>
1015+ {
1016+ // We only care about method calls corresponding to the real `Clone` trait.
1017+ let Some ( typeck_results) = self . typeck_results . as_ref ( ) else { return false } ;
1018+ let Some ( ( DefKind :: AssocFn , did) ) = typeck_results. type_dependent_def ( * hir_id)
1019+ else {
1020+ return false ;
1021+ } ;
1022+ if self . tcx . trait_of_item ( did) != Some ( clone_trait) {
1023+ return false ;
1024+ }
1025+ Some ( ident. span )
1026+ }
1027+ _ => return false ,
1028+ } ;
1029+
10011030 let new_obligation = self . mk_trait_obligation_with_new_self_ty (
10021031 obligation. param_env ,
10031032 trait_pred. map_bound ( |trait_pred| ( trait_pred, * inner_ty) ) ,
@@ -1015,12 +1044,23 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
10151044 None ,
10161045 ) ;
10171046 }
1018- err. span_suggestion_verbose (
1019- obligation. cause . span . shrink_to_hi ( ) ,
1020- "consider using clone here" ,
1021- ".clone()" . to_string ( ) ,
1022- Applicability :: MaybeIncorrect ,
1023- ) ;
1047+ if let Some ( existing_clone_call) = existing_clone_call {
1048+ err. span_note (
1049+ existing_clone_call,
1050+ format ! (
1051+ "this `clone()` copies the reference, \
1052+ which does not do anything, \
1053+ because `{inner_ty}` does not implement `Clone`"
1054+ ) ,
1055+ ) ;
1056+ } else {
1057+ err. span_suggestion_verbose (
1058+ obligation. cause . span . shrink_to_hi ( ) ,
1059+ "consider using clone here" ,
1060+ ".clone()" . to_string ( ) ,
1061+ Applicability :: MaybeIncorrect ,
1062+ ) ;
1063+ }
10241064 return true ;
10251065 }
10261066 false
0 commit comments