55//! used between functions, and they operate in a purely top-down
66//! way. Therefore, we break lifetime name resolution into a separate pass.
77
8+ use crate :: diagnostics:: {
9+ add_missing_lifetime_specifiers_label, report_missing_lifetime_specifiers,
10+ } ;
811use rustc:: hir:: map:: Map ;
912use rustc:: lint;
1013use rustc:: middle:: resolve_lifetime:: * ;
11- use rustc:: session:: Session ;
1214use rustc:: ty:: { self , DefIdTree , GenericParamDefKind , TyCtxt } ;
1315use rustc:: { bug, span_bug} ;
1416use rustc_data_structures:: fx:: { FxHashMap , FxHashSet } ;
15- use rustc_errors:: { pluralize , struct_span_err, Applicability , DiagnosticBuilder } ;
17+ use rustc_errors:: { struct_span_err, Applicability , DiagnosticBuilder } ;
1618use rustc_hir as hir;
1719use rustc_hir:: def:: { DefKind , Res } ;
1820use rustc_hir:: def_id:: { CrateNum , DefId , DefIdMap , LocalDefId , LOCAL_CRATE } ;
@@ -181,6 +183,10 @@ struct LifetimeContext<'a, 'tcx> {
181183 xcrate_object_lifetime_defaults : DefIdMap < Vec < ObjectLifetimeDefault > > ,
182184
183185 lifetime_uses : & ' a mut DefIdMap < LifetimeUseSet < ' tcx > > ,
186+
187+ /// When encountering an undefined named lifetime, we will suggest introducing it in these
188+ /// places.
189+ missing_named_lifetime_spots : Vec < & ' tcx hir:: Generics < ' tcx > > ,
184190}
185191
186192#[ derive( Debug ) ]
@@ -340,6 +346,7 @@ fn krate(tcx: TyCtxt<'_>) -> NamedRegionMap {
340346 labels_in_fn : vec ! [ ] ,
341347 xcrate_object_lifetime_defaults : Default :: default ( ) ,
342348 lifetime_uses : & mut Default :: default ( ) ,
349+ missing_named_lifetime_spots : vec ! [ ] ,
343350 } ;
344351 for ( _, item) in & krate. items {
345352 visitor. visit_item ( item) ;
@@ -382,9 +389,11 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
382389 fn visit_item ( & mut self , item : & ' tcx hir:: Item < ' tcx > ) {
383390 match item. kind {
384391 hir:: ItemKind :: Fn ( ref sig, ref generics, _) => {
392+ self . missing_named_lifetime_spots . push ( generics) ;
385393 self . visit_early_late ( None , & sig. decl , generics, |this| {
386394 intravisit:: walk_item ( this, item) ;
387395 } ) ;
396+ self . missing_named_lifetime_spots . pop ( ) ;
388397 }
389398
390399 hir:: ItemKind :: ExternCrate ( _)
@@ -415,6 +424,8 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
415424 | hir:: ItemKind :: Trait ( _, _, ref generics, ..)
416425 | hir:: ItemKind :: TraitAlias ( ref generics, ..)
417426 | hir:: ItemKind :: Impl { ref generics, .. } => {
427+ self . missing_named_lifetime_spots . push ( generics) ;
428+
418429 // Impls permit `'_` to be used and it is equivalent to "some fresh lifetime name".
419430 // This is not true for other kinds of items.x
420431 let track_lifetime_uses = match item. kind {
@@ -452,6 +463,7 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
452463 this. check_lifetime_params ( old_scope, & generics. params ) ;
453464 intravisit:: walk_item ( this, item) ;
454465 } ) ;
466+ self . missing_named_lifetime_spots . pop ( ) ;
455467 }
456468 }
457469 }
@@ -684,6 +696,7 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
684696
685697 fn visit_trait_item ( & mut self , trait_item : & ' tcx hir:: TraitItem < ' tcx > ) {
686698 use self :: hir:: TraitItemKind :: * ;
699+ self . missing_named_lifetime_spots . push ( & trait_item. generics ) ;
687700 match trait_item. kind {
688701 Method ( ref sig, _) => {
689702 let tcx = self . tcx ;
@@ -735,10 +748,12 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
735748 intravisit:: walk_trait_item ( self , trait_item) ;
736749 }
737750 }
751+ self . missing_named_lifetime_spots . pop ( ) ;
738752 }
739753
740754 fn visit_impl_item ( & mut self , impl_item : & ' tcx hir:: ImplItem < ' tcx > ) {
741755 use self :: hir:: ImplItemKind :: * ;
756+ self . missing_named_lifetime_spots . push ( & impl_item. generics ) ;
742757 match impl_item. kind {
743758 Method ( ref sig, _) => {
744759 let tcx = self . tcx ;
@@ -822,6 +837,7 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
822837 intravisit:: walk_impl_item ( self , impl_item) ;
823838 }
824839 }
840+ self . missing_named_lifetime_spots . pop ( ) ;
825841 }
826842
827843 fn visit_lifetime ( & mut self , lifetime_ref : & ' tcx hir:: Lifetime ) {
@@ -1307,6 +1323,7 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
13071323 let LifetimeContext { tcx, map, lifetime_uses, .. } = self ;
13081324 let labels_in_fn = take ( & mut self . labels_in_fn ) ;
13091325 let xcrate_object_lifetime_defaults = take ( & mut self . xcrate_object_lifetime_defaults ) ;
1326+ let missing_named_lifetime_spots = take ( & mut self . missing_named_lifetime_spots ) ;
13101327 let mut this = LifetimeContext {
13111328 tcx : * tcx,
13121329 map : map,
@@ -1315,14 +1332,16 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
13151332 is_in_fn_syntax : self . is_in_fn_syntax ,
13161333 labels_in_fn,
13171334 xcrate_object_lifetime_defaults,
1318- lifetime_uses : lifetime_uses,
1335+ lifetime_uses,
1336+ missing_named_lifetime_spots,
13191337 } ;
13201338 debug ! ( "entering scope {:?}" , this. scope) ;
13211339 f ( self . scope , & mut this) ;
13221340 this. check_uses_for_lifetimes_defined_by_scope ( ) ;
13231341 debug ! ( "exiting scope {:?}" , this. scope) ;
13241342 self . labels_in_fn = this. labels_in_fn ;
13251343 self . xcrate_object_lifetime_defaults = this. xcrate_object_lifetime_defaults ;
1344+ self . missing_named_lifetime_spots = this. missing_named_lifetime_spots ;
13261345 }
13271346
13281347 /// helper method to determine the span to remove when suggesting the
@@ -1805,15 +1824,29 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
18051824
18061825 self . insert_lifetime ( lifetime_ref, def) ;
18071826 } else {
1808- struct_span_err ! (
1827+ let mut err = struct_span_err ! (
18091828 self . tcx. sess,
18101829 lifetime_ref. span,
18111830 E0261 ,
18121831 "use of undeclared lifetime name `{}`" ,
18131832 lifetime_ref
1814- )
1815- . span_label ( lifetime_ref. span , "undeclared lifetime" )
1816- . emit ( ) ;
1833+ ) ;
1834+ 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+ ) ;
1847+ }
1848+ }
1849+ err. emit ( ) ;
18171850 }
18181851 }
18191852
@@ -2367,6 +2400,7 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
23672400 lifetime_refs. len ( ) ,
23682401 & lifetime_names,
23692402 self . tcx . sess . source_map ( ) . span_to_snippet ( span) . ok ( ) . as_ref ( ) . map ( |s| s. as_str ( ) ) ,
2403+ & self . missing_named_lifetime_spots ,
23702404 ) ;
23712405 }
23722406
@@ -2862,34 +2896,3 @@ fn insert_late_bound_lifetimes(
28622896 }
28632897 }
28642898}
2865-
2866- fn report_missing_lifetime_specifiers (
2867- sess : & Session ,
2868- span : Span ,
2869- count : usize ,
2870- ) -> DiagnosticBuilder < ' _ > {
2871- struct_span_err ! ( sess, span, E0106 , "missing lifetime specifier{}" , pluralize!( count) )
2872- }
2873-
2874- fn add_missing_lifetime_specifiers_label (
2875- err : & mut DiagnosticBuilder < ' _ > ,
2876- span : Span ,
2877- count : usize ,
2878- lifetime_names : & FxHashSet < ast:: Ident > ,
2879- snippet : Option < & str > ,
2880- ) {
2881- if count > 1 {
2882- err. span_label ( span, format ! ( "expected {} lifetime parameters" , count) ) ;
2883- } else if let ( 1 , Some ( name) , Some ( "&" ) ) =
2884- ( lifetime_names. len ( ) , lifetime_names. iter ( ) . next ( ) , snippet)
2885- {
2886- err. span_suggestion (
2887- span,
2888- "consider using the named lifetime" ,
2889- format ! ( "&{} " , name) ,
2890- Applicability :: MaybeIncorrect ,
2891- ) ;
2892- } else {
2893- err. span_label ( span, "expected lifetime parameter" ) ;
2894- }
2895- }
0 commit comments