Skip to content

Commit bd1a869

Browse files
committed
Auto merge of #90204 - cjgillot:owner-pull, r=michaelwoerister
Make lowering pull-based ~Based on #90451 Part of #88186 The current lowering code visits all the item-likes in the AST in order, and lowers them one by one. This PR changes it to index the AST and then proceed to lowering on-demand. This is closer to the logic of query-based lowering.
2 parents 0331491 + 6b099db commit bd1a869

File tree

5 files changed

+273
-250
lines changed

5 files changed

+273
-250
lines changed

compiler/rustc_ast_lowering/src/item.rs

+132-116
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,19 @@
11
use super::{AnonymousLifetimeMode, LoweringContext, ParamMode};
2-
use super::{ImplTraitContext, ImplTraitPosition};
2+
use super::{AstOwner, ImplTraitContext, ImplTraitPosition, ResolverAstLowering};
33
use crate::{Arena, FnDeclKind};
44

55
use rustc_ast::ptr::P;
6-
use rustc_ast::visit::{self, AssocCtxt, FnCtxt, FnKind, Visitor};
6+
use rustc_ast::visit::AssocCtxt;
77
use rustc_ast::*;
8-
use rustc_data_structures::fx::FxHashSet;
8+
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
9+
use rustc_data_structures::sorted_map::SortedMap;
910
use rustc_errors::struct_span_err;
1011
use rustc_hir as hir;
1112
use rustc_hir::def::{DefKind, Res};
12-
use rustc_hir::def_id::LocalDefId;
13-
use rustc_index::vec::Idx;
13+
use rustc_hir::def_id::{LocalDefId, CRATE_DEF_ID};
14+
use rustc_index::vec::{Idx, IndexVec};
15+
use rustc_session::utils::NtToTokenstream;
16+
use rustc_session::Session;
1417
use rustc_span::source_map::{respan, DesugaringKind};
1518
use rustc_span::symbol::{kw, sym, Ident};
1619
use rustc_span::Span;
@@ -19,10 +22,14 @@ use smallvec::{smallvec, SmallVec};
1922
use tracing::debug;
2023

2124
use std::iter;
22-
use std::mem;
2325

24-
pub(super) struct ItemLowerer<'a, 'lowering, 'hir> {
25-
pub(super) lctx: &'a mut LoweringContext<'lowering, 'hir>,
26+
pub(super) struct ItemLowerer<'a, 'hir> {
27+
pub(super) sess: &'a Session,
28+
pub(super) resolver: &'a mut dyn ResolverAstLowering,
29+
pub(super) nt_to_tokenstream: NtToTokenstream,
30+
pub(super) arena: &'hir Arena<'hir>,
31+
pub(super) ast_index: &'a IndexVec<LocalDefId, AstOwner<'a>>,
32+
pub(super) owners: &'a mut IndexVec<LocalDefId, hir::MaybeOwner<&'hir hir::OwnerInfo<'hir>>>,
2633
}
2734

2835
/// When we have a ty alias we *may* have two where clauses. To give the best diagnostics, we set the span
@@ -45,130 +52,140 @@ fn add_ty_alias_where_clause(
4552
}
4653
}
4754

48-
impl ItemLowerer<'_, '_, '_> {
49-
fn with_trait_impl_ref<T>(
55+
impl<'a, 'hir> ItemLowerer<'a, 'hir> {
56+
fn with_lctx(
5057
&mut self,
51-
impl_ref: &Option<TraitRef>,
52-
f: impl FnOnce(&mut Self) -> T,
53-
) -> T {
54-
let old = self.lctx.is_in_trait_impl;
55-
self.lctx.is_in_trait_impl = impl_ref.is_some();
56-
let ret = f(self);
57-
self.lctx.is_in_trait_impl = old;
58-
ret
59-
}
60-
}
61-
62-
impl<'a> Visitor<'a> for ItemLowerer<'a, '_, '_> {
63-
fn visit_attribute(&mut self, _: &'a Attribute) {
64-
// We do not want to lower expressions that appear in attributes,
65-
// as they are not accessible to the rest of the HIR.
66-
}
58+
owner: NodeId,
59+
f: impl FnOnce(&mut LoweringContext<'_, 'hir>) -> hir::OwnerNode<'hir>,
60+
) {
61+
let mut lctx = LoweringContext {
62+
// Pseudo-globals.
63+
sess: &self.sess,
64+
resolver: self.resolver,
65+
nt_to_tokenstream: self.nt_to_tokenstream,
66+
arena: self.arena,
67+
68+
// HirId handling.
69+
bodies: Vec::new(),
70+
attrs: SortedMap::default(),
71+
children: FxHashMap::default(),
72+
current_hir_id_owner: CRATE_DEF_ID,
73+
item_local_id_counter: hir::ItemLocalId::new(0),
74+
node_id_to_local_id: Default::default(),
75+
local_id_to_def_id: SortedMap::new(),
76+
trait_map: Default::default(),
77+
78+
// Lowering state.
79+
catch_scope: None,
80+
loop_scope: None,
81+
is_in_loop_condition: false,
82+
is_in_trait_impl: false,
83+
is_in_dyn_type: false,
84+
anonymous_lifetime_mode: AnonymousLifetimeMode::PassThrough,
85+
generator_kind: None,
86+
task_context: None,
87+
current_item: None,
88+
lifetimes_to_define: Vec::new(),
89+
is_collecting_anonymous_lifetimes: None,
90+
in_scope_lifetimes: Vec::new(),
91+
allow_try_trait: Some([sym::try_trait_v2][..].into()),
92+
allow_gen_future: Some([sym::gen_future][..].into()),
93+
allow_into_future: Some([sym::into_future][..].into()),
94+
};
95+
lctx.with_hir_id_owner(owner, |lctx| f(lctx));
6796

68-
fn visit_item(&mut self, item: &'a Item) {
69-
let hir_id = self.lctx.with_hir_id_owner(item.id, |lctx| {
70-
let node = lctx.without_in_scope_lifetime_defs(|lctx| lctx.lower_item(item));
71-
hir::OwnerNode::Item(node)
72-
});
73-
74-
self.lctx.with_parent_item_lifetime_defs(hir_id, |this| {
75-
let this = &mut ItemLowerer { lctx: this };
76-
match item.kind {
77-
ItemKind::Impl(box Impl { ref of_trait, .. }) => {
78-
this.with_trait_impl_ref(of_trait, |this| visit::walk_item(this, item));
79-
}
80-
_ => visit::walk_item(this, item),
81-
}
82-
});
97+
for (def_id, info) in lctx.children {
98+
self.owners.ensure_contains_elem(def_id, || hir::MaybeOwner::Phantom);
99+
debug_assert!(matches!(self.owners[def_id], hir::MaybeOwner::Phantom));
100+
self.owners[def_id] = info;
101+
}
83102
}
84103

85-
fn visit_fn(&mut self, fk: FnKind<'a>, sp: Span, _: NodeId) {
86-
match fk {
87-
FnKind::Fn(FnCtxt::Foreign, _, sig, _, _) => {
88-
self.visit_fn_header(&sig.header);
89-
visit::walk_fn_decl(self, &sig.decl);
90-
// Don't visit the foreign function body even if it has one, since lowering the
91-
// body would have no meaning and will have already been caught as a parse error.
104+
pub(super) fn lower_node(
105+
&mut self,
106+
def_id: LocalDefId,
107+
) -> hir::MaybeOwner<&'hir hir::OwnerInfo<'hir>> {
108+
self.owners.ensure_contains_elem(def_id, || hir::MaybeOwner::Phantom);
109+
if let hir::MaybeOwner::Phantom = self.owners[def_id] {
110+
let node = self.ast_index[def_id];
111+
match node {
112+
AstOwner::NonOwner => {}
113+
AstOwner::Crate(c) => self.lower_crate(c),
114+
AstOwner::Item(item) => self.lower_item(item),
115+
AstOwner::AssocItem(item, ctxt) => self.lower_assoc_item(item, ctxt),
116+
AstOwner::ForeignItem(item) => self.lower_foreign_item(item),
92117
}
93-
_ => visit::walk_fn(self, fk, sp),
94118
}
95-
}
96-
97-
fn visit_assoc_item(&mut self, item: &'a AssocItem, ctxt: AssocCtxt) {
98-
debug!(in_scope_lifetimes = ?self.lctx.in_scope_lifetimes);
99-
self.lctx.with_hir_id_owner(item.id, |lctx| match ctxt {
100-
AssocCtxt::Trait => hir::OwnerNode::TraitItem(lctx.lower_trait_item(item)),
101-
AssocCtxt::Impl => hir::OwnerNode::ImplItem(lctx.lower_impl_item(item)),
102-
});
103119

104-
visit::walk_assoc_item(self, item, ctxt);
120+
self.owners[def_id]
105121
}
106122

107-
fn visit_foreign_item(&mut self, item: &'a ForeignItem) {
108-
self.lctx.with_hir_id_owner(item.id, |lctx| {
109-
hir::OwnerNode::ForeignItem(lctx.lower_foreign_item(item))
110-
});
123+
fn lower_crate(&mut self, c: &Crate) {
124+
debug_assert_eq!(self.resolver.local_def_id(CRATE_NODE_ID), CRATE_DEF_ID);
111125

112-
visit::walk_foreign_item(self, item);
126+
self.with_lctx(CRATE_NODE_ID, |lctx| {
127+
let module = lctx.lower_mod(&c.items, c.spans.inner_span);
128+
lctx.lower_attrs(hir::CRATE_HIR_ID, &c.attrs);
129+
hir::OwnerNode::Crate(lctx.arena.alloc(module))
130+
})
113131
}
114-
}
115132

116-
impl<'hir> LoweringContext<'_, 'hir> {
117-
// Same as the method above, but accepts `hir::GenericParam`s
118-
// instead of `ast::GenericParam`s.
119-
// This should only be used with generics that have already had their
120-
// in-band lifetimes added. In practice, this means that this function is
121-
// only used when lowering a child item of a trait or impl.
122-
#[tracing::instrument(level = "debug", skip(self, f))]
123-
fn with_parent_item_lifetime_defs<T>(
124-
&mut self,
125-
parent_hir_id: LocalDefId,
126-
f: impl FnOnce(&mut Self) -> T,
127-
) -> T {
128-
let parent_generics = match self.owners[parent_hir_id].unwrap().node().expect_item().kind {
129-
hir::ItemKind::Impl(hir::Impl { ref generics, .. })
130-
| hir::ItemKind::Trait(_, _, ref generics, ..) => generics.params,
131-
_ => &[],
132-
};
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);
144-
145-
let res = f(self);
146-
147-
self.in_scope_lifetimes = old_in_scope_lifetimes;
148-
res
133+
fn lower_item(&mut self, item: &Item) {
134+
self.with_lctx(item.id, |lctx| hir::OwnerNode::Item(lctx.lower_item(item)))
149135
}
150136

151-
// Clears (and restores) the `in_scope_lifetimes` field. Used when
152-
// visiting nested items, which never inherit in-scope lifetimes
153-
// from their surrounding environment.
154-
#[tracing::instrument(level = "debug", skip(self, f))]
155-
fn without_in_scope_lifetime_defs<T>(&mut self, f: impl FnOnce(&mut Self) -> T) -> T {
156-
let old_in_scope_lifetimes = mem::replace(&mut self.in_scope_lifetimes, vec![]);
157-
debug!(?old_in_scope_lifetimes);
137+
fn lower_assoc_item(&mut self, item: &AssocItem, ctxt: AssocCtxt) {
138+
let def_id = self.resolver.local_def_id(item.id);
158139

159-
// this vector is only used when walking over impl headers,
160-
// input types, and the like, and should not be non-empty in
161-
// between items
162-
assert!(self.lifetimes_to_define.is_empty());
140+
let parent_id = {
141+
let parent = self.resolver.definitions().def_key(def_id).parent;
142+
let local_def_index = parent.unwrap();
143+
LocalDefId { local_def_index }
144+
};
163145

164-
let res = f(self);
146+
let parent_hir = self.lower_node(parent_id).unwrap().node().expect_item();
147+
self.with_lctx(item.id, |lctx| {
148+
// Evaluate with the lifetimes in `params` in-scope.
149+
// This is used to track which lifetimes have already been defined,
150+
// and which need to be replicated when lowering an async fn.
151+
match parent_hir.kind {
152+
hir::ItemKind::Impl(hir::Impl { ref of_trait, ref generics, .. }) => {
153+
lctx.is_in_trait_impl = of_trait.is_some();
154+
lctx.in_scope_lifetimes = generics
155+
.params
156+
.iter()
157+
.filter(|param| {
158+
matches!(param.kind, hir::GenericParamKind::Lifetime { .. })
159+
})
160+
.map(|param| param.name)
161+
.collect();
162+
}
163+
hir::ItemKind::Trait(_, _, ref generics, ..) => {
164+
lctx.in_scope_lifetimes = generics
165+
.params
166+
.iter()
167+
.filter(|param| {
168+
matches!(param.kind, hir::GenericParamKind::Lifetime { .. })
169+
})
170+
.map(|param| param.name)
171+
.collect();
172+
}
173+
_ => {}
174+
};
165175

166-
assert!(self.in_scope_lifetimes.is_empty());
167-
self.in_scope_lifetimes = old_in_scope_lifetimes;
176+
match ctxt {
177+
AssocCtxt::Trait => hir::OwnerNode::TraitItem(lctx.lower_trait_item(item)),
178+
AssocCtxt::Impl => hir::OwnerNode::ImplItem(lctx.lower_impl_item(item)),
179+
}
180+
})
181+
}
168182

169-
res
183+
fn lower_foreign_item(&mut self, item: &ForeignItem) {
184+
self.with_lctx(item.id, |lctx| hir::OwnerNode::ForeignItem(lctx.lower_foreign_item(item)))
170185
}
186+
}
171187

188+
impl<'hir> LoweringContext<'_, 'hir> {
172189
pub(super) fn lower_mod(&mut self, items: &[P<Item>], inner: Span) -> hir::Mod<'hir> {
173190
hir::Mod {
174191
inner: self.lower_span(inner),
@@ -548,12 +565,11 @@ impl<'hir> LoweringContext<'_, 'hir> {
548565
let new_id = self.resolver.local_def_id(new_node_id);
549566
let Some(res) = resolutions.next() else {
550567
// Associate an HirId to both ids even if there is no resolution.
551-
self.owners.ensure_contains_elem(new_id, || hir::MaybeOwner::Phantom);
552-
let _old = std::mem::replace(
553-
&mut self.owners[new_id],
568+
let _old = self.children.insert(
569+
new_id,
554570
hir::MaybeOwner::NonOwner(hir::HirId::make_owner(new_id)),
555571
);
556-
debug_assert!(matches!(_old, hir::MaybeOwner::Phantom));
572+
debug_assert!(_old.is_none());
557573
continue;
558574
};
559575
let ident = *ident;

0 commit comments

Comments
 (0)