Intern GenericParams

Also share the same instance between `ItemTree` and `generic_params`
query.
This commit is contained in:
Jonas Schievink 2021-04-05 03:50:10 +02:00
parent adcf18e27d
commit 7c0c713a10
9 changed files with 47 additions and 82 deletions

View file

@ -13,6 +13,7 @@ use crate::{
data::{ConstData, FunctionData, ImplData, StaticData, TraitData, TypeAliasData}, data::{ConstData, FunctionData, ImplData, StaticData, TraitData, TypeAliasData},
generics::GenericParams, generics::GenericParams,
import_map::ImportMap, import_map::ImportMap,
intern::Interned,
item_tree::ItemTree, item_tree::ItemTree,
lang_item::{LangItemTarget, LangItems}, lang_item::{LangItemTarget, LangItems},
nameres::DefMap, nameres::DefMap,
@ -113,7 +114,7 @@ pub trait DefDatabase: InternDatabase + AstDatabase + Upcast<dyn AstDatabase> {
fn expr_scopes(&self, def: DefWithBodyId) -> Arc<ExprScopes>; fn expr_scopes(&self, def: DefWithBodyId) -> Arc<ExprScopes>;
#[salsa::invoke(GenericParams::generic_params_query)] #[salsa::invoke(GenericParams::generic_params_query)]
fn generic_params(&self, def: GenericDefId) -> Arc<GenericParams>; fn generic_params(&self, def: GenericDefId) -> Interned<GenericParams>;
#[salsa::invoke(Attrs::variants_attrs_query)] #[salsa::invoke(Attrs::variants_attrs_query)]
fn variants_attrs(&self, def: EnumId) -> Arc<ArenaMap<LocalEnumVariantId, Attrs>>; fn variants_attrs(&self, def: EnumId) -> Arc<ArenaMap<LocalEnumVariantId, Attrs>>;

View file

@ -2,7 +2,6 @@
//! structs, impls, traits, etc. This module provides a common HIR for these //! structs, impls, traits, etc. This module provides a common HIR for these
//! generic parameters. See also the `Generics` type and the `generics_of` query //! generic parameters. See also the `Generics` type and the `generics_of` query
//! in rustc. //! in rustc.
use std::sync::Arc;
use base_db::FileId; use base_db::FileId;
use either::Either; use either::Either;
@ -27,7 +26,7 @@ use crate::{
}; };
/// Data about a generic type parameter (to a function, struct, impl, ...). /// Data about a generic type parameter (to a function, struct, impl, ...).
#[derive(Clone, PartialEq, Eq, Debug)] #[derive(Clone, PartialEq, Eq, Debug, Hash)]
pub struct TypeParamData { pub struct TypeParamData {
pub name: Option<Name>, pub name: Option<Name>,
pub default: Option<Interned<TypeRef>>, pub default: Option<Interned<TypeRef>>,
@ -35,19 +34,19 @@ pub struct TypeParamData {
} }
/// Data about a generic lifetime parameter (to a function, struct, impl, ...). /// Data about a generic lifetime parameter (to a function, struct, impl, ...).
#[derive(Clone, PartialEq, Eq, Debug)] #[derive(Clone, PartialEq, Eq, Debug, Hash)]
pub struct LifetimeParamData { pub struct LifetimeParamData {
pub name: Name, pub name: Name,
} }
/// Data about a generic const parameter (to a function, struct, impl, ...). /// Data about a generic const parameter (to a function, struct, impl, ...).
#[derive(Clone, PartialEq, Eq, Debug)] #[derive(Clone, PartialEq, Eq, Debug, Hash)]
pub struct ConstParamData { pub struct ConstParamData {
pub name: Name, pub name: Name,
pub ty: Interned<TypeRef>, pub ty: Interned<TypeRef>,
} }
#[derive(Copy, Clone, PartialEq, Eq, Debug)] #[derive(Copy, Clone, PartialEq, Eq, Debug, Hash)]
pub enum TypeParamProvenance { pub enum TypeParamProvenance {
TypeParamList, TypeParamList,
TraitSelf, TraitSelf,
@ -55,7 +54,7 @@ pub enum TypeParamProvenance {
} }
/// Data about the generic parameters of a function, struct, impl, etc. /// Data about the generic parameters of a function, struct, impl, etc.
#[derive(Clone, PartialEq, Eq, Debug, Default)] #[derive(Clone, PartialEq, Eq, Debug, Default, Hash)]
pub struct GenericParams { pub struct GenericParams {
pub types: Arena<TypeParamData>, pub types: Arena<TypeParamData>,
pub lifetimes: Arena<LifetimeParamData>, pub lifetimes: Arena<LifetimeParamData>,
@ -67,14 +66,14 @@ pub struct GenericParams {
/// where clauses like `where T: Foo + Bar` are turned into multiple of these. /// where clauses like `where T: Foo + Bar` are turned into multiple of these.
/// It might still result in multiple actual predicates though, because of /// It might still result in multiple actual predicates though, because of
/// associated type bindings like `Iterator<Item = u32>`. /// associated type bindings like `Iterator<Item = u32>`.
#[derive(Clone, PartialEq, Eq, Debug)] #[derive(Clone, PartialEq, Eq, Debug, Hash)]
pub enum WherePredicate { pub enum WherePredicate {
TypeBound { target: WherePredicateTypeTarget, bound: TypeBound }, TypeBound { target: WherePredicateTypeTarget, bound: TypeBound },
Lifetime { target: LifetimeRef, bound: LifetimeRef }, Lifetime { target: LifetimeRef, bound: LifetimeRef },
ForLifetime { lifetimes: Box<[Name]>, target: WherePredicateTypeTarget, bound: TypeBound }, ForLifetime { lifetimes: Box<[Name]>, target: WherePredicateTypeTarget, bound: TypeBound },
} }
#[derive(Clone, PartialEq, Eq, Debug)] #[derive(Clone, PartialEq, Eq, Debug, Hash)]
pub enum WherePredicateTypeTarget { pub enum WherePredicateTypeTarget {
TypeRef(Interned<TypeRef>), TypeRef(Interned<TypeRef>),
/// For desugared where predicates that can directly refer to a type param. /// For desugared where predicates that can directly refer to a type param.
@ -92,7 +91,7 @@ impl GenericParams {
pub(crate) fn generic_params_query( pub(crate) fn generic_params_query(
db: &dyn DefDatabase, db: &dyn DefDatabase,
def: GenericDefId, def: GenericDefId,
) -> Arc<GenericParams> { ) -> Interned<GenericParams> {
let _p = profile::span("generic_params_query"); let _p = profile::span("generic_params_query");
let generics = match def { let generics = match def {
@ -100,47 +99,49 @@ impl GenericParams {
let id = id.lookup(db).id; let id = id.lookup(db).id;
let tree = id.item_tree(db); let tree = id.item_tree(db);
let item = &tree[id.value]; let item = &tree[id.value];
tree[item.generic_params].clone() item.generic_params.clone()
} }
GenericDefId::AdtId(AdtId::StructId(id)) => { GenericDefId::AdtId(AdtId::StructId(id)) => {
let id = id.lookup(db).id; let id = id.lookup(db).id;
let tree = id.item_tree(db); let tree = id.item_tree(db);
let item = &tree[id.value]; let item = &tree[id.value];
tree[item.generic_params].clone() item.generic_params.clone()
} }
GenericDefId::AdtId(AdtId::EnumId(id)) => { GenericDefId::AdtId(AdtId::EnumId(id)) => {
let id = id.lookup(db).id; let id = id.lookup(db).id;
let tree = id.item_tree(db); let tree = id.item_tree(db);
let item = &tree[id.value]; let item = &tree[id.value];
tree[item.generic_params].clone() item.generic_params.clone()
} }
GenericDefId::AdtId(AdtId::UnionId(id)) => { GenericDefId::AdtId(AdtId::UnionId(id)) => {
let id = id.lookup(db).id; let id = id.lookup(db).id;
let tree = id.item_tree(db); let tree = id.item_tree(db);
let item = &tree[id.value]; let item = &tree[id.value];
tree[item.generic_params].clone() item.generic_params.clone()
} }
GenericDefId::TraitId(id) => { GenericDefId::TraitId(id) => {
let id = id.lookup(db).id; let id = id.lookup(db).id;
let tree = id.item_tree(db); let tree = id.item_tree(db);
let item = &tree[id.value]; let item = &tree[id.value];
tree[item.generic_params].clone() item.generic_params.clone()
} }
GenericDefId::TypeAliasId(id) => { GenericDefId::TypeAliasId(id) => {
let id = id.lookup(db).id; let id = id.lookup(db).id;
let tree = id.item_tree(db); let tree = id.item_tree(db);
let item = &tree[id.value]; let item = &tree[id.value];
tree[item.generic_params].clone() item.generic_params.clone()
} }
GenericDefId::ImplId(id) => { GenericDefId::ImplId(id) => {
let id = id.lookup(db).id; let id = id.lookup(db).id;
let tree = id.item_tree(db); let tree = id.item_tree(db);
let item = &tree[id.value]; let item = &tree[id.value];
tree[item.generic_params].clone() item.generic_params.clone()
}
GenericDefId::EnumVariantId(_) | GenericDefId::ConstId(_) => {
Interned::new(GenericParams::default())
} }
GenericDefId::EnumVariantId(_) | GenericDefId::ConstId(_) => GenericParams::default(),
}; };
Arc::new(generics) generics
} }
fn new(db: &dyn DefDatabase, def: GenericDefId) -> (GenericParams, InFile<SourceMap>) { fn new(db: &dyn DefDatabase, def: GenericDefId) -> (GenericParams, InFile<SourceMap>) {

View file

@ -14,6 +14,8 @@ use dashmap::{lock::RwLockWriteGuard, DashMap, SharedValue};
use once_cell::sync::OnceCell; use once_cell::sync::OnceCell;
use rustc_hash::FxHasher; use rustc_hash::FxHasher;
use crate::generics::GenericParams;
type InternMap<T> = DashMap<Arc<T>, (), BuildHasherDefault<FxHasher>>; type InternMap<T> = DashMap<Arc<T>, (), BuildHasherDefault<FxHasher>>;
type Guard<T> = type Guard<T> =
RwLockWriteGuard<'static, HashMap<Arc<T>, SharedValue<()>, BuildHasherDefault<FxHasher>>>; RwLockWriteGuard<'static, HashMap<Arc<T>, SharedValue<()>, BuildHasherDefault<FxHasher>>>;
@ -194,4 +196,10 @@ macro_rules! impl_internable {
)+ }; )+ };
} }
impl_internable!(crate::type_ref::TypeRef, crate::type_ref::TraitRef, crate::path::ModPath, str); impl_internable!(
crate::type_ref::TypeRef,
crate::type_ref::TraitRef,
crate::path::ModPath,
GenericParams,
str
);

View file

@ -58,13 +58,6 @@ impl fmt::Debug for RawVisibilityId {
} }
} }
#[derive(Debug, Copy, Clone, Eq, PartialEq)]
pub struct GenericParamsId(u32);
impl GenericParamsId {
pub const EMPTY: Self = GenericParamsId(u32::max_value());
}
/// The item tree of a source file. /// The item tree of a source file.
#[derive(Debug, Default, Eq, PartialEq)] #[derive(Debug, Default, Eq, PartialEq)]
pub struct ItemTree { pub struct ItemTree {
@ -146,7 +139,6 @@ impl ItemTree {
macro_rules, macro_rules,
macro_defs, macro_defs,
vis, vis,
generics,
inner_items, inner_items,
} = &mut **data; } = &mut **data;
@ -170,7 +162,6 @@ impl ItemTree {
macro_defs.shrink_to_fit(); macro_defs.shrink_to_fit();
vis.arena.shrink_to_fit(); vis.arena.shrink_to_fit();
generics.arena.shrink_to_fit();
inner_items.shrink_to_fit(); inner_items.shrink_to_fit();
} }
@ -241,32 +232,6 @@ static VIS_PUB: RawVisibility = RawVisibility::Public;
static VIS_PRIV: RawVisibility = RawVisibility::Module(ModPath::from_kind(PathKind::Super(0))); static VIS_PRIV: RawVisibility = RawVisibility::Module(ModPath::from_kind(PathKind::Super(0)));
static VIS_PUB_CRATE: RawVisibility = RawVisibility::Module(ModPath::from_kind(PathKind::Crate)); static VIS_PUB_CRATE: RawVisibility = RawVisibility::Module(ModPath::from_kind(PathKind::Crate));
#[derive(Default, Debug, Eq, PartialEq)]
struct GenericParamsStorage {
arena: Arena<GenericParams>,
}
impl GenericParamsStorage {
fn alloc(&mut self, params: GenericParams) -> GenericParamsId {
if params.types.is_empty()
&& params.lifetimes.is_empty()
&& params.consts.is_empty()
&& params.where_predicates.is_empty()
{
return GenericParamsId::EMPTY;
}
GenericParamsId(self.arena.alloc(params).into_raw().into())
}
}
static EMPTY_GENERICS: GenericParams = GenericParams {
types: Arena::new(),
lifetimes: Arena::new(),
consts: Arena::new(),
where_predicates: Vec::new(),
};
#[derive(Default, Debug, Eq, PartialEq)] #[derive(Default, Debug, Eq, PartialEq)]
struct ItemTreeData { struct ItemTreeData {
imports: Arena<Import>, imports: Arena<Import>,
@ -289,7 +254,6 @@ struct ItemTreeData {
macro_defs: Arena<MacroDef>, macro_defs: Arena<MacroDef>,
vis: ItemVisibilities, vis: ItemVisibilities,
generics: GenericParamsStorage,
inner_items: FxHashMap<FileAstId<ast::BlockExpr>, SmallVec<[ModItem; 1]>>, inner_items: FxHashMap<FileAstId<ast::BlockExpr>, SmallVec<[ModItem; 1]>>,
} }
@ -508,17 +472,6 @@ impl Index<RawVisibilityId> for ItemTree {
} }
} }
impl Index<GenericParamsId> for ItemTree {
type Output = GenericParams;
fn index(&self, index: GenericParamsId) -> &Self::Output {
match index {
GenericParamsId::EMPTY => &EMPTY_GENERICS,
_ => &self.data().generics.arena[Idx::from_raw(index.0.into())],
}
}
}
impl<N: ItemTreeNode> Index<FileItemTreeId<N>> for ItemTree { impl<N: ItemTreeNode> Index<FileItemTreeId<N>> for ItemTree {
type Output = N; type Output = N;
fn index(&self, id: FileItemTreeId<N>) -> &N { fn index(&self, id: FileItemTreeId<N>) -> &N {
@ -555,7 +508,7 @@ pub struct ExternCrate {
pub struct Function { pub struct Function {
pub name: Name, pub name: Name,
pub visibility: RawVisibilityId, pub visibility: RawVisibilityId,
pub generic_params: GenericParamsId, pub generic_params: Interned<GenericParams>,
pub abi: Option<Interned<str>>, pub abi: Option<Interned<str>>,
pub params: IdRange<Param>, pub params: IdRange<Param>,
pub ret_type: Interned<TypeRef>, pub ret_type: Interned<TypeRef>,
@ -590,7 +543,7 @@ impl FnFlags {
pub struct Struct { pub struct Struct {
pub name: Name, pub name: Name,
pub visibility: RawVisibilityId, pub visibility: RawVisibilityId,
pub generic_params: GenericParamsId, pub generic_params: Interned<GenericParams>,
pub fields: Fields, pub fields: Fields,
pub ast_id: FileAstId<ast::Struct>, pub ast_id: FileAstId<ast::Struct>,
pub kind: StructDefKind, pub kind: StructDefKind,
@ -610,7 +563,7 @@ pub enum StructDefKind {
pub struct Union { pub struct Union {
pub name: Name, pub name: Name,
pub visibility: RawVisibilityId, pub visibility: RawVisibilityId,
pub generic_params: GenericParamsId, pub generic_params: Interned<GenericParams>,
pub fields: Fields, pub fields: Fields,
pub ast_id: FileAstId<ast::Union>, pub ast_id: FileAstId<ast::Union>,
} }
@ -619,7 +572,7 @@ pub struct Union {
pub struct Enum { pub struct Enum {
pub name: Name, pub name: Name,
pub visibility: RawVisibilityId, pub visibility: RawVisibilityId,
pub generic_params: GenericParamsId, pub generic_params: Interned<GenericParams>,
pub variants: IdRange<Variant>, pub variants: IdRange<Variant>,
pub ast_id: FileAstId<ast::Enum>, pub ast_id: FileAstId<ast::Enum>,
} }
@ -648,7 +601,7 @@ pub struct Static {
pub struct Trait { pub struct Trait {
pub name: Name, pub name: Name,
pub visibility: RawVisibilityId, pub visibility: RawVisibilityId,
pub generic_params: GenericParamsId, pub generic_params: Interned<GenericParams>,
pub is_auto: bool, pub is_auto: bool,
pub is_unsafe: bool, pub is_unsafe: bool,
pub bounds: Box<[TypeBound]>, pub bounds: Box<[TypeBound]>,
@ -658,7 +611,7 @@ pub struct Trait {
#[derive(Debug, Clone, Eq, PartialEq)] #[derive(Debug, Clone, Eq, PartialEq)]
pub struct Impl { pub struct Impl {
pub generic_params: GenericParamsId, pub generic_params: Interned<GenericParams>,
pub target_trait: Option<Interned<TraitRef>>, pub target_trait: Option<Interned<TraitRef>>,
pub self_ty: Interned<TypeRef>, pub self_ty: Interned<TypeRef>,
pub is_negative: bool, pub is_negative: bool,
@ -672,7 +625,7 @@ pub struct TypeAlias {
pub visibility: RawVisibilityId, pub visibility: RawVisibilityId,
/// Bounds on the type alias itself. Only valid in trait declarations, eg. `type Assoc: Copy;`. /// Bounds on the type alias itself. Only valid in trait declarations, eg. `type Assoc: Copy;`.
pub bounds: Box<[TypeBound]>, pub bounds: Box<[TypeBound]>,
pub generic_params: GenericParamsId, pub generic_params: Interned<GenericParams>,
pub type_ref: Option<Interned<TypeRef>>, pub type_ref: Option<Interned<TypeRef>>,
pub is_extern: bool, pub is_extern: bool,
pub ast_id: FileAstId<ast::TypeAlias>, pub ast_id: FileAstId<ast::TypeAlias>,

View file

@ -434,7 +434,7 @@ impl Ctx {
let mut res = Function { let mut res = Function {
name, name,
visibility, visibility,
generic_params: GenericParamsId::EMPTY, generic_params: Interned::new(GenericParams::default()),
abi, abi,
params, params,
ret_type: Interned::new(ret_type), ret_type: Interned::new(ret_type),
@ -682,7 +682,7 @@ impl Ctx {
&mut self, &mut self,
owner: GenericsOwner<'_>, owner: GenericsOwner<'_>,
node: &impl ast::GenericParamsOwner, node: &impl ast::GenericParamsOwner,
) -> GenericParamsId { ) -> Interned<GenericParams> {
// Generics are part of item headers and may contain inner items we need to collect. // Generics are part of item headers and may contain inner items we need to collect.
if let Some(params) = node.generic_param_list() { if let Some(params) = node.generic_param_list() {
self.collect_inner_items(params.syntax()); self.collect_inner_items(params.syntax());
@ -698,7 +698,7 @@ impl Ctx {
&mut self, &mut self,
owner: GenericsOwner<'_>, owner: GenericsOwner<'_>,
node: &impl ast::GenericParamsOwner, node: &impl ast::GenericParamsOwner,
) -> GenericParamsId { ) -> Interned<GenericParams> {
let mut sm = &mut Default::default(); let mut sm = &mut Default::default();
let mut generics = GenericParams::default(); let mut generics = GenericParams::default();
match owner { match owner {
@ -740,7 +740,7 @@ impl Ctx {
} }
generics.shrink_to_fit(); generics.shrink_to_fit();
self.data().generics.alloc(generics) Interned::new(generics)
} }
fn lower_type_bounds(&mut self, node: &impl ast::TypeBoundsOwner) -> Vec<TypeBound> { fn lower_type_bounds(&mut self, node: &impl ast::TypeBoundsOwner) -> Vec<TypeBound> {

View file

@ -27,6 +27,7 @@ pub mod dyn_map;
pub mod keys; pub mod keys;
pub mod item_tree; pub mod item_tree;
pub mod intern;
pub mod adt; pub mod adt;
pub mod data; pub mod data;
@ -49,7 +50,6 @@ pub mod import_map;
#[cfg(test)] #[cfg(test)]
mod test_db; mod test_db;
mod intern;
use std::{ use std::{
hash::{Hash, Hasher}, hash::{Hash, Hasher},

View file

@ -14,6 +14,7 @@ use crate::{
db::DefDatabase, db::DefDatabase,
expr::{ExprId, LabelId, PatId}, expr::{ExprId, LabelId, PatId},
generics::GenericParams, generics::GenericParams,
intern::Interned,
item_scope::{BuiltinShadowMode, BUILTIN_SCOPE}, item_scope::{BuiltinShadowMode, BUILTIN_SCOPE},
nameres::DefMap, nameres::DefMap,
path::{ModPath, PathKind}, path::{ModPath, PathKind},
@ -50,7 +51,7 @@ enum Scope {
/// All the items and imported names of a module /// All the items and imported names of a module
ModuleScope(ModuleItemMap), ModuleScope(ModuleItemMap),
/// Brings the generic parameters of an item into scope /// Brings the generic parameters of an item into scope
GenericParams { def: GenericDefId, params: Arc<GenericParams> }, GenericParams { def: GenericDefId, params: Interned<GenericParams> },
/// Brings `Self` in `impl` block into scope /// Brings `Self` in `impl` block into scope
ImplDefScope(ImplId), ImplDefScope(ImplId),
/// Brings `Self` in enum, struct and union definitions into scope /// Brings `Self` in enum, struct and union definitions into scope

View file

@ -9,6 +9,7 @@ use hir_def::{
generics::{ generics::{
GenericParams, TypeParamData, TypeParamProvenance, WherePredicate, WherePredicateTypeTarget, GenericParams, TypeParamData, TypeParamProvenance, WherePredicate, WherePredicateTypeTarget,
}, },
intern::Interned,
path::Path, path::Path,
resolver::{HasResolver, TypeNs}, resolver::{HasResolver, TypeNs},
type_ref::TypeRef, type_ref::TypeRef,
@ -158,7 +159,7 @@ pub(crate) fn generics(db: &dyn DefDatabase, def: GenericDefId) -> Generics {
#[derive(Debug)] #[derive(Debug)]
pub(crate) struct Generics { pub(crate) struct Generics {
def: GenericDefId, def: GenericDefId,
pub(crate) params: Arc<GenericParams>, pub(crate) params: Interned<GenericParams>,
parent_generics: Option<Box<Generics>>, parent_generics: Option<Box<Generics>>,
} }

View file

@ -90,7 +90,7 @@ impl<T> Idx<T> {
} }
/// Yet another index-based arena. /// Yet another index-based arena.
#[derive(Clone, PartialEq, Eq)] #[derive(Clone, PartialEq, Eq, Hash)]
pub struct Arena<T> { pub struct Arena<T> {
data: Vec<T>, data: Vec<T>,
} }