Auto merge of #88703 - cjgillot:lazymod, r=petrochenkov

Gather module items after lowering.

This avoids having a non-local analysis inside lowering.

By implementing `hir_module_items` using a visitor, we make sure that iterations and visitors are consistent.
This commit is contained in:
bors
2021-09-19 16:13:42 +00:00
14 changed files with 147 additions and 83 deletions

View File

@@ -1,6 +1,6 @@
use self::collector::NodeCollector;
use crate::hir::{AttributeMap, IndexedHir, Owner};
use crate::hir::{AttributeMap, IndexedHir, ModuleItems, Owner};
use crate::ty::TyCtxt;
use rustc_ast as ast;
use rustc_data_structures::fingerprint::Fingerprint;
@@ -19,6 +19,7 @@ use rustc_span::source_map::Spanned;
use rustc_span::symbol::{kw, sym, Ident, Symbol};
use rustc_span::Span;
use rustc_target::spec::abi::Abi;
use std::collections::VecDeque;
pub mod blocks;
mod collector;
@@ -536,23 +537,55 @@ impl<'hir> Map<'hir> {
{
let module = self.tcx.hir_module_items(module);
for id in &module.items {
for id in module.items.iter() {
visitor.visit_item(self.item(*id));
}
for id in &module.trait_items {
for id in module.trait_items.iter() {
visitor.visit_trait_item(self.trait_item(*id));
}
for id in &module.impl_items {
for id in module.impl_items.iter() {
visitor.visit_impl_item(self.impl_item(*id));
}
for id in &module.foreign_items {
for id in module.foreign_items.iter() {
visitor.visit_foreign_item(self.foreign_item(*id));
}
}
pub fn for_each_module(&self, f: impl Fn(LocalDefId)) {
let mut queue = VecDeque::new();
queue.push_back(CRATE_DEF_ID);
while let Some(id) = queue.pop_front() {
f(id);
let items = self.tcx.hir_module_items(id);
queue.extend(items.submodules.iter().copied())
}
}
#[cfg(not(parallel_compiler))]
#[inline]
pub fn par_for_each_module(&self, f: impl Fn(LocalDefId)) {
self.for_each_module(f)
}
#[cfg(parallel_compiler)]
pub fn par_for_each_module(&self, f: impl Fn(LocalDefId) + Sync) {
use rustc_data_structures::sync::{par_iter, ParallelIterator};
par_iter_submodules(self.tcx, CRATE_DEF_ID, &f);
fn par_iter_submodules<F>(tcx: TyCtxt<'_>, module: LocalDefId, f: &F)
where
F: Fn(LocalDefId) + Sync,
{
(*f)(module);
let items = tcx.hir_module_items(module);
par_iter(&items.submodules[..]).for_each(|&sm| par_iter_submodules(tcx, sm, f));
}
}
/// Returns an iterator for the nodes in the ancestor tree of the `current_id`
/// until the crate root is reached. Prefer this over your own loop using `get_parent_node`.
pub fn parent_iter(&self, current_id: HirId) -> ParentHirIterator<'_, 'hir> {
@@ -1113,3 +1146,69 @@ fn hir_id_to_string(map: &Map<'_>, id: HirId) -> String {
None => format!("unknown node{}", id_str),
}
}
pub(super) fn hir_module_items(tcx: TyCtxt<'_>, module_id: LocalDefId) -> ModuleItems {
let mut collector = ModuleCollector {
tcx,
submodules: Vec::default(),
items: Vec::default(),
trait_items: Vec::default(),
impl_items: Vec::default(),
foreign_items: Vec::default(),
};
let (hir_mod, span, hir_id) = tcx.hir().get_module(module_id);
collector.visit_mod(hir_mod, span, hir_id);
let ModuleCollector { submodules, items, trait_items, impl_items, foreign_items, .. } =
collector;
return ModuleItems {
submodules: submodules.into_boxed_slice(),
items: items.into_boxed_slice(),
trait_items: trait_items.into_boxed_slice(),
impl_items: impl_items.into_boxed_slice(),
foreign_items: foreign_items.into_boxed_slice(),
};
struct ModuleCollector<'tcx> {
tcx: TyCtxt<'tcx>,
submodules: Vec<LocalDefId>,
items: Vec<ItemId>,
trait_items: Vec<TraitItemId>,
impl_items: Vec<ImplItemId>,
foreign_items: Vec<ForeignItemId>,
}
impl<'hir> Visitor<'hir> for ModuleCollector<'hir> {
type Map = Map<'hir>;
fn nested_visit_map(&mut self) -> intravisit::NestedVisitorMap<Self::Map> {
intravisit::NestedVisitorMap::All(self.tcx.hir())
}
fn visit_item(&mut self, item: &'hir Item<'hir>) {
self.items.push(item.item_id());
if let ItemKind::Mod(..) = item.kind {
// If this declares another module, do not recurse inside it.
self.submodules.push(item.def_id);
} else {
intravisit::walk_item(self, item)
}
}
fn visit_trait_item(&mut self, item: &'hir TraitItem<'hir>) {
self.trait_items.push(item.trait_item_id());
intravisit::walk_trait_item(self, item)
}
fn visit_impl_item(&mut self, item: &'hir ImplItem<'hir>) {
self.impl_items.push(item.impl_item_id());
intravisit::walk_impl_item(self, item)
}
fn visit_foreign_item(&mut self, item: &'hir ForeignItem<'hir>) {
self.foreign_items.push(item.foreign_item_id());
intravisit::walk_foreign_item(self, item)
}
}
}

View File

@@ -121,6 +121,17 @@ impl<'tcx> AttributeMap<'tcx> {
}
}
/// Gather the LocalDefId for each item-like within a module, including items contained within
/// bodies. The Ids are in visitor order. This is used to partition a pass between modules.
#[derive(Debug, HashStable)]
pub struct ModuleItems {
submodules: Box<[LocalDefId]>,
items: Box<[ItemId]>,
trait_items: Box<[TraitItemId]>,
impl_items: Box<[ImplItemId]>,
foreign_items: Box<[ForeignItemId]>,
}
impl<'tcx> TyCtxt<'tcx> {
#[inline(always)]
pub fn hir(self) -> map::Map<'tcx> {
@@ -140,7 +151,7 @@ pub fn provide(providers: &mut Providers) {
providers.hir_crate = |tcx, ()| tcx.untracked_crate;
providers.index_hir = map::index_hir;
providers.crate_hash = map::crate_hash;
providers.hir_module_items = |tcx, id| &tcx.untracked_crate.modules[&id];
providers.hir_module_items = map::hir_module_items;
providers.hir_owner = |tcx, id| {
let owner = tcx.index_hir(()).map[id].as_ref()?;
let node = owner.nodes[ItemLocalId::new(0)].as_ref().unwrap().node;