@@ -153,6 +153,22 @@ struct NamedRegionMap {
153153 object_lifetime_defaults : HirIdMap < Vec < ObjectLifetimeDefault > > ,
154154}
155155
156+ crate enum MissingLifetimeSpot < ' tcx > {
157+ Generics ( & ' tcx hir:: Generics < ' tcx > ) ,
158+ HRLT { span : Span , span_type : HRLTSpanType } ,
159+ }
160+
161+ crate enum HRLTSpanType {
162+ Empty ,
163+ Tail ,
164+ }
165+
166+ impl < ' tcx > Into < MissingLifetimeSpot < ' tcx > > for & ' tcx hir:: Generics < ' tcx > {
167+ fn into ( self ) -> MissingLifetimeSpot < ' tcx > {
168+ MissingLifetimeSpot :: Generics ( self )
169+ }
170+ }
171+
156172struct LifetimeContext < ' a , ' tcx > {
157173 tcx : TyCtxt < ' tcx > ,
158174 map : & ' a mut NamedRegionMap ,
@@ -186,7 +202,7 @@ struct LifetimeContext<'a, 'tcx> {
186202
187203 /// When encountering an undefined named lifetime, we will suggest introducing it in these
188204 /// places.
189- missing_named_lifetime_spots : Vec < & ' tcx hir :: Generics < ' tcx > > ,
205+ missing_named_lifetime_spots : Vec < MissingLifetimeSpot < ' tcx > > ,
190206}
191207
192208#[ derive( Debug ) ]
@@ -389,7 +405,7 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
389405 fn visit_item ( & mut self , item : & ' tcx hir:: Item < ' tcx > ) {
390406 match item. kind {
391407 hir:: ItemKind :: Fn ( ref sig, ref generics, _) => {
392- self . missing_named_lifetime_spots . push ( generics) ;
408+ self . missing_named_lifetime_spots . push ( generics. into ( ) ) ;
393409 self . visit_early_late ( None , & sig. decl , generics, |this| {
394410 intravisit:: walk_item ( this, item) ;
395411 } ) ;
@@ -424,7 +440,7 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
424440 | hir:: ItemKind :: Trait ( _, _, ref generics, ..)
425441 | hir:: ItemKind :: TraitAlias ( ref generics, ..)
426442 | hir:: ItemKind :: Impl { ref generics, .. } => {
427- self . missing_named_lifetime_spots . push ( generics) ;
443+ self . missing_named_lifetime_spots . push ( generics. into ( ) ) ;
428444
429445 // Impls permit `'_` to be used and it is equivalent to "some fresh lifetime name".
430446 // This is not true for other kinds of items.x
@@ -696,7 +712,7 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
696712
697713 fn visit_trait_item ( & mut self , trait_item : & ' tcx hir:: TraitItem < ' tcx > ) {
698714 use self :: hir:: TraitItemKind :: * ;
699- self . missing_named_lifetime_spots . push ( & trait_item. generics ) ;
715+ self . missing_named_lifetime_spots . push ( ( & trait_item. generics ) . into ( ) ) ;
700716 match trait_item. kind {
701717 Method ( ref sig, _) => {
702718 let tcx = self . tcx ;
@@ -753,7 +769,7 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
753769
754770 fn visit_impl_item ( & mut self , impl_item : & ' tcx hir:: ImplItem < ' tcx > ) {
755771 use self :: hir:: ImplItemKind :: * ;
756- self . missing_named_lifetime_spots . push ( & impl_item. generics ) ;
772+ self . missing_named_lifetime_spots . push ( ( & impl_item. generics ) . into ( ) ) ;
757773 match impl_item. kind {
758774 Method ( ref sig, _) => {
759775 let tcx = self . tcx ;
@@ -953,6 +969,7 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
953969 ) {
954970 debug ! ( "visit_poly_trait_ref(trait_ref={:?})" , trait_ref) ;
955971
972+ let should_pop_missing_lt = self . is_trait_ref_fn_scope ( trait_ref) ;
956973 if !self . trait_ref_hack
957974 || trait_ref. bound_generic_params . iter ( ) . any ( |param| match param. kind {
958975 GenericParamKind :: Lifetime { .. } => true ,
@@ -988,10 +1005,13 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
9881005 self . with ( scope, |old_scope, this| {
9891006 this. check_lifetime_params ( old_scope, & trait_ref. bound_generic_params ) ;
9901007 walk_list ! ( this, visit_generic_param, trait_ref. bound_generic_params) ;
991- this. visit_trait_ref ( & trait_ref. trait_ref )
1008+ this. visit_trait_ref ( & trait_ref. trait_ref ) ;
9921009 } )
9931010 } else {
994- self . visit_trait_ref ( & trait_ref. trait_ref )
1011+ self . visit_trait_ref ( & trait_ref. trait_ref ) ;
1012+ }
1013+ if should_pop_missing_lt {
1014+ self . missing_named_lifetime_spots . pop ( ) ;
9951015 }
9961016 }
9971017}
@@ -1832,18 +1852,41 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
18321852 lifetime_ref
18331853 ) ;
18341854 err. span_label ( lifetime_ref. span , "undeclared lifetime" ) ;
1835- if !self . is_in_fn_syntax {
1836- for generics in & self . missing_named_lifetime_spots {
1837- let ( span, sugg) = match & generics. params {
1838- [ ] => ( generics. span , format ! ( "<{}>" , lifetime_ref) ) ,
1839- [ param, ..] => ( param. span . shrink_to_lo ( ) , format ! ( "{}, " , lifetime_ref) ) ,
1840- } ;
1841- err. span_suggestion (
1842- span,
1843- & format ! ( "consider introducing lifetime `{}` here" , lifetime_ref) ,
1844- sugg,
1845- Applicability :: MaybeIncorrect ,
1846- ) ;
1855+ for missing in & self . missing_named_lifetime_spots {
1856+ match missing {
1857+ MissingLifetimeSpot :: Generics ( generics) => {
1858+ let ( span, sugg) = match & generics. params {
1859+ [ ] => ( generics. span , format ! ( "<{}>" , lifetime_ref) ) ,
1860+ [ param, ..] => {
1861+ ( param. span . shrink_to_lo ( ) , format ! ( "{}, " , lifetime_ref) )
1862+ }
1863+ } ;
1864+ err. span_suggestion (
1865+ span,
1866+ & format ! ( "consider introducing lifetime `{}` here" , lifetime_ref) ,
1867+ sugg,
1868+ Applicability :: MaybeIncorrect ,
1869+ ) ;
1870+ }
1871+ MissingLifetimeSpot :: HRLT { span, span_type } => {
1872+ err. span_suggestion (
1873+ * span,
1874+ & format ! (
1875+ "consider introducing a Higher-Ranked lifetime `{}` here" ,
1876+ lifetime_ref
1877+ ) ,
1878+ match span_type {
1879+ HRLTSpanType :: Empty => format ! ( "for<{}> " , lifetime_ref) ,
1880+ HRLTSpanType :: Tail => format ! ( ", {}" , lifetime_ref) ,
1881+ }
1882+ . to_string ( ) ,
1883+ Applicability :: MaybeIncorrect ,
1884+ ) ;
1885+ err. note (
1886+ "for more information on Higher-Ranked lifetimes, visit \
1887+ https://doc.rust-lang.org/nomicon/hrtb.html",
1888+ ) ;
1889+ }
18471890 }
18481891 }
18491892 err. emit ( ) ;
@@ -2441,6 +2484,7 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
24412484
24422485 let elided_len = elided_params. len ( ) ;
24432486
2487+ // FIXME: collect spans of the input params when appropriate to use in the diagnostic.
24442488 for ( i, info) in elided_params. into_iter ( ) . enumerate ( ) {
24452489 let ElisionFailureInfo { parent, index, lifetime_count : n, have_bound_regions } = info;
24462490
@@ -2747,6 +2791,27 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
27472791 let old_value = self . map . defs . remove ( & lifetime_ref. hir_id ) ;
27482792 assert_eq ! ( old_value, Some ( bad_def) ) ;
27492793 }
2794+
2795+ fn is_trait_ref_fn_scope ( & mut self , trait_ref : & ' tcx hir:: PolyTraitRef < ' tcx > ) -> bool {
2796+ if let Res :: Def ( _, did) = trait_ref. trait_ref . path . res {
2797+ if [
2798+ self . tcx . lang_items ( ) . fn_once_trait ( ) ,
2799+ self . tcx . lang_items ( ) . fn_trait ( ) ,
2800+ self . tcx . lang_items ( ) . fn_mut_trait ( ) ,
2801+ ]
2802+ . contains ( & Some ( did) )
2803+ {
2804+ let ( span, span_type) = match & trait_ref. bound_generic_params {
2805+ [ ] => ( trait_ref. span . shrink_to_lo ( ) , HRLTSpanType :: Empty ) ,
2806+ [ .., bound] => ( bound. span . shrink_to_hi ( ) , HRLTSpanType :: Tail ) ,
2807+ } ;
2808+ self . missing_named_lifetime_spots
2809+ . push ( MissingLifetimeSpot :: HRLT { span, span_type } ) ;
2810+ return true ;
2811+ }
2812+ } ;
2813+ false
2814+ }
27502815}
27512816
27522817/// Detects late-bound lifetimes and inserts them into
0 commit comments