2
2
3
3
use crate :: infer:: error_reporting:: nice_region_error:: NiceRegionError ;
4
4
use crate :: infer:: lexical_region_resolve:: RegionResolutionError ;
5
- use crate :: infer:: { Subtype , ValuePairs } ;
5
+ use crate :: infer:: { Subtype , TyCtxtInferExt , ValuePairs } ;
6
6
use crate :: traits:: ObligationCauseCode :: CompareImplMethodObligation ;
7
7
use rustc_data_structures:: fx:: FxIndexSet ;
8
8
use rustc_errors:: ErrorReported ;
9
+ use rustc_hir as hir;
9
10
use rustc_hir:: def_id:: DefId ;
11
+ use rustc_hir:: intravisit:: Visitor ;
10
12
use rustc_hir:: ItemKind ;
11
13
use rustc_middle:: ty:: error:: ExpectedFound ;
12
14
use rustc_middle:: ty:: fold:: TypeFoldable ;
13
- use rustc_middle:: ty:: { self , Ty } ;
15
+ use rustc_middle:: ty:: { self , Ty , TyCtxt } ;
14
16
use rustc_span:: Span ;
15
17
16
18
impl < ' a , ' tcx > NiceRegionError < ' a , ' tcx > {
@@ -59,8 +61,8 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> {
59
61
. tcx ( )
60
62
. sess
61
63
. 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) ) ;
64
66
let trait_fn_sig = tcx. fn_sig ( trait_def_id) ;
65
67
66
68
// 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> {
73
75
struct AssocTypeFinder ( FxIndexSet < ty:: ParamTy > ) ;
74
76
impl < ' tcx > ty:: fold:: TypeVisitor < ' tcx > for AssocTypeFinder {
75
77
fn visit_ty ( & mut self , ty : Ty < ' tcx > ) -> bool {
76
- debug ! ( "assoc type finder ty {:?} {:?}" , ty, ty. kind) ;
77
78
if let ty:: Param ( param) = ty. kind {
78
79
self . 0 . insert ( param) ;
79
80
}
@@ -86,18 +87,40 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> {
86
87
let parent_id = tcx. hir ( ) . get_parent_item ( id) ;
87
88
let trait_item = tcx. hir ( ) . expect_item ( parent_id) ;
88
89
if let ItemKind :: Trait ( _, _, generics, _, _) = & trait_item. kind {
89
- for param_ty in visitor. 0 {
90
+ for param_ty in & visitor. 0 {
90
91
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
+ ) ;
96
97
}
97
98
}
98
99
}
99
100
}
100
101
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
+
101
124
if let Some ( ( expected, found) ) = tcx
102
125
. infer_ctxt ( )
103
126
. enter ( |infcx| infcx. expected_found_str_ty ( & ExpectedFound { expected, found } ) )
@@ -116,3 +139,41 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> {
116
139
err. emit ( ) ;
117
140
}
118
141
}
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