22
33use crate :: infer:: error_reporting:: nice_region_error:: NiceRegionError ;
44use crate :: infer:: lexical_region_resolve:: RegionResolutionError ;
5- use crate :: infer:: { Subtype , ValuePairs } ;
5+ use crate :: infer:: { Subtype , TyCtxtInferExt , ValuePairs } ;
66use crate :: traits:: ObligationCauseCode :: CompareImplMethodObligation ;
77use rustc_errors:: ErrorReported ;
8- use rustc_middle:: ty:: Ty ;
9- use rustc_span:: Span ;
8+ use rustc_hir as hir;
9+ use rustc_hir:: def:: Res ;
10+ use rustc_hir:: def_id:: DefId ;
11+ use rustc_hir:: intravisit:: Visitor ;
12+ use rustc_middle:: ty:: error:: ExpectedFound ;
13+ use rustc_middle:: ty:: { self , Ty , TyCtxt } ;
14+ use rustc_span:: { MultiSpan , Span } ;
1015
1116impl < ' a , ' tcx > NiceRegionError < ' a , ' tcx > {
1217 /// Print the error message for lifetime errors when the `impl` doesn't conform to the `trait`.
@@ -36,7 +41,7 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> {
3641 var_origin. span ( ) ,
3742 sub_expected_found. expected ,
3843 sub_expected_found. found ,
39- self . tcx ( ) . def_span ( * trait_item_def_id) ,
44+ * trait_item_def_id,
4045 ) ;
4146 return Some ( ErrorReported ) ;
4247 }
@@ -47,14 +52,100 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> {
4752 None
4853 }
4954
50- fn emit_err ( & self , sp : Span , expected : Ty < ' tcx > , found : Ty < ' tcx > , impl_sp : Span ) {
55+ fn emit_err ( & self , sp : Span , expected : Ty < ' tcx > , found : Ty < ' tcx > , trait_def_id : DefId ) {
56+ let tcx = self . tcx ( ) ;
57+ let trait_sp = self . tcx ( ) . def_span ( trait_def_id) ;
5158 let mut err = self
5259 . tcx ( )
5360 . sess
5461 . struct_span_err ( sp, "`impl` item signature doesn't match `trait` item signature" ) ;
55- err. note ( & format ! ( "expected `{:?}`\n found `{:?}`" , expected, found) ) ;
56- err. span_label ( sp, & format ! ( "found {:?}" , found) ) ;
57- err. span_label ( impl_sp, & format ! ( "expected {:?}" , expected) ) ;
62+ err. span_label ( sp, & format ! ( "found `{:?}`" , found) ) ;
63+ err. span_label ( trait_sp, & format ! ( "expected `{:?}`" , expected) ) ;
64+
65+ // Get the span of all the used type parameters in the method.
66+ let assoc_item = self . tcx ( ) . associated_item ( trait_def_id) ;
67+ let mut visitor = TypeParamSpanVisitor { tcx : self . tcx ( ) , types : vec ! [ ] } ;
68+ match assoc_item. kind {
69+ ty:: AssocKind :: Fn => {
70+ let hir = self . tcx ( ) . hir ( ) ;
71+ if let Some ( hir_id) = assoc_item. def_id . as_local ( ) . map ( |id| hir. as_local_hir_id ( id) )
72+ {
73+ if let Some ( decl) = hir. fn_decl_by_hir_id ( hir_id) {
74+ visitor. visit_fn_decl ( decl) ;
75+ }
76+ }
77+ }
78+ _ => { }
79+ }
80+ let mut type_param_span: MultiSpan =
81+ visitor. types . iter ( ) . cloned ( ) . collect :: < Vec < _ > > ( ) . into ( ) ;
82+ for & span in & visitor. types {
83+ type_param_span. push_span_label (
84+ span,
85+ "consider borrowing this type parameter in the trait" . to_string ( ) ,
86+ ) ;
87+ }
88+
89+ if let Some ( ( expected, found) ) = tcx
90+ . infer_ctxt ( )
91+ . enter ( |infcx| infcx. expected_found_str_ty ( & ExpectedFound { expected, found } ) )
92+ {
93+ // Highlighted the differences when showing the "expected/found" note.
94+ err. note_expected_found ( & "" , expected, & "" , found) ;
95+ } else {
96+ // This fallback shouldn't be necessary, but let's keep it in just in case.
97+ err. note ( & format ! ( "expected `{:?}`\n found `{:?}`" , expected, found) ) ;
98+ }
99+ err. span_help (
100+ type_param_span,
101+ "the lifetime requirements from the `impl` do not correspond to the requirements in \
102+ the `trait`",
103+ ) ;
104+ if visitor. types . is_empty ( ) {
105+ err. help (
106+ "verify the lifetime relationships in the `trait` and `impl` between the `self` \
107+ argument, the other inputs and its output",
108+ ) ;
109+ }
58110 err. emit ( ) ;
59111 }
60112}
113+
114+ struct TypeParamSpanVisitor < ' tcx > {
115+ tcx : TyCtxt < ' tcx > ,
116+ types : Vec < Span > ,
117+ }
118+
119+ impl Visitor < ' tcx > for TypeParamSpanVisitor < ' tcx > {
120+ type Map = rustc_middle:: hir:: map:: Map < ' tcx > ;
121+
122+ fn nested_visit_map ( & mut self ) -> hir:: intravisit:: NestedVisitorMap < Self :: Map > {
123+ hir:: intravisit:: NestedVisitorMap :: OnlyBodies ( self . tcx . hir ( ) )
124+ }
125+
126+ fn visit_ty ( & mut self , arg : & ' tcx hir:: Ty < ' tcx > ) {
127+ match arg. kind {
128+ hir:: TyKind :: Rptr ( _, ref mut_ty) => {
129+ // We don't want to suggest looking into borrowing `&T` or `&Self`.
130+ hir:: intravisit:: walk_ty ( self , mut_ty. ty ) ;
131+ return ;
132+ }
133+ hir:: TyKind :: Path ( hir:: QPath :: Resolved ( None , path) ) => match & path. segments {
134+ [ segment]
135+ if segment
136+ . res
137+ . map ( |res| match res {
138+ Res :: SelfTy ( _, _) | Res :: Def ( hir:: def:: DefKind :: TyParam , _) => true ,
139+ _ => false ,
140+ } )
141+ . unwrap_or ( false ) =>
142+ {
143+ self . types . push ( path. span ) ;
144+ }
145+ _ => { }
146+ } ,
147+ _ => { }
148+ }
149+ hir:: intravisit:: walk_ty ( self , arg) ;
150+ }
151+ }
0 commit comments