mirror of
https://github.com/rust-lang/rust.git
synced 2024-11-26 08:44:35 +00:00
Auto merge of #90204 - cjgillot:owner-pull, r=michaelwoerister
Make lowering pull-based ~Based on https://github.com/rust-lang/rust/pull/90451~ Part of https://github.com/rust-lang/rust/pull/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.
This commit is contained in:
commit
bd1a8692f6
@ -1,16 +1,19 @@
|
||||
use super::{AnonymousLifetimeMode, LoweringContext, ParamMode};
|
||||
use super::{ImplTraitContext, ImplTraitPosition};
|
||||
use super::{AstOwner, ImplTraitContext, ImplTraitPosition, ResolverAstLowering};
|
||||
use crate::{Arena, FnDeclKind};
|
||||
|
||||
use rustc_ast::ptr::P;
|
||||
use rustc_ast::visit::{self, AssocCtxt, FnCtxt, FnKind, Visitor};
|
||||
use rustc_ast::visit::AssocCtxt;
|
||||
use rustc_ast::*;
|
||||
use rustc_data_structures::fx::FxHashSet;
|
||||
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
|
||||
use rustc_data_structures::sorted_map::SortedMap;
|
||||
use rustc_errors::struct_span_err;
|
||||
use rustc_hir as hir;
|
||||
use rustc_hir::def::{DefKind, Res};
|
||||
use rustc_hir::def_id::LocalDefId;
|
||||
use rustc_index::vec::Idx;
|
||||
use rustc_hir::def_id::{LocalDefId, CRATE_DEF_ID};
|
||||
use rustc_index::vec::{Idx, IndexVec};
|
||||
use rustc_session::utils::NtToTokenstream;
|
||||
use rustc_session::Session;
|
||||
use rustc_span::source_map::{respan, DesugaringKind};
|
||||
use rustc_span::symbol::{kw, sym, Ident};
|
||||
use rustc_span::Span;
|
||||
@ -19,10 +22,14 @@ use smallvec::{smallvec, SmallVec};
|
||||
use tracing::debug;
|
||||
|
||||
use std::iter;
|
||||
use std::mem;
|
||||
|
||||
pub(super) struct ItemLowerer<'a, 'lowering, 'hir> {
|
||||
pub(super) lctx: &'a mut LoweringContext<'lowering, 'hir>,
|
||||
pub(super) struct ItemLowerer<'a, 'hir> {
|
||||
pub(super) sess: &'a Session,
|
||||
pub(super) resolver: &'a mut dyn ResolverAstLowering,
|
||||
pub(super) nt_to_tokenstream: NtToTokenstream,
|
||||
pub(super) arena: &'hir Arena<'hir>,
|
||||
pub(super) ast_index: &'a IndexVec<LocalDefId, AstOwner<'a>>,
|
||||
pub(super) owners: &'a mut IndexVec<LocalDefId, hir::MaybeOwner<&'hir hir::OwnerInfo<'hir>>>,
|
||||
}
|
||||
|
||||
/// 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(
|
||||
}
|
||||
}
|
||||
|
||||
impl ItemLowerer<'_, '_, '_> {
|
||||
fn with_trait_impl_ref<T>(
|
||||
impl<'a, 'hir> ItemLowerer<'a, 'hir> {
|
||||
fn with_lctx(
|
||||
&mut self,
|
||||
impl_ref: &Option<TraitRef>,
|
||||
f: impl FnOnce(&mut Self) -> T,
|
||||
) -> T {
|
||||
let old = self.lctx.is_in_trait_impl;
|
||||
self.lctx.is_in_trait_impl = impl_ref.is_some();
|
||||
let ret = f(self);
|
||||
self.lctx.is_in_trait_impl = old;
|
||||
ret
|
||||
}
|
||||
}
|
||||
owner: NodeId,
|
||||
f: impl FnOnce(&mut LoweringContext<'_, 'hir>) -> hir::OwnerNode<'hir>,
|
||||
) {
|
||||
let mut lctx = LoweringContext {
|
||||
// Pseudo-globals.
|
||||
sess: &self.sess,
|
||||
resolver: self.resolver,
|
||||
nt_to_tokenstream: self.nt_to_tokenstream,
|
||||
arena: self.arena,
|
||||
|
||||
impl<'a> Visitor<'a> for ItemLowerer<'a, '_, '_> {
|
||||
fn visit_attribute(&mut self, _: &'a Attribute) {
|
||||
// We do not want to lower expressions that appear in attributes,
|
||||
// as they are not accessible to the rest of the HIR.
|
||||
}
|
||||
// HirId handling.
|
||||
bodies: Vec::new(),
|
||||
attrs: SortedMap::default(),
|
||||
children: FxHashMap::default(),
|
||||
current_hir_id_owner: CRATE_DEF_ID,
|
||||
item_local_id_counter: hir::ItemLocalId::new(0),
|
||||
node_id_to_local_id: Default::default(),
|
||||
local_id_to_def_id: SortedMap::new(),
|
||||
trait_map: Default::default(),
|
||||
|
||||
fn visit_item(&mut self, item: &'a Item) {
|
||||
let hir_id = self.lctx.with_hir_id_owner(item.id, |lctx| {
|
||||
let node = lctx.without_in_scope_lifetime_defs(|lctx| lctx.lower_item(item));
|
||||
hir::OwnerNode::Item(node)
|
||||
});
|
||||
// Lowering state.
|
||||
catch_scope: None,
|
||||
loop_scope: None,
|
||||
is_in_loop_condition: false,
|
||||
is_in_trait_impl: false,
|
||||
is_in_dyn_type: false,
|
||||
anonymous_lifetime_mode: AnonymousLifetimeMode::PassThrough,
|
||||
generator_kind: None,
|
||||
task_context: None,
|
||||
current_item: None,
|
||||
lifetimes_to_define: Vec::new(),
|
||||
is_collecting_anonymous_lifetimes: None,
|
||||
in_scope_lifetimes: Vec::new(),
|
||||
allow_try_trait: Some([sym::try_trait_v2][..].into()),
|
||||
allow_gen_future: Some([sym::gen_future][..].into()),
|
||||
allow_into_future: Some([sym::into_future][..].into()),
|
||||
};
|
||||
lctx.with_hir_id_owner(owner, |lctx| f(lctx));
|
||||
|
||||
self.lctx.with_parent_item_lifetime_defs(hir_id, |this| {
|
||||
let this = &mut ItemLowerer { lctx: this };
|
||||
match item.kind {
|
||||
ItemKind::Impl(box Impl { ref of_trait, .. }) => {
|
||||
this.with_trait_impl_ref(of_trait, |this| visit::walk_item(this, item));
|
||||
}
|
||||
_ => visit::walk_item(this, item),
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
fn visit_fn(&mut self, fk: FnKind<'a>, sp: Span, _: NodeId) {
|
||||
match fk {
|
||||
FnKind::Fn(FnCtxt::Foreign, _, sig, _, _) => {
|
||||
self.visit_fn_header(&sig.header);
|
||||
visit::walk_fn_decl(self, &sig.decl);
|
||||
// Don't visit the foreign function body even if it has one, since lowering the
|
||||
// body would have no meaning and will have already been caught as a parse error.
|
||||
}
|
||||
_ => visit::walk_fn(self, fk, sp),
|
||||
for (def_id, info) in lctx.children {
|
||||
self.owners.ensure_contains_elem(def_id, || hir::MaybeOwner::Phantom);
|
||||
debug_assert!(matches!(self.owners[def_id], hir::MaybeOwner::Phantom));
|
||||
self.owners[def_id] = info;
|
||||
}
|
||||
}
|
||||
|
||||
fn visit_assoc_item(&mut self, item: &'a AssocItem, ctxt: AssocCtxt) {
|
||||
debug!(in_scope_lifetimes = ?self.lctx.in_scope_lifetimes);
|
||||
self.lctx.with_hir_id_owner(item.id, |lctx| match ctxt {
|
||||
AssocCtxt::Trait => hir::OwnerNode::TraitItem(lctx.lower_trait_item(item)),
|
||||
AssocCtxt::Impl => hir::OwnerNode::ImplItem(lctx.lower_impl_item(item)),
|
||||
});
|
||||
pub(super) fn lower_node(
|
||||
&mut self,
|
||||
def_id: LocalDefId,
|
||||
) -> hir::MaybeOwner<&'hir hir::OwnerInfo<'hir>> {
|
||||
self.owners.ensure_contains_elem(def_id, || hir::MaybeOwner::Phantom);
|
||||
if let hir::MaybeOwner::Phantom = self.owners[def_id] {
|
||||
let node = self.ast_index[def_id];
|
||||
match node {
|
||||
AstOwner::NonOwner => {}
|
||||
AstOwner::Crate(c) => self.lower_crate(c),
|
||||
AstOwner::Item(item) => self.lower_item(item),
|
||||
AstOwner::AssocItem(item, ctxt) => self.lower_assoc_item(item, ctxt),
|
||||
AstOwner::ForeignItem(item) => self.lower_foreign_item(item),
|
||||
}
|
||||
}
|
||||
|
||||
visit::walk_assoc_item(self, item, ctxt);
|
||||
self.owners[def_id]
|
||||
}
|
||||
|
||||
fn visit_foreign_item(&mut self, item: &'a ForeignItem) {
|
||||
self.lctx.with_hir_id_owner(item.id, |lctx| {
|
||||
hir::OwnerNode::ForeignItem(lctx.lower_foreign_item(item))
|
||||
});
|
||||
fn lower_crate(&mut self, c: &Crate) {
|
||||
debug_assert_eq!(self.resolver.local_def_id(CRATE_NODE_ID), CRATE_DEF_ID);
|
||||
|
||||
visit::walk_foreign_item(self, item);
|
||||
self.with_lctx(CRATE_NODE_ID, |lctx| {
|
||||
let module = lctx.lower_mod(&c.items, c.spans.inner_span);
|
||||
lctx.lower_attrs(hir::CRATE_HIR_ID, &c.attrs);
|
||||
hir::OwnerNode::Crate(lctx.arena.alloc(module))
|
||||
})
|
||||
}
|
||||
|
||||
fn lower_item(&mut self, item: &Item) {
|
||||
self.with_lctx(item.id, |lctx| hir::OwnerNode::Item(lctx.lower_item(item)))
|
||||
}
|
||||
|
||||
fn lower_assoc_item(&mut self, item: &AssocItem, ctxt: AssocCtxt) {
|
||||
let def_id = self.resolver.local_def_id(item.id);
|
||||
|
||||
let parent_id = {
|
||||
let parent = self.resolver.definitions().def_key(def_id).parent;
|
||||
let local_def_index = parent.unwrap();
|
||||
LocalDefId { local_def_index }
|
||||
};
|
||||
|
||||
let parent_hir = self.lower_node(parent_id).unwrap().node().expect_item();
|
||||
self.with_lctx(item.id, |lctx| {
|
||||
// Evaluate with the lifetimes in `params` in-scope.
|
||||
// This is used to track which lifetimes have already been defined,
|
||||
// and which need to be replicated when lowering an async fn.
|
||||
match parent_hir.kind {
|
||||
hir::ItemKind::Impl(hir::Impl { ref of_trait, ref generics, .. }) => {
|
||||
lctx.is_in_trait_impl = of_trait.is_some();
|
||||
lctx.in_scope_lifetimes = generics
|
||||
.params
|
||||
.iter()
|
||||
.filter(|param| {
|
||||
matches!(param.kind, hir::GenericParamKind::Lifetime { .. })
|
||||
})
|
||||
.map(|param| param.name)
|
||||
.collect();
|
||||
}
|
||||
hir::ItemKind::Trait(_, _, ref generics, ..) => {
|
||||
lctx.in_scope_lifetimes = generics
|
||||
.params
|
||||
.iter()
|
||||
.filter(|param| {
|
||||
matches!(param.kind, hir::GenericParamKind::Lifetime { .. })
|
||||
})
|
||||
.map(|param| param.name)
|
||||
.collect();
|
||||
}
|
||||
_ => {}
|
||||
};
|
||||
|
||||
match ctxt {
|
||||
AssocCtxt::Trait => hir::OwnerNode::TraitItem(lctx.lower_trait_item(item)),
|
||||
AssocCtxt::Impl => hir::OwnerNode::ImplItem(lctx.lower_impl_item(item)),
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
fn lower_foreign_item(&mut self, item: &ForeignItem) {
|
||||
self.with_lctx(item.id, |lctx| hir::OwnerNode::ForeignItem(lctx.lower_foreign_item(item)))
|
||||
}
|
||||
}
|
||||
|
||||
impl<'hir> LoweringContext<'_, 'hir> {
|
||||
// Same as the method above, but accepts `hir::GenericParam`s
|
||||
// instead of `ast::GenericParam`s.
|
||||
// This should only be used with generics that have already had their
|
||||
// in-band lifetimes added. In practice, this means that this function is
|
||||
// only used when lowering a child item of a trait or impl.
|
||||
#[tracing::instrument(level = "debug", skip(self, f))]
|
||||
fn with_parent_item_lifetime_defs<T>(
|
||||
&mut self,
|
||||
parent_hir_id: LocalDefId,
|
||||
f: impl FnOnce(&mut Self) -> T,
|
||||
) -> T {
|
||||
let parent_generics = match self.owners[parent_hir_id].unwrap().node().expect_item().kind {
|
||||
hir::ItemKind::Impl(hir::Impl { ref generics, .. })
|
||||
| hir::ItemKind::Trait(_, _, ref generics, ..) => generics.params,
|
||||
_ => &[],
|
||||
};
|
||||
let lt_def_names = parent_generics
|
||||
.iter()
|
||||
.filter_map(|param| match param.kind {
|
||||
hir::GenericParamKind::Lifetime { .. } => {
|
||||
Some(param.name.normalize_to_macros_2_0())
|
||||
}
|
||||
_ => None,
|
||||
})
|
||||
.collect();
|
||||
let old_in_scope_lifetimes = mem::replace(&mut self.in_scope_lifetimes, lt_def_names);
|
||||
debug!(in_scope_lifetimes = ?self.in_scope_lifetimes);
|
||||
|
||||
let res = f(self);
|
||||
|
||||
self.in_scope_lifetimes = old_in_scope_lifetimes;
|
||||
res
|
||||
}
|
||||
|
||||
// Clears (and restores) the `in_scope_lifetimes` field. Used when
|
||||
// visiting nested items, which never inherit in-scope lifetimes
|
||||
// from their surrounding environment.
|
||||
#[tracing::instrument(level = "debug", skip(self, f))]
|
||||
fn without_in_scope_lifetime_defs<T>(&mut self, f: impl FnOnce(&mut Self) -> T) -> T {
|
||||
let old_in_scope_lifetimes = mem::replace(&mut self.in_scope_lifetimes, vec![]);
|
||||
debug!(?old_in_scope_lifetimes);
|
||||
|
||||
// this vector is only used when walking over impl headers,
|
||||
// input types, and the like, and should not be non-empty in
|
||||
// between items
|
||||
assert!(self.lifetimes_to_define.is_empty());
|
||||
|
||||
let res = f(self);
|
||||
|
||||
assert!(self.in_scope_lifetimes.is_empty());
|
||||
self.in_scope_lifetimes = old_in_scope_lifetimes;
|
||||
|
||||
res
|
||||
}
|
||||
|
||||
pub(super) fn lower_mod(&mut self, items: &[P<Item>], inner: Span) -> hir::Mod<'hir> {
|
||||
hir::Mod {
|
||||
inner: self.lower_span(inner),
|
||||
@ -548,12 +565,11 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
||||
let new_id = self.resolver.local_def_id(new_node_id);
|
||||
let Some(res) = resolutions.next() else {
|
||||
// Associate an HirId to both ids even if there is no resolution.
|
||||
self.owners.ensure_contains_elem(new_id, || hir::MaybeOwner::Phantom);
|
||||
let _old = std::mem::replace(
|
||||
&mut self.owners[new_id],
|
||||
let _old = self.children.insert(
|
||||
new_id,
|
||||
hir::MaybeOwner::NonOwner(hir::HirId::make_owner(new_id)),
|
||||
);
|
||||
debug_assert!(matches!(_old, hir::MaybeOwner::Phantom));
|
||||
debug_assert!(_old.is_none());
|
||||
continue;
|
||||
};
|
||||
let ident = *ident;
|
||||
|
@ -57,7 +57,6 @@ use rustc_hir::intravisit;
|
||||
use rustc_hir::{ConstArg, GenericArg, ItemLocalId, ParamName, TraitCandidate};
|
||||
use rustc_index::vec::{Idx, IndexVec};
|
||||
use rustc_query_system::ich::StableHashingContext;
|
||||
use rustc_session::lint::LintBuffer;
|
||||
use rustc_session::parse::feature_err;
|
||||
use rustc_session::utils::{FlattenNonterminals, NtToTokenstream};
|
||||
use rustc_session::Session;
|
||||
@ -100,12 +99,12 @@ struct LoweringContext<'a, 'hir: 'a> {
|
||||
/// Used to allocate HIR nodes.
|
||||
arena: &'hir Arena<'hir>,
|
||||
|
||||
/// The items being lowered are collected here.
|
||||
owners: IndexVec<LocalDefId, hir::MaybeOwner<&'hir hir::OwnerInfo<'hir>>>,
|
||||
/// Bodies inside the owner being lowered.
|
||||
bodies: Vec<(hir::ItemLocalId, &'hir hir::Body<'hir>)>,
|
||||
/// Attributes inside the owner being lowered.
|
||||
attrs: SortedMap<hir::ItemLocalId, &'hir [Attribute]>,
|
||||
/// Collect items that were created by lowering the current owner.
|
||||
children: FxHashMap<LocalDefId, hir::MaybeOwner<&'hir hir::OwnerInfo<'hir>>>,
|
||||
|
||||
generator_kind: Option<hir::GeneratorKind>,
|
||||
|
||||
@ -159,7 +158,7 @@ struct LoweringContext<'a, 'hir: 'a> {
|
||||
}
|
||||
|
||||
pub trait ResolverAstLowering {
|
||||
fn def_key(&mut self, id: DefId) -> DefKey;
|
||||
fn def_key(&self, id: DefId) -> DefKey;
|
||||
|
||||
fn def_span(&self, id: LocalDefId) -> Span;
|
||||
|
||||
@ -171,18 +170,14 @@ pub trait ResolverAstLowering {
|
||||
fn get_partial_res(&self, id: NodeId) -> Option<PartialRes>;
|
||||
|
||||
/// Obtains per-namespace resolutions for `use` statement with the given `NodeId`.
|
||||
fn get_import_res(&mut self, id: NodeId) -> PerNS<Option<Res<NodeId>>>;
|
||||
fn get_import_res(&self, id: NodeId) -> PerNS<Option<Res<NodeId>>>;
|
||||
|
||||
/// Obtains resolution for a label with the given `NodeId`.
|
||||
fn get_label_res(&mut self, id: NodeId) -> Option<NodeId>;
|
||||
|
||||
/// We must keep the set of definitions up to date as we add nodes that weren't in the AST.
|
||||
/// This should only return `None` during testing.
|
||||
fn definitions(&mut self) -> &mut Definitions;
|
||||
fn get_label_res(&self, id: NodeId) -> Option<NodeId>;
|
||||
|
||||
fn create_stable_hashing_context(&self) -> StableHashingContext<'_>;
|
||||
|
||||
fn lint_buffer(&mut self) -> &mut LintBuffer;
|
||||
fn definitions(&self) -> &Definitions;
|
||||
|
||||
fn next_node_id(&mut self) -> NodeId;
|
||||
|
||||
@ -337,6 +332,81 @@ impl FnDeclKind {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone)]
|
||||
enum AstOwner<'a> {
|
||||
NonOwner,
|
||||
Crate(&'a ast::Crate),
|
||||
Item(&'a ast::Item),
|
||||
AssocItem(&'a ast::AssocItem, visit::AssocCtxt),
|
||||
ForeignItem(&'a ast::ForeignItem),
|
||||
}
|
||||
|
||||
fn index_crate<'a>(
|
||||
resolver: &dyn ResolverAstLowering,
|
||||
krate: &'a Crate,
|
||||
) -> IndexVec<LocalDefId, AstOwner<'a>> {
|
||||
let mut indexer = Indexer { resolver, index: IndexVec::new() };
|
||||
indexer.index.ensure_contains_elem(CRATE_DEF_ID, || AstOwner::NonOwner);
|
||||
indexer.index[CRATE_DEF_ID] = AstOwner::Crate(krate);
|
||||
visit::walk_crate(&mut indexer, krate);
|
||||
return indexer.index;
|
||||
|
||||
struct Indexer<'s, 'a> {
|
||||
resolver: &'s dyn ResolverAstLowering,
|
||||
index: IndexVec<LocalDefId, AstOwner<'a>>,
|
||||
}
|
||||
|
||||
impl<'a> visit::Visitor<'a> for Indexer<'_, 'a> {
|
||||
fn visit_attribute(&mut self, _: &'a Attribute) {
|
||||
// We do not want to lower expressions that appear in attributes,
|
||||
// as they are not accessible to the rest of the HIR.
|
||||
}
|
||||
|
||||
fn visit_item(&mut self, item: &'a ast::Item) {
|
||||
let def_id = self.resolver.local_def_id(item.id);
|
||||
self.index.ensure_contains_elem(def_id, || AstOwner::NonOwner);
|
||||
self.index[def_id] = AstOwner::Item(item);
|
||||
visit::walk_item(self, item)
|
||||
}
|
||||
|
||||
fn visit_assoc_item(&mut self, item: &'a ast::AssocItem, ctxt: visit::AssocCtxt) {
|
||||
let def_id = self.resolver.local_def_id(item.id);
|
||||
self.index.ensure_contains_elem(def_id, || AstOwner::NonOwner);
|
||||
self.index[def_id] = AstOwner::AssocItem(item, ctxt);
|
||||
visit::walk_assoc_item(self, item, ctxt);
|
||||
}
|
||||
|
||||
fn visit_foreign_item(&mut self, item: &'a ast::ForeignItem) {
|
||||
let def_id = self.resolver.local_def_id(item.id);
|
||||
self.index.ensure_contains_elem(def_id, || AstOwner::NonOwner);
|
||||
self.index[def_id] = AstOwner::ForeignItem(item);
|
||||
visit::walk_foreign_item(self, item);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Compute the hash for the HIR of the full crate.
|
||||
/// This hash will then be part of the crate_hash which is stored in the metadata.
|
||||
fn compute_hir_hash(
|
||||
resolver: &mut dyn ResolverAstLowering,
|
||||
owners: &IndexVec<LocalDefId, hir::MaybeOwner<&hir::OwnerInfo<'_>>>,
|
||||
) -> Fingerprint {
|
||||
let mut hir_body_nodes: Vec<_> = owners
|
||||
.iter_enumerated()
|
||||
.filter_map(|(def_id, info)| {
|
||||
let info = info.as_owner()?;
|
||||
let def_path_hash = resolver.definitions().def_path_hash(def_id);
|
||||
Some((def_path_hash, info))
|
||||
})
|
||||
.collect();
|
||||
hir_body_nodes.sort_unstable_by_key(|bn| bn.0);
|
||||
|
||||
let mut stable_hasher = StableHasher::new();
|
||||
let mut hcx = resolver.create_stable_hashing_context();
|
||||
hir_body_nodes.hash_stable(&mut hcx, &mut stable_hasher);
|
||||
stable_hasher.finish()
|
||||
}
|
||||
|
||||
pub fn lower_crate<'a, 'hir>(
|
||||
sess: &'a Session,
|
||||
krate: &'a Crate,
|
||||
@ -346,38 +416,26 @@ pub fn lower_crate<'a, 'hir>(
|
||||
) -> &'hir hir::Crate<'hir> {
|
||||
let _prof_timer = sess.prof.verbose_generic_activity("hir_lowering");
|
||||
|
||||
let owners =
|
||||
let ast_index = index_crate(resolver, krate);
|
||||
|
||||
let mut owners =
|
||||
IndexVec::from_fn_n(|_| hir::MaybeOwner::Phantom, resolver.definitions().def_index_count());
|
||||
LoweringContext {
|
||||
sess,
|
||||
resolver,
|
||||
nt_to_tokenstream,
|
||||
arena,
|
||||
owners,
|
||||
bodies: Vec::new(),
|
||||
attrs: SortedMap::new(),
|
||||
catch_scope: None,
|
||||
loop_scope: None,
|
||||
is_in_loop_condition: false,
|
||||
is_in_trait_impl: false,
|
||||
is_in_dyn_type: false,
|
||||
anonymous_lifetime_mode: AnonymousLifetimeMode::PassThrough,
|
||||
current_hir_id_owner: CRATE_DEF_ID,
|
||||
item_local_id_counter: hir::ItemLocalId::new(0),
|
||||
node_id_to_local_id: FxHashMap::default(),
|
||||
local_id_to_def_id: SortedMap::new(),
|
||||
trait_map: FxHashMap::default(),
|
||||
generator_kind: None,
|
||||
task_context: None,
|
||||
current_item: None,
|
||||
lifetimes_to_define: Vec::new(),
|
||||
is_collecting_anonymous_lifetimes: None,
|
||||
in_scope_lifetimes: Vec::new(),
|
||||
allow_try_trait: Some([sym::try_trait_v2][..].into()),
|
||||
allow_gen_future: Some([sym::gen_future][..].into()),
|
||||
allow_into_future: Some([sym::into_future][..].into()),
|
||||
|
||||
for def_id in ast_index.indices() {
|
||||
item::ItemLowerer {
|
||||
sess,
|
||||
resolver,
|
||||
nt_to_tokenstream,
|
||||
arena,
|
||||
ast_index: &ast_index,
|
||||
owners: &mut owners,
|
||||
}
|
||||
.lower_node(def_id);
|
||||
}
|
||||
.lower_crate(krate)
|
||||
|
||||
let hir_hash = compute_hir_hash(resolver, &owners);
|
||||
let krate = hir::Crate { owners, hir_hash };
|
||||
arena.alloc(krate)
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, PartialEq)]
|
||||
@ -446,49 +504,11 @@ enum AnonymousLifetimeMode {
|
||||
}
|
||||
|
||||
impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
||||
fn lower_crate(mut self, c: &Crate) -> &'hir hir::Crate<'hir> {
|
||||
debug_assert_eq!(self.resolver.local_def_id(CRATE_NODE_ID), CRATE_DEF_ID);
|
||||
|
||||
visit::walk_crate(&mut item::ItemLowerer { lctx: &mut self }, c);
|
||||
|
||||
self.with_hir_id_owner(CRATE_NODE_ID, |lctx| {
|
||||
let module = lctx.lower_mod(&c.items, c.spans.inner_span);
|
||||
lctx.lower_attrs(hir::CRATE_HIR_ID, &c.attrs);
|
||||
hir::OwnerNode::Crate(lctx.arena.alloc(module))
|
||||
});
|
||||
|
||||
let hir_hash = self.compute_hir_hash();
|
||||
|
||||
let krate = hir::Crate { owners: self.owners, hir_hash };
|
||||
self.arena.alloc(krate)
|
||||
}
|
||||
|
||||
/// Compute the hash for the HIR of the full crate.
|
||||
/// This hash will then be part of the crate_hash which is stored in the metadata.
|
||||
fn compute_hir_hash(&mut self) -> Fingerprint {
|
||||
let definitions = self.resolver.definitions();
|
||||
let mut hir_body_nodes: Vec<_> = self
|
||||
.owners
|
||||
.iter_enumerated()
|
||||
.filter_map(|(def_id, info)| {
|
||||
let info = info.as_owner()?;
|
||||
let def_path_hash = definitions.def_path_hash(def_id);
|
||||
Some((def_path_hash, info))
|
||||
})
|
||||
.collect();
|
||||
hir_body_nodes.sort_unstable_by_key(|bn| bn.0);
|
||||
|
||||
let mut stable_hasher = StableHasher::new();
|
||||
let mut hcx = self.resolver.create_stable_hashing_context();
|
||||
hir_body_nodes.hash_stable(&mut hcx, &mut stable_hasher);
|
||||
stable_hasher.finish()
|
||||
}
|
||||
|
||||
fn with_hir_id_owner(
|
||||
&mut self,
|
||||
owner: NodeId,
|
||||
f: impl FnOnce(&mut Self) -> hir::OwnerNode<'hir>,
|
||||
) -> LocalDefId {
|
||||
) {
|
||||
let def_id = self.resolver.local_def_id(owner);
|
||||
|
||||
let current_attrs = std::mem::take(&mut self.attrs);
|
||||
@ -516,15 +536,15 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
||||
self.current_hir_id_owner = current_owner;
|
||||
self.item_local_id_counter = current_local_counter;
|
||||
|
||||
self.owners.ensure_contains_elem(def_id, || hir::MaybeOwner::Phantom);
|
||||
self.owners[def_id] = hir::MaybeOwner::Owner(self.arena.alloc(info));
|
||||
|
||||
def_id
|
||||
let _old = self.children.insert(def_id, hir::MaybeOwner::Owner(info));
|
||||
debug_assert!(_old.is_none())
|
||||
}
|
||||
|
||||
fn make_owner_info(&mut self, node: hir::OwnerNode<'hir>) -> hir::OwnerInfo<'hir> {
|
||||
fn make_owner_info(&mut self, node: hir::OwnerNode<'hir>) -> &'hir hir::OwnerInfo<'hir> {
|
||||
let attrs = std::mem::take(&mut self.attrs);
|
||||
let mut bodies = std::mem::take(&mut self.bodies);
|
||||
let local_id_to_def_id = std::mem::take(&mut self.local_id_to_def_id);
|
||||
let trait_map = std::mem::take(&mut self.trait_map);
|
||||
|
||||
#[cfg(debug_assertions)]
|
||||
for (id, attrs) in attrs.iter() {
|
||||
@ -544,7 +564,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
||||
hash_without_bodies,
|
||||
nodes,
|
||||
bodies,
|
||||
local_id_to_def_id: std::mem::take(&mut self.local_id_to_def_id),
|
||||
local_id_to_def_id,
|
||||
};
|
||||
let attrs = {
|
||||
let mut hcx = self.resolver.create_stable_hashing_context();
|
||||
@ -554,7 +574,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
||||
hir::AttributeMap { map: attrs, hash }
|
||||
};
|
||||
|
||||
hir::OwnerInfo { nodes, parenting, attrs, trait_map: std::mem::take(&mut self.trait_map) }
|
||||
self.arena.alloc(hir::OwnerInfo { nodes, parenting, attrs, trait_map })
|
||||
}
|
||||
|
||||
/// Hash the HIR node twice, one deep and one shallow hash. This allows to differentiate
|
||||
@ -602,11 +622,8 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
||||
|
||||
assert_ne!(local_id, hir::ItemLocalId::new(0));
|
||||
if let Some(def_id) = self.resolver.opt_local_def_id(ast_node_id) {
|
||||
self.owners.ensure_contains_elem(def_id, || hir::MaybeOwner::Phantom);
|
||||
if let o @ hir::MaybeOwner::Phantom = &mut self.owners[def_id] {
|
||||
// Do not override a `MaybeOwner::Owner` that may already here.
|
||||
*o = hir::MaybeOwner::NonOwner(hir_id);
|
||||
}
|
||||
// Do not override a `MaybeOwner::Owner` that may already here.
|
||||
self.children.entry(def_id).or_insert(hir::MaybeOwner::NonOwner(hir_id));
|
||||
self.local_id_to_def_id.insert(local_id, def_id);
|
||||
}
|
||||
|
||||
|
@ -99,6 +99,7 @@ impl DefPathTable {
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct Definitions {
|
||||
table: DefPathTable,
|
||||
next_disambiguator: FxHashMap<(LocalDefId, DefPathData), u32>,
|
||||
|
||||
/// Item with a given `LocalDefId` was defined during macro expansion with ID `ExpnId`.
|
||||
expansions_that_defined: FxHashMap<LocalDefId, ExpnId>,
|
||||
@ -340,6 +341,7 @@ impl Definitions {
|
||||
|
||||
Definitions {
|
||||
table,
|
||||
next_disambiguator: Default::default(),
|
||||
expansions_that_defined: Default::default(),
|
||||
def_id_to_span,
|
||||
stable_crate_id,
|
||||
@ -357,7 +359,6 @@ impl Definitions {
|
||||
parent: LocalDefId,
|
||||
data: DefPathData,
|
||||
expn_id: ExpnId,
|
||||
mut next_disambiguator: impl FnMut(LocalDefId, DefPathData) -> u32,
|
||||
span: Span,
|
||||
) -> LocalDefId {
|
||||
debug!("create_def(parent={:?}, data={:?}, expn_id={:?})", parent, data, expn_id);
|
||||
@ -365,7 +366,13 @@ impl Definitions {
|
||||
// The root node must be created with `create_root_def()`.
|
||||
assert!(data != DefPathData::CrateRoot);
|
||||
|
||||
let disambiguator = next_disambiguator(parent, data);
|
||||
// Find the next free disambiguator for this key.
|
||||
let disambiguator = {
|
||||
let next_disamb = self.next_disambiguator.entry((parent, data)).or_insert(0);
|
||||
let disambiguator = *next_disamb;
|
||||
*next_disamb = next_disamb.checked_add(1).expect("disambiguator overflow");
|
||||
disambiguator
|
||||
};
|
||||
let key = DefKey {
|
||||
parent: Some(parent.local_def_index),
|
||||
disambiguated_data: DisambiguatedDefPathData { data, disambiguator },
|
||||
|
@ -487,12 +487,24 @@ pub fn configure_and_expand(
|
||||
}
|
||||
});
|
||||
|
||||
sess.time("early_lint_checks", || {
|
||||
let lint_buffer = Some(std::mem::take(resolver.lint_buffer()));
|
||||
rustc_lint::check_ast_node(
|
||||
sess,
|
||||
false,
|
||||
lint_store,
|
||||
resolver.registered_tools(),
|
||||
lint_buffer,
|
||||
rustc_lint::BuiltinCombinedEarlyLintPass::new(),
|
||||
&krate,
|
||||
)
|
||||
});
|
||||
|
||||
Ok(krate)
|
||||
}
|
||||
|
||||
pub fn lower_to_hir<'res, 'tcx>(
|
||||
sess: &'tcx Session,
|
||||
lint_store: &LintStore,
|
||||
resolver: &'res mut Resolver<'_>,
|
||||
krate: Rc<ast::Crate>,
|
||||
arena: &'tcx rustc_ast_lowering::Arena<'tcx>,
|
||||
@ -506,19 +518,6 @@ pub fn lower_to_hir<'res, 'tcx>(
|
||||
arena,
|
||||
);
|
||||
|
||||
sess.time("early_lint_checks", || {
|
||||
let lint_buffer = Some(std::mem::take(resolver.lint_buffer()));
|
||||
rustc_lint::check_ast_node(
|
||||
sess,
|
||||
false,
|
||||
lint_store,
|
||||
resolver.registered_tools(),
|
||||
lint_buffer,
|
||||
rustc_lint::BuiltinCombinedEarlyLintPass::new(),
|
||||
&*krate,
|
||||
)
|
||||
});
|
||||
|
||||
// Drop AST to free memory
|
||||
sess.time("drop_ast", || std::mem::drop(krate));
|
||||
|
||||
@ -852,9 +851,8 @@ pub fn create_global_ctxt<'tcx>(
|
||||
dep_graph.assert_ignored();
|
||||
|
||||
let sess = &compiler.session();
|
||||
let krate = resolver
|
||||
.borrow_mut()
|
||||
.access(|resolver| lower_to_hir(sess, &lint_store, resolver, krate, hir_arena));
|
||||
let krate =
|
||||
resolver.borrow_mut().access(|resolver| lower_to_hir(sess, resolver, krate, hir_arena));
|
||||
let resolver_outputs = BoxedResolver::to_resolver_outputs(resolver);
|
||||
|
||||
let query_result_on_disk_cache = rustc_incremental::load_query_result_cache(sess);
|
||||
|
@ -1061,7 +1061,6 @@ pub struct Resolver<'a> {
|
||||
/// and how the `impl Trait` fragments were introduced.
|
||||
invocation_parents: FxHashMap<LocalExpnId, (LocalDefId, ImplTraitContext)>,
|
||||
|
||||
next_disambiguator: FxHashMap<(LocalDefId, DefPathData), u32>,
|
||||
/// Some way to know that we are in a *trait* impl in `visit_assoc_item`.
|
||||
/// FIXME: Replace with a more general AST map (together with some other fields).
|
||||
trait_impl_items: FxHashSet<LocalDefId>,
|
||||
@ -1160,9 +1159,9 @@ impl<'a, 'b> DefIdTree for &'a Resolver<'b> {
|
||||
/// This interface is used through the AST→HIR step, to embed full paths into the HIR. After that
|
||||
/// the resolver is no longer needed as all the relevant information is inline.
|
||||
impl ResolverAstLowering for Resolver<'_> {
|
||||
fn def_key(&mut self, id: DefId) -> DefKey {
|
||||
fn def_key(&self, id: DefId) -> DefKey {
|
||||
if let Some(id) = id.as_local() {
|
||||
self.definitions().def_key(id)
|
||||
self.definitions.def_key(id)
|
||||
} else {
|
||||
self.cstore().def_key(id)
|
||||
}
|
||||
@ -1189,24 +1188,20 @@ impl ResolverAstLowering for Resolver<'_> {
|
||||
self.partial_res_map.get(&id).cloned()
|
||||
}
|
||||
|
||||
fn get_import_res(&mut self, id: NodeId) -> PerNS<Option<Res>> {
|
||||
fn get_import_res(&self, id: NodeId) -> PerNS<Option<Res>> {
|
||||
self.import_res_map.get(&id).cloned().unwrap_or_default()
|
||||
}
|
||||
|
||||
fn get_label_res(&mut self, id: NodeId) -> Option<NodeId> {
|
||||
fn get_label_res(&self, id: NodeId) -> Option<NodeId> {
|
||||
self.label_res_map.get(&id).cloned()
|
||||
}
|
||||
|
||||
fn definitions(&mut self) -> &mut Definitions {
|
||||
&mut self.definitions
|
||||
}
|
||||
|
||||
fn create_stable_hashing_context(&self) -> StableHashingContext<'_> {
|
||||
StableHashingContext::new(self.session, &self.definitions, self.crate_loader.cstore())
|
||||
}
|
||||
|
||||
fn lint_buffer(&mut self) -> &mut LintBuffer {
|
||||
&mut self.lint_buffer
|
||||
fn definitions(&self) -> &Definitions {
|
||||
&self.definitions
|
||||
}
|
||||
|
||||
fn next_node_id(&mut self) -> NodeId {
|
||||
@ -1249,16 +1244,7 @@ impl ResolverAstLowering for Resolver<'_> {
|
||||
self.definitions.def_key(self.node_id_to_def_id[&node_id]),
|
||||
);
|
||||
|
||||
// Find the next free disambiguator for this key.
|
||||
let next_disambiguator = &mut self.next_disambiguator;
|
||||
let next_disambiguator = |parent, data| {
|
||||
let next_disamb = next_disambiguator.entry((parent, data)).or_insert(0);
|
||||
let disambiguator = *next_disamb;
|
||||
*next_disamb = next_disamb.checked_add(1).expect("disambiguator overflow");
|
||||
disambiguator
|
||||
};
|
||||
|
||||
let def_id = self.definitions.create_def(parent, data, expn_id, next_disambiguator, span);
|
||||
let def_id = self.definitions.create_def(parent, data, expn_id, span);
|
||||
|
||||
// Some things for which we allocate `LocalDefId`s don't correspond to
|
||||
// anything in the AST, so they don't have a `NodeId`. For these cases
|
||||
@ -1430,7 +1416,6 @@ impl<'a> Resolver<'a> {
|
||||
def_id_to_node_id,
|
||||
placeholder_field_indices: Default::default(),
|
||||
invocation_parents,
|
||||
next_disambiguator: Default::default(),
|
||||
trait_impl_items: Default::default(),
|
||||
legacy_const_generic_args: Default::default(),
|
||||
item_generics_num_lifetimes: Default::default(),
|
||||
|
Loading…
Reference in New Issue
Block a user