Auto merge of #12840 - Veykril:be-lazy, r=Veykril

internal: Use ItemTree for variant, field and module attribute collection in attrs_query

Less parsing = very good, should speed up lang item collection as that basically probes attributes of all enum variants which currently triggers parsing

Not fond of how this is searching for the correct index, ideally we'd map between HIR and item tree Id here but I am not sure how, storing the item tree ids in the HIR version doesn't work due to the usage of `Trace`...
This commit is contained in:
bors 2022-07-22 20:35:31 +00:00
commit d469e0de9a
5 changed files with 182 additions and 116 deletions

View file

@ -136,9 +136,9 @@ impl EnumData {
let enum_ = &item_tree[loc.id.value];
let mut variants = Arena::new();
for var_id in enum_.variants.clone() {
if item_tree.attrs(db, krate, var_id.into()).is_cfg_enabled(&cfg_options) {
let var = &item_tree[var_id];
for tree_id in enum_.variants.clone() {
if item_tree.attrs(db, krate, tree_id.into()).is_cfg_enabled(&cfg_options) {
let var = &item_tree[tree_id];
let var_data = lower_fields(
db,
krate,

View file

@ -7,7 +7,7 @@ use cfg::{CfgExpr, CfgOptions};
use either::Either;
use hir_expand::{hygiene::Hygiene, name::AsName, HirFileId, InFile};
use itertools::Itertools;
use la_arena::ArenaMap;
use la_arena::{ArenaMap, Idx, RawIdx};
use mbe::{syntax_node_to_token_tree, DelimiterKind, Punct};
use smallvec::{smallvec, SmallVec};
use syntax::{
@ -19,12 +19,12 @@ use tt::Subtree;
use crate::{
db::DefDatabase,
intern::Interned,
item_tree::{ItemTreeId, ItemTreeNode},
nameres::ModuleSource,
item_tree::{AttrOwner, Fields, ItemTreeId, ItemTreeNode},
nameres::{ModuleOrigin, ModuleSource},
path::{ModPath, PathKind},
src::{HasChildSource, HasSource},
AdtId, AttrDefId, EnumId, GenericParamId, HasModule, LocalEnumVariantId, LocalFieldId, Lookup,
MacroId, VariantId,
AdtId, AttrDefId, EnumId, GenericParamId, LocalEnumVariantId, LocalFieldId, Lookup, MacroId,
VariantId,
};
/// Holds documentation
@ -201,15 +201,23 @@ impl Attrs {
db: &dyn DefDatabase,
e: EnumId,
) -> Arc<ArenaMap<LocalEnumVariantId, Attrs>> {
let krate = e.lookup(db).container.krate;
let src = e.child_source(db);
// FIXME: There should be some proper form of mapping between item tree enum variant ids and hir enum variant ids
let mut res = ArenaMap::default();
for (id, var) in src.value.iter() {
let attrs = RawAttrs::from_attrs_owner(db, src.with_value(var as &dyn ast::HasAttrs))
.filter(db, krate);
let loc = e.lookup(db);
let krate = loc.container.krate;
let item_tree = loc.id.item_tree(db);
let enum_ = &item_tree[loc.id.value];
let crate_graph = db.crate_graph();
let cfg_options = &crate_graph[krate].cfg_options;
res.insert(id, attrs)
let mut idx = 0;
for variant in enum_.variants.clone() {
let attrs = item_tree.attrs(db, krate, variant.into());
if attrs.is_cfg_enabled(cfg_options) {
res.insert(Idx::from_raw(RawIdx::from(idx)), attrs);
idx += 1;
}
}
Arc::new(res)
@ -219,18 +227,64 @@ impl Attrs {
db: &dyn DefDatabase,
v: VariantId,
) -> Arc<ArenaMap<LocalFieldId, Attrs>> {
let krate = v.module(db).krate;
let src = v.child_source(db);
// FIXME: There should be some proper form of mapping between item tree field ids and hir field ids
let mut res = ArenaMap::default();
for (id, fld) in src.value.iter() {
let owner: &dyn HasAttrs = match fld {
Either::Left(tuple) => tuple,
Either::Right(record) => record,
};
let attrs = RawAttrs::from_attrs_owner(db, src.with_value(owner)).filter(db, krate);
let crate_graph = db.crate_graph();
let (fields, item_tree, krate) = match v {
VariantId::EnumVariantId(it) => {
let e = it.parent;
let loc = e.lookup(db);
let krate = loc.container.krate;
let item_tree = loc.id.item_tree(db);
let enum_ = &item_tree[loc.id.value];
res.insert(id, attrs);
let cfg_options = &crate_graph[krate].cfg_options;
let variant = 'tri: loop {
let mut idx = 0;
for variant in enum_.variants.clone() {
let attrs = item_tree.attrs(db, krate, variant.into());
if attrs.is_cfg_enabled(cfg_options) {
if it.local_id == Idx::from_raw(RawIdx::from(idx)) {
break 'tri variant;
}
idx += 1;
}
}
return Arc::new(res);
};
(item_tree[variant].fields.clone(), item_tree, krate)
}
VariantId::StructId(it) => {
let loc = it.lookup(db);
let krate = loc.container.krate;
let item_tree = loc.id.item_tree(db);
let struct_ = &item_tree[loc.id.value];
(struct_.fields.clone(), item_tree, krate)
}
VariantId::UnionId(it) => {
let loc = it.lookup(db);
let krate = loc.container.krate;
let item_tree = loc.id.item_tree(db);
let union_ = &item_tree[loc.id.value];
(union_.fields.clone(), item_tree, krate)
}
};
let fields = match fields {
Fields::Record(fields) | Fields::Tuple(fields) => fields,
Fields::Unit => return Arc::new(res),
};
let cfg_options = &crate_graph[krate].cfg_options;
let mut idx = 0;
for field in fields {
let attrs = item_tree.attrs(db, krate, field.into());
if attrs.is_cfg_enabled(cfg_options) {
res.insert(Idx::from_raw(RawIdx::from(idx)), attrs);
idx += 1;
}
}
Arc::new(res)
@ -243,11 +297,14 @@ impl Attrs {
impl Attrs {
pub fn cfg(&self) -> Option<CfgExpr> {
let mut cfgs = self.by_key("cfg").tt_values().map(CfgExpr::parse).collect::<Vec<_>>();
match cfgs.len() {
0 => None,
1 => Some(cfgs.pop().unwrap()),
_ => Some(CfgExpr::All(cfgs)),
let mut cfgs = self.by_key("cfg").tt_values().map(CfgExpr::parse);
let first = cfgs.next()?;
match cfgs.next() {
Some(second) => {
let cfgs = [first, second].into_iter().chain(cfgs);
Some(CfgExpr::All(cfgs.collect()))
}
None => Some(first),
}
}
pub(crate) fn is_cfg_enabled(&self, cfg_options: &CfgOptions) -> bool {
@ -315,25 +372,30 @@ impl AttrsWithOwner {
AttrDefId::ModuleId(module) => {
let def_map = module.def_map(db);
let mod_data = &def_map[module.local_id];
match mod_data.declaration_source(db) {
Some(it) => {
let raw_attrs = RawAttrs::from_attrs_owner(
db,
it.as_ref().map(|it| it as &dyn ast::HasAttrs),
);
match mod_data.definition_source(db) {
InFile { file_id, value: ModuleSource::SourceFile(file) } => raw_attrs
.merge(RawAttrs::from_attrs_owner(db, InFile::new(file_id, &file))),
_ => raw_attrs,
}
match mod_data.origin {
ModuleOrigin::File { definition, declaration_tree_id, .. } => {
let decl_attrs = declaration_tree_id
.item_tree(db)
.raw_attrs(AttrOwner::ModItem(declaration_tree_id.value.into()))
.clone();
let tree = db.file_item_tree(definition.into());
let def_attrs = tree.raw_attrs(AttrOwner::TopLevel).clone();
decl_attrs.merge(def_attrs)
}
None => RawAttrs::from_attrs_owner(
ModuleOrigin::CrateRoot { definition } => {
let tree = db.file_item_tree(definition.into());
tree.raw_attrs(AttrOwner::TopLevel).clone()
}
ModuleOrigin::Inline { definition_tree_id, .. } => definition_tree_id
.item_tree(db)
.raw_attrs(AttrOwner::ModItem(definition_tree_id.value.into()))
.clone(),
ModuleOrigin::BlockExpr { block } => RawAttrs::from_attrs_owner(
db,
mod_data.definition_source(db).as_ref().map(|src| match src {
ModuleSource::SourceFile(file) => file as &dyn ast::HasAttrs,
ModuleSource::Module(module) => module as &dyn ast::HasAttrs,
ModuleSource::BlockExpr(block) => block as &dyn ast::HasAttrs,
}),
InFile::new(block.file_id, block.to_node(db.upcast()))
.as_ref()
.map(|it| it as &dyn ast::HasAttrs),
),
}
}

View file

@ -1,8 +1,9 @@
//! Contains basic data about various HIR declarations.
use std::{mem, sync::Arc};
use std::sync::Arc;
use hir_expand::{name::Name, AstId, ExpandResult, HirFileId, InFile, MacroCallId, MacroDefKind};
use hir_expand::{name::Name, AstId, ExpandResult, HirFileId, MacroCallId, MacroDefKind};
use smallvec::SmallVec;
use syntax::ast;
use crate::{
@ -10,13 +11,13 @@ use crate::{
body::{Expander, Mark},
db::DefDatabase,
intern::Interned,
item_tree::{self, AssocItem, FnFlags, ItemTreeId, ModItem, Param, TreeId},
item_tree::{self, AssocItem, FnFlags, ItemTree, ItemTreeId, ModItem, Param, TreeId},
nameres::{attr_resolution::ResolvedAttr, DefMap},
type_ref::{TraitRef, TypeBound, TypeRef},
visibility::RawVisibility,
AssocItemId, AstIdWithPath, ConstId, ConstLoc, FunctionId, FunctionLoc, HasModule, ImplId,
Intern, ItemContainerId, Lookup, Macro2Id, MacroRulesId, ModuleId, ProcMacroId, StaticId,
TraitId, TypeAliasId, TypeAliasLoc,
Intern, ItemContainerId, ItemLoc, Lookup, Macro2Id, MacroRulesId, ModuleId, ProcMacroId,
StaticId, TraitId, TypeAliasId, TypeAliasLoc,
};
#[derive(Debug, Clone, PartialEq, Eq)]
@ -209,9 +210,9 @@ pub struct TraitData {
impl TraitData {
pub(crate) fn trait_data_query(db: &dyn DefDatabase, tr: TraitId) -> Arc<TraitData> {
let tr_loc = tr.lookup(db);
let item_tree = tr_loc.id.item_tree(db);
let tr_def = &item_tree[tr_loc.id.value];
let tr_loc @ ItemLoc { container: module_id, id: tree_id } = tr.lookup(db);
let item_tree = tree_id.item_tree(db);
let tr_def = &item_tree[tree_id.value];
let _cx = stdx::panic_context::enter(format!(
"trait_data_query({:?} -> {:?} -> {:?})",
tr, tr_loc, tr_def
@ -219,25 +220,21 @@ impl TraitData {
let name = tr_def.name.clone();
let is_auto = tr_def.is_auto;
let is_unsafe = tr_def.is_unsafe;
let module_id = tr_loc.container;
let visibility = item_tree[tr_def.visibility].clone();
let skip_array_during_method_dispatch = item_tree
.attrs(db, tr_loc.container.krate(), ModItem::from(tr_loc.id.value).into())
.attrs(db, module_id.krate(), ModItem::from(tree_id.value).into())
.by_key("rustc_skip_array_during_method_dispatch")
.exists();
let mut collector = AssocItemCollector::new(
db,
module_id,
tr_loc.id.file_id(),
ItemContainerId::TraitId(tr),
);
collector.collect(tr_loc.id.tree_id(), &tr_def.items);
let mut collector =
AssocItemCollector::new(db, module_id, tree_id.file_id(), ItemContainerId::TraitId(tr));
collector.collect(&item_tree, tree_id.tree_id(), &tr_def.items);
let (items, attribute_calls) = collector.finish();
Arc::new(TraitData {
name,
attribute_calls: collector.take_attr_calls(),
items: collector.items,
attribute_calls,
items,
is_auto,
is_unsafe,
visibility,
@ -284,25 +281,20 @@ pub struct ImplData {
impl ImplData {
pub(crate) fn impl_data_query(db: &dyn DefDatabase, id: ImplId) -> Arc<ImplData> {
let _p = profile::span("impl_data_query");
let impl_loc = id.lookup(db);
let ItemLoc { container: module_id, id: tree_id } = id.lookup(db);
let item_tree = impl_loc.id.item_tree(db);
let impl_def = &item_tree[impl_loc.id.value];
let item_tree = tree_id.item_tree(db);
let impl_def = &item_tree[tree_id.value];
let target_trait = impl_def.target_trait.clone();
let self_ty = impl_def.self_ty.clone();
let is_negative = impl_def.is_negative;
let module_id = impl_loc.container;
let mut collector = AssocItemCollector::new(
db,
module_id,
impl_loc.id.file_id(),
ItemContainerId::ImplId(id),
);
collector.collect(impl_loc.id.tree_id(), &impl_def.items);
let mut collector =
AssocItemCollector::new(db, module_id, tree_id.file_id(), ItemContainerId::ImplId(id));
collector.collect(&item_tree, tree_id.tree_id(), &impl_def.items);
let attribute_calls = collector.take_attr_calls();
let items = collector.items.into_iter().map(|(_, item)| item).collect();
let (items, attribute_calls) = collector.finish();
let items = items.into_iter().map(|(_, item)| item).collect();
Arc::new(ImplData { target_trait, self_ty, items, is_negative, attribute_calls })
}
@ -463,18 +455,19 @@ impl<'a> AssocItemCollector<'a> {
}
}
fn take_attr_calls(&mut self) -> Option<Box<Vec<(AstId<ast::Item>, MacroCallId)>>> {
let attribute_calls = mem::take(&mut self.attr_calls);
if attribute_calls.is_empty() {
None
} else {
Some(Box::new(attribute_calls))
}
fn finish(
self,
) -> (Vec<(Name, AssocItemId)>, Option<Box<Vec<(AstId<ast::Item>, MacroCallId)>>>) {
(
self.items,
if self.attr_calls.is_empty() { None } else { Some(Box::new(self.attr_calls)) },
)
}
// FIXME: proc-macro diagnostics
fn collect(&mut self, tree_id: TreeId, assoc_items: &[AssocItem]) {
let item_tree = tree_id.item_tree(self.db);
fn collect(&mut self, item_tree: &ItemTree, tree_id: TreeId, assoc_items: &[AssocItem]) {
let container = self.container;
self.items.reserve(assoc_items.len());
'items: for &item in assoc_items {
let attrs = item_tree.attrs(self.db, self.module_id.krate, ModItem::from(item).into());
@ -509,9 +502,9 @@ impl<'a> AssocItemCollector<'a> {
continue 'attrs;
}
}
match self.expander.enter_expand_id(self.db, call_id) {
ExpandResult { value: Some((mark, mac)), .. } => {
self.collect_macro_items(mark, mac);
match self.expander.enter_expand_id::<ast::MacroItems>(self.db, call_id) {
ExpandResult { value: Some((mark, _)), .. } => {
self.collect_macro_items(mark);
continue 'items;
}
ExpandResult { .. } => {}
@ -522,44 +515,43 @@ impl<'a> AssocItemCollector<'a> {
match item {
AssocItem::Function(id) => {
let item = &item_tree[id];
let def =
FunctionLoc { container: self.container, id: ItemTreeId::new(tree_id, id) }
.intern(self.db);
FunctionLoc { container, id: ItemTreeId::new(tree_id, id) }.intern(self.db);
self.items.push((item.name.clone(), def.into()));
}
AssocItem::Const(id) => {
let item = &item_tree[id];
let name = match item.name.clone() {
Some(name) => name,
None => continue,
};
let def =
ConstLoc { container: self.container, id: ItemTreeId::new(tree_id, id) }
.intern(self.db);
ConstLoc { container, id: ItemTreeId::new(tree_id, id) }.intern(self.db);
self.items.push((name, def.into()));
}
AssocItem::TypeAlias(id) => {
let item = &item_tree[id];
let def = TypeAliasLoc {
container: self.container,
id: ItemTreeId::new(tree_id, id),
}
.intern(self.db);
let def = TypeAliasLoc { container, id: ItemTreeId::new(tree_id, id) }
.intern(self.db);
self.items.push((item.name.clone(), def.into()));
}
AssocItem::MacroCall(call) => {
let call = &item_tree[call];
let ast_id_map = self.db.ast_id_map(self.expander.current_file_id());
if let Some(root) = self.db.parse_or_expand(self.expander.current_file_id()) {
let call = &item_tree[call];
let ast_id_map = self.db.ast_id_map(self.expander.current_file_id());
let call = ast_id_map.get(call.ast_id).to_node(&root);
let _cx = stdx::panic_context::enter(format!(
"collect_items MacroCall: {}",
call
));
let res = self.expander.enter_expand(self.db, call);
let res = self.expander.enter_expand::<ast::MacroItems>(self.db, call);
if let Ok(ExpandResult { value: Some((mark, mac)), .. }) = res {
self.collect_macro_items(mark, mac);
if let Ok(ExpandResult { value: Some((mark, _)), .. }) = res {
self.collect_macro_items(mark);
}
}
}
@ -567,14 +559,13 @@ impl<'a> AssocItemCollector<'a> {
}
}
fn collect_macro_items(&mut self, mark: Mark, mac: ast::MacroItems) {
let src: InFile<ast::MacroItems> = self.expander.to_source(mac);
let tree_id = item_tree::TreeId::new(src.file_id, None);
fn collect_macro_items(&mut self, mark: Mark) {
let tree_id = item_tree::TreeId::new(self.expander.current_file_id(), None);
let item_tree = tree_id.item_tree(self.db);
let iter: Vec<_> =
let iter: SmallVec<[_; 2]> =
item_tree.top_level_items().iter().filter_map(ModItem::as_assoc_item).collect();
self.collect(tree_id, &iter);
self.collect(&item_tree, tree_id, &iter);
self.expander.exit(self.db, mark);
}

View file

@ -70,7 +70,7 @@ use syntax::{ast, SmolStr};
use crate::{
db::DefDatabase,
item_scope::{BuiltinShadowMode, ItemScope},
item_tree::TreeId,
item_tree::{ItemTreeId, Mod, TreeId},
nameres::{diagnostics::DefDiagnostic, path_resolution::ResolveMode},
path::ModPath,
per_ns::PerNs,
@ -141,9 +141,11 @@ pub enum ModuleOrigin {
File {
is_mod_rs: bool,
declaration: AstId<ast::Module>,
declaration_tree_id: ItemTreeId<Mod>,
definition: FileId,
},
Inline {
definition_tree_id: ItemTreeId<Mod>,
definition: AstId<ast::Module>,
},
/// Pseudo-module introduced by a block scope (contains only inner items).
@ -186,7 +188,7 @@ impl ModuleOrigin {
let sf = db.parse(file_id).tree();
InFile::new(file_id.into(), ModuleSource::SourceFile(sf))
}
ModuleOrigin::Inline { definition } => InFile::new(
ModuleOrigin::Inline { definition, .. } => InFile::new(
definition.file_id,
ModuleSource::Module(definition.to_node(db.upcast())),
),

View file

@ -1525,7 +1525,7 @@ impl ModCollector<'_, '_> {
};
match item {
ModItem::Mod(m) => self.collect_module(&self.item_tree[m], &attrs),
ModItem::Mod(m) => self.collect_module(m, &attrs),
ModItem::Import(import_id) => {
let imports = Import::from_use(
db,
@ -1700,9 +1700,10 @@ impl ModCollector<'_, '_> {
}
}
fn collect_module(&mut self, module: &Mod, attrs: &Attrs) {
fn collect_module(&mut self, module_id: FileItemTreeId<Mod>, attrs: &Attrs) {
let path_attr = attrs.by_key("path").string_value();
let is_macro_use = attrs.by_key("macro_use").exists();
let module = &self.item_tree[module_id];
match &module.kind {
// inline module, just recurse
ModKind::Inline { items } => {
@ -1711,6 +1712,7 @@ impl ModCollector<'_, '_> {
AstId::new(self.file_id(), module.ast_id),
None,
&self.item_tree[module.visibility],
module_id,
);
if let Some(mod_dir) = self.mod_dir.descend_into_definition(&module.name, path_attr)
@ -1748,6 +1750,7 @@ impl ModCollector<'_, '_> {
ast_id,
Some((file_id, is_mod_rs)),
&self.item_tree[module.visibility],
module_id,
);
ModCollector {
def_collector: self.def_collector,
@ -1774,6 +1777,7 @@ impl ModCollector<'_, '_> {
ast_id,
None,
&self.item_tree[module.visibility],
module_id,
);
self.def_collector.def_map.diagnostics.push(
DefDiagnostic::unresolved_module(self.module_id, ast_id, candidates),
@ -1790,6 +1794,7 @@ impl ModCollector<'_, '_> {
declaration: AstId<ast::Module>,
definition: Option<(FileId, bool)>,
visibility: &crate::visibility::RawVisibility,
mod_tree_id: FileItemTreeId<Mod>,
) -> LocalModuleId {
let def_map = &mut self.def_collector.def_map;
let vis = def_map
@ -1797,10 +1802,16 @@ impl ModCollector<'_, '_> {
.unwrap_or(Visibility::Public);
let modules = &mut def_map.modules;
let origin = match definition {
None => ModuleOrigin::Inline { definition: declaration },
Some((definition, is_mod_rs)) => {
ModuleOrigin::File { declaration, definition, is_mod_rs }
}
None => ModuleOrigin::Inline {
definition: declaration,
definition_tree_id: ItemTreeId::new(self.tree_id, mod_tree_id),
},
Some((definition, is_mod_rs)) => ModuleOrigin::File {
declaration,
definition,
is_mod_rs,
declaration_tree_id: ItemTreeId::new(self.tree_id, mod_tree_id),
},
};
let res = modules.alloc(ModuleData::new(origin, vis));