88
99use crate :: late:: diagnostics:: { ForLifetimeSpanType , MissingLifetimeSpot } ;
1010use rustc_ast:: walk_list;
11- use rustc_data_structures:: fx:: { FxHashMap , FxHashSet } ;
11+ use rustc_data_structures:: fx:: { FxHashMap , FxHashSet , FxIndexMap } ;
1212use rustc_errors:: { struct_span_err, Applicability , DiagnosticBuilder } ;
1313use rustc_hir as hir;
1414use rustc_hir:: def:: { DefKind , Res } ;
15- use rustc_hir:: def_id:: DefIdMap ;
15+ use rustc_hir:: def_id:: { DefIdMap , LocalDefId } ;
1616use rustc_hir:: hir_id:: ItemLocalId ;
1717use rustc_hir:: intravisit:: { self , NestedVisitorMap , Visitor } ;
1818use rustc_hir:: { GenericArg , GenericParam , LifetimeName , Node , ParamName , QPath } ;
@@ -22,7 +22,7 @@ use rustc_middle::middle::resolve_lifetime::*;
2222use rustc_middle:: ty:: { self , DefIdTree , GenericParamDefKind , TyCtxt } ;
2323use rustc_middle:: { bug, span_bug} ;
2424use rustc_session:: lint;
25- use rustc_span:: def_id:: { DefId , LocalDefId } ;
25+ use rustc_span:: def_id:: DefId ;
2626use rustc_span:: symbol:: { kw, sym, Ident , Symbol } ;
2727use rustc_span:: Span ;
2828use std:: borrow:: Cow ;
@@ -158,6 +158,9 @@ struct NamedRegionMap {
158158 // - trait refs
159159 // - bound types (like `T` in `for<'a> T<'a>: Foo`)
160160 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 > > > ,
161164}
162165
163166crate struct LifetimeContext < ' a , ' tcx > {
@@ -195,7 +198,9 @@ enum Scope<'a> {
195198 /// it should be shifted by the number of `Binder`s in between the
196199 /// declaration `Binder` and the location it's referenced from.
197200 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 > ,
199204
200205 /// if we extend this scope with another scope, what is the next index
201206 /// we should use for an early-bound region?
@@ -379,6 +384,10 @@ pub fn provide(providers: &mut ty::query::Providers) {
379384 }
380385 } ,
381386 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+ } ,
382391
383392 ..* providers
384393 } ;
@@ -419,27 +428,29 @@ fn resolve_lifetimes_trait_definition(
419428 tcx : TyCtxt < ' _ > ,
420429 local_def_id : LocalDefId ,
421430) -> ResolveLifetimes {
422- do_resolve ( tcx, local_def_id, true )
431+ convert_named_region_map ( do_resolve ( tcx, local_def_id, true , false ) )
423432}
424433
425434/// Computes the `ResolveLifetimes` map that contains data for an entire `Item`.
426435/// You should not read the result of this query directly, but rather use
427436/// `named_region_map`, `is_late_bound_map`, etc.
428437#[ tracing:: instrument( level = "debug" , skip( tcx) ) ]
429438fn 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 ) )
431440}
432441
433442fn do_resolve (
434443 tcx : TyCtxt < ' _ > ,
435444 local_def_id : LocalDefId ,
436445 trait_definition_only : bool ,
437- ) -> ResolveLifetimes {
446+ with_scope_for_path : bool ,
447+ ) -> NamedRegionMap {
438448 let item = tcx. hir ( ) . expect_item ( tcx. hir ( ) . local_def_id_to_hir_id ( local_def_id) ) ;
439449 let mut named_region_map = NamedRegionMap {
440450 defs : Default :: default ( ) ,
441451 late_bound : Default :: default ( ) ,
442452 late_bound_vars : Default :: default ( ) ,
453+ scope_for_path : with_scope_for_path. then ( || Default :: default ( ) ) ,
443454 } ;
444455 let mut visitor = LifetimeContext {
445456 tcx,
@@ -455,6 +466,10 @@ fn do_resolve(
455466 } ;
456467 visitor. visit_item ( item) ;
457468
469+ named_region_map
470+ }
471+
472+ fn convert_named_region_map ( named_region_map : NamedRegionMap ) -> ResolveLifetimes {
458473 let mut rl = ResolveLifetimes :: default ( ) ;
459474
460475 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::
567582 }
568583}
569584
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+
570620impl < ' a , ' tcx > LifetimeContext < ' a , ' tcx > {
571621 /// Returns the binders in scope and the type of `Binder` that should be created for a poly trait ref.
572622 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> {
656706 self . map . late_bound_vars . insert ( hir_id, vec ! [ ] ) ;
657707 let scope = Scope :: Binder {
658708 hir_id,
659- lifetimes : FxHashMap :: default ( ) ,
709+ lifetimes : FxIndexMap :: default ( ) ,
660710 next_early_index : self . next_early_index ( ) ,
661711 s : self . scope ,
662712 track_lifetime_uses : true ,
@@ -720,9 +770,7 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
720770 // We need to add *all* deps, since opaque tys may want them from *us*
721771 for ( & owner, defs) in resolved_lifetimes. defs . iter ( ) {
722772 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) ;
726774 } ) ;
727775 }
728776 for ( & owner, late_bound) in resolved_lifetimes. late_bound . iter ( ) {
@@ -836,7 +884,7 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
836884 } ;
837885 self . missing_named_lifetime_spots
838886 . 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
840888 . generic_params
841889 . iter ( )
842890 . filter_map ( |param| match param. kind {
@@ -1010,7 +1058,7 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
10101058 debug ! ( ?index) ;
10111059
10121060 let mut elision = None ;
1013- let mut lifetimes = FxHashMap :: default ( ) ;
1061+ let mut lifetimes = FxIndexMap :: default ( ) ;
10141062 let mut non_lifetime_count = 0 ;
10151063 for param in generics. params {
10161064 match param. kind {
@@ -1181,7 +1229,7 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
11811229 let mut index = self . next_early_index ( ) ;
11821230 let mut non_lifetime_count = 0 ;
11831231 debug ! ( "visit_ty: index = {}" , index) ;
1184- let lifetimes: FxHashMap < hir:: ParamName , Region > = generics
1232+ let lifetimes: FxIndexMap < hir:: ParamName , Region > = generics
11851233 . params
11861234 . iter ( )
11871235 . filter_map ( |param| match param. kind {
@@ -1241,15 +1289,53 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
12411289 self . resolve_lifetime_ref ( lifetime_ref) ;
12421290 }
12431291
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+
12441304 fn visit_path ( & mut self , path : & ' tcx hir:: Path < ' tcx > , _: hir:: HirId ) {
12451305 for ( i, segment) in path. segments . iter ( ) . enumerate ( ) {
12461306 let depth = path. segments . len ( ) - i - 1 ;
12471307 if let Some ( ref args) = segment. args {
12481308 self . visit_segment_args ( path. res , depth, args) ;
12491309 }
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+ }
12501323 }
12511324 }
12521325
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+
12531339 fn visit_fn_decl ( & mut self , fd : & ' tcx hir:: FnDecl < ' tcx > ) {
12541340 let output = match fd. output {
12551341 hir:: FnRetTy :: DefaultReturn ( _) => None ,
@@ -1290,7 +1376,7 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
12901376 ref bound_generic_params,
12911377 ..
12921378 } ) => {
1293- let ( lifetimes, binders) : ( FxHashMap < hir:: ParamName , Region > , Vec < _ > ) =
1379+ let ( lifetimes, binders) : ( FxIndexMap < hir:: ParamName , Region > , Vec < _ > ) =
12941380 bound_generic_params
12951381 . iter ( )
12961382 . filter_map ( |param| match param. kind {
@@ -1360,7 +1446,7 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
13601446 self . map . late_bound_vars . insert ( * hir_id, binders) ;
13611447 let scope = Scope :: Binder {
13621448 hir_id : * hir_id,
1363- lifetimes : FxHashMap :: default ( ) ,
1449+ lifetimes : FxIndexMap :: default ( ) ,
13641450 s : self . scope ,
13651451 next_early_index : self . next_early_index ( ) ,
13661452 track_lifetime_uses : true ,
@@ -1388,7 +1474,7 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
13881474 let ( mut binders, scope_type) = self . poly_trait_ref_binder_info ( ) ;
13891475
13901476 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 ( ) ;
13921478 let binders_iter = trait_ref
13931479 . bound_generic_params
13941480 . iter ( )
@@ -2115,7 +2201,7 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
21152201
21162202 let mut non_lifetime_count = 0 ;
21172203 let mut named_late_bound_vars = 0 ;
2118- let lifetimes: FxHashMap < hir:: ParamName , Region > = generics
2204+ let lifetimes: FxIndexMap < hir:: ParamName , Region > = generics
21192205 . params
21202206 . iter ( )
21212207 . filter_map ( |param| match param. kind {
@@ -3034,6 +3120,16 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
30343120 }
30353121 } ;
30363122
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+
30373133 let mut spans: Vec < _ > = lifetime_refs. iter ( ) . map ( |lt| lt. span ) . collect ( ) ;
30383134 spans. sort ( ) ;
30393135 let mut spans_dedup = spans. clone ( ) ;
0 commit comments