@@ -3,6 +3,7 @@ use reexport::*;
3
3
use rustc:: lint:: * ;
4
4
use syntax:: codemap:: Span ;
5
5
use rustc_front:: visit:: { Visitor , walk_ty, walk_ty_param_bound} ;
6
+ use rustc:: middle:: def:: Def :: { DefTy , DefTrait } ;
6
7
use std:: collections:: HashSet ;
7
8
8
9
use utils:: { in_external_macro, span_lint} ;
@@ -53,16 +54,16 @@ use self::RefLt::*;
53
54
54
55
fn check_fn_inner ( cx : & LateContext , decl : & FnDecl , slf : Option < & ExplicitSelf > ,
55
56
generics : & Generics , span : Span ) {
56
- if in_external_macro ( cx, span) || has_where_lifetimes ( & generics. where_clause ) {
57
+ if in_external_macro ( cx, span) || has_where_lifetimes ( cx , & generics. where_clause ) {
57
58
return ;
58
59
}
59
- if could_use_elision ( decl, slf, & generics. lifetimes ) {
60
+ if could_use_elision ( cx , decl, slf, & generics. lifetimes ) {
60
61
span_lint ( cx, NEEDLESS_LIFETIMES , span,
61
62
"explicit lifetimes given in parameter types where they could be elided" ) ;
62
63
}
63
64
}
64
65
65
- fn could_use_elision ( func : & FnDecl , slf : Option < & ExplicitSelf > ,
66
+ fn could_use_elision ( cx : & LateContext , func : & FnDecl , slf : Option < & ExplicitSelf > ,
66
67
named_lts : & [ LifetimeDef ] ) -> bool {
67
68
// There are two scenarios where elision works:
68
69
// * no output references, all input references have different LT
@@ -74,8 +75,8 @@ fn could_use_elision(func: &FnDecl, slf: Option<&ExplicitSelf>,
74
75
let allowed_lts = allowed_lts_from ( named_lts) ;
75
76
76
77
// these will collect all the lifetimes for references in arg/return types
77
- let mut input_visitor = RefVisitor ( Vec :: new ( ) ) ;
78
- let mut output_visitor = RefVisitor ( Vec :: new ( ) ) ;
78
+ let mut input_visitor = RefVisitor :: new ( cx ) ;
79
+ let mut output_visitor = RefVisitor :: new ( cx ) ;
79
80
80
81
// extract lifetime in "self" argument for methods (there is a "self" argument
81
82
// in func.inputs, but its type is TyInfer)
@@ -88,14 +89,11 @@ fn could_use_elision(func: &FnDecl, slf: Option<&ExplicitSelf>,
88
89
}
89
90
// extract lifetimes in input argument types
90
91
for arg in & func. inputs {
91
- walk_ty ( & mut input_visitor, & arg. ty ) ;
92
- if let TyRptr ( None , _) = arg. ty . node {
93
- input_visitor. record ( & None ) ;
94
- }
92
+ input_visitor. visit_ty ( & arg. ty ) ;
95
93
}
96
94
// extract lifetimes in output type
97
95
if let Return ( ref ty) = func. output {
98
- walk_ty ( & mut output_visitor, ty) ;
96
+ output_visitor. visit_ty ( ty) ;
99
97
}
100
98
101
99
let input_lts = input_visitor. into_vec ( ) ;
@@ -159,52 +157,92 @@ fn unique_lifetimes(lts: &[RefLt]) -> usize {
159
157
}
160
158
161
159
/// A visitor usable for rustc_front::visit::walk_ty().
162
- struct RefVisitor ( Vec < RefLt > ) ;
160
+ struct RefVisitor < ' v , ' t : ' v > {
161
+ cx : & ' v LateContext < ' v , ' t > , // context reference
162
+ lts : Vec < RefLt >
163
+ }
164
+
165
+ impl < ' v , ' t > RefVisitor < ' v , ' t > {
166
+ fn new ( cx : & ' v LateContext < ' v , ' t > ) -> RefVisitor < ' v , ' t > {
167
+ RefVisitor { cx : cx, lts : Vec :: new ( ) }
168
+ }
163
169
164
- impl RefVisitor {
165
170
fn record ( & mut self , lifetime : & Option < Lifetime > ) {
166
171
if let & Some ( ref lt) = lifetime {
167
172
if lt. name . as_str ( ) == "'static" {
168
- self . 0 . push ( Static ) ;
173
+ self . lts . push ( Static ) ;
169
174
} else {
170
- self . 0 . push ( Named ( lt. name ) ) ;
175
+ self . lts . push ( Named ( lt. name ) ) ;
171
176
}
172
177
} else {
173
- self . 0 . push ( Unnamed ) ;
178
+ self . lts . push ( Unnamed ) ;
174
179
}
175
180
}
176
181
177
182
fn into_vec ( self ) -> Vec < RefLt > {
178
- self . 0
183
+ self . lts
184
+ }
185
+
186
+ fn collect_anonymous_lifetimes ( & mut self , path : & Path , ty : & Ty ) {
187
+ let last_path_segment = path. segments . last ( ) . map ( |s| & s. parameters ) ;
188
+ if let Some ( & AngleBracketedParameters ( ref params) ) = last_path_segment {
189
+ if params. lifetimes . is_empty ( ) {
190
+ let def = self . cx . tcx . def_map . borrow ( ) . get ( & ty. id ) . map ( |r| r. full_def ( ) ) ;
191
+ match def {
192
+ Some ( DefTy ( def_id, _) ) => {
193
+ if let Some ( ty_def) = self . cx . tcx . adt_defs . borrow ( ) . get ( & def_id) {
194
+ let scheme = ty_def. type_scheme ( self . cx . tcx ) ;
195
+ for _ in scheme. generics . regions . as_slice ( ) {
196
+ self . record ( & None ) ;
197
+ }
198
+ }
199
+ } ,
200
+ Some ( DefTrait ( def_id) ) => {
201
+ let trait_def = self . cx . tcx . trait_defs . borrow ( ) [ & def_id] ;
202
+ for _ in & trait_def. generics . regions {
203
+ self . record ( & None ) ;
204
+ }
205
+ } ,
206
+ _ => { }
207
+ }
208
+ }
209
+ }
179
210
}
180
211
}
181
212
182
- impl < ' v > Visitor < ' v > for RefVisitor {
213
+ impl < ' v , ' t > Visitor < ' v > for RefVisitor < ' v , ' t > {
214
+
183
215
// for lifetimes as parameters of generics
184
216
fn visit_lifetime ( & mut self , lifetime : & ' v Lifetime ) {
185
217
self . record ( & Some ( * lifetime) ) ;
186
218
}
187
219
188
220
fn visit_ty ( & mut self , ty : & ' v Ty ) {
189
- if let TyRptr ( None , _) = ty. node {
190
- self . record ( & None ) ;
221
+ match ty. node {
222
+ TyRptr ( None , _) => {
223
+ self . record ( & None ) ;
224
+ } ,
225
+ TyPath ( _, ref path) => {
226
+ self . collect_anonymous_lifetimes ( path, ty) ;
227
+ } ,
228
+ _ => { }
191
229
}
192
230
walk_ty ( self , ty) ;
193
231
}
194
232
}
195
233
196
234
/// Are any lifetimes mentioned in the `where` clause? If yes, we don't try to
197
235
/// reason about elision.
198
- fn has_where_lifetimes ( where_clause : & WhereClause ) -> bool {
236
+ fn has_where_lifetimes ( cx : & LateContext , where_clause : & WhereClause ) -> bool {
199
237
for predicate in & where_clause. predicates {
200
238
match * predicate {
201
239
WherePredicate :: RegionPredicate ( ..) => return true ,
202
240
WherePredicate :: BoundPredicate ( ref pred) => {
203
241
// a predicate like F: Trait or F: for<'a> Trait<'a>
204
- let mut visitor = RefVisitor ( Vec :: new ( ) ) ;
242
+ let mut visitor = RefVisitor :: new ( cx ) ;
205
243
// walk the type F, it may not contain LT refs
206
244
walk_ty ( & mut visitor, & pred. bounded_ty ) ;
207
- if !visitor. 0 . is_empty ( ) { return true ; }
245
+ if !visitor. lts . is_empty ( ) { return true ; }
208
246
// if the bounds define new lifetimes, they are fine to occur
209
247
let allowed_lts = allowed_lts_from ( & pred. bound_lifetimes ) ;
210
248
// now walk the bounds
@@ -219,9 +257,9 @@ fn has_where_lifetimes(where_clause: &WhereClause) -> bool {
219
257
}
220
258
}
221
259
WherePredicate :: EqPredicate ( ref pred) => {
222
- let mut visitor = RefVisitor ( Vec :: new ( ) ) ;
260
+ let mut visitor = RefVisitor :: new ( cx ) ;
223
261
walk_ty ( & mut visitor, & pred. ty ) ;
224
- if !visitor. 0 . is_empty ( ) { return true ; }
262
+ if !visitor. lts . is_empty ( ) { return true ; }
225
263
}
226
264
}
227
265
}
0 commit comments