@@ -2,8 +2,6 @@ use super::FnCtxt;
22use crate :: astconv:: AstConv ;
33
44use rustc_ast:: util:: parser:: ExprPrecedence ;
5- use rustc_span:: { self , Span } ;
6-
75use rustc_errors:: { Applicability , Diagnostic , MultiSpan } ;
86use rustc_hir as hir;
97use rustc_hir:: def:: { CtorOf , DefKind } ;
@@ -13,12 +11,14 @@ use rustc_hir::{
1311 WherePredicate ,
1412} ;
1513use rustc_infer:: infer:: { self , TyCtxtInferExt } ;
16-
14+ use rustc_infer :: traits ;
1715use rustc_middle:: lint:: in_external_macro;
18- use rustc_middle:: ty:: { self , Binder , Ty } ;
16+ use rustc_middle:: ty:: subst:: GenericArgKind ;
17+ use rustc_middle:: ty:: { self , Binder , ToPredicate , Ty } ;
1918use rustc_span:: symbol:: { kw, sym} ;
19+ use rustc_span:: Span ;
20+ use rustc_trait_selection:: traits:: query:: evaluate_obligation:: InferCtxtExt ;
2021
21- use rustc_middle:: ty:: subst:: GenericArgKind ;
2222use std:: iter;
2323
2424impl < ' a , ' tcx > FnCtxt < ' a , ' tcx > {
@@ -846,4 +846,53 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
846846 let node = self . tcx . hir ( ) . get ( id) ;
847847 matches ! ( node, Node :: Stmt ( Stmt { kind: StmtKind :: Local ( ..) , .. } ) )
848848 }
849+
850+ /// Suggest that `&T` was cloned instead of `T` because `T` does not implement `Clone`,
851+ /// which is a side-effect of autoref.
852+ pub ( crate ) fn note_type_is_not_clone (
853+ & self ,
854+ diag : & mut Diagnostic ,
855+ expected_ty : Ty < ' tcx > ,
856+ found_ty : Ty < ' tcx > ,
857+ expr : & hir:: Expr < ' _ > ,
858+ ) {
859+ let hir:: ExprKind :: MethodCall ( segment, & [ ref callee_expr] , _) = expr. kind else { return ; } ;
860+ let Some ( clone_trait_did) = self . tcx . lang_items ( ) . clone_trait ( ) else { return ; } ;
861+ let ty:: Ref ( _, pointee_ty, _) = found_ty. kind ( ) else { return } ;
862+ let results = self . typeck_results . borrow ( ) ;
863+ // First, look for a `Clone::clone` call
864+ if segment. ident . name == sym:: clone
865+ && results. type_dependent_def_id ( expr. hir_id ) . map_or (
866+ false ,
867+ |did| {
868+ self . tcx . associated_item ( did) . container
869+ == ty:: AssocItemContainer :: TraitContainer ( clone_trait_did)
870+ } ,
871+ )
872+ // If that clone call hasn't already dereferenced the self type (i.e. don't give this
873+ // diagnostic in cases where we have `(&&T).clone()` and we expect `T`).
874+ && !results. expr_adjustments ( callee_expr) . iter ( ) . any ( |adj| matches ! ( adj. kind, ty:: adjustment:: Adjust :: Deref ( ..) ) )
875+ // Check that we're in fact trying to clone into the expected type
876+ && self . can_coerce ( * pointee_ty, expected_ty)
877+ // And the expected type doesn't implement `Clone`
878+ && !self . predicate_must_hold_considering_regions ( & traits:: Obligation {
879+ cause : traits:: ObligationCause :: dummy ( ) ,
880+ param_env : self . param_env ,
881+ recursion_depth : 0 ,
882+ predicate : ty:: Binder :: dummy ( ty:: TraitRef {
883+ def_id : clone_trait_did,
884+ substs : self . tcx . mk_substs ( [ expected_ty. into ( ) ] . iter ( ) ) ,
885+ } )
886+ . without_const ( )
887+ . to_predicate ( self . tcx ) ,
888+ } )
889+ {
890+ diag. span_note (
891+ callee_expr. span ,
892+ & format ! (
893+ "`{expected_ty}` does not implement `Clone`, so `{found_ty}` was cloned instead"
894+ ) ,
895+ ) ;
896+ }
897+ }
849898}
0 commit comments