Skip to content

Commit d3b7ea6

Browse files
committed
Identify anonymous lifetimes by their DefId in HIR.
1 parent 012720f commit d3b7ea6

File tree

3 files changed

+104
-69
lines changed

3 files changed

+104
-69
lines changed

compiler/rustc_ast_lowering/src/item.rs

+16-8
Original file line numberDiff line numberDiff line change
@@ -95,6 +95,7 @@ impl<'a> Visitor<'a> for ItemLowerer<'a, '_, '_> {
9595
}
9696

9797
fn visit_assoc_item(&mut self, item: &'a AssocItem, ctxt: AssocCtxt) {
98+
debug!(in_scope_lifetimes = ?self.lctx.in_scope_lifetimes);
9899
self.lctx.with_hir_id_owner(item.id, |lctx| match ctxt {
99100
AssocCtxt::Trait => hir::OwnerNode::TraitItem(lctx.lower_trait_item(item)),
100101
AssocCtxt::Impl => hir::OwnerNode::ImplItem(lctx.lower_impl_item(item)),
@@ -118,35 +119,42 @@ impl<'hir> LoweringContext<'_, 'hir> {
118119
// This should only be used with generics that have already had their
119120
// in-band lifetimes added. In practice, this means that this function is
120121
// only used when lowering a child item of a trait or impl.
122+
#[tracing::instrument(level = "debug", skip(self, f))]
121123
fn with_parent_item_lifetime_defs<T>(
122124
&mut self,
123125
parent_hir_id: LocalDefId,
124126
f: impl FnOnce(&mut Self) -> T,
125127
) -> T {
126-
let old_len = self.in_scope_lifetimes.len();
127-
128128
let parent_generics = match self.owners[parent_hir_id].unwrap().node().expect_item().kind {
129129
hir::ItemKind::Impl(hir::Impl { ref generics, .. })
130130
| hir::ItemKind::Trait(_, _, ref generics, ..) => generics.params,
131131
_ => &[],
132132
};
133-
let lt_def_names = parent_generics.iter().filter_map(|param| match param.kind {
134-
hir::GenericParamKind::Lifetime { .. } => Some(param.name.normalize_to_macros_2_0()),
135-
_ => None,
136-
});
137-
self.in_scope_lifetimes.extend(lt_def_names);
133+
let lt_def_names = parent_generics
134+
.iter()
135+
.filter_map(|param| match param.kind {
136+
hir::GenericParamKind::Lifetime { .. } => {
137+
Some(param.name.normalize_to_macros_2_0())
138+
}
139+
_ => None,
140+
})
141+
.collect();
142+
let old_in_scope_lifetimes = mem::replace(&mut self.in_scope_lifetimes, lt_def_names);
143+
debug!(in_scope_lifetimes = ?self.in_scope_lifetimes);
138144

139145
let res = f(self);
140146

141-
self.in_scope_lifetimes.truncate(old_len);
147+
self.in_scope_lifetimes = old_in_scope_lifetimes;
142148
res
143149
}
144150

145151
// Clears (and restores) the `in_scope_lifetimes` field. Used when
146152
// visiting nested items, which never inherit in-scope lifetimes
147153
// from their surrounding environment.
154+
#[tracing::instrument(level = "debug", skip(self, f))]
148155
fn without_in_scope_lifetime_defs<T>(&mut self, f: impl FnOnce(&mut Self) -> T) -> T {
149156
let old_in_scope_lifetimes = mem::replace(&mut self.in_scope_lifetimes, vec![]);
157+
debug!(?old_in_scope_lifetimes);
150158

151159
// this vector is only used when walking over impl headers,
152160
// input types, and the like, and should not be non-empty in

compiler/rustc_ast_lowering/src/lib.rs

+86-59
Original file line numberDiff line numberDiff line change
@@ -136,13 +136,13 @@ struct LoweringContext<'a, 'hir: 'a> {
136136
/// (i.e., it doesn't appear in the in_scope_lifetimes list), it is added
137137
/// to this list. The results of this list are then added to the list of
138138
/// lifetime definitions in the corresponding impl or function generics.
139-
lifetimes_to_define: Vec<(Span, ParamName)>,
139+
lifetimes_to_define: Vec<(Span, NodeId)>,
140140

141141
/// `true` if in-band lifetimes are being collected. This is used to
142142
/// indicate whether or not we're in a place where new lifetimes will result
143143
/// in in-band lifetime definitions, such a function or an impl header,
144144
/// including implicit lifetimes from `impl_header_lifetime_elision`.
145-
is_collecting_anonymous_lifetimes: bool,
145+
is_collecting_anonymous_lifetimes: Option<LocalDefId>,
146146

147147
/// Currently in-scope lifetimes defined in impl headers, fn headers, or HRTB.
148148
/// We always store a `normalize_to_macros_2_0()` version of the param-name in this
@@ -375,7 +375,7 @@ pub fn lower_crate<'a, 'hir>(
375375
task_context: None,
376376
current_item: None,
377377
lifetimes_to_define: Vec::new(),
378-
is_collecting_anonymous_lifetimes: false,
378+
is_collecting_anonymous_lifetimes: None,
379379
in_scope_lifetimes: Vec::new(),
380380
allow_try_trait: Some([sym::try_trait_v2][..].into()),
381381
allow_gen_future: Some([sym::gen_future][..].into()),
@@ -720,9 +720,11 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
720720
/// parameter while `f` is running (and restored afterwards).
721721
fn collect_in_band_defs<T>(
722722
&mut self,
723+
parent_def_id: LocalDefId,
723724
f: impl FnOnce(&mut Self) -> T,
724-
) -> (Vec<(Span, ParamName)>, T) {
725-
let was_collecting = std::mem::replace(&mut self.is_collecting_anonymous_lifetimes, true);
725+
) -> (Vec<(Span, NodeId)>, T) {
726+
let was_collecting =
727+
std::mem::replace(&mut self.is_collecting_anonymous_lifetimes, Some(parent_def_id));
726728
let len = self.lifetimes_to_define.len();
727729

728730
let res = f(self);
@@ -733,49 +735,41 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
733735
}
734736

735737
/// Converts a lifetime into a new generic parameter.
736-
fn lifetime_to_generic_param(
738+
fn fresh_lifetime_to_generic_param(
737739
&mut self,
738740
span: Span,
739-
hir_name: ParamName,
740-
parent_def_id: LocalDefId,
741+
node_id: NodeId,
741742
) -> hir::GenericParam<'hir> {
742-
let node_id = self.resolver.next_node_id();
743-
744-
// Get the name we'll use to make the def-path. Note
745-
// that collisions are ok here and this shouldn't
746-
// really show up for end-user.
747-
let (str_name, kind) = match hir_name {
748-
ParamName::Plain(ident) => (ident.name, hir::LifetimeParamKind::Explicit),
749-
ParamName::Fresh(_) => (kw::UnderscoreLifetime, hir::LifetimeParamKind::Elided),
750-
ParamName::Error => (kw::UnderscoreLifetime, hir::LifetimeParamKind::Error),
751-
};
752-
753-
// Add a definition for the in-band lifetime def.
754-
self.resolver.create_def(
755-
parent_def_id,
756-
node_id,
757-
DefPathData::LifetimeNs(str_name),
758-
ExpnId::root(),
759-
span.with_parent(None),
760-
);
761-
743+
let hir_id = self.lower_node_id(node_id);
744+
let def_id = self.resolver.local_def_id(node_id);
762745
hir::GenericParam {
763-
hir_id: self.lower_node_id(node_id),
764-
name: hir_name,
746+
hir_id,
747+
name: hir::ParamName::Fresh(def_id),
765748
bounds: &[],
766749
span: self.lower_span(span),
767750
pure_wrt_drop: false,
768-
kind: hir::GenericParamKind::Lifetime { kind },
751+
kind: hir::GenericParamKind::Lifetime { kind: hir::LifetimeParamKind::Elided },
769752
}
770753
}
771754

772755
/// When we have either an elided or `'_` lifetime in an impl
773756
/// header, we convert it to an in-band lifetime.
774757
fn collect_fresh_anonymous_lifetime(&mut self, span: Span) -> ParamName {
775-
assert!(self.is_collecting_anonymous_lifetimes);
776-
let index = self.lifetimes_to_define.len() + self.in_scope_lifetimes.len();
777-
let hir_name = ParamName::Fresh(index);
778-
self.lifetimes_to_define.push((span, hir_name));
758+
let Some(parent_def_id) = self.is_collecting_anonymous_lifetimes else { panic!() };
759+
760+
let node_id = self.resolver.next_node_id();
761+
762+
// Add a definition for the in-band lifetime def.
763+
let param_def_id = self.resolver.create_def(
764+
parent_def_id,
765+
node_id,
766+
DefPathData::LifetimeNs(kw::UnderscoreLifetime),
767+
ExpnId::root(),
768+
span.with_parent(None),
769+
);
770+
771+
let hir_name = ParamName::Fresh(param_def_id);
772+
self.lifetimes_to_define.push((span, node_id));
779773
hir_name
780774
}
781775

@@ -817,7 +811,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
817811
f: impl FnOnce(&mut Self, &mut Vec<hir::GenericParam<'hir>>) -> T,
818812
) -> (hir::Generics<'hir>, T) {
819813
let (lifetimes_to_define, (mut lowered_generics, impl_trait_defs, res)) = self
820-
.collect_in_band_defs(|this| {
814+
.collect_in_band_defs(parent_def_id, |this| {
821815
this.with_anonymous_lifetime_mode(anonymous_lifetime_mode, |this| {
822816
this.with_in_scope_lifetime_defs(&generics.params, |this| {
823817
let mut impl_trait_defs = Vec::new();
@@ -844,9 +838,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
844838
lowered_generics.params.extend(
845839
lifetimes_to_define
846840
.into_iter()
847-
.map(|(span, hir_name)| {
848-
self.lifetime_to_generic_param(span, hir_name, parent_def_id)
849-
})
841+
.map(|(span, node_id)| self.fresh_lifetime_to_generic_param(span, node_id))
850842
.chain(impl_trait_defs),
851843
);
852844

@@ -1763,15 +1755,53 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
17631755
.in_scope_lifetimes
17641756
.iter()
17651757
.cloned()
1766-
.map(|name| (name.ident().span, name, hir::LifetimeName::Param(name)))
1767-
.chain(
1768-
self.lifetimes_to_define
1769-
.iter()
1770-
.map(|&(span, name)| (span, name, hir::LifetimeName::Param(name))),
1771-
)
1758+
.map(|name| (name.ident().span, hir::LifetimeName::Param(name)))
1759+
.chain(self.lifetimes_to_define.iter().map(|&(span, node_id)| {
1760+
let def_id = self.resolver.local_def_id(node_id);
1761+
let name = hir::ParamName::Fresh(def_id);
1762+
(span, hir::LifetimeName::Param(name))
1763+
}))
17721764
.collect();
17731765

17741766
self.with_hir_id_owner(opaque_ty_node_id, |this| {
1767+
let mut generic_params: Vec<_> = lifetime_params
1768+
.iter()
1769+
.map(|&(span, name)| {
1770+
// We can only get lifetime names from the outside.
1771+
let hir::LifetimeName::Param(hir_name) = name else { panic!() };
1772+
1773+
let node_id = this.resolver.next_node_id();
1774+
1775+
// Add a definition for the in-band lifetime def.
1776+
let def_id = this.resolver.create_def(
1777+
opaque_ty_def_id,
1778+
node_id,
1779+
DefPathData::LifetimeNs(hir_name.ident().name),
1780+
ExpnId::root(),
1781+
span.with_parent(None),
1782+
);
1783+
1784+
let (kind, name) = match hir_name {
1785+
ParamName::Plain(ident) => {
1786+
(hir::LifetimeParamKind::Explicit, hir::ParamName::Plain(ident))
1787+
}
1788+
ParamName::Fresh(_) => {
1789+
(hir::LifetimeParamKind::Elided, hir::ParamName::Fresh(def_id))
1790+
}
1791+
ParamName::Error => (hir::LifetimeParamKind::Error, hir::ParamName::Error),
1792+
};
1793+
1794+
hir::GenericParam {
1795+
hir_id: this.lower_node_id(node_id),
1796+
name,
1797+
bounds: &[],
1798+
span: this.lower_span(span),
1799+
pure_wrt_drop: false,
1800+
kind: hir::GenericParamKind::Lifetime { kind },
1801+
}
1802+
})
1803+
.collect();
1804+
17751805
// We have to be careful to get elision right here. The
17761806
// idea is that we create a lifetime parameter for each
17771807
// lifetime in the return type. So, given a return type
@@ -1782,25 +1812,22 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
17821812
// hence the elision takes place at the fn site.
17831813
let (lifetimes_to_define, future_bound) =
17841814
this.with_anonymous_lifetime_mode(AnonymousLifetimeMode::CreateParameter, |this| {
1785-
this.collect_in_band_defs(|this| {
1815+
this.collect_in_band_defs(opaque_ty_def_id, |this| {
17861816
this.lower_async_fn_output_type_to_future_bound(output, fn_def_id, span)
17871817
})
17881818
});
17891819
debug!("lower_async_fn_ret_ty: future_bound={:#?}", future_bound);
17901820
debug!("lower_async_fn_ret_ty: lifetimes_to_define={:#?}", lifetimes_to_define);
17911821

1792-
lifetime_params.extend(
1793-
// Output lifetime like `'_`:
1794-
lifetimes_to_define
1795-
.into_iter()
1796-
.map(|(span, name)| (span, name, hir::LifetimeName::Implicit(false))),
1797-
);
1822+
// Output lifetime like `'_`:
1823+
for (span, node_id) in lifetimes_to_define {
1824+
let param = this.fresh_lifetime_to_generic_param(span, node_id);
1825+
lifetime_params.push((span, hir::LifetimeName::Implicit(false)));
1826+
generic_params.push(param);
1827+
}
1828+
let generic_params = this.arena.alloc_from_iter(generic_params);
17981829
debug!("lower_async_fn_ret_ty: lifetime_params={:#?}", lifetime_params);
1799-
1800-
let generic_params =
1801-
this.arena.alloc_from_iter(lifetime_params.iter().map(|&(span, hir_name, _)| {
1802-
this.lifetime_to_generic_param(span, hir_name, opaque_ty_def_id)
1803-
}));
1830+
debug!("lower_async_fn_ret_ty: generic_params={:#?}", generic_params);
18041831

18051832
let opaque_ty_item = hir::OpaqueTy {
18061833
generics: hir::Generics {
@@ -1833,7 +1860,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
18331860
// For the "output" lifetime parameters, we just want to
18341861
// generate `'_`.
18351862
let generic_args =
1836-
self.arena.alloc_from_iter(lifetime_params.into_iter().map(|(span, _, name)| {
1863+
self.arena.alloc_from_iter(lifetime_params.into_iter().map(|(span, name)| {
18371864
GenericArg::Lifetime(hir::Lifetime {
18381865
hir_id: self.next_id(),
18391866
span: self.lower_span(span),
@@ -1969,7 +1996,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
19691996
let (name, kind) = match param.kind {
19701997
GenericParamKind::Lifetime => {
19711998
let was_collecting_in_band = self.is_collecting_anonymous_lifetimes;
1972-
self.is_collecting_anonymous_lifetimes = false;
1999+
self.is_collecting_anonymous_lifetimes = None;
19732000

19742001
let lt = self
19752002
.with_anonymous_lifetime_mode(AnonymousLifetimeMode::ReportError, |this| {

compiler/rustc_hir/src/hir.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,7 @@ pub enum ParamName {
5959
///
6060
/// where `'f` is something like `Fresh(0)`. The indices are
6161
/// unique per impl, but not necessarily continuous.
62-
Fresh(usize),
62+
Fresh(LocalDefId),
6363

6464
/// Indicates an illegal name was given and an error has been
6565
/// reported (so we should squelch other derived errors). Occurs
@@ -3303,7 +3303,7 @@ mod size_asserts {
33033303
rustc_data_structures::static_assert_size!(super::Expr<'static>, 56);
33043304
rustc_data_structures::static_assert_size!(super::Pat<'static>, 88);
33053305
rustc_data_structures::static_assert_size!(super::QPath<'static>, 24);
3306-
rustc_data_structures::static_assert_size!(super::Ty<'static>, 80);
3306+
rustc_data_structures::static_assert_size!(super::Ty<'static>, 72);
33073307

33083308
rustc_data_structures::static_assert_size!(super::Item<'static>, 184);
33093309
rustc_data_structures::static_assert_size!(super::TraitItem<'static>, 128);

0 commit comments

Comments
 (0)