@@ -202,143 +202,6 @@ fn check_fn_inner<'tcx>(
202202 }
203203}
204204
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-
342205fn could_use_elision < ' tcx > (
343206 cx : & LateContext < ' tcx > ,
344207 func : & ' tcx FnDecl < ' _ > ,
@@ -461,6 +324,22 @@ fn allowed_lts_from(named_generics: &[GenericParam<'_>]) -> FxHashSet<LocalDefId
461324 . collect ( )
462325}
463326
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+
464343/// Number of times each named lifetime occurs in the given slice. Returns a vector to preserve
465344/// relative order.
466345#[ must_use]
@@ -481,6 +360,13 @@ fn named_lifetime_occurrences(lts: &[Lifetime]) -> Vec<(LocalDefId, usize)> {
481360 occurrences
482361}
483362
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+
484370struct RefVisitor < ' a , ' tcx > {
485371 cx : & ' a LateContext < ' tcx > ,
486372 lts : Vec < Lifetime > ,
@@ -781,6 +667,120 @@ fn report_elidable_impl_lifetimes<'tcx>(
781667 report_elidable_lifetimes ( cx, impl_. generics , & elidable_lts, & usages, true ) ;
782668}
783669
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+
784784struct BodyLifetimeChecker ;
785785
786786impl < ' tcx > Visitor < ' tcx > for BodyLifetimeChecker {
0 commit comments