@@ -2,8 +2,6 @@ use super::FnCtxt;
2
2
use crate :: astconv:: AstConv ;
3
3
4
4
use rustc_ast:: util:: parser:: ExprPrecedence ;
5
- use rustc_span:: { self , Span } ;
6
-
7
5
use rustc_errors:: { Applicability , Diagnostic , MultiSpan } ;
8
6
use rustc_hir as hir;
9
7
use rustc_hir:: def:: { CtorOf , DefKind } ;
@@ -13,12 +11,14 @@ use rustc_hir::{
13
11
WherePredicate ,
14
12
} ;
15
13
use rustc_infer:: infer:: { self , TyCtxtInferExt } ;
16
-
14
+ use rustc_infer :: traits ;
17
15
use 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 } ;
19
18
use rustc_span:: symbol:: { kw, sym} ;
19
+ use rustc_span:: Span ;
20
+ use rustc_trait_selection:: traits:: query:: evaluate_obligation:: InferCtxtExt ;
20
21
21
- use rustc_middle:: ty:: subst:: GenericArgKind ;
22
22
use std:: iter;
23
23
24
24
impl < ' a , ' tcx > FnCtxt < ' a , ' tcx > {
@@ -846,4 +846,53 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
846
846
let node = self . tcx . hir ( ) . get ( id) ;
847
847
matches ! ( node, Node :: Stmt ( Stmt { kind: StmtKind :: Local ( ..) , .. } ) )
848
848
}
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
+ }
849
898
}
0 commit comments