5
5
//! used between functions, and they operate in a purely top-down
6
6
//! way. Therefore, we break lifetime name resolution into a separate pass.
7
7
8
+ use crate :: diagnostics:: {
9
+ add_missing_lifetime_specifiers_label, report_missing_lifetime_specifiers,
10
+ } ;
8
11
use rustc:: hir:: map:: Map ;
9
12
use rustc:: lint;
10
13
use rustc:: middle:: resolve_lifetime:: * ;
11
- use rustc:: session:: Session ;
12
14
use rustc:: ty:: { self , DefIdTree , GenericParamDefKind , TyCtxt } ;
13
15
use rustc:: { bug, span_bug} ;
14
16
use 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 } ;
16
18
use rustc_hir as hir;
17
19
use rustc_hir:: def:: { DefKind , Res } ;
18
20
use rustc_hir:: def_id:: { CrateNum , DefId , DefIdMap , LocalDefId , LOCAL_CRATE } ;
@@ -181,6 +183,10 @@ struct LifetimeContext<'a, 'tcx> {
181
183
xcrate_object_lifetime_defaults : DefIdMap < Vec < ObjectLifetimeDefault > > ,
182
184
183
185
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 > > ,
184
190
}
185
191
186
192
#[ derive( Debug ) ]
@@ -340,6 +346,7 @@ fn krate(tcx: TyCtxt<'_>) -> NamedRegionMap {
340
346
labels_in_fn : vec ! [ ] ,
341
347
xcrate_object_lifetime_defaults : Default :: default ( ) ,
342
348
lifetime_uses : & mut Default :: default ( ) ,
349
+ missing_named_lifetime_spots : vec ! [ ] ,
343
350
} ;
344
351
for ( _, item) in & krate. items {
345
352
visitor. visit_item ( item) ;
@@ -382,9 +389,11 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
382
389
fn visit_item ( & mut self , item : & ' tcx hir:: Item < ' tcx > ) {
383
390
match item. kind {
384
391
hir:: ItemKind :: Fn ( ref sig, ref generics, _) => {
392
+ self . missing_named_lifetime_spots . push ( generics) ;
385
393
self . visit_early_late ( None , & sig. decl , generics, |this| {
386
394
intravisit:: walk_item ( this, item) ;
387
395
} ) ;
396
+ self . missing_named_lifetime_spots . pop ( ) ;
388
397
}
389
398
390
399
hir:: ItemKind :: ExternCrate ( _)
@@ -415,6 +424,8 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
415
424
| hir:: ItemKind :: Trait ( _, _, ref generics, ..)
416
425
| hir:: ItemKind :: TraitAlias ( ref generics, ..)
417
426
| hir:: ItemKind :: Impl { ref generics, .. } => {
427
+ self . missing_named_lifetime_spots . push ( generics) ;
428
+
418
429
// Impls permit `'_` to be used and it is equivalent to "some fresh lifetime name".
419
430
// This is not true for other kinds of items.x
420
431
let track_lifetime_uses = match item. kind {
@@ -452,6 +463,7 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
452
463
this. check_lifetime_params ( old_scope, & generics. params ) ;
453
464
intravisit:: walk_item ( this, item) ;
454
465
} ) ;
466
+ self . missing_named_lifetime_spots . pop ( ) ;
455
467
}
456
468
}
457
469
}
@@ -684,6 +696,7 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
684
696
685
697
fn visit_trait_item ( & mut self , trait_item : & ' tcx hir:: TraitItem < ' tcx > ) {
686
698
use self :: hir:: TraitItemKind :: * ;
699
+ self . missing_named_lifetime_spots . push ( & trait_item. generics ) ;
687
700
match trait_item. kind {
688
701
Method ( ref sig, _) => {
689
702
let tcx = self . tcx ;
@@ -735,10 +748,12 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
735
748
intravisit:: walk_trait_item ( self , trait_item) ;
736
749
}
737
750
}
751
+ self . missing_named_lifetime_spots . pop ( ) ;
738
752
}
739
753
740
754
fn visit_impl_item ( & mut self , impl_item : & ' tcx hir:: ImplItem < ' tcx > ) {
741
755
use self :: hir:: ImplItemKind :: * ;
756
+ self . missing_named_lifetime_spots . push ( & impl_item. generics ) ;
742
757
match impl_item. kind {
743
758
Method ( ref sig, _) => {
744
759
let tcx = self . tcx ;
@@ -822,6 +837,7 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
822
837
intravisit:: walk_impl_item ( self , impl_item) ;
823
838
}
824
839
}
840
+ self . missing_named_lifetime_spots . pop ( ) ;
825
841
}
826
842
827
843
fn visit_lifetime ( & mut self , lifetime_ref : & ' tcx hir:: Lifetime ) {
@@ -1307,6 +1323,7 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
1307
1323
let LifetimeContext { tcx, map, lifetime_uses, .. } = self ;
1308
1324
let labels_in_fn = take ( & mut self . labels_in_fn ) ;
1309
1325
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 ) ;
1310
1327
let mut this = LifetimeContext {
1311
1328
tcx : * tcx,
1312
1329
map : map,
@@ -1315,14 +1332,16 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
1315
1332
is_in_fn_syntax : self . is_in_fn_syntax ,
1316
1333
labels_in_fn,
1317
1334
xcrate_object_lifetime_defaults,
1318
- lifetime_uses : lifetime_uses,
1335
+ lifetime_uses,
1336
+ missing_named_lifetime_spots,
1319
1337
} ;
1320
1338
debug ! ( "entering scope {:?}" , this. scope) ;
1321
1339
f ( self . scope , & mut this) ;
1322
1340
this. check_uses_for_lifetimes_defined_by_scope ( ) ;
1323
1341
debug ! ( "exiting scope {:?}" , this. scope) ;
1324
1342
self . labels_in_fn = this. labels_in_fn ;
1325
1343
self . xcrate_object_lifetime_defaults = this. xcrate_object_lifetime_defaults ;
1344
+ self . missing_named_lifetime_spots = this. missing_named_lifetime_spots ;
1326
1345
}
1327
1346
1328
1347
/// helper method to determine the span to remove when suggesting the
@@ -1805,15 +1824,29 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
1805
1824
1806
1825
self . insert_lifetime ( lifetime_ref, def) ;
1807
1826
} else {
1808
- struct_span_err ! (
1827
+ let mut err = struct_span_err ! (
1809
1828
self . tcx. sess,
1810
1829
lifetime_ref. span,
1811
1830
E0261 ,
1812
1831
"use of undeclared lifetime name `{}`" ,
1813
1832
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 ( ) ;
1817
1850
}
1818
1851
}
1819
1852
@@ -2367,6 +2400,7 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
2367
2400
lifetime_refs. len ( ) ,
2368
2401
& lifetime_names,
2369
2402
self . tcx . sess . source_map ( ) . span_to_snippet ( span) . ok ( ) . as_ref ( ) . map ( |s| s. as_str ( ) ) ,
2403
+ & self . missing_named_lifetime_spots ,
2370
2404
) ;
2371
2405
}
2372
2406
@@ -2862,34 +2896,3 @@ fn insert_late_bound_lifetimes(
2862
2896
}
2863
2897
}
2864
2898
}
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