Save a bit on empty item trees by deduplicating them

This commit is contained in:
Lukas Wirth 2024-06-23 16:13:01 +02:00
parent 3168ab5b99
commit 5548aecdca
8 changed files with 76 additions and 43 deletions

View file

@ -80,9 +80,11 @@ pub trait InternDatabase: SourceDatabase {
#[salsa::query_group(DefDatabaseStorage)] #[salsa::query_group(DefDatabaseStorage)]
pub trait DefDatabase: InternDatabase + ExpandDatabase + Upcast<dyn ExpandDatabase> { pub trait DefDatabase: InternDatabase + ExpandDatabase + Upcast<dyn ExpandDatabase> {
/// Whether to expand procedural macros during name resolution.
#[salsa::input] #[salsa::input]
fn expand_proc_attr_macros(&self) -> bool; fn expand_proc_attr_macros(&self) -> bool;
/// Computes an [`ItemTree`] for the given file or macro expansion.
#[salsa::invoke(ItemTree::file_item_tree_query)] #[salsa::invoke(ItemTree::file_item_tree_query)]
fn file_item_tree(&self, file_id: HirFileId) -> Arc<ItemTree>; fn file_item_tree(&self, file_id: HirFileId) -> Arc<ItemTree>;
@ -96,6 +98,7 @@ pub trait DefDatabase: InternDatabase + ExpandDatabase + Upcast<dyn ExpandDataba
#[salsa::invoke(DefMap::block_def_map_query)] #[salsa::invoke(DefMap::block_def_map_query)]
fn block_def_map(&self, block: BlockId) -> Arc<DefMap>; fn block_def_map(&self, block: BlockId) -> Arc<DefMap>;
/// Turns a MacroId into a MacroDefId, describing the macro's definition post name resolution.
fn macro_def(&self, m: MacroId) -> MacroDefId; fn macro_def(&self, m: MacroId) -> MacroDefId;
// region:data // region:data

View file

@ -48,6 +48,7 @@ use either::Either;
use hir_expand::{attrs::RawAttrs, name::Name, ExpandTo, HirFileId, InFile}; use hir_expand::{attrs::RawAttrs, name::Name, ExpandTo, HirFileId, InFile};
use intern::Interned; use intern::Interned;
use la_arena::{Arena, Idx, IdxRange, RawIdx}; use la_arena::{Arena, Idx, IdxRange, RawIdx};
use once_cell::sync::OnceCell;
use rustc_hash::FxHashMap; use rustc_hash::FxHashMap;
use smallvec::SmallVec; use smallvec::SmallVec;
use span::{AstIdNode, FileAstId, SyntaxContextId}; use span::{AstIdNode, FileAstId, SyntaxContextId};
@ -100,6 +101,7 @@ pub struct ItemTree {
impl ItemTree { impl ItemTree {
pub(crate) fn file_item_tree_query(db: &dyn DefDatabase, file_id: HirFileId) -> Arc<ItemTree> { pub(crate) fn file_item_tree_query(db: &dyn DefDatabase, file_id: HirFileId) -> Arc<ItemTree> {
let _p = tracing::info_span!("file_item_tree_query", ?file_id).entered(); let _p = tracing::info_span!("file_item_tree_query", ?file_id).entered();
static EMPTY: OnceCell<Arc<ItemTree>> = OnceCell::new();
let syntax = db.parse_or_expand(file_id); let syntax = db.parse_or_expand(file_id);
@ -131,19 +133,48 @@ impl ItemTree {
if let Some(attrs) = top_attrs { if let Some(attrs) = top_attrs {
item_tree.attrs.insert(AttrOwner::TopLevel, attrs); item_tree.attrs.insert(AttrOwner::TopLevel, attrs);
} }
if item_tree.data.is_none() && item_tree.top_level.is_empty() && item_tree.attrs.is_empty()
{
EMPTY
.get_or_init(|| {
Arc::new(ItemTree {
top_level: SmallVec::new_const(),
attrs: FxHashMap::default(),
data: None,
})
})
.clone()
} else {
item_tree.shrink_to_fit(); item_tree.shrink_to_fit();
Arc::new(item_tree) Arc::new(item_tree)
} }
}
pub(crate) fn block_item_tree_query(db: &dyn DefDatabase, block: BlockId) -> Arc<ItemTree> { pub(crate) fn block_item_tree_query(db: &dyn DefDatabase, block: BlockId) -> Arc<ItemTree> {
let _p = tracing::info_span!("block_item_tree_query", ?block).entered();
static EMPTY: OnceCell<Arc<ItemTree>> = OnceCell::new();
let loc = block.lookup(db); let loc = block.lookup(db);
let block = loc.ast_id.to_node(db.upcast()); let block = loc.ast_id.to_node(db.upcast());
let ctx = lower::Ctx::new(db, loc.ast_id.file_id); let ctx = lower::Ctx::new(db, loc.ast_id.file_id);
let mut item_tree = ctx.lower_block(&block); let mut item_tree = ctx.lower_block(&block);
if item_tree.data.is_none() && item_tree.top_level.is_empty() && item_tree.attrs.is_empty()
{
EMPTY
.get_or_init(|| {
Arc::new(ItemTree {
top_level: SmallVec::new_const(),
attrs: FxHashMap::default(),
data: None,
})
})
.clone()
} else {
item_tree.shrink_to_fit(); item_tree.shrink_to_fit();
Arc::new(item_tree) Arc::new(item_tree)
} }
}
/// Returns an iterator over all items located at the top level of the `HirFileId` this /// Returns an iterator over all items located at the top level of the `HirFileId` this
/// `ItemTree` was created from. /// `ItemTree` was created from.

View file

@ -977,6 +977,14 @@ impl GenericDefId {
_ => None, _ => None,
} }
} }
pub fn from_callable(db: &dyn DefDatabase, def: CallableDefId) -> GenericDefId {
match def {
CallableDefId::FunctionId(f) => f.into(),
CallableDefId::StructId(s) => s.into(),
CallableDefId::EnumVariantId(e) => e.lookup(db).parent.into(),
}
}
} }
impl From<AssocItemId> for GenericDefId { impl From<AssocItemId> for GenericDefId {
@ -1019,16 +1027,6 @@ impl CallableDefId {
} }
} }
impl GenericDefId {
pub fn from(db: &dyn DefDatabase, def: CallableDefId) -> GenericDefId {
match def {
CallableDefId::FunctionId(f) => f.into(),
CallableDefId::StructId(s) => s.into(),
CallableDefId::EnumVariantId(e) => e.lookup(db).parent.into(),
}
}
}
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
pub enum AttrDefId { pub enum AttrDefId {
ModuleId(ModuleId), ModuleId(ModuleId),

View file

@ -915,7 +915,7 @@ fn type_alias_associated_ty_value(
pub(crate) fn fn_def_datum_query(db: &dyn HirDatabase, fn_def_id: FnDefId) -> Arc<FnDefDatum> { pub(crate) fn fn_def_datum_query(db: &dyn HirDatabase, fn_def_id: FnDefId) -> Arc<FnDefDatum> {
let callable_def: CallableDefId = from_chalk(db, fn_def_id); let callable_def: CallableDefId = from_chalk(db, fn_def_id);
let generic_def = GenericDefId::from(db.upcast(), callable_def); let generic_def = GenericDefId::from_callable(db.upcast(), callable_def);
let generic_params = generics(db.upcast(), generic_def); let generic_params = generics(db.upcast(), generic_def);
let (sig, binders) = db.callable_item_signature(callable_def).into_value_and_skipped_binders(); let (sig, binders) = db.callable_item_signature(callable_def).into_value_and_skipped_binders();
let bound_vars = generic_params.bound_vars_subst(db, DebruijnIndex::INNERMOST); let bound_vars = generic_params.bound_vars_subst(db, DebruijnIndex::INNERMOST);
@ -946,7 +946,8 @@ pub(crate) fn fn_def_datum_query(db: &dyn HirDatabase, fn_def_id: FnDefId) -> Ar
pub(crate) fn fn_def_variance_query(db: &dyn HirDatabase, fn_def_id: FnDefId) -> Variances { pub(crate) fn fn_def_variance_query(db: &dyn HirDatabase, fn_def_id: FnDefId) -> Variances {
let callable_def: CallableDefId = from_chalk(db, fn_def_id); let callable_def: CallableDefId = from_chalk(db, fn_def_id);
let generic_params = generics(db.upcast(), GenericDefId::from(db.upcast(), callable_def)); let generic_params =
generics(db.upcast(), GenericDefId::from_callable(db.upcast(), callable_def));
Variances::from_iter( Variances::from_iter(
Interner, Interner,
std::iter::repeat(chalk_ir::Variance::Invariant).take(generic_params.len()), std::iter::repeat(chalk_ir::Variance::Invariant).take(generic_params.len()),

View file

@ -188,7 +188,7 @@ impl TyExt for Ty {
fn as_generic_def(&self, db: &dyn HirDatabase) -> Option<GenericDefId> { fn as_generic_def(&self, db: &dyn HirDatabase) -> Option<GenericDefId> {
match *self.kind(Interner) { match *self.kind(Interner) {
TyKind::Adt(AdtId(adt), ..) => Some(adt.into()), TyKind::Adt(AdtId(adt), ..) => Some(adt.into()),
TyKind::FnDef(callable, ..) => Some(GenericDefId::from( TyKind::FnDef(callable, ..) => Some(GenericDefId::from_callable(
db.upcast(), db.upcast(),
db.lookup_intern_callable_def(callable.into()), db.lookup_intern_callable_def(callable.into()),
)), )),

View file

@ -80,8 +80,32 @@ pub trait HirDatabase: DefDatabase + Upcast<dyn DefDatabase> {
#[salsa::cycle(crate::consteval::const_eval_discriminant_recover)] #[salsa::cycle(crate::consteval::const_eval_discriminant_recover)]
fn const_eval_discriminant(&self, def: EnumVariantId) -> Result<i128, ConstEvalError>; fn const_eval_discriminant(&self, def: EnumVariantId) -> Result<i128, ConstEvalError>;
#[salsa::invoke(crate::method_resolution::lookup_impl_method_query)]
fn lookup_impl_method(
&self,
env: Arc<TraitEnvironment>,
func: FunctionId,
fn_subst: Substitution,
) -> (FunctionId, Substitution);
// endregion:mir // endregion:mir
#[salsa::invoke(crate::layout::layout_of_adt_query)]
#[salsa::cycle(crate::layout::layout_of_adt_recover)]
fn layout_of_adt(
&self,
def: AdtId,
subst: Substitution,
env: Arc<TraitEnvironment>,
) -> Result<Arc<Layout>, LayoutError>;
#[salsa::invoke(crate::layout::layout_of_ty_query)]
#[salsa::cycle(crate::layout::layout_of_ty_recover)]
fn layout_of_ty(&self, ty: Ty, env: Arc<TraitEnvironment>) -> Result<Arc<Layout>, LayoutError>;
#[salsa::invoke(crate::layout::target_data_layout_query)]
fn target_data_layout(&self, krate: CrateId) -> Result<Arc<TargetDataLayout>, Arc<str>>;
#[salsa::invoke(crate::lower::ty_query)] #[salsa::invoke(crate::lower::ty_query)]
#[salsa::cycle(crate::lower::ty_recover)] #[salsa::cycle(crate::lower::ty_recover)]
fn ty(&self, def: TyDefId) -> Binders<Ty>; fn ty(&self, def: TyDefId) -> Binders<Ty>;
@ -104,30 +128,6 @@ pub trait HirDatabase: DefDatabase + Upcast<dyn DefDatabase> {
#[salsa::invoke(crate::lower::field_types_query)] #[salsa::invoke(crate::lower::field_types_query)]
fn field_types(&self, var: VariantId) -> Arc<ArenaMap<LocalFieldId, Binders<Ty>>>; fn field_types(&self, var: VariantId) -> Arc<ArenaMap<LocalFieldId, Binders<Ty>>>;
#[salsa::invoke(crate::layout::layout_of_adt_query)]
#[salsa::cycle(crate::layout::layout_of_adt_recover)]
fn layout_of_adt(
&self,
def: AdtId,
subst: Substitution,
env: Arc<TraitEnvironment>,
) -> Result<Arc<Layout>, LayoutError>;
#[salsa::invoke(crate::layout::layout_of_ty_query)]
#[salsa::cycle(crate::layout::layout_of_ty_recover)]
fn layout_of_ty(&self, ty: Ty, env: Arc<TraitEnvironment>) -> Result<Arc<Layout>, LayoutError>;
#[salsa::invoke(crate::layout::target_data_layout_query)]
fn target_data_layout(&self, krate: CrateId) -> Result<Arc<TargetDataLayout>, Arc<str>>;
#[salsa::invoke(crate::method_resolution::lookup_impl_method_query)]
fn lookup_impl_method(
&self,
env: Arc<TraitEnvironment>,
func: FunctionId,
fn_subst: Substitution,
) -> (FunctionId, Substitution);
#[salsa::invoke(crate::lower::callable_item_sig)] #[salsa::invoke(crate::lower::callable_item_sig)]
fn callable_item_signature(&self, def: CallableDefId) -> PolyFnSig; fn callable_item_signature(&self, def: CallableDefId) -> PolyFnSig;

View file

@ -988,7 +988,7 @@ impl HirDisplay for Ty {
f.end_location_link(); f.end_location_link();
if parameters.len(Interner) > 0 { if parameters.len(Interner) > 0 {
let generic_def_id = GenericDefId::from(db.upcast(), def); let generic_def_id = GenericDefId::from_callable(db.upcast(), def);
let generics = generics(db.upcast(), generic_def_id); let generics = generics(db.upcast(), generic_def_id);
let (parent_len, self_param, type_, const_, impl_, lifetime) = let (parent_len, self_param, type_, const_, impl_, lifetime) =
generics.provenance_split(); generics.provenance_split();

View file

@ -1896,7 +1896,7 @@ impl InferenceContext<'_> {
if let TyKind::FnDef(fn_def, parameters) = callable_ty.kind(Interner) { if let TyKind::FnDef(fn_def, parameters) = callable_ty.kind(Interner) {
let def: CallableDefId = from_chalk(self.db, *fn_def); let def: CallableDefId = from_chalk(self.db, *fn_def);
let generic_predicates = let generic_predicates =
self.db.generic_predicates(GenericDefId::from(self.db.upcast(), def)); self.db.generic_predicates(GenericDefId::from_callable(self.db.upcast(), def));
for predicate in generic_predicates.iter() { for predicate in generic_predicates.iter() {
let (predicate, binders) = predicate let (predicate, binders) = predicate
.clone() .clone()