mirror of
https://github.com/rust-lang/rust-analyzer
synced 2025-01-13 13:48:50 +00:00
Global TypeRef/TraitRef interning
This commit is contained in:
parent
25201b2dad
commit
b00266b79f
11 changed files with 205 additions and 120 deletions
1
Cargo.lock
generated
1
Cargo.lock
generated
|
@ -500,6 +500,7 @@ dependencies = [
|
||||||
"base_db",
|
"base_db",
|
||||||
"cfg",
|
"cfg",
|
||||||
"cov-mark",
|
"cov-mark",
|
||||||
|
"dashmap",
|
||||||
"drop_bomb",
|
"drop_bomb",
|
||||||
"either",
|
"either",
|
||||||
"expect-test",
|
"expect-test",
|
||||||
|
|
|
@ -91,7 +91,7 @@ impl HirDisplay for Function {
|
||||||
let ret_type = if !qual.is_async {
|
let ret_type = if !qual.is_async {
|
||||||
&data.ret_type
|
&data.ret_type
|
||||||
} else {
|
} else {
|
||||||
match &data.ret_type {
|
match &*data.ret_type {
|
||||||
TypeRef::ImplTrait(bounds) => match &bounds[0] {
|
TypeRef::ImplTrait(bounds) => match &bounds[0] {
|
||||||
TypeBound::Path(path) => {
|
TypeBound::Path(path) => {
|
||||||
path.segments().iter().last().unwrap().args_and_bindings.unwrap().bindings
|
path.segments().iter().last().unwrap().args_and_bindings.unwrap().bindings
|
||||||
|
|
|
@ -957,7 +957,7 @@ impl SelfParam {
|
||||||
func_data
|
func_data
|
||||||
.params
|
.params
|
||||||
.first()
|
.first()
|
||||||
.map(|param| match *param {
|
.map(|param| match &**param {
|
||||||
TypeRef::Reference(.., mutability) => match mutability {
|
TypeRef::Reference(.., mutability) => match mutability {
|
||||||
hir_def::type_ref::Mutability::Shared => Access::Shared,
|
hir_def::type_ref::Mutability::Shared => Access::Shared,
|
||||||
hir_def::type_ref::Mutability::Mut => Access::Exclusive,
|
hir_def::type_ref::Mutability::Mut => Access::Exclusive,
|
||||||
|
@ -1011,7 +1011,7 @@ impl Const {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn type_ref(self, db: &dyn HirDatabase) -> TypeRef {
|
pub fn type_ref(self, db: &dyn HirDatabase) -> TypeRef {
|
||||||
db.const_data(self.id).type_ref.clone()
|
db.const_data(self.id).type_ref.as_ref().clone()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1101,7 +1101,7 @@ impl TypeAlias {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn type_ref(self, db: &dyn HirDatabase) -> Option<TypeRef> {
|
pub fn type_ref(self, db: &dyn HirDatabase) -> Option<TypeRef> {
|
||||||
db.type_alias_data(self.id).type_ref.clone()
|
db.type_alias_data(self.id).type_ref.as_deref().cloned()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn ty(self, db: &dyn HirDatabase) -> Type {
|
pub fn ty(self, db: &dyn HirDatabase) -> Type {
|
||||||
|
@ -1615,7 +1615,7 @@ impl Impl {
|
||||||
// FIXME: the return type is wrong. This should be a hir version of
|
// FIXME: the return type is wrong. This should be a hir version of
|
||||||
// `TraitRef` (ie, resolved `TypeRef`).
|
// `TraitRef` (ie, resolved `TypeRef`).
|
||||||
pub fn trait_(self, db: &dyn HirDatabase) -> Option<TraitRef> {
|
pub fn trait_(self, db: &dyn HirDatabase) -> Option<TraitRef> {
|
||||||
db.impl_data(self.id).target_trait.clone()
|
db.impl_data(self.id).target_trait.as_deref().cloned()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn self_ty(self, db: &dyn HirDatabase) -> Type {
|
pub fn self_ty(self, db: &dyn HirDatabase) -> Type {
|
||||||
|
|
|
@ -11,6 +11,7 @@ doctest = false
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
cov-mark = { version = "1.1", features = ["thread-local"] }
|
cov-mark = { version = "1.1", features = ["thread-local"] }
|
||||||
|
dashmap = { version = "4.0.2", features = ["raw-api"] }
|
||||||
log = "0.4.8"
|
log = "0.4.8"
|
||||||
once_cell = "1.3.1"
|
once_cell = "1.3.1"
|
||||||
rustc-hash = "1.1.0"
|
rustc-hash = "1.1.0"
|
||||||
|
|
|
@ -15,6 +15,7 @@ use tt::{Delimiter, DelimiterKind, Leaf, Subtree, TokenTree};
|
||||||
use crate::{
|
use crate::{
|
||||||
body::{CfgExpander, LowerCtx},
|
body::{CfgExpander, LowerCtx},
|
||||||
db::DefDatabase,
|
db::DefDatabase,
|
||||||
|
intern::Interned,
|
||||||
item_tree::{AttrOwner, Field, Fields, ItemTree, ModItem, RawVisibilityId},
|
item_tree::{AttrOwner, Field, Fields, ItemTree, ModItem, RawVisibilityId},
|
||||||
src::HasChildSource,
|
src::HasChildSource,
|
||||||
src::HasSource,
|
src::HasSource,
|
||||||
|
@ -58,7 +59,7 @@ pub enum VariantData {
|
||||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||||
pub struct FieldData {
|
pub struct FieldData {
|
||||||
pub name: Name,
|
pub name: Name,
|
||||||
pub type_ref: TypeRef,
|
pub type_ref: Interned<TypeRef>,
|
||||||
pub visibility: RawVisibility,
|
pub visibility: RawVisibility,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -292,7 +293,7 @@ fn lower_struct(
|
||||||
|| Either::Left(fd.clone()),
|
|| Either::Left(fd.clone()),
|
||||||
|| FieldData {
|
|| FieldData {
|
||||||
name: Name::new_tuple_field(i),
|
name: Name::new_tuple_field(i),
|
||||||
type_ref: TypeRef::from_ast_opt(&ctx, fd.ty()),
|
type_ref: Interned::new(TypeRef::from_ast_opt(&ctx, fd.ty())),
|
||||||
visibility: RawVisibility::from_ast(db, ast.with_value(fd.visibility())),
|
visibility: RawVisibility::from_ast(db, ast.with_value(fd.visibility())),
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
@ -309,7 +310,7 @@ fn lower_struct(
|
||||||
|| Either::Right(fd.clone()),
|
|| Either::Right(fd.clone()),
|
||||||
|| FieldData {
|
|| FieldData {
|
||||||
name: fd.name().map(|n| n.as_name()).unwrap_or_else(Name::missing),
|
name: fd.name().map(|n| n.as_name()).unwrap_or_else(Name::missing),
|
||||||
type_ref: TypeRef::from_ast_opt(&ctx, fd.ty()),
|
type_ref: Interned::new(TypeRef::from_ast_opt(&ctx, fd.ty())),
|
||||||
visibility: RawVisibility::from_ast(db, ast.with_value(fd.visibility())),
|
visibility: RawVisibility::from_ast(db, ast.with_value(fd.visibility())),
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
@ -358,7 +359,7 @@ fn lower_field(
|
||||||
) -> FieldData {
|
) -> FieldData {
|
||||||
FieldData {
|
FieldData {
|
||||||
name: field.name.clone(),
|
name: field.name.clone(),
|
||||||
type_ref: item_tree[field.type_ref].clone(),
|
type_ref: field.type_ref.clone(),
|
||||||
visibility: item_tree[override_visibility.unwrap_or(field.visibility)].clone(),
|
visibility: item_tree[override_visibility.unwrap_or(field.visibility)].clone(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,6 +9,7 @@ use crate::{
|
||||||
attr::Attrs,
|
attr::Attrs,
|
||||||
body::Expander,
|
body::Expander,
|
||||||
db::DefDatabase,
|
db::DefDatabase,
|
||||||
|
intern::Interned,
|
||||||
item_tree::{AssocItem, FunctionQualifier, ItemTreeId, ModItem, Param},
|
item_tree::{AssocItem, FunctionQualifier, ItemTreeId, ModItem, Param},
|
||||||
type_ref::{TraitRef, TypeBound, TypeRef},
|
type_ref::{TraitRef, TypeBound, TypeRef},
|
||||||
visibility::RawVisibility,
|
visibility::RawVisibility,
|
||||||
|
@ -19,8 +20,8 @@ use crate::{
|
||||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||||
pub struct FunctionData {
|
pub struct FunctionData {
|
||||||
pub name: Name,
|
pub name: Name,
|
||||||
pub params: Vec<TypeRef>,
|
pub params: Vec<Interned<TypeRef>>,
|
||||||
pub ret_type: TypeRef,
|
pub ret_type: Interned<TypeRef>,
|
||||||
pub attrs: Attrs,
|
pub attrs: Attrs,
|
||||||
/// True if the first param is `self`. This is relevant to decide whether this
|
/// True if the first param is `self`. This is relevant to decide whether this
|
||||||
/// can be called as a method.
|
/// can be called as a method.
|
||||||
|
@ -57,11 +58,11 @@ impl FunctionData {
|
||||||
params: enabled_params
|
params: enabled_params
|
||||||
.clone()
|
.clone()
|
||||||
.filter_map(|id| match &item_tree[id] {
|
.filter_map(|id| match &item_tree[id] {
|
||||||
Param::Normal(ty) => Some(item_tree[*ty].clone()),
|
Param::Normal(ty) => Some(ty.clone()),
|
||||||
Param::Varargs => None,
|
Param::Varargs => None,
|
||||||
})
|
})
|
||||||
.collect(),
|
.collect(),
|
||||||
ret_type: item_tree[func.ret_type].clone(),
|
ret_type: func.ret_type.clone(),
|
||||||
attrs: item_tree.attrs(db, krate, ModItem::from(loc.id.value).into()),
|
attrs: item_tree.attrs(db, krate, ModItem::from(loc.id.value).into()),
|
||||||
has_self_param: func.has_self_param,
|
has_self_param: func.has_self_param,
|
||||||
has_body: func.has_body,
|
has_body: func.has_body,
|
||||||
|
@ -76,7 +77,7 @@ impl FunctionData {
|
||||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||||
pub struct TypeAliasData {
|
pub struct TypeAliasData {
|
||||||
pub name: Name,
|
pub name: Name,
|
||||||
pub type_ref: Option<TypeRef>,
|
pub type_ref: Option<Interned<TypeRef>>,
|
||||||
pub visibility: RawVisibility,
|
pub visibility: RawVisibility,
|
||||||
pub is_extern: bool,
|
pub is_extern: bool,
|
||||||
/// Bounds restricting the type alias itself (eg. `type Ty: Bound;` in a trait or impl).
|
/// Bounds restricting the type alias itself (eg. `type Ty: Bound;` in a trait or impl).
|
||||||
|
@ -94,7 +95,7 @@ impl TypeAliasData {
|
||||||
|
|
||||||
Arc::new(TypeAliasData {
|
Arc::new(TypeAliasData {
|
||||||
name: typ.name.clone(),
|
name: typ.name.clone(),
|
||||||
type_ref: typ.type_ref.map(|id| item_tree[id].clone()),
|
type_ref: typ.type_ref.clone(),
|
||||||
visibility: item_tree[typ.visibility].clone(),
|
visibility: item_tree[typ.visibility].clone(),
|
||||||
is_extern: typ.is_extern,
|
is_extern: typ.is_extern,
|
||||||
bounds: typ.bounds.to_vec(),
|
bounds: typ.bounds.to_vec(),
|
||||||
|
@ -156,8 +157,8 @@ impl TraitData {
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||||
pub struct ImplData {
|
pub struct ImplData {
|
||||||
pub target_trait: Option<TraitRef>,
|
pub target_trait: Option<Interned<TraitRef>>,
|
||||||
pub self_ty: TypeRef,
|
pub self_ty: Interned<TypeRef>,
|
||||||
pub items: Vec<AssocItemId>,
|
pub items: Vec<AssocItemId>,
|
||||||
pub is_negative: bool,
|
pub is_negative: bool,
|
||||||
}
|
}
|
||||||
|
@ -169,8 +170,8 @@ impl ImplData {
|
||||||
|
|
||||||
let item_tree = impl_loc.id.item_tree(db);
|
let item_tree = impl_loc.id.item_tree(db);
|
||||||
let impl_def = &item_tree[impl_loc.id.value];
|
let impl_def = &item_tree[impl_loc.id.value];
|
||||||
let target_trait = impl_def.target_trait.map(|id| item_tree[id].clone());
|
let target_trait = impl_def.target_trait.clone();
|
||||||
let self_ty = item_tree[impl_def.self_ty].clone();
|
let self_ty = impl_def.self_ty.clone();
|
||||||
let is_negative = impl_def.is_negative;
|
let is_negative = impl_def.is_negative;
|
||||||
let module_id = impl_loc.container;
|
let module_id = impl_loc.container;
|
||||||
let container = AssocContainerId::ImplId(id);
|
let container = AssocContainerId::ImplId(id);
|
||||||
|
@ -195,7 +196,7 @@ impl ImplData {
|
||||||
pub struct ConstData {
|
pub struct ConstData {
|
||||||
/// const _: () = ();
|
/// const _: () = ();
|
||||||
pub name: Option<Name>,
|
pub name: Option<Name>,
|
||||||
pub type_ref: TypeRef,
|
pub type_ref: Interned<TypeRef>,
|
||||||
pub visibility: RawVisibility,
|
pub visibility: RawVisibility,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -207,7 +208,7 @@ impl ConstData {
|
||||||
|
|
||||||
Arc::new(ConstData {
|
Arc::new(ConstData {
|
||||||
name: konst.name.clone(),
|
name: konst.name.clone(),
|
||||||
type_ref: item_tree[konst.type_ref].clone(),
|
type_ref: konst.type_ref.clone(),
|
||||||
visibility: item_tree[konst.visibility].clone(),
|
visibility: item_tree[konst.visibility].clone(),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
@ -216,7 +217,7 @@ impl ConstData {
|
||||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||||
pub struct StaticData {
|
pub struct StaticData {
|
||||||
pub name: Option<Name>,
|
pub name: Option<Name>,
|
||||||
pub type_ref: TypeRef,
|
pub type_ref: Interned<TypeRef>,
|
||||||
pub visibility: RawVisibility,
|
pub visibility: RawVisibility,
|
||||||
pub mutable: bool,
|
pub mutable: bool,
|
||||||
pub is_extern: bool,
|
pub is_extern: bool,
|
||||||
|
@ -230,7 +231,7 @@ impl StaticData {
|
||||||
|
|
||||||
Arc::new(StaticData {
|
Arc::new(StaticData {
|
||||||
name: Some(statik.name.clone()),
|
name: Some(statik.name.clone()),
|
||||||
type_ref: item_tree[statik.type_ref].clone(),
|
type_ref: statik.type_ref.clone(),
|
||||||
visibility: item_tree[statik.visibility].clone(),
|
visibility: item_tree[statik.visibility].clone(),
|
||||||
mutable: statik.mutable,
|
mutable: statik.mutable,
|
||||||
is_extern: statik.is_extern,
|
is_extern: statik.is_extern,
|
||||||
|
|
157
crates/hir_def/src/intern.rs
Normal file
157
crates/hir_def/src/intern.rs
Normal file
|
@ -0,0 +1,157 @@
|
||||||
|
//! Global `Arc`-based object interning infrastructure.
|
||||||
|
//!
|
||||||
|
//! Eventually this should probably be replaced with salsa-based interning.
|
||||||
|
|
||||||
|
use std::{
|
||||||
|
fmt::{self, Debug},
|
||||||
|
hash::{BuildHasherDefault, Hash},
|
||||||
|
ops::Deref,
|
||||||
|
sync::Arc,
|
||||||
|
};
|
||||||
|
|
||||||
|
use dashmap::{DashMap, SharedValue};
|
||||||
|
use once_cell::sync::OnceCell;
|
||||||
|
use rustc_hash::FxHasher;
|
||||||
|
|
||||||
|
type InternMap<T> = DashMap<Arc<T>, (), BuildHasherDefault<FxHasher>>;
|
||||||
|
|
||||||
|
pub struct Interned<T: Internable> {
|
||||||
|
arc: Arc<T>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T: Internable> Interned<T> {
|
||||||
|
pub fn new(obj: T) -> Self {
|
||||||
|
let storage = T::storage().get();
|
||||||
|
let shard_idx = storage.determine_map(&obj);
|
||||||
|
let shard = &storage.shards()[shard_idx];
|
||||||
|
let shard = shard.upgradeable_read();
|
||||||
|
|
||||||
|
// Atomically,
|
||||||
|
// - check if `obj` is already in the map
|
||||||
|
// - if so, clone its `Arc` and return it
|
||||||
|
// - if not, box it up, insert it, and return a clone
|
||||||
|
// This needs to be atomic (locking the shard) to avoid races with other thread, which could
|
||||||
|
// insert the same object between us looking it up and inserting it.
|
||||||
|
|
||||||
|
// FIXME: avoid double lookup by using raw entry API (once stable, or when hashbrown can be
|
||||||
|
// plugged into dashmap)
|
||||||
|
if let Some((arc, _)) = shard.get_key_value(&obj) {
|
||||||
|
return Self { arc: arc.clone() };
|
||||||
|
}
|
||||||
|
|
||||||
|
let arc = Arc::new(obj);
|
||||||
|
let arc2 = arc.clone();
|
||||||
|
|
||||||
|
{
|
||||||
|
let mut shard = shard.upgrade();
|
||||||
|
shard.insert(arc2, SharedValue::new(()));
|
||||||
|
}
|
||||||
|
|
||||||
|
Self { arc }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T: Internable> Drop for Interned<T> {
|
||||||
|
fn drop(&mut self) {
|
||||||
|
// When the last `Ref` is dropped, remove the object from the global map.
|
||||||
|
if Arc::strong_count(&self.arc) == 2 {
|
||||||
|
// Only `self` and the global map point to the object.
|
||||||
|
|
||||||
|
let storage = T::storage().get();
|
||||||
|
let shard_idx = storage.determine_map(&self.arc);
|
||||||
|
let shard = &storage.shards()[shard_idx];
|
||||||
|
let mut shard = shard.write();
|
||||||
|
|
||||||
|
// FIXME: avoid double lookup
|
||||||
|
let (arc, _) =
|
||||||
|
shard.get_key_value(&self.arc).expect("interned value removed prematurely");
|
||||||
|
|
||||||
|
if Arc::strong_count(arc) != 2 {
|
||||||
|
// Another thread has interned another copy
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
shard.remove(&self.arc);
|
||||||
|
|
||||||
|
// Shrink the backing storage if the shard is less than 50% occupied.
|
||||||
|
if shard.len() * 2 < shard.capacity() {
|
||||||
|
shard.shrink_to_fit();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Compares interned `Ref`s using pointer equality.
|
||||||
|
impl<T: Internable> PartialEq for Interned<T> {
|
||||||
|
#[inline]
|
||||||
|
fn eq(&self, other: &Self) -> bool {
|
||||||
|
Arc::ptr_eq(&self.arc, &other.arc)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T: Internable> Eq for Interned<T> {}
|
||||||
|
|
||||||
|
impl<T: Internable> AsRef<T> for Interned<T> {
|
||||||
|
#[inline]
|
||||||
|
fn as_ref(&self) -> &T {
|
||||||
|
&self.arc
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T: Internable> Deref for Interned<T> {
|
||||||
|
type Target = T;
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn deref(&self) -> &Self::Target {
|
||||||
|
&self.arc
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T: Internable> Clone for Interned<T> {
|
||||||
|
fn clone(&self) -> Self {
|
||||||
|
Self { arc: self.arc.clone() }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T: Debug + Internable> Debug for Interned<T> {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
|
(*self.arc).fmt(f)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct InternStorage<T> {
|
||||||
|
map: OnceCell<InternMap<T>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T> InternStorage<T> {
|
||||||
|
pub const fn new() -> Self {
|
||||||
|
Self { map: OnceCell::new() }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T: Internable> InternStorage<T> {
|
||||||
|
fn get(&self) -> &InternMap<T> {
|
||||||
|
self.map.get_or_init(DashMap::default)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub trait Internable: Hash + Eq + Sized + 'static {
|
||||||
|
fn storage() -> &'static InternStorage<Self>;
|
||||||
|
}
|
||||||
|
|
||||||
|
// region:`Internable` implementations
|
||||||
|
|
||||||
|
macro_rules! impl_internable {
|
||||||
|
( $($t:ty),+ $(,)? ) => { $(
|
||||||
|
impl Internable for $t {
|
||||||
|
fn storage() -> &'static InternStorage<Self> {
|
||||||
|
static STORAGE: InternStorage<$t> = InternStorage::new();
|
||||||
|
&STORAGE
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)+ };
|
||||||
|
}
|
||||||
|
|
||||||
|
impl_internable!(crate::type_ref::TypeRef, crate::type_ref::TraitRef);
|
||||||
|
|
||||||
|
// endregion
|
|
@ -30,6 +30,7 @@ use crate::{
|
||||||
attr::{Attrs, RawAttrs},
|
attr::{Attrs, RawAttrs},
|
||||||
db::DefDatabase,
|
db::DefDatabase,
|
||||||
generics::GenericParams,
|
generics::GenericParams,
|
||||||
|
intern::Interned,
|
||||||
path::{path, AssociatedTypeBinding, GenericArgs, ImportAlias, ModPath, Path, PathKind},
|
path::{path, AssociatedTypeBinding, GenericArgs, ImportAlias, ModPath, Path, PathKind},
|
||||||
type_ref::{Mutability, TraitRef, TypeBound, TypeRef},
|
type_ref::{Mutability, TraitRef, TypeBound, TypeRef},
|
||||||
visibility::RawVisibility,
|
visibility::RawVisibility,
|
||||||
|
@ -146,8 +147,6 @@ impl ItemTree {
|
||||||
macro_defs,
|
macro_defs,
|
||||||
vis,
|
vis,
|
||||||
generics,
|
generics,
|
||||||
type_refs,
|
|
||||||
trait_refs,
|
|
||||||
inner_items,
|
inner_items,
|
||||||
} = &mut **data;
|
} = &mut **data;
|
||||||
|
|
||||||
|
@ -172,9 +171,6 @@ impl ItemTree {
|
||||||
|
|
||||||
vis.arena.shrink_to_fit();
|
vis.arena.shrink_to_fit();
|
||||||
generics.arena.shrink_to_fit();
|
generics.arena.shrink_to_fit();
|
||||||
type_refs.arena.shrink_to_fit();
|
|
||||||
type_refs.map.shrink_to_fit();
|
|
||||||
trait_refs.map.shrink_to_fit();
|
|
||||||
|
|
||||||
inner_items.shrink_to_fit();
|
inner_items.shrink_to_fit();
|
||||||
}
|
}
|
||||||
|
@ -271,58 +267,6 @@ static EMPTY_GENERICS: GenericParams = GenericParams {
|
||||||
where_predicates: Vec::new(),
|
where_predicates: Vec::new(),
|
||||||
};
|
};
|
||||||
|
|
||||||
/// `TypeRef` interner.
|
|
||||||
#[derive(Default, Debug, Eq, PartialEq)]
|
|
||||||
struct TypeRefStorage {
|
|
||||||
arena: Arena<Arc<TypeRef>>,
|
|
||||||
map: FxHashMap<Arc<TypeRef>, Idx<Arc<TypeRef>>>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl TypeRefStorage {
|
|
||||||
// Note: We lie about the `Idx<TypeRef>` to hide the interner details.
|
|
||||||
|
|
||||||
fn intern(&mut self, ty: TypeRef) -> Idx<TypeRef> {
|
|
||||||
if let Some(id) = self.map.get(&ty) {
|
|
||||||
return Idx::from_raw(id.into_raw());
|
|
||||||
}
|
|
||||||
|
|
||||||
let ty = Arc::new(ty);
|
|
||||||
let idx = self.arena.alloc(ty.clone());
|
|
||||||
self.map.insert(ty, idx);
|
|
||||||
Idx::from_raw(idx.into_raw())
|
|
||||||
}
|
|
||||||
|
|
||||||
fn lookup(&self, id: Idx<TypeRef>) -> &TypeRef {
|
|
||||||
&self.arena[Idx::from_raw(id.into_raw())]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// `TraitRef` interner.
|
|
||||||
#[derive(Default, Debug, Eq, PartialEq)]
|
|
||||||
struct TraitRefStorage {
|
|
||||||
arena: Arena<Arc<TraitRef>>,
|
|
||||||
map: FxHashMap<Arc<TraitRef>, Idx<Arc<TraitRef>>>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl TraitRefStorage {
|
|
||||||
// Note: We lie about the `Idx<TraitRef>` to hide the interner details.
|
|
||||||
|
|
||||||
fn intern(&mut self, ty: TraitRef) -> Idx<TraitRef> {
|
|
||||||
if let Some(id) = self.map.get(&ty) {
|
|
||||||
return Idx::from_raw(id.into_raw());
|
|
||||||
}
|
|
||||||
|
|
||||||
let ty = Arc::new(ty);
|
|
||||||
let idx = self.arena.alloc(ty.clone());
|
|
||||||
self.map.insert(ty, idx);
|
|
||||||
Idx::from_raw(idx.into_raw())
|
|
||||||
}
|
|
||||||
|
|
||||||
fn lookup(&self, id: Idx<TraitRef>) -> &TraitRef {
|
|
||||||
&self.arena[Idx::from_raw(id.into_raw())]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Default, Debug, Eq, PartialEq)]
|
#[derive(Default, Debug, Eq, PartialEq)]
|
||||||
struct ItemTreeData {
|
struct ItemTreeData {
|
||||||
imports: Arena<Import>,
|
imports: Arena<Import>,
|
||||||
|
@ -346,8 +290,6 @@ struct ItemTreeData {
|
||||||
|
|
||||||
vis: ItemVisibilities,
|
vis: ItemVisibilities,
|
||||||
generics: GenericParamsStorage,
|
generics: GenericParamsStorage,
|
||||||
type_refs: TypeRefStorage,
|
|
||||||
trait_refs: TraitRefStorage,
|
|
||||||
|
|
||||||
inner_items: FxHashMap<FileAstId<ast::BlockExpr>, SmallVec<[ModItem; 1]>>,
|
inner_items: FxHashMap<FileAstId<ast::BlockExpr>, SmallVec<[ModItem; 1]>>,
|
||||||
}
|
}
|
||||||
|
@ -577,22 +519,6 @@ impl Index<GenericParamsId> for ItemTree {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Index<Idx<TypeRef>> for ItemTree {
|
|
||||||
type Output = TypeRef;
|
|
||||||
|
|
||||||
fn index(&self, id: Idx<TypeRef>) -> &Self::Output {
|
|
||||||
self.data().type_refs.lookup(id)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Index<Idx<TraitRef>> for ItemTree {
|
|
||||||
type Output = TraitRef;
|
|
||||||
|
|
||||||
fn index(&self, id: Idx<TraitRef>) -> &Self::Output {
|
|
||||||
self.data().trait_refs.lookup(id)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
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 {
|
||||||
|
@ -637,13 +563,13 @@ pub struct Function {
|
||||||
/// `extern "abi" fn`).
|
/// `extern "abi" fn`).
|
||||||
pub is_in_extern_block: bool,
|
pub is_in_extern_block: bool,
|
||||||
pub params: IdRange<Param>,
|
pub params: IdRange<Param>,
|
||||||
pub ret_type: Idx<TypeRef>,
|
pub ret_type: Interned<TypeRef>,
|
||||||
pub ast_id: FileAstId<ast::Fn>,
|
pub ast_id: FileAstId<ast::Fn>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, Eq, PartialEq)]
|
#[derive(Debug, Clone, Eq, PartialEq)]
|
||||||
pub enum Param {
|
pub enum Param {
|
||||||
Normal(Idx<TypeRef>),
|
Normal(Interned<TypeRef>),
|
||||||
Varargs,
|
Varargs,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -699,7 +625,7 @@ pub struct Const {
|
||||||
/// const _: () = ();
|
/// const _: () = ();
|
||||||
pub name: Option<Name>,
|
pub name: Option<Name>,
|
||||||
pub visibility: RawVisibilityId,
|
pub visibility: RawVisibilityId,
|
||||||
pub type_ref: Idx<TypeRef>,
|
pub type_ref: Interned<TypeRef>,
|
||||||
pub ast_id: FileAstId<ast::Const>,
|
pub ast_id: FileAstId<ast::Const>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -710,7 +636,7 @@ pub struct Static {
|
||||||
pub mutable: bool,
|
pub mutable: bool,
|
||||||
/// Whether the static is in an `extern` block.
|
/// Whether the static is in an `extern` block.
|
||||||
pub is_extern: bool,
|
pub is_extern: bool,
|
||||||
pub type_ref: Idx<TypeRef>,
|
pub type_ref: Interned<TypeRef>,
|
||||||
pub ast_id: FileAstId<ast::Static>,
|
pub ast_id: FileAstId<ast::Static>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -729,8 +655,8 @@ 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: GenericParamsId,
|
||||||
pub target_trait: Option<Idx<TraitRef>>,
|
pub target_trait: Option<Interned<TraitRef>>,
|
||||||
pub self_ty: Idx<TypeRef>,
|
pub self_ty: Interned<TypeRef>,
|
||||||
pub is_negative: bool,
|
pub is_negative: bool,
|
||||||
pub items: Box<[AssocItem]>,
|
pub items: Box<[AssocItem]>,
|
||||||
pub ast_id: FileAstId<ast::Impl>,
|
pub ast_id: FileAstId<ast::Impl>,
|
||||||
|
@ -743,7 +669,7 @@ pub struct TypeAlias {
|
||||||
/// 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: GenericParamsId,
|
||||||
pub type_ref: Option<Idx<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>,
|
||||||
}
|
}
|
||||||
|
@ -933,6 +859,6 @@ pub enum Fields {
|
||||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||||
pub struct Field {
|
pub struct Field {
|
||||||
pub name: Name,
|
pub name: Name,
|
||||||
pub type_ref: Idx<TypeRef>,
|
pub type_ref: Interned<TypeRef>,
|
||||||
pub visibility: RawVisibilityId,
|
pub visibility: RawVisibilityId,
|
||||||
}
|
}
|
||||||
|
|
|
@ -362,7 +362,7 @@ impl Ctx {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
let ty = self.data().type_refs.intern(self_type);
|
let ty = Interned::new(self_type);
|
||||||
let idx = self.data().params.alloc(Param::Normal(ty));
|
let idx = self.data().params.alloc(Param::Normal(ty));
|
||||||
self.add_attrs(idx.into(), RawAttrs::new(&self_param, &self.hygiene));
|
self.add_attrs(idx.into(), RawAttrs::new(&self_param, &self.hygiene));
|
||||||
has_self_param = true;
|
has_self_param = true;
|
||||||
|
@ -372,7 +372,7 @@ impl Ctx {
|
||||||
Some(_) => self.data().params.alloc(Param::Varargs),
|
Some(_) => self.data().params.alloc(Param::Varargs),
|
||||||
None => {
|
None => {
|
||||||
let type_ref = TypeRef::from_ast_opt(&self.body_ctx, param.ty());
|
let type_ref = TypeRef::from_ast_opt(&self.body_ctx, param.ty());
|
||||||
let ty = self.data().type_refs.intern(type_ref);
|
let ty = Interned::new(type_ref);
|
||||||
self.data().params.alloc(Param::Normal(ty))
|
self.data().params.alloc(Param::Normal(ty))
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -395,8 +395,6 @@ impl Ctx {
|
||||||
ret_type
|
ret_type
|
||||||
};
|
};
|
||||||
|
|
||||||
let ret_type = self.data().type_refs.intern(ret_type);
|
|
||||||
|
|
||||||
let has_body = func.body().is_some();
|
let has_body = func.body().is_some();
|
||||||
|
|
||||||
let ast_id = self.source_ast_id_map.ast_id(func);
|
let ast_id = self.source_ast_id_map.ast_id(func);
|
||||||
|
@ -428,7 +426,7 @@ impl Ctx {
|
||||||
qualifier,
|
qualifier,
|
||||||
is_in_extern_block: false,
|
is_in_extern_block: false,
|
||||||
params,
|
params,
|
||||||
ret_type,
|
ret_type: Interned::new(ret_type),
|
||||||
ast_id,
|
ast_id,
|
||||||
};
|
};
|
||||||
res.generic_params = self.lower_generic_params(GenericsOwner::Function(&res), func);
|
res.generic_params = self.lower_generic_params(GenericsOwner::Function(&res), func);
|
||||||
|
@ -694,8 +692,7 @@ impl Ctx {
|
||||||
generics.fill(&self.body_ctx, sm, node);
|
generics.fill(&self.body_ctx, sm, node);
|
||||||
// lower `impl Trait` in arguments
|
// lower `impl Trait` in arguments
|
||||||
for id in func.params.clone() {
|
for id in func.params.clone() {
|
||||||
if let Param::Normal(ty) = self.data().params[id] {
|
if let Param::Normal(ty) = &self.data().params[id] {
|
||||||
let ty = self.data().type_refs.lookup(ty);
|
|
||||||
generics.fill_implicit_impl_trait_args(ty);
|
generics.fill_implicit_impl_trait_args(ty);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -749,20 +746,20 @@ impl Ctx {
|
||||||
self.data().vis.alloc(vis)
|
self.data().vis.alloc(vis)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn lower_trait_ref(&mut self, trait_ref: &ast::Type) -> Option<Idx<TraitRef>> {
|
fn lower_trait_ref(&mut self, trait_ref: &ast::Type) -> Option<Interned<TraitRef>> {
|
||||||
let trait_ref = TraitRef::from_ast(&self.body_ctx, trait_ref.clone())?;
|
let trait_ref = TraitRef::from_ast(&self.body_ctx, trait_ref.clone())?;
|
||||||
Some(self.data().trait_refs.intern(trait_ref))
|
Some(Interned::new(trait_ref))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn lower_type_ref(&mut self, type_ref: &ast::Type) -> Idx<TypeRef> {
|
fn lower_type_ref(&mut self, type_ref: &ast::Type) -> Interned<TypeRef> {
|
||||||
let tyref = TypeRef::from_ast(&self.body_ctx, type_ref.clone());
|
let tyref = TypeRef::from_ast(&self.body_ctx, type_ref.clone());
|
||||||
self.data().type_refs.intern(tyref)
|
Interned::new(tyref)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn lower_type_ref_opt(&mut self, type_ref: Option<ast::Type>) -> Idx<TypeRef> {
|
fn lower_type_ref_opt(&mut self, type_ref: Option<ast::Type>) -> Interned<TypeRef> {
|
||||||
match type_ref.map(|ty| self.lower_type_ref(&ty)) {
|
match type_ref.map(|ty| self.lower_type_ref(&ty)) {
|
||||||
Some(it) => it,
|
Some(it) => it,
|
||||||
None => self.data().type_refs.intern(TypeRef::Error),
|
None => Interned::new(TypeRef::Error),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -49,6 +49,7 @@ 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},
|
||||||
|
|
|
@ -1157,7 +1157,7 @@ fn type_for_type_alias(db: &dyn HirDatabase, t: TypeAliasId) -> Binders<Ty> {
|
||||||
Binders::new(0, TyKind::ForeignType(crate::to_foreign_def_id(t)).intern(&Interner))
|
Binders::new(0, TyKind::ForeignType(crate::to_foreign_def_id(t)).intern(&Interner))
|
||||||
} else {
|
} else {
|
||||||
let type_ref = &db.type_alias_data(t).type_ref;
|
let type_ref = &db.type_alias_data(t).type_ref;
|
||||||
let inner = ctx.lower_ty(type_ref.as_ref().unwrap_or(&TypeRef::Error));
|
let inner = ctx.lower_ty(type_ref.as_deref().unwrap_or(&TypeRef::Error));
|
||||||
Binders::new(generics.len(), inner)
|
Binders::new(generics.len(), inner)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue