@@ -202,143 +202,6 @@ fn check_fn_inner<'tcx>(
202
202
}
203
203
}
204
204
205
- /// Generate diagnostic messages for elidable lifetimes.
206
- fn report_elidable_lifetimes (
207
- cx : & LateContext < ' _ > ,
208
- generics : & Generics < ' _ > ,
209
- elidable_lts : & [ LocalDefId ] ,
210
- usages : & [ Lifetime ] ,
211
- include_suggestions : bool ,
212
- ) {
213
- let lts = elidable_lts
214
- . iter ( )
215
- // In principle, the result of the call to `Node::ident` could be `unwrap`ped, as `DefId` should refer to a
216
- // `Node::GenericParam`.
217
- . filter_map ( |& def_id| cx. tcx . hir_node_by_def_id ( def_id) . ident ( ) )
218
- . map ( |ident| ident. to_string ( ) )
219
- . collect :: < Vec < _ > > ( )
220
- . join ( ", " ) ;
221
-
222
- span_lint_and_then (
223
- cx,
224
- NEEDLESS_LIFETIMES ,
225
- elidable_lts
226
- . iter ( )
227
- . map ( |& lt| cx. tcx . def_span ( lt) )
228
- . chain ( usages. iter ( ) . filter_map ( |usage| {
229
- if let LifetimeName :: Param ( def_id) = usage. res
230
- && elidable_lts. contains ( & def_id)
231
- {
232
- return Some ( usage. ident . span ) ;
233
- }
234
-
235
- None
236
- } ) )
237
- . collect_vec ( ) ,
238
- format ! ( "the following explicit lifetimes could be elided: {lts}" ) ,
239
- |diag| {
240
- if !include_suggestions {
241
- return ;
242
- } ;
243
-
244
- if let Some ( suggestions) = elision_suggestions ( cx, generics, elidable_lts, usages) {
245
- diag. multipart_suggestion ( "elide the lifetimes" , suggestions, Applicability :: MachineApplicable ) ;
246
- }
247
- } ,
248
- ) ;
249
- }
250
-
251
- fn elision_suggestions (
252
- cx : & LateContext < ' _ > ,
253
- generics : & Generics < ' _ > ,
254
- elidable_lts : & [ LocalDefId ] ,
255
- usages : & [ Lifetime ] ,
256
- ) -> Option < Vec < ( Span , String ) > > {
257
- let explicit_params = generics
258
- . params
259
- . iter ( )
260
- . filter ( |param| !param. is_elided_lifetime ( ) && !param. is_impl_trait ( ) )
261
- . collect :: < Vec < _ > > ( ) ;
262
-
263
- let mut suggestions = if elidable_lts. len ( ) == explicit_params. len ( ) {
264
- // if all the params are elided remove the whole generic block
265
- //
266
- // fn x<'a>() {}
267
- // ^^^^
268
- vec ! [ ( generics. span, String :: new( ) ) ]
269
- } else {
270
- elidable_lts
271
- . iter ( )
272
- . map ( |& id| {
273
- let pos = explicit_params. iter ( ) . position ( |param| param. def_id == id) ?;
274
- let param = explicit_params. get ( pos) ?;
275
-
276
- let span = if let Some ( next) = explicit_params. get ( pos + 1 ) {
277
- // fn x<'prev, 'a, 'next>() {}
278
- // ^^^^
279
- param. span . until ( next. span )
280
- } else {
281
- // `pos` should be at least 1 here, because the param in position 0 would either have a `next`
282
- // param or would have taken the `elidable_lts.len() == explicit_params.len()` branch.
283
- let prev = explicit_params. get ( pos - 1 ) ?;
284
-
285
- // fn x<'prev, 'a>() {}
286
- // ^^^^
287
- param. span . with_lo ( prev. span . hi ( ) )
288
- } ;
289
-
290
- Some ( ( span, String :: new ( ) ) )
291
- } )
292
- . collect :: < Option < Vec < _ > > > ( ) ?
293
- } ;
294
-
295
- suggestions. extend (
296
- usages
297
- . iter ( )
298
- . filter ( |usage| named_lifetime ( usage) . map_or ( false , |id| elidable_lts. contains ( & id) ) )
299
- . map ( |usage| {
300
- match cx. tcx . parent_hir_node ( usage. hir_id ) {
301
- Node :: Ty ( Ty {
302
- kind : TyKind :: Ref ( ..) , ..
303
- } ) => {
304
- // expand `&'a T` to `&'a T`
305
- // ^^ ^^^
306
- let span = cx. sess ( ) . source_map ( ) . span_extend_while_whitespace ( usage. ident . span ) ;
307
-
308
- ( span, String :: new ( ) )
309
- } ,
310
- // `T<'a>` and `impl Foo + 'a` should be replaced by `'_`
311
- _ => ( usage. ident . span , String :: from ( "'_" ) ) ,
312
- }
313
- } ) ,
314
- ) ;
315
-
316
- Some ( suggestions)
317
- }
318
-
319
- // elision doesn't work for explicit self types, see rust-lang/rust#69064
320
- fn explicit_self_type < ' tcx > ( cx : & LateContext < ' tcx > , func : & FnDecl < ' tcx > , ident : Option < Ident > ) -> bool {
321
- if let Some ( ident) = ident
322
- && ident. name == kw:: SelfLower
323
- && !func. implicit_self . has_implicit_self ( )
324
- && let Some ( self_ty) = func. inputs . first ( )
325
- {
326
- let mut visitor = RefVisitor :: new ( cx) ;
327
- visitor. visit_ty ( self_ty) ;
328
-
329
- !visitor. all_lts ( ) . is_empty ( )
330
- } else {
331
- false
332
- }
333
- }
334
-
335
- fn named_lifetime ( lt : & Lifetime ) -> Option < LocalDefId > {
336
- match lt. res {
337
- LifetimeName :: Param ( id) if !lt. is_anonymous ( ) => Some ( id) ,
338
- _ => None ,
339
- }
340
- }
341
-
342
205
fn could_use_elision < ' tcx > (
343
206
cx : & LateContext < ' tcx > ,
344
207
func : & ' tcx FnDecl < ' _ > ,
@@ -461,6 +324,22 @@ fn allowed_lts_from(named_generics: &[GenericParam<'_>]) -> FxHashSet<LocalDefId
461
324
. collect ( )
462
325
}
463
326
327
+ // elision doesn't work for explicit self types, see rust-lang/rust#69064
328
+ fn explicit_self_type < ' tcx > ( cx : & LateContext < ' tcx > , func : & FnDecl < ' tcx > , ident : Option < Ident > ) -> bool {
329
+ if let Some ( ident) = ident
330
+ && ident. name == kw:: SelfLower
331
+ && !func. implicit_self . has_implicit_self ( )
332
+ && let Some ( self_ty) = func. inputs . first ( )
333
+ {
334
+ let mut visitor = RefVisitor :: new ( cx) ;
335
+ visitor. visit_ty ( self_ty) ;
336
+
337
+ !visitor. all_lts ( ) . is_empty ( )
338
+ } else {
339
+ false
340
+ }
341
+ }
342
+
464
343
/// Number of times each named lifetime occurs in the given slice. Returns a vector to preserve
465
344
/// relative order.
466
345
#[ must_use]
@@ -481,6 +360,13 @@ fn named_lifetime_occurrences(lts: &[Lifetime]) -> Vec<(LocalDefId, usize)> {
481
360
occurrences
482
361
}
483
362
363
+ fn named_lifetime ( lt : & Lifetime ) -> Option < LocalDefId > {
364
+ match lt. res {
365
+ LifetimeName :: Param ( id) if !lt. is_anonymous ( ) => Some ( id) ,
366
+ _ => None ,
367
+ }
368
+ }
369
+
484
370
struct RefVisitor < ' a , ' tcx > {
485
371
cx : & ' a LateContext < ' tcx > ,
486
372
lts : Vec < Lifetime > ,
@@ -781,6 +667,120 @@ fn report_elidable_impl_lifetimes<'tcx>(
781
667
report_elidable_lifetimes ( cx, impl_. generics , & elidable_lts, & usages, true ) ;
782
668
}
783
669
670
+ /// Generate diagnostic messages for elidable lifetimes.
671
+ fn report_elidable_lifetimes (
672
+ cx : & LateContext < ' _ > ,
673
+ generics : & Generics < ' _ > ,
674
+ elidable_lts : & [ LocalDefId ] ,
675
+ usages : & [ Lifetime ] ,
676
+ include_suggestions : bool ,
677
+ ) {
678
+ let lts = elidable_lts
679
+ . iter ( )
680
+ // In principle, the result of the call to `Node::ident` could be `unwrap`ped, as `DefId` should refer to a
681
+ // `Node::GenericParam`.
682
+ . filter_map ( |& def_id| cx. tcx . hir_node_by_def_id ( def_id) . ident ( ) )
683
+ . map ( |ident| ident. to_string ( ) )
684
+ . collect :: < Vec < _ > > ( )
685
+ . join ( ", " ) ;
686
+
687
+ span_lint_and_then (
688
+ cx,
689
+ NEEDLESS_LIFETIMES ,
690
+ elidable_lts
691
+ . iter ( )
692
+ . map ( |& lt| cx. tcx . def_span ( lt) )
693
+ . chain ( usages. iter ( ) . filter_map ( |usage| {
694
+ if let LifetimeName :: Param ( def_id) = usage. res
695
+ && elidable_lts. contains ( & def_id)
696
+ {
697
+ return Some ( usage. ident . span ) ;
698
+ }
699
+
700
+ None
701
+ } ) )
702
+ . collect_vec ( ) ,
703
+ format ! ( "the following explicit lifetimes could be elided: {lts}" ) ,
704
+ |diag| {
705
+ if !include_suggestions {
706
+ return ;
707
+ } ;
708
+
709
+ if let Some ( suggestions) = elision_suggestions ( cx, generics, elidable_lts, usages) {
710
+ diag. multipart_suggestion ( "elide the lifetimes" , suggestions, Applicability :: MachineApplicable ) ;
711
+ }
712
+ } ,
713
+ ) ;
714
+ }
715
+
716
+ fn elision_suggestions (
717
+ cx : & LateContext < ' _ > ,
718
+ generics : & Generics < ' _ > ,
719
+ elidable_lts : & [ LocalDefId ] ,
720
+ usages : & [ Lifetime ] ,
721
+ ) -> Option < Vec < ( Span , String ) > > {
722
+ let explicit_params = generics
723
+ . params
724
+ . iter ( )
725
+ . filter ( |param| !param. is_elided_lifetime ( ) && !param. is_impl_trait ( ) )
726
+ . collect :: < Vec < _ > > ( ) ;
727
+
728
+ let mut suggestions = if elidable_lts. len ( ) == explicit_params. len ( ) {
729
+ // if all the params are elided remove the whole generic block
730
+ //
731
+ // fn x<'a>() {}
732
+ // ^^^^
733
+ vec ! [ ( generics. span, String :: new( ) ) ]
734
+ } else {
735
+ elidable_lts
736
+ . iter ( )
737
+ . map ( |& id| {
738
+ let pos = explicit_params. iter ( ) . position ( |param| param. def_id == id) ?;
739
+ let param = explicit_params. get ( pos) ?;
740
+
741
+ let span = if let Some ( next) = explicit_params. get ( pos + 1 ) {
742
+ // fn x<'prev, 'a, 'next>() {}
743
+ // ^^^^
744
+ param. span . until ( next. span )
745
+ } else {
746
+ // `pos` should be at least 1 here, because the param in position 0 would either have a `next`
747
+ // param or would have taken the `elidable_lts.len() == explicit_params.len()` branch.
748
+ let prev = explicit_params. get ( pos - 1 ) ?;
749
+
750
+ // fn x<'prev, 'a>() {}
751
+ // ^^^^
752
+ param. span . with_lo ( prev. span . hi ( ) )
753
+ } ;
754
+
755
+ Some ( ( span, String :: new ( ) ) )
756
+ } )
757
+ . collect :: < Option < Vec < _ > > > ( ) ?
758
+ } ;
759
+
760
+ suggestions. extend (
761
+ usages
762
+ . iter ( )
763
+ . filter ( |usage| named_lifetime ( usage) . map_or ( false , |id| elidable_lts. contains ( & id) ) )
764
+ . map ( |usage| {
765
+ match cx. tcx . parent_hir_node ( usage. hir_id ) {
766
+ Node :: Ty ( Ty {
767
+ kind : TyKind :: Ref ( ..) , ..
768
+ } ) => {
769
+ // expand `&'a T` to `&'a T`
770
+ // ^^ ^^^
771
+ let span = cx. sess ( ) . source_map ( ) . span_extend_while_whitespace ( usage. ident . span ) ;
772
+
773
+ ( span, String :: new ( ) )
774
+ } ,
775
+ // `T<'a>` and `impl Foo + 'a` should be replaced by `'_`
776
+ _ => ( usage. ident . span , String :: from ( "'_" ) ) ,
777
+ }
778
+ } ) ,
779
+ ) ;
780
+
781
+ Some ( suggestions)
782
+ }
783
+
784
784
struct BodyLifetimeChecker ;
785
785
786
786
impl < ' tcx > Visitor < ' tcx > for BodyLifetimeChecker {
0 commit comments