Skip to content

Commit 44c10e4

Browse files
committed
Resolve lifetimes independently for each item-like.
1 parent 0ff1d1e commit 44c10e4

File tree

2 files changed

+67
-187
lines changed

2 files changed

+67
-187
lines changed

compiler/rustc_hir_analysis/src/collect/lifetimes.rs

+66-177
Original file line numberDiff line numberDiff line change
@@ -94,11 +94,6 @@ struct LifetimeContext<'a, 'tcx> {
9494
tcx: TyCtxt<'tcx>,
9595
map: &'a mut NamedRegionMap,
9696
scope: ScopeRef<'a>,
97-
98-
/// Indicates that we only care about the definition of a trait. This should
99-
/// be false if the `Item` we are resolving lifetimes for is not a trait or
100-
/// we eventually need lifetimes resolve for trait items.
101-
trait_definition_only: bool,
10297
}
10398

10499
#[derive(Debug)]
@@ -166,7 +161,9 @@ enum Scope<'a> {
166161
s: ScopeRef<'a>,
167162
},
168163

169-
Root,
164+
Root {
165+
opt_parent_item: Option<LocalDefId>,
166+
},
170167
}
171168

172169
#[derive(Copy, Clone, Debug)]
@@ -214,95 +211,58 @@ impl<'a> fmt::Debug for TruncatedScopeDebug<'a> {
214211
.field("s", &"..")
215212
.finish(),
216213
Scope::TraitRefBoundary { s: _ } => f.debug_struct("TraitRefBoundary").finish(),
217-
Scope::Root => f.debug_struct("Root").finish(),
214+
Scope::Root { opt_parent_item } => {
215+
f.debug_struct("Root").field("opt_parent_item", &opt_parent_item).finish()
216+
}
218217
}
219218
}
220219
}
221220

222221
type ScopeRef<'a> = &'a Scope<'a>;
223222

224-
const ROOT_SCOPE: ScopeRef<'static> = &Scope::Root;
225-
226223
pub(crate) fn provide(providers: &mut ty::query::Providers) {
227224
*providers = ty::query::Providers {
228-
resolve_lifetimes_trait_definition,
229225
resolve_lifetimes,
230226

231-
named_region_map: |tcx, id| resolve_lifetimes_for(tcx, id).defs.get(&id),
227+
named_region_map: |tcx, id| tcx.resolve_lifetimes(id).defs.get(&id),
232228
is_late_bound_map,
233229
object_lifetime_default,
234-
late_bound_vars_map: |tcx, id| resolve_lifetimes_for(tcx, id).late_bound_vars.get(&id),
230+
late_bound_vars_map: |tcx, id| tcx.resolve_lifetimes(id).late_bound_vars.get(&id),
235231

236232
..*providers
237233
};
238234
}
239235

240-
/// Like `resolve_lifetimes`, but does not resolve lifetimes for trait items.
241-
/// Also does not generate any diagnostics.
242-
///
243-
/// This is ultimately a subset of the `resolve_lifetimes` work. It effectively
244-
/// resolves lifetimes only within the trait "header" -- that is, the trait
245-
/// and supertrait list. In contrast, `resolve_lifetimes` resolves all the
246-
/// lifetimes within the trait and its items. There is room to refactor this,
247-
/// for example to resolve lifetimes for each trait item in separate queries,
248-
/// but it's convenient to do the entire trait at once because the lifetimes
249-
/// from the trait definition are in scope within the trait items as well.
250-
///
251-
/// The reason for this separate call is to resolve what would otherwise
252-
/// be a cycle. Consider this example:
253-
///
254-
/// ```ignore UNSOLVED (maybe @jackh726 knows what lifetime parameter to give Sub)
255-
/// trait Base<'a> {
256-
/// type BaseItem;
257-
/// }
258-
/// trait Sub<'b>: for<'a> Base<'a> {
259-
/// type SubItem: Sub<BaseItem = &'b u32>;
260-
/// }
261-
/// ```
262-
///
263-
/// When we resolve `Sub` and all its items, we also have to resolve `Sub<BaseItem = &'b u32>`.
264-
/// To figure out the index of `'b`, we have to know about the supertraits
265-
/// of `Sub` so that we can determine that the `for<'a>` will be in scope.
266-
/// (This is because we -- currently at least -- flatten all the late-bound
267-
/// lifetimes into a single binder.) This requires us to resolve the
268-
/// *trait definition* of `Sub`; basically just enough lifetime information
269-
/// to look at the supertraits.
270-
#[instrument(level = "debug", skip(tcx))]
271-
fn resolve_lifetimes_trait_definition(
272-
tcx: TyCtxt<'_>,
273-
local_def_id: LocalDefId,
274-
) -> ResolveLifetimes {
275-
convert_named_region_map(do_resolve(tcx, local_def_id, true))
276-
}
277-
278236
/// Computes the `ResolveLifetimes` map that contains data for an entire `Item`.
279237
/// You should not read the result of this query directly, but rather use
280238
/// `named_region_map`, `is_late_bound_map`, etc.
281239
#[instrument(level = "debug", skip(tcx))]
282-
fn resolve_lifetimes(tcx: TyCtxt<'_>, local_def_id: LocalDefId) -> ResolveLifetimes {
283-
convert_named_region_map(do_resolve(tcx, local_def_id, false))
284-
}
285-
286-
fn do_resolve(
287-
tcx: TyCtxt<'_>,
288-
local_def_id: LocalDefId,
289-
trait_definition_only: bool,
290-
) -> NamedRegionMap {
291-
let item = tcx.hir().expect_item(local_def_id);
240+
fn resolve_lifetimes(tcx: TyCtxt<'_>, local_def_id: hir::OwnerId) -> ResolveLifetimes {
292241
let mut named_region_map =
293242
NamedRegionMap { defs: Default::default(), late_bound_vars: Default::default() };
294243
let mut visitor = LifetimeContext {
295244
tcx,
296245
map: &mut named_region_map,
297-
scope: ROOT_SCOPE,
298-
trait_definition_only,
246+
scope: &Scope::Root { opt_parent_item: None },
299247
};
300-
visitor.visit_item(item);
301-
302-
named_region_map
303-
}
248+
match tcx.hir().owner(local_def_id) {
249+
hir::OwnerNode::Item(item) => visitor.visit_item(item),
250+
hir::OwnerNode::ForeignItem(item) => visitor.visit_foreign_item(item),
251+
hir::OwnerNode::TraitItem(item) => {
252+
let scope =
253+
Scope::Root { opt_parent_item: Some(tcx.local_parent(item.owner_id.def_id)) };
254+
visitor.scope = &scope;
255+
visitor.visit_trait_item(item)
256+
}
257+
hir::OwnerNode::ImplItem(item) => {
258+
let scope =
259+
Scope::Root { opt_parent_item: Some(tcx.local_parent(item.owner_id.def_id)) };
260+
visitor.scope = &scope;
261+
visitor.visit_impl_item(item)
262+
}
263+
hir::OwnerNode::Crate(_) => {}
264+
}
304265

305-
fn convert_named_region_map(named_region_map: NamedRegionMap) -> ResolveLifetimes {
306266
let mut rl = ResolveLifetimes::default();
307267

308268
for (hir_id, v) in named_region_map.defs {
@@ -319,53 +279,6 @@ fn convert_named_region_map(named_region_map: NamedRegionMap) -> ResolveLifetime
319279
rl
320280
}
321281

322-
/// Given `any` owner (structs, traits, trait methods, etc.), does lifetime resolution.
323-
/// There are two important things this does.
324-
/// First, we have to resolve lifetimes for
325-
/// the entire *`Item`* that contains this owner, because that's the largest "scope"
326-
/// where we can have relevant lifetimes.
327-
/// Second, if we are asking for lifetimes in a trait *definition*, we use `resolve_lifetimes_trait_definition`
328-
/// instead of `resolve_lifetimes`, which does not descend into the trait items and does not emit diagnostics.
329-
/// This allows us to avoid cycles. Importantly, if we ask for lifetimes for lifetimes that have an owner
330-
/// other than the trait itself (like the trait methods or associated types), then we just use the regular
331-
/// `resolve_lifetimes`.
332-
fn resolve_lifetimes_for<'tcx>(tcx: TyCtxt<'tcx>, def_id: hir::OwnerId) -> &'tcx ResolveLifetimes {
333-
let item_id = item_for(tcx, def_id.def_id);
334-
let local_def_id = item_id.owner_id.def_id;
335-
if item_id.owner_id == def_id {
336-
let item = tcx.hir().item(item_id);
337-
match item.kind {
338-
hir::ItemKind::Trait(..) => tcx.resolve_lifetimes_trait_definition(local_def_id),
339-
_ => tcx.resolve_lifetimes(local_def_id),
340-
}
341-
} else {
342-
tcx.resolve_lifetimes(local_def_id)
343-
}
344-
}
345-
346-
/// Finds the `Item` that contains the given `LocalDefId`
347-
fn item_for(tcx: TyCtxt<'_>, local_def_id: LocalDefId) -> hir::ItemId {
348-
match tcx.hir().find_by_def_id(local_def_id) {
349-
Some(Node::Item(item)) => {
350-
return item.item_id();
351-
}
352-
_ => {}
353-
}
354-
let item = {
355-
let hir_id = tcx.hir().local_def_id_to_hir_id(local_def_id);
356-
let mut parent_iter = tcx.hir().parent_iter(hir_id);
357-
loop {
358-
let node = parent_iter.next().map(|n| n.1);
359-
match node {
360-
Some(hir::Node::Item(item)) => break item.item_id(),
361-
Some(hir::Node::Crate(_)) | None => bug!("Called `item_for` on an Item."),
362-
_ => {}
363-
}
364-
}
365-
};
366-
item
367-
}
368-
369282
fn late_region_as_bound_region<'tcx>(tcx: TyCtxt<'tcx>, region: &Region) -> ty::BoundVariableKind {
370283
match region {
371284
Region::LateBound(_, _, def_id) => {
@@ -383,7 +296,7 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
383296
let mut supertrait_lifetimes = vec![];
384297
loop {
385298
match scope {
386-
Scope::Body { .. } | Scope::Root => {
299+
Scope::Body { .. } | Scope::Root { .. } => {
387300
break (vec![], BinderScopeType::Normal);
388301
}
389302

@@ -414,21 +327,12 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
414327
}
415328
}
416329
impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
417-
type NestedFilter = nested_filter::All;
330+
type NestedFilter = nested_filter::OnlyBodies;
418331

419332
fn nested_visit_map(&mut self) -> Self::Map {
420333
self.tcx.hir()
421334
}
422335

423-
// We want to nest trait/impl items in their parent, but nothing else.
424-
fn visit_nested_item(&mut self, _: hir::ItemId) {}
425-
426-
fn visit_trait_item_ref(&mut self, ii: &'tcx hir::TraitItemRef) {
427-
if !self.trait_definition_only {
428-
intravisit::walk_trait_item_ref(self, ii)
429-
}
430-
}
431-
432336
fn visit_nested_body(&mut self, body: hir::BodyId) {
433337
let body = self.tcx.hir().body(body);
434338
self.with(Scope::Body { id: body.id(), s: self.scope }, |this| {
@@ -557,33 +461,21 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
557461
// their owner, we can keep going until we find the Item that owns that. We then
558462
// conservatively add all resolved lifetimes. Otherwise we run into problems in
559463
// cases like `type Foo<'a> = impl Bar<As = impl Baz + 'a>`.
560-
for (_hir_id, node) in self.tcx.hir().parent_iter(item.owner_id.into()) {
561-
match node {
562-
hir::Node::Item(parent_item) => {
563-
let resolved_lifetimes: &ResolveLifetimes = self.tcx.resolve_lifetimes(
564-
item_for(self.tcx, parent_item.owner_id.def_id).owner_id.def_id,
565-
);
566-
// We need to add *all* deps, since opaque tys may want them from *us*
567-
for (&owner, defs) in resolved_lifetimes.defs.iter() {
568-
defs.iter().for_each(|(&local_id, region)| {
569-
self.map.defs.insert(hir::HirId { owner, local_id }, *region);
570-
});
571-
}
572-
for (&owner, late_bound_vars) in
573-
resolved_lifetimes.late_bound_vars.iter()
574-
{
575-
late_bound_vars.iter().for_each(|(&local_id, late_bound_vars)| {
576-
self.record_late_bound_vars(
577-
hir::HirId { owner, local_id },
578-
late_bound_vars.clone(),
579-
);
580-
});
581-
}
582-
break;
583-
}
584-
hir::Node::Crate(_) => bug!("No Item about an OpaqueTy"),
585-
_ => {}
586-
}
464+
let parent_item = self.tcx.hir().get_parent_item(item.hir_id());
465+
let resolved_lifetimes: &ResolveLifetimes = self.tcx.resolve_lifetimes(parent_item);
466+
// We need to add *all* deps, since opaque tys may want them from *us*
467+
for (&owner, defs) in resolved_lifetimes.defs.iter() {
468+
defs.iter().for_each(|(&local_id, region)| {
469+
self.map.defs.insert(hir::HirId { owner, local_id }, *region);
470+
});
471+
}
472+
for (&owner, late_bound_vars) in resolved_lifetimes.late_bound_vars.iter() {
473+
late_bound_vars.iter().for_each(|(&local_id, late_bound_vars)| {
474+
self.record_late_bound_vars(
475+
hir::HirId { owner, local_id },
476+
late_bound_vars.clone(),
477+
);
478+
});
587479
}
588480
}
589481
hir::ItemKind::TyAlias(_, ref generics)
@@ -609,7 +501,7 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
609501
hir_id: item.hir_id(),
610502
lifetimes,
611503
scope_type: BinderScopeType::Normal,
612-
s: ROOT_SCOPE,
504+
s: self.scope,
613505
where_bound_origin: None,
614506
};
615507
self.with(scope, |this| {
@@ -766,30 +658,26 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
766658
// Ensure that the parent of the def is an item, not HRTB
767659
let parent_id = self.tcx.hir().get_parent_node(hir_id);
768660
if !parent_id.is_owner() {
769-
if !self.trait_definition_only {
770-
struct_span_err!(
771-
self.tcx.sess,
772-
lifetime.span,
773-
E0657,
774-
"`impl Trait` can only capture lifetimes \
661+
struct_span_err!(
662+
self.tcx.sess,
663+
lifetime.span,
664+
E0657,
665+
"`impl Trait` can only capture lifetimes \
775666
bound at the fn or impl level"
776-
)
777-
.emit();
778-
}
667+
)
668+
.emit();
779669
self.uninsert_lifetime_on_error(lifetime, def.unwrap());
780670
}
781671
if let hir::Node::Item(hir::Item {
782672
kind: hir::ItemKind::OpaqueTy { .. }, ..
783673
}) = self.tcx.hir().get(parent_id)
784674
{
785-
if !self.trait_definition_only {
786-
let mut err = self.tcx.sess.struct_span_err(
675+
let mut err = self.tcx.sess.struct_span_err(
787676
lifetime.span,
788677
"higher kinded lifetime bounds on nested opaque types are not supported yet",
789678
);
790-
err.span_note(self.tcx.def_span(def_id), "lifetime declared here");
791-
err.emit();
792-
}
679+
err.span_note(self.tcx.def_span(def_id), "lifetime declared here");
680+
err.emit();
793681
self.uninsert_lifetime_on_error(lifetime, def.unwrap());
794682
}
795683
}
@@ -1193,12 +1081,7 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
11931081
F: for<'b> FnOnce(&mut LifetimeContext<'b, 'tcx>),
11941082
{
11951083
let LifetimeContext { tcx, map, .. } = self;
1196-
let mut this = LifetimeContext {
1197-
tcx: *tcx,
1198-
map,
1199-
scope: &wrap_scope,
1200-
trait_definition_only: self.trait_definition_only,
1201-
};
1084+
let mut this = LifetimeContext { tcx: *tcx, map, scope: &wrap_scope };
12021085
let span = debug_span!("scope", scope = ?TruncatedScopeDebug(&this.scope));
12031086
{
12041087
let _enter = span.enter();
@@ -1303,7 +1186,13 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
13031186
scope = s;
13041187
}
13051188

1306-
Scope::Root => {
1189+
Scope::Root { opt_parent_item } => {
1190+
if let Some(parent_item) = opt_parent_item
1191+
&& let parent_generics = self.tcx.generics_of(parent_item)
1192+
&& parent_generics.param_def_id_to_index.contains_key(&region_def_id.to_def_id())
1193+
{
1194+
break Some(Region::EarlyBound(region_def_id.to_def_id()));
1195+
}
13071196
break None;
13081197
}
13091198

@@ -1417,7 +1306,7 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
14171306
err.emit();
14181307
return;
14191308
}
1420-
Scope::Root => break,
1309+
Scope::Root { .. } => break,
14211310
Scope::Binder { s, .. }
14221311
| Scope::Body { s, .. }
14231312
| Scope::Elision { s, .. }
@@ -1495,7 +1384,7 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
14951384
let mut scope = self.scope;
14961385
loop {
14971386
match *scope {
1498-
Scope::Root => break false,
1387+
Scope::Root { .. } => break false,
14991388

15001389
Scope::Body { .. } => break true,
15011390

@@ -1732,7 +1621,7 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
17321621
scope = s;
17331622
}
17341623

1735-
Scope::Root | Scope::Elision { .. } => break Region::Static,
1624+
Scope::Root { .. } | Scope::Elision { .. } => break Region::Static,
17361625

17371626
Scope::Body { .. } | Scope::ObjectLifetimeDefault { lifetime: None, .. } => return,
17381627

0 commit comments

Comments
 (0)