@@ -987,17 +987,46 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
987
987
else {
988
988
return false ;
989
989
} ;
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
- } ;
994
990
995
991
let clone_trait = self . tcx . require_lang_item ( LangItem :: Clone , None ) ;
996
992
let has_clone = |ty| {
997
993
self . type_implements_trait ( clone_trait, [ ty] , obligation. param_env )
998
994
. must_apply_modulo_regions ( )
999
995
} ;
1000
996
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
+
1001
1030
let new_obligation = self . mk_trait_obligation_with_new_self_ty (
1002
1031
obligation. param_env ,
1003
1032
trait_pred. map_bound ( |trait_pred| ( trait_pred, * inner_ty) ) ,
@@ -1015,12 +1044,23 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
1015
1044
None ,
1016
1045
) ;
1017
1046
}
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
+ }
1024
1064
return true ;
1025
1065
}
1026
1066
false
0 commit comments