@@ -153,6 +153,22 @@ struct NamedRegionMap {
153
153
object_lifetime_defaults : HirIdMap < Vec < ObjectLifetimeDefault > > ,
154
154
}
155
155
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
+
156
172
struct LifetimeContext < ' a , ' tcx > {
157
173
tcx : TyCtxt < ' tcx > ,
158
174
map : & ' a mut NamedRegionMap ,
@@ -186,7 +202,7 @@ struct LifetimeContext<'a, 'tcx> {
186
202
187
203
/// When encountering an undefined named lifetime, we will suggest introducing it in these
188
204
/// places.
189
- missing_named_lifetime_spots : Vec < & ' tcx hir :: Generics < ' tcx > > ,
205
+ missing_named_lifetime_spots : Vec < MissingLifetimeSpot < ' tcx > > ,
190
206
}
191
207
192
208
#[ derive( Debug ) ]
@@ -389,7 +405,7 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
389
405
fn visit_item ( & mut self , item : & ' tcx hir:: Item < ' tcx > ) {
390
406
match item. kind {
391
407
hir:: ItemKind :: Fn ( ref sig, ref generics, _) => {
392
- self . missing_named_lifetime_spots . push ( generics) ;
408
+ self . missing_named_lifetime_spots . push ( generics. into ( ) ) ;
393
409
self . visit_early_late ( None , & sig. decl , generics, |this| {
394
410
intravisit:: walk_item ( this, item) ;
395
411
} ) ;
@@ -424,7 +440,7 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
424
440
| hir:: ItemKind :: Trait ( _, _, ref generics, ..)
425
441
| hir:: ItemKind :: TraitAlias ( ref generics, ..)
426
442
| hir:: ItemKind :: Impl { ref generics, .. } => {
427
- self . missing_named_lifetime_spots . push ( generics) ;
443
+ self . missing_named_lifetime_spots . push ( generics. into ( ) ) ;
428
444
429
445
// Impls permit `'_` to be used and it is equivalent to "some fresh lifetime name".
430
446
// This is not true for other kinds of items.x
@@ -696,7 +712,7 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
696
712
697
713
fn visit_trait_item ( & mut self , trait_item : & ' tcx hir:: TraitItem < ' tcx > ) {
698
714
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 ( ) ) ;
700
716
match trait_item. kind {
701
717
Method ( ref sig, _) => {
702
718
let tcx = self . tcx ;
@@ -753,7 +769,7 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
753
769
754
770
fn visit_impl_item ( & mut self , impl_item : & ' tcx hir:: ImplItem < ' tcx > ) {
755
771
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 ( ) ) ;
757
773
match impl_item. kind {
758
774
Method ( ref sig, _) => {
759
775
let tcx = self . tcx ;
@@ -953,6 +969,7 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
953
969
) {
954
970
debug ! ( "visit_poly_trait_ref(trait_ref={:?})" , trait_ref) ;
955
971
972
+ let should_pop_missing_lt = self . is_trait_ref_fn_scope ( trait_ref) ;
956
973
if !self . trait_ref_hack
957
974
|| trait_ref. bound_generic_params . iter ( ) . any ( |param| match param. kind {
958
975
GenericParamKind :: Lifetime { .. } => true ,
@@ -988,10 +1005,13 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
988
1005
self . with ( scope, |old_scope, this| {
989
1006
this. check_lifetime_params ( old_scope, & trait_ref. bound_generic_params ) ;
990
1007
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 ) ;
992
1009
} )
993
1010
} 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 ( ) ;
995
1015
}
996
1016
}
997
1017
}
@@ -1832,18 +1852,41 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
1832
1852
lifetime_ref
1833
1853
) ;
1834
1854
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
+ }
1847
1890
}
1848
1891
}
1849
1892
err. emit ( ) ;
@@ -2441,6 +2484,7 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
2441
2484
2442
2485
let elided_len = elided_params. len ( ) ;
2443
2486
2487
+ // FIXME: collect spans of the input params when appropriate to use in the diagnostic.
2444
2488
for ( i, info) in elided_params. into_iter ( ) . enumerate ( ) {
2445
2489
let ElisionFailureInfo { parent, index, lifetime_count : n, have_bound_regions } = info;
2446
2490
@@ -2747,6 +2791,27 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
2747
2791
let old_value = self . map . defs . remove ( & lifetime_ref. hir_id ) ;
2748
2792
assert_eq ! ( old_value, Some ( bad_def) ) ;
2749
2793
}
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
+ }
2750
2815
}
2751
2816
2752
2817
/// Detects late-bound lifetimes and inserts them into
0 commit comments