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_data_structures:: fx:: FxIndexSet ;
88use rustc_errors:: ErrorReported ;
9+ use rustc_hir as hir;
910use rustc_hir:: def_id:: DefId ;
11+ use rustc_hir:: intravisit:: Visitor ;
1012use rustc_hir:: ItemKind ;
1113use rustc_middle:: ty:: error:: ExpectedFound ;
1214use rustc_middle:: ty:: fold:: TypeFoldable ;
13- use rustc_middle:: ty:: { self , Ty } ;
15+ use rustc_middle:: ty:: { self , Ty , TyCtxt } ;
1416use rustc_span:: Span ;
1517
1618impl < ' a , ' tcx > NiceRegionError < ' a , ' tcx > {
@@ -59,8 +61,8 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> {
5961 . tcx ( )
6062 . sess
6163 . struct_span_err ( sp, "`impl` item signature doesn't match `trait` item signature" ) ;
62- err. span_label ( sp, & format ! ( "found {:?}" , found) ) ;
63- err. span_label ( trait_sp, & format ! ( "expected {:?}" , expected) ) ;
64+ err. span_label ( sp, & format ! ( "found ` {:?}` " , found) ) ;
65+ err. span_label ( trait_sp, & format ! ( "expected ` {:?}` " , expected) ) ;
6466 let trait_fn_sig = tcx. fn_sig ( trait_def_id) ;
6567
6668 // Check the `trait`'s method's output to look for type parameters that might have
@@ -73,7 +75,6 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> {
7375 struct AssocTypeFinder ( FxIndexSet < ty:: ParamTy > ) ;
7476 impl < ' tcx > ty:: fold:: TypeVisitor < ' tcx > for AssocTypeFinder {
7577 fn visit_ty ( & mut self , ty : Ty < ' tcx > ) -> bool {
76- debug ! ( "assoc type finder ty {:?} {:?}" , ty, ty. kind) ;
7778 if let ty:: Param ( param) = ty. kind {
7879 self . 0 . insert ( param) ;
7980 }
@@ -86,18 +87,40 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> {
8687 let parent_id = tcx. hir ( ) . get_parent_item ( id) ;
8788 let trait_item = tcx. hir ( ) . expect_item ( parent_id) ;
8889 if let ItemKind :: Trait ( _, _, generics, _, _) = & trait_item. kind {
89- for param_ty in visitor. 0 {
90+ for param_ty in & visitor. 0 {
9091 if let Some ( generic) = generics. get_named ( param_ty. name ) {
91- err. span_label ( generic . span , & format ! (
92- "for `impl` items to implement the method, this type parameter might \
93- need a lifetime restriction like `{}: 'a`" ,
94- param_ty . name ,
95- ) ) ;
92+ err. span_label (
93+ generic . span ,
94+ "this type parameter might not have a lifetime compatible with the \
95+ `impl`" ,
96+ ) ;
9697 }
9798 }
9899 }
99100 }
100101
102+ // Get the span of all the used type parameters in the method.
103+ let assoc_item = self . tcx ( ) . associated_item ( trait_def_id) ;
104+ let mut visitor = TypeParamSpanVisitor { tcx : self . tcx ( ) , types : vec ! [ ] } ;
105+ match assoc_item. kind {
106+ ty:: AssocKind :: Method => {
107+ let hir = self . tcx ( ) . hir ( ) ;
108+ if let Some ( hir_id) = hir. as_local_hir_id ( assoc_item. def_id ) {
109+ if let Some ( decl) = hir. fn_decl_by_hir_id ( hir_id) {
110+ visitor. visit_fn_decl ( decl) ;
111+ }
112+ }
113+ }
114+ _ => { }
115+ }
116+ for span in visitor. types {
117+ err. span_label (
118+ span,
119+ "you might want to borrow this type parameter in the trait to make it match the \
120+ `impl`",
121+ ) ;
122+ }
123+
101124 if let Some ( ( expected, found) ) = tcx
102125 . infer_ctxt ( )
103126 . enter ( |infcx| infcx. expected_found_str_ty ( & ExpectedFound { expected, found } ) )
@@ -116,3 +139,41 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> {
116139 err. emit ( ) ;
117140 }
118141}
142+
143+ struct TypeParamSpanVisitor < ' tcx > {
144+ tcx : TyCtxt < ' tcx > ,
145+ types : Vec < Span > ,
146+ }
147+
148+ impl Visitor < ' tcx > for TypeParamSpanVisitor < ' tcx > {
149+ type Map = hir:: intravisit:: Map < ' tcx > ;
150+
151+ fn nested_visit_map < ' this > (
152+ & ' this mut self ,
153+ ) -> hir:: intravisit:: NestedVisitorMap < ' this , Self :: Map > {
154+ hir:: intravisit:: NestedVisitorMap :: OnlyBodies ( & self . tcx . hir ( ) )
155+ }
156+
157+ fn visit_ty ( & mut self , arg : & ' tcx hir:: Ty < ' tcx > ) {
158+ match arg. kind {
159+ hir:: TyKind :: Slice ( _) | hir:: TyKind :: Tup ( _) | hir:: TyKind :: Array ( ..) => {
160+ hir:: intravisit:: walk_ty ( self , arg) ;
161+ }
162+ hir:: TyKind :: Path ( hir:: QPath :: Resolved ( None , path) ) => match & path. segments {
163+ [ segment]
164+ if segment
165+ . res
166+ . map ( |res| match res {
167+ hir:: def:: Res :: Def ( hir:: def:: DefKind :: TyParam , _) => true ,
168+ _ => false ,
169+ } )
170+ . unwrap_or ( false ) =>
171+ {
172+ self . types . push ( path. span ) ;
173+ }
174+ _ => { }
175+ } ,
176+ _ => { }
177+ }
178+ }
179+ }
0 commit comments