8
8
9
9
use crate :: late:: diagnostics:: { ForLifetimeSpanType , MissingLifetimeSpot } ;
10
10
use rustc_ast:: walk_list;
11
- use rustc_data_structures:: fx:: { FxHashMap , FxHashSet } ;
11
+ use rustc_data_structures:: fx:: { FxHashMap , FxHashSet , FxIndexMap } ;
12
12
use rustc_errors:: { struct_span_err, Applicability , DiagnosticBuilder } ;
13
13
use rustc_hir as hir;
14
14
use rustc_hir:: def:: { DefKind , Res } ;
15
- use rustc_hir:: def_id:: DefIdMap ;
15
+ use rustc_hir:: def_id:: { DefIdMap , LocalDefId } ;
16
16
use rustc_hir:: hir_id:: ItemLocalId ;
17
17
use rustc_hir:: intravisit:: { self , NestedVisitorMap , Visitor } ;
18
18
use rustc_hir:: { GenericArg , GenericParam , LifetimeName , Node , ParamName , QPath } ;
@@ -22,7 +22,7 @@ use rustc_middle::middle::resolve_lifetime::*;
22
22
use rustc_middle:: ty:: { self , DefIdTree , GenericParamDefKind , TyCtxt } ;
23
23
use rustc_middle:: { bug, span_bug} ;
24
24
use rustc_session:: lint;
25
- use rustc_span:: def_id:: { DefId , LocalDefId } ;
25
+ use rustc_span:: def_id:: DefId ;
26
26
use rustc_span:: symbol:: { kw, sym, Ident , Symbol } ;
27
27
use rustc_span:: Span ;
28
28
use std:: borrow:: Cow ;
@@ -158,6 +158,9 @@ struct NamedRegionMap {
158
158
// - trait refs
159
159
// - bound types (like `T` in `for<'a> T<'a>: Foo`)
160
160
late_bound_vars : HirIdMap < Vec < ty:: BoundVariableKind > > ,
161
+
162
+ // maps `PathSegment` `HirId`s to lifetime scopes.
163
+ scope_for_path : Option < FxHashMap < LocalDefId , FxHashMap < ItemLocalId , LifetimeScopeForPath > > > ,
161
164
}
162
165
163
166
crate struct LifetimeContext < ' a , ' tcx > {
@@ -195,7 +198,9 @@ enum Scope<'a> {
195
198
/// it should be shifted by the number of `Binder`s in between the
196
199
/// declaration `Binder` and the location it's referenced from.
197
200
Binder {
198
- lifetimes : FxHashMap < hir:: ParamName , Region > ,
201
+ /// We use an IndexMap here because we want these lifetimes in order
202
+ /// for diagnostics.
203
+ lifetimes : FxIndexMap < hir:: ParamName , Region > ,
199
204
200
205
/// if we extend this scope with another scope, what is the next index
201
206
/// we should use for an early-bound region?
@@ -379,6 +384,10 @@ pub fn provide(providers: &mut ty::query::Providers) {
379
384
}
380
385
} ,
381
386
late_bound_vars_map : |tcx, id| resolve_lifetimes_for ( tcx, id) . late_bound_vars . get ( & id) ,
387
+ lifetime_scope_map : |tcx, id| {
388
+ let item_id = item_for ( tcx, id) ;
389
+ do_resolve ( tcx, item_id, false , true ) . scope_for_path . unwrap ( ) . remove ( & id)
390
+ } ,
382
391
383
392
..* providers
384
393
} ;
@@ -419,27 +428,29 @@ fn resolve_lifetimes_trait_definition(
419
428
tcx : TyCtxt < ' _ > ,
420
429
local_def_id : LocalDefId ,
421
430
) -> ResolveLifetimes {
422
- do_resolve ( tcx, local_def_id, true )
431
+ convert_named_region_map ( do_resolve ( tcx, local_def_id, true , false ) )
423
432
}
424
433
425
434
/// Computes the `ResolveLifetimes` map that contains data for an entire `Item`.
426
435
/// You should not read the result of this query directly, but rather use
427
436
/// `named_region_map`, `is_late_bound_map`, etc.
428
437
#[ tracing:: instrument( level = "debug" , skip( tcx) ) ]
429
438
fn resolve_lifetimes ( tcx : TyCtxt < ' _ > , local_def_id : LocalDefId ) -> ResolveLifetimes {
430
- do_resolve ( tcx, local_def_id, false )
439
+ convert_named_region_map ( do_resolve ( tcx, local_def_id, false , false ) )
431
440
}
432
441
433
442
fn do_resolve (
434
443
tcx : TyCtxt < ' _ > ,
435
444
local_def_id : LocalDefId ,
436
445
trait_definition_only : bool ,
437
- ) -> ResolveLifetimes {
446
+ with_scope_for_path : bool ,
447
+ ) -> NamedRegionMap {
438
448
let item = tcx. hir ( ) . expect_item ( tcx. hir ( ) . local_def_id_to_hir_id ( local_def_id) ) ;
439
449
let mut named_region_map = NamedRegionMap {
440
450
defs : Default :: default ( ) ,
441
451
late_bound : Default :: default ( ) ,
442
452
late_bound_vars : Default :: default ( ) ,
453
+ scope_for_path : with_scope_for_path. then ( || Default :: default ( ) ) ,
443
454
} ;
444
455
let mut visitor = LifetimeContext {
445
456
tcx,
@@ -455,6 +466,10 @@ fn do_resolve(
455
466
} ;
456
467
visitor. visit_item ( item) ;
457
468
469
+ named_region_map
470
+ }
471
+
472
+ fn convert_named_region_map ( named_region_map : NamedRegionMap ) -> ResolveLifetimes {
458
473
let mut rl = ResolveLifetimes :: default ( ) ;
459
474
460
475
for ( hir_id, v) in named_region_map. defs {
@@ -567,6 +582,41 @@ fn late_region_as_bound_region<'tcx>(tcx: TyCtxt<'tcx>, region: &Region) -> ty::
567
582
}
568
583
}
569
584
585
+ #[ tracing:: instrument( level = "debug" ) ]
586
+ fn get_lifetime_scopes_for_path ( mut scope : & Scope < ' _ > ) -> LifetimeScopeForPath {
587
+ let mut available_lifetimes = vec ! [ ] ;
588
+ loop {
589
+ match scope {
590
+ Scope :: Binder { lifetimes, s, .. } => {
591
+ available_lifetimes. extend ( lifetimes. keys ( ) . filter_map ( |p| match p {
592
+ hir:: ParamName :: Plain ( ident) => Some ( ident. name . to_string ( ) ) ,
593
+ _ => None ,
594
+ } ) ) ;
595
+ scope = s;
596
+ }
597
+ Scope :: Body { s, .. } => {
598
+ scope = s;
599
+ }
600
+ Scope :: Elision { elide, s } => {
601
+ if let Elide :: Exact ( _) = elide {
602
+ return LifetimeScopeForPath :: Elided ;
603
+ } else {
604
+ scope = s;
605
+ }
606
+ }
607
+ Scope :: ObjectLifetimeDefault { s, .. } => {
608
+ scope = s;
609
+ }
610
+ Scope :: Root => {
611
+ return LifetimeScopeForPath :: NonElided ( available_lifetimes) ;
612
+ }
613
+ Scope :: Supertrait { s, .. } | Scope :: TraitRefBoundary { s, .. } => {
614
+ scope = s;
615
+ }
616
+ }
617
+ }
618
+ }
619
+
570
620
impl < ' a , ' tcx > LifetimeContext < ' a , ' tcx > {
571
621
/// Returns the binders in scope and the type of `Binder` that should be created for a poly trait ref.
572
622
fn poly_trait_ref_binder_info ( & mut self ) -> ( Vec < ty:: BoundVariableKind > , BinderScopeType ) {
@@ -656,7 +706,7 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
656
706
self . map . late_bound_vars . insert ( hir_id, vec ! [ ] ) ;
657
707
let scope = Scope :: Binder {
658
708
hir_id,
659
- lifetimes : FxHashMap :: default ( ) ,
709
+ lifetimes : FxIndexMap :: default ( ) ,
660
710
next_early_index : self . next_early_index ( ) ,
661
711
s : self . scope ,
662
712
track_lifetime_uses : true ,
@@ -720,9 +770,7 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
720
770
// We need to add *all* deps, since opaque tys may want them from *us*
721
771
for ( & owner, defs) in resolved_lifetimes. defs . iter ( ) {
722
772
defs. iter ( ) . for_each ( |( & local_id, region) | {
723
- self . map
724
- . defs
725
- . insert ( hir:: HirId { owner, local_id } , region. clone ( ) ) ;
773
+ self . map . defs . insert ( hir:: HirId { owner, local_id } , * region) ;
726
774
} ) ;
727
775
}
728
776
for ( & owner, late_bound) in resolved_lifetimes. late_bound . iter ( ) {
@@ -836,7 +884,7 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
836
884
} ;
837
885
self . missing_named_lifetime_spots
838
886
. push ( MissingLifetimeSpot :: HigherRanked { span, span_type } ) ;
839
- let ( lifetimes, binders) : ( FxHashMap < hir:: ParamName , Region > , Vec < _ > ) = c
887
+ let ( lifetimes, binders) : ( FxIndexMap < hir:: ParamName , Region > , Vec < _ > ) = c
840
888
. generic_params
841
889
. iter ( )
842
890
. filter_map ( |param| match param. kind {
@@ -1010,7 +1058,7 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
1010
1058
debug ! ( ?index) ;
1011
1059
1012
1060
let mut elision = None ;
1013
- let mut lifetimes = FxHashMap :: default ( ) ;
1061
+ let mut lifetimes = FxIndexMap :: default ( ) ;
1014
1062
let mut non_lifetime_count = 0 ;
1015
1063
for param in generics. params {
1016
1064
match param. kind {
@@ -1181,7 +1229,7 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
1181
1229
let mut index = self . next_early_index ( ) ;
1182
1230
let mut non_lifetime_count = 0 ;
1183
1231
debug ! ( "visit_ty: index = {}" , index) ;
1184
- let lifetimes: FxHashMap < hir:: ParamName , Region > = generics
1232
+ let lifetimes: FxIndexMap < hir:: ParamName , Region > = generics
1185
1233
. params
1186
1234
. iter ( )
1187
1235
. filter_map ( |param| match param. kind {
@@ -1241,15 +1289,53 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
1241
1289
self . resolve_lifetime_ref ( lifetime_ref) ;
1242
1290
}
1243
1291
1292
+ fn visit_assoc_type_binding ( & mut self , type_binding : & ' tcx hir:: TypeBinding < ' _ > ) {
1293
+ let scope = self . scope ;
1294
+ if let Some ( scope_for_path) = self . map . scope_for_path . as_mut ( ) {
1295
+ // We add lifetime scope information for `Ident`s in associated type bindings and use
1296
+ // the `HirId` of the type binding as the key in `LifetimeMap`
1297
+ let lifetime_scope = get_lifetime_scopes_for_path ( scope) ;
1298
+ let map = scope_for_path. entry ( type_binding. hir_id . owner ) . or_default ( ) ;
1299
+ map. insert ( type_binding. hir_id . local_id , lifetime_scope) ;
1300
+ }
1301
+ hir:: intravisit:: walk_assoc_type_binding ( self , type_binding) ;
1302
+ }
1303
+
1244
1304
fn visit_path ( & mut self , path : & ' tcx hir:: Path < ' tcx > , _: hir:: HirId ) {
1245
1305
for ( i, segment) in path. segments . iter ( ) . enumerate ( ) {
1246
1306
let depth = path. segments . len ( ) - i - 1 ;
1247
1307
if let Some ( ref args) = segment. args {
1248
1308
self . visit_segment_args ( path. res , depth, args) ;
1249
1309
}
1310
+
1311
+ let scope = self . scope ;
1312
+ if let Some ( scope_for_path) = self . map . scope_for_path . as_mut ( ) {
1313
+ // Add lifetime scope information to path segment. Note we cannot call `visit_path_segment`
1314
+ // here because that call would yield to resolution problems due to `walk_path_segment`
1315
+ // being called, which processes the path segments generic args, which we have already
1316
+ // processed using `visit_segment_args`.
1317
+ let lifetime_scope = get_lifetime_scopes_for_path ( scope) ;
1318
+ if let Some ( hir_id) = segment. hir_id {
1319
+ let map = scope_for_path. entry ( hir_id. owner ) . or_default ( ) ;
1320
+ map. insert ( hir_id. local_id , lifetime_scope) ;
1321
+ }
1322
+ }
1250
1323
}
1251
1324
}
1252
1325
1326
+ fn visit_path_segment ( & mut self , path_span : Span , path_segment : & ' tcx hir:: PathSegment < ' tcx > ) {
1327
+ let scope = self . scope ;
1328
+ if let Some ( scope_for_path) = self . map . scope_for_path . as_mut ( ) {
1329
+ let lifetime_scope = get_lifetime_scopes_for_path ( scope) ;
1330
+ if let Some ( hir_id) = path_segment. hir_id {
1331
+ let map = scope_for_path. entry ( hir_id. owner ) . or_default ( ) ;
1332
+ map. insert ( hir_id. local_id , lifetime_scope) ;
1333
+ }
1334
+ }
1335
+
1336
+ intravisit:: walk_path_segment ( self , path_span, path_segment) ;
1337
+ }
1338
+
1253
1339
fn visit_fn_decl ( & mut self , fd : & ' tcx hir:: FnDecl < ' tcx > ) {
1254
1340
let output = match fd. output {
1255
1341
hir:: FnRetTy :: DefaultReturn ( _) => None ,
@@ -1290,7 +1376,7 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
1290
1376
ref bound_generic_params,
1291
1377
..
1292
1378
} ) => {
1293
- let ( lifetimes, binders) : ( FxHashMap < hir:: ParamName , Region > , Vec < _ > ) =
1379
+ let ( lifetimes, binders) : ( FxIndexMap < hir:: ParamName , Region > , Vec < _ > ) =
1294
1380
bound_generic_params
1295
1381
. iter ( )
1296
1382
. filter_map ( |param| match param. kind {
@@ -1360,7 +1446,7 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
1360
1446
self . map . late_bound_vars . insert ( * hir_id, binders) ;
1361
1447
let scope = Scope :: Binder {
1362
1448
hir_id : * hir_id,
1363
- lifetimes : FxHashMap :: default ( ) ,
1449
+ lifetimes : FxIndexMap :: default ( ) ,
1364
1450
s : self . scope ,
1365
1451
next_early_index : self . next_early_index ( ) ,
1366
1452
track_lifetime_uses : true ,
@@ -1388,7 +1474,7 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
1388
1474
let ( mut binders, scope_type) = self . poly_trait_ref_binder_info ( ) ;
1389
1475
1390
1476
let initial_bound_vars = binders. len ( ) as u32 ;
1391
- let mut lifetimes: FxHashMap < hir:: ParamName , Region > = FxHashMap :: default ( ) ;
1477
+ let mut lifetimes: FxIndexMap < hir:: ParamName , Region > = FxIndexMap :: default ( ) ;
1392
1478
let binders_iter = trait_ref
1393
1479
. bound_generic_params
1394
1480
. iter ( )
@@ -2115,7 +2201,7 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
2115
2201
2116
2202
let mut non_lifetime_count = 0 ;
2117
2203
let mut named_late_bound_vars = 0 ;
2118
- let lifetimes: FxHashMap < hir:: ParamName , Region > = generics
2204
+ let lifetimes: FxIndexMap < hir:: ParamName , Region > = generics
2119
2205
. params
2120
2206
. iter ( )
2121
2207
. filter_map ( |param| match param. kind {
@@ -3034,6 +3120,16 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
3034
3120
}
3035
3121
} ;
3036
3122
3123
+ // If we specifically need the `scope_for_path` map, then we're in the
3124
+ // diagnostic pass and we don't want to emit more errors.
3125
+ if self . map . scope_for_path . is_some ( ) {
3126
+ self . tcx . sess . delay_span_bug (
3127
+ rustc_span:: DUMMY_SP ,
3128
+ "Encountered unexpected errors during diagnostics related part" ,
3129
+ ) ;
3130
+ return ;
3131
+ }
3132
+
3037
3133
let mut spans: Vec < _ > = lifetime_refs. iter ( ) . map ( |lt| lt. span ) . collect ( ) ;
3038
3134
spans. sort ( ) ;
3039
3135
let mut spans_dedup = spans. clone ( ) ;
0 commit comments