diff options
author | Jonas Schievink <[email protected]> | 2021-04-01 18:46:43 +0100 |
---|---|---|
committer | Jonas Schievink <[email protected]> | 2021-04-01 18:46:43 +0100 |
commit | b00266b79f0e2c2a5e332b30f7e6aba83b5e6e5a (patch) | |
tree | c7e591ec8a1ec6b401a8a7ea00115120a4789db5 /crates | |
parent | 25201b2dad7b4b0d41494e238ebf643ad7ad8cd6 (diff) |
Global TypeRef/TraitRef interning
Diffstat (limited to 'crates')
-rw-r--r-- | crates/hir/src/display.rs | 2 | ||||
-rw-r--r-- | crates/hir/src/lib.rs | 8 | ||||
-rw-r--r-- | crates/hir_def/Cargo.toml | 1 | ||||
-rw-r--r-- | crates/hir_def/src/adt.rs | 9 | ||||
-rw-r--r-- | crates/hir_def/src/data.rs | 29 | ||||
-rw-r--r-- | crates/hir_def/src/intern.rs | 157 | ||||
-rw-r--r-- | crates/hir_def/src/item_tree.rs | 92 | ||||
-rw-r--r-- | crates/hir_def/src/item_tree/lower.rs | 23 | ||||
-rw-r--r-- | crates/hir_def/src/lib.rs | 1 | ||||
-rw-r--r-- | crates/hir_ty/src/lower.rs | 2 |
10 files changed, 204 insertions, 120 deletions
diff --git a/crates/hir/src/display.rs b/crates/hir/src/display.rs index 97a78ca25..ab04c55bc 100644 --- a/crates/hir/src/display.rs +++ b/crates/hir/src/display.rs | |||
@@ -91,7 +91,7 @@ impl HirDisplay for Function { | |||
91 | let ret_type = if !qual.is_async { | 91 | let ret_type = if !qual.is_async { |
92 | &data.ret_type | 92 | &data.ret_type |
93 | } else { | 93 | } else { |
94 | match &data.ret_type { | 94 | match &*data.ret_type { |
95 | TypeRef::ImplTrait(bounds) => match &bounds[0] { | 95 | TypeRef::ImplTrait(bounds) => match &bounds[0] { |
96 | TypeBound::Path(path) => { | 96 | TypeBound::Path(path) => { |
97 | path.segments().iter().last().unwrap().args_and_bindings.unwrap().bindings | 97 | path.segments().iter().last().unwrap().args_and_bindings.unwrap().bindings |
diff --git a/crates/hir/src/lib.rs b/crates/hir/src/lib.rs index 97f162315..06fd6542d 100644 --- a/crates/hir/src/lib.rs +++ b/crates/hir/src/lib.rs | |||
@@ -957,7 +957,7 @@ impl SelfParam { | |||
957 | func_data | 957 | func_data |
958 | .params | 958 | .params |
959 | .first() | 959 | .first() |
960 | .map(|param| match *param { | 960 | .map(|param| match &**param { |
961 | TypeRef::Reference(.., mutability) => match mutability { | 961 | TypeRef::Reference(.., mutability) => match mutability { |
962 | hir_def::type_ref::Mutability::Shared => Access::Shared, | 962 | hir_def::type_ref::Mutability::Shared => Access::Shared, |
963 | hir_def::type_ref::Mutability::Mut => Access::Exclusive, | 963 | hir_def::type_ref::Mutability::Mut => Access::Exclusive, |
@@ -1011,7 +1011,7 @@ impl Const { | |||
1011 | } | 1011 | } |
1012 | 1012 | ||
1013 | pub fn type_ref(self, db: &dyn HirDatabase) -> TypeRef { | 1013 | pub fn type_ref(self, db: &dyn HirDatabase) -> TypeRef { |
1014 | db.const_data(self.id).type_ref.clone() | 1014 | db.const_data(self.id).type_ref.as_ref().clone() |
1015 | } | 1015 | } |
1016 | } | 1016 | } |
1017 | 1017 | ||
@@ -1101,7 +1101,7 @@ impl TypeAlias { | |||
1101 | } | 1101 | } |
1102 | 1102 | ||
1103 | pub fn type_ref(self, db: &dyn HirDatabase) -> Option<TypeRef> { | 1103 | pub fn type_ref(self, db: &dyn HirDatabase) -> Option<TypeRef> { |
1104 | db.type_alias_data(self.id).type_ref.clone() | 1104 | db.type_alias_data(self.id).type_ref.as_deref().cloned() |
1105 | } | 1105 | } |
1106 | 1106 | ||
1107 | pub fn ty(self, db: &dyn HirDatabase) -> Type { | 1107 | pub fn ty(self, db: &dyn HirDatabase) -> Type { |
@@ -1615,7 +1615,7 @@ impl Impl { | |||
1615 | // FIXME: the return type is wrong. This should be a hir version of | 1615 | // FIXME: the return type is wrong. This should be a hir version of |
1616 | // `TraitRef` (ie, resolved `TypeRef`). | 1616 | // `TraitRef` (ie, resolved `TypeRef`). |
1617 | pub fn trait_(self, db: &dyn HirDatabase) -> Option<TraitRef> { | 1617 | pub fn trait_(self, db: &dyn HirDatabase) -> Option<TraitRef> { |
1618 | db.impl_data(self.id).target_trait.clone() | 1618 | db.impl_data(self.id).target_trait.as_deref().cloned() |
1619 | } | 1619 | } |
1620 | 1620 | ||
1621 | pub fn self_ty(self, db: &dyn HirDatabase) -> Type { | 1621 | pub fn self_ty(self, db: &dyn HirDatabase) -> Type { |
diff --git a/crates/hir_def/Cargo.toml b/crates/hir_def/Cargo.toml index 475d337f3..43324d8d9 100644 --- a/crates/hir_def/Cargo.toml +++ b/crates/hir_def/Cargo.toml | |||
@@ -11,6 +11,7 @@ doctest = false | |||
11 | 11 | ||
12 | [dependencies] | 12 | [dependencies] |
13 | cov-mark = { version = "1.1", features = ["thread-local"] } | 13 | cov-mark = { version = "1.1", features = ["thread-local"] } |
14 | dashmap = { version = "4.0.2", features = ["raw-api"] } | ||
14 | log = "0.4.8" | 15 | log = "0.4.8" |
15 | once_cell = "1.3.1" | 16 | once_cell = "1.3.1" |
16 | rustc-hash = "1.1.0" | 17 | rustc-hash = "1.1.0" |
diff --git a/crates/hir_def/src/adt.rs b/crates/hir_def/src/adt.rs index 58e35353b..402fb1d8d 100644 --- a/crates/hir_def/src/adt.rs +++ b/crates/hir_def/src/adt.rs | |||
@@ -15,6 +15,7 @@ use tt::{Delimiter, DelimiterKind, Leaf, Subtree, TokenTree}; | |||
15 | use crate::{ | 15 | use crate::{ |
16 | body::{CfgExpander, LowerCtx}, | 16 | body::{CfgExpander, LowerCtx}, |
17 | db::DefDatabase, | 17 | db::DefDatabase, |
18 | intern::Interned, | ||
18 | item_tree::{AttrOwner, Field, Fields, ItemTree, ModItem, RawVisibilityId}, | 19 | item_tree::{AttrOwner, Field, Fields, ItemTree, ModItem, RawVisibilityId}, |
19 | src::HasChildSource, | 20 | src::HasChildSource, |
20 | src::HasSource, | 21 | src::HasSource, |
@@ -58,7 +59,7 @@ pub enum VariantData { | |||
58 | #[derive(Debug, Clone, PartialEq, Eq)] | 59 | #[derive(Debug, Clone, PartialEq, Eq)] |
59 | pub struct FieldData { | 60 | pub struct FieldData { |
60 | pub name: Name, | 61 | pub name: Name, |
61 | pub type_ref: TypeRef, | 62 | pub type_ref: Interned<TypeRef>, |
62 | pub visibility: RawVisibility, | 63 | pub visibility: RawVisibility, |
63 | } | 64 | } |
64 | 65 | ||
@@ -292,7 +293,7 @@ fn lower_struct( | |||
292 | || Either::Left(fd.clone()), | 293 | || Either::Left(fd.clone()), |
293 | || FieldData { | 294 | || FieldData { |
294 | name: Name::new_tuple_field(i), | 295 | name: Name::new_tuple_field(i), |
295 | type_ref: TypeRef::from_ast_opt(&ctx, fd.ty()), | 296 | type_ref: Interned::new(TypeRef::from_ast_opt(&ctx, fd.ty())), |
296 | visibility: RawVisibility::from_ast(db, ast.with_value(fd.visibility())), | 297 | visibility: RawVisibility::from_ast(db, ast.with_value(fd.visibility())), |
297 | }, | 298 | }, |
298 | ); | 299 | ); |
@@ -309,7 +310,7 @@ fn lower_struct( | |||
309 | || Either::Right(fd.clone()), | 310 | || Either::Right(fd.clone()), |
310 | || FieldData { | 311 | || FieldData { |
311 | name: fd.name().map(|n| n.as_name()).unwrap_or_else(Name::missing), | 312 | name: fd.name().map(|n| n.as_name()).unwrap_or_else(Name::missing), |
312 | type_ref: TypeRef::from_ast_opt(&ctx, fd.ty()), | 313 | type_ref: Interned::new(TypeRef::from_ast_opt(&ctx, fd.ty())), |
313 | visibility: RawVisibility::from_ast(db, ast.with_value(fd.visibility())), | 314 | visibility: RawVisibility::from_ast(db, ast.with_value(fd.visibility())), |
314 | }, | 315 | }, |
315 | ); | 316 | ); |
@@ -358,7 +359,7 @@ fn lower_field( | |||
358 | ) -> FieldData { | 359 | ) -> FieldData { |
359 | FieldData { | 360 | FieldData { |
360 | name: field.name.clone(), | 361 | name: field.name.clone(), |
361 | type_ref: item_tree[field.type_ref].clone(), | 362 | type_ref: field.type_ref.clone(), |
362 | visibility: item_tree[override_visibility.unwrap_or(field.visibility)].clone(), | 363 | visibility: item_tree[override_visibility.unwrap_or(field.visibility)].clone(), |
363 | } | 364 | } |
364 | } | 365 | } |
diff --git a/crates/hir_def/src/data.rs b/crates/hir_def/src/data.rs index 214bcc648..31f994681 100644 --- a/crates/hir_def/src/data.rs +++ b/crates/hir_def/src/data.rs | |||
@@ -9,6 +9,7 @@ use crate::{ | |||
9 | attr::Attrs, | 9 | attr::Attrs, |
10 | body::Expander, | 10 | body::Expander, |
11 | db::DefDatabase, | 11 | db::DefDatabase, |
12 | intern::Interned, | ||
12 | item_tree::{AssocItem, FunctionQualifier, ItemTreeId, ModItem, Param}, | 13 | item_tree::{AssocItem, FunctionQualifier, ItemTreeId, ModItem, Param}, |
13 | type_ref::{TraitRef, TypeBound, TypeRef}, | 14 | type_ref::{TraitRef, TypeBound, TypeRef}, |
14 | visibility::RawVisibility, | 15 | visibility::RawVisibility, |
@@ -19,8 +20,8 @@ use crate::{ | |||
19 | #[derive(Debug, Clone, PartialEq, Eq)] | 20 | #[derive(Debug, Clone, PartialEq, Eq)] |
20 | pub struct FunctionData { | 21 | pub struct FunctionData { |
21 | pub name: Name, | 22 | pub name: Name, |
22 | pub params: Vec<TypeRef>, | 23 | pub params: Vec<Interned<TypeRef>>, |
23 | pub ret_type: TypeRef, | 24 | pub ret_type: Interned<TypeRef>, |
24 | pub attrs: Attrs, | 25 | pub attrs: Attrs, |
25 | /// True if the first param is `self`. This is relevant to decide whether this | 26 | /// True if the first param is `self`. This is relevant to decide whether this |
26 | /// can be called as a method. | 27 | /// can be called as a method. |
@@ -57,11 +58,11 @@ impl FunctionData { | |||
57 | params: enabled_params | 58 | params: enabled_params |
58 | .clone() | 59 | .clone() |
59 | .filter_map(|id| match &item_tree[id] { | 60 | .filter_map(|id| match &item_tree[id] { |
60 | Param::Normal(ty) => Some(item_tree[*ty].clone()), | 61 | Param::Normal(ty) => Some(ty.clone()), |
61 | Param::Varargs => None, | 62 | Param::Varargs => None, |
62 | }) | 63 | }) |
63 | .collect(), | 64 | .collect(), |
64 | ret_type: item_tree[func.ret_type].clone(), | 65 | ret_type: func.ret_type.clone(), |
65 | attrs: item_tree.attrs(db, krate, ModItem::from(loc.id.value).into()), | 66 | attrs: item_tree.attrs(db, krate, ModItem::from(loc.id.value).into()), |
66 | has_self_param: func.has_self_param, | 67 | has_self_param: func.has_self_param, |
67 | has_body: func.has_body, | 68 | has_body: func.has_body, |
@@ -76,7 +77,7 @@ impl FunctionData { | |||
76 | #[derive(Debug, Clone, PartialEq, Eq)] | 77 | #[derive(Debug, Clone, PartialEq, Eq)] |
77 | pub struct TypeAliasData { | 78 | pub struct TypeAliasData { |
78 | pub name: Name, | 79 | pub name: Name, |
79 | pub type_ref: Option<TypeRef>, | 80 | pub type_ref: Option<Interned<TypeRef>>, |
80 | pub visibility: RawVisibility, | 81 | pub visibility: RawVisibility, |
81 | pub is_extern: bool, | 82 | pub is_extern: bool, |
82 | /// Bounds restricting the type alias itself (eg. `type Ty: Bound;` in a trait or impl). | 83 | /// Bounds restricting the type alias itself (eg. `type Ty: Bound;` in a trait or impl). |
@@ -94,7 +95,7 @@ impl TypeAliasData { | |||
94 | 95 | ||
95 | Arc::new(TypeAliasData { | 96 | Arc::new(TypeAliasData { |
96 | name: typ.name.clone(), | 97 | name: typ.name.clone(), |
97 | type_ref: typ.type_ref.map(|id| item_tree[id].clone()), | 98 | type_ref: typ.type_ref.clone(), |
98 | visibility: item_tree[typ.visibility].clone(), | 99 | visibility: item_tree[typ.visibility].clone(), |
99 | is_extern: typ.is_extern, | 100 | is_extern: typ.is_extern, |
100 | bounds: typ.bounds.to_vec(), | 101 | bounds: typ.bounds.to_vec(), |
@@ -156,8 +157,8 @@ impl TraitData { | |||
156 | 157 | ||
157 | #[derive(Debug, Clone, PartialEq, Eq)] | 158 | #[derive(Debug, Clone, PartialEq, Eq)] |
158 | pub struct ImplData { | 159 | pub struct ImplData { |
159 | pub target_trait: Option<TraitRef>, | 160 | pub target_trait: Option<Interned<TraitRef>>, |
160 | pub self_ty: TypeRef, | 161 | pub self_ty: Interned<TypeRef>, |
161 | pub items: Vec<AssocItemId>, | 162 | pub items: Vec<AssocItemId>, |
162 | pub is_negative: bool, | 163 | pub is_negative: bool, |
163 | } | 164 | } |
@@ -169,8 +170,8 @@ impl ImplData { | |||
169 | 170 | ||
170 | let item_tree = impl_loc.id.item_tree(db); | 171 | let item_tree = impl_loc.id.item_tree(db); |
171 | let impl_def = &item_tree[impl_loc.id.value]; | 172 | let impl_def = &item_tree[impl_loc.id.value]; |
172 | let target_trait = impl_def.target_trait.map(|id| item_tree[id].clone()); | 173 | let target_trait = impl_def.target_trait.clone(); |
173 | let self_ty = item_tree[impl_def.self_ty].clone(); | 174 | let self_ty = impl_def.self_ty.clone(); |
174 | let is_negative = impl_def.is_negative; | 175 | let is_negative = impl_def.is_negative; |
175 | let module_id = impl_loc.container; | 176 | let module_id = impl_loc.container; |
176 | let container = AssocContainerId::ImplId(id); | 177 | let container = AssocContainerId::ImplId(id); |
@@ -195,7 +196,7 @@ impl ImplData { | |||
195 | pub struct ConstData { | 196 | pub struct ConstData { |
196 | /// const _: () = (); | 197 | /// const _: () = (); |
197 | pub name: Option<Name>, | 198 | pub name: Option<Name>, |
198 | pub type_ref: TypeRef, | 199 | pub type_ref: Interned<TypeRef>, |
199 | pub visibility: RawVisibility, | 200 | pub visibility: RawVisibility, |
200 | } | 201 | } |
201 | 202 | ||
@@ -207,7 +208,7 @@ impl ConstData { | |||
207 | 208 | ||
208 | Arc::new(ConstData { | 209 | Arc::new(ConstData { |
209 | name: konst.name.clone(), | 210 | name: konst.name.clone(), |
210 | type_ref: item_tree[konst.type_ref].clone(), | 211 | type_ref: konst.type_ref.clone(), |
211 | visibility: item_tree[konst.visibility].clone(), | 212 | visibility: item_tree[konst.visibility].clone(), |
212 | }) | 213 | }) |
213 | } | 214 | } |
@@ -216,7 +217,7 @@ impl ConstData { | |||
216 | #[derive(Debug, Clone, PartialEq, Eq)] | 217 | #[derive(Debug, Clone, PartialEq, Eq)] |
217 | pub struct StaticData { | 218 | pub struct StaticData { |
218 | pub name: Option<Name>, | 219 | pub name: Option<Name>, |
219 | pub type_ref: TypeRef, | 220 | pub type_ref: Interned<TypeRef>, |
220 | pub visibility: RawVisibility, | 221 | pub visibility: RawVisibility, |
221 | pub mutable: bool, | 222 | pub mutable: bool, |
222 | pub is_extern: bool, | 223 | pub is_extern: bool, |
@@ -230,7 +231,7 @@ impl StaticData { | |||
230 | 231 | ||
231 | Arc::new(StaticData { | 232 | Arc::new(StaticData { |
232 | name: Some(statik.name.clone()), | 233 | name: Some(statik.name.clone()), |
233 | type_ref: item_tree[statik.type_ref].clone(), | 234 | type_ref: statik.type_ref.clone(), |
234 | visibility: item_tree[statik.visibility].clone(), | 235 | visibility: item_tree[statik.visibility].clone(), |
235 | mutable: statik.mutable, | 236 | mutable: statik.mutable, |
236 | is_extern: statik.is_extern, | 237 | is_extern: statik.is_extern, |
diff --git a/crates/hir_def/src/intern.rs b/crates/hir_def/src/intern.rs new file mode 100644 index 000000000..28ec72cff --- /dev/null +++ b/crates/hir_def/src/intern.rs | |||
@@ -0,0 +1,157 @@ | |||
1 | //! Global `Arc`-based object interning infrastructure. | ||
2 | //! | ||
3 | //! Eventually this should probably be replaced with salsa-based interning. | ||
4 | |||
5 | use std::{ | ||
6 | fmt::{self, Debug}, | ||
7 | hash::{BuildHasherDefault, Hash}, | ||
8 | ops::Deref, | ||
9 | sync::Arc, | ||
10 | }; | ||
11 | |||
12 | use dashmap::{DashMap, SharedValue}; | ||
13 | use once_cell::sync::OnceCell; | ||
14 | use rustc_hash::FxHasher; | ||
15 | |||
16 | type InternMap<T> = DashMap<Arc<T>, (), BuildHasherDefault<FxHasher>>; | ||
17 | |||
18 | pub struct Interned<T: Internable> { | ||
19 | arc: Arc<T>, | ||
20 | } | ||
21 | |||
22 | impl<T: Internable> Interned<T> { | ||
23 | pub fn new(obj: T) -> Self { | ||
24 | let storage = T::storage().get(); | ||
25 | let shard_idx = storage.determine_map(&obj); | ||
26 | let shard = &storage.shards()[shard_idx]; | ||
27 | let shard = shard.upgradeable_read(); | ||
28 | |||
29 | // Atomically, | ||
30 | // - check if `obj` is already in the map | ||
31 | // - if so, clone its `Arc` and return it | ||
32 | // - if not, box it up, insert it, and return a clone | ||
33 | // This needs to be atomic (locking the shard) to avoid races with other thread, which could | ||
34 | // insert the same object between us looking it up and inserting it. | ||
35 | |||
36 | // FIXME: avoid double lookup by using raw entry API (once stable, or when hashbrown can be | ||
37 | // plugged into dashmap) | ||
38 | if let Some((arc, _)) = shard.get_key_value(&obj) { | ||
39 | return Self { arc: arc.clone() }; | ||
40 | } | ||
41 | |||
42 | let arc = Arc::new(obj); | ||
43 | let arc2 = arc.clone(); | ||
44 | |||
45 | { | ||
46 | let mut shard = shard.upgrade(); | ||
47 | shard.insert(arc2, SharedValue::new(())); | ||
48 | } | ||
49 | |||
50 | Self { arc } | ||
51 | } | ||
52 | } | ||
53 | |||
54 | impl<T: Internable> Drop for Interned<T> { | ||
55 | fn drop(&mut self) { | ||
56 | // When the last `Ref` is dropped, remove the object from the global map. | ||
57 | if Arc::strong_count(&self.arc) == 2 { | ||
58 | // Only `self` and the global map point to the object. | ||
59 | |||
60 | let storage = T::storage().get(); | ||
61 | let shard_idx = storage.determine_map(&self.arc); | ||
62 | let shard = &storage.shards()[shard_idx]; | ||
63 | let mut shard = shard.write(); | ||
64 | |||
65 | // FIXME: avoid double lookup | ||
66 | let (arc, _) = | ||
67 | shard.get_key_value(&self.arc).expect("interned value removed prematurely"); | ||
68 | |||
69 | if Arc::strong_count(arc) != 2 { | ||
70 | // Another thread has interned another copy | ||
71 | return; | ||
72 | } | ||
73 | |||
74 | shard.remove(&self.arc); | ||
75 | |||
76 | // Shrink the backing storage if the shard is less than 50% occupied. | ||
77 | if shard.len() * 2 < shard.capacity() { | ||
78 | shard.shrink_to_fit(); | ||
79 | } | ||
80 | } | ||
81 | } | ||
82 | } | ||
83 | |||
84 | /// Compares interned `Ref`s using pointer equality. | ||
85 | impl<T: Internable> PartialEq for Interned<T> { | ||
86 | #[inline] | ||
87 | fn eq(&self, other: &Self) -> bool { | ||
88 | Arc::ptr_eq(&self.arc, &other.arc) | ||
89 | } | ||
90 | } | ||
91 | |||
92 | impl<T: Internable> Eq for Interned<T> {} | ||
93 | |||
94 | impl<T: Internable> AsRef<T> for Interned<T> { | ||
95 | #[inline] | ||
96 | fn as_ref(&self) -> &T { | ||
97 | &self.arc | ||
98 | } | ||
99 | } | ||
100 | |||
101 | impl<T: Internable> Deref for Interned<T> { | ||
102 | type Target = T; | ||
103 | |||
104 | #[inline] | ||
105 | fn deref(&self) -> &Self::Target { | ||
106 | &self.arc | ||
107 | } | ||
108 | } | ||
109 | |||
110 | impl<T: Internable> Clone for Interned<T> { | ||
111 | fn clone(&self) -> Self { | ||
112 | Self { arc: self.arc.clone() } | ||
113 | } | ||
114 | } | ||
115 | |||
116 | impl<T: Debug + Internable> Debug for Interned<T> { | ||
117 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { | ||
118 | (*self.arc).fmt(f) | ||
119 | } | ||
120 | } | ||
121 | |||
122 | pub struct InternStorage<T> { | ||
123 | map: OnceCell<InternMap<T>>, | ||
124 | } | ||
125 | |||
126 | impl<T> InternStorage<T> { | ||
127 | pub const fn new() -> Self { | ||
128 | Self { map: OnceCell::new() } | ||
129 | } | ||
130 | } | ||
131 | |||
132 | impl<T: Internable> InternStorage<T> { | ||
133 | fn get(&self) -> &InternMap<T> { | ||
134 | self.map.get_or_init(DashMap::default) | ||
135 | } | ||
136 | } | ||
137 | |||
138 | pub trait Internable: Hash + Eq + Sized + 'static { | ||
139 | fn storage() -> &'static InternStorage<Self>; | ||
140 | } | ||
141 | |||
142 | // region:`Internable` implementations | ||
143 | |||
144 | macro_rules! impl_internable { | ||
145 | ( $($t:ty),+ $(,)? ) => { $( | ||
146 | impl Internable for $t { | ||
147 | fn storage() -> &'static InternStorage<Self> { | ||
148 | static STORAGE: InternStorage<$t> = InternStorage::new(); | ||
149 | &STORAGE | ||
150 | } | ||
151 | } | ||
152 | )+ }; | ||
153 | } | ||
154 | |||
155 | impl_internable!(crate::type_ref::TypeRef, crate::type_ref::TraitRef); | ||
156 | |||
157 | // endregion | ||
diff --git a/crates/hir_def/src/item_tree.rs b/crates/hir_def/src/item_tree.rs index 5449bbf5d..9f6bb3a7c 100644 --- a/crates/hir_def/src/item_tree.rs +++ b/crates/hir_def/src/item_tree.rs | |||
@@ -30,6 +30,7 @@ use crate::{ | |||
30 | attr::{Attrs, RawAttrs}, | 30 | attr::{Attrs, RawAttrs}, |
31 | db::DefDatabase, | 31 | db::DefDatabase, |
32 | generics::GenericParams, | 32 | generics::GenericParams, |
33 | intern::Interned, | ||
33 | path::{path, AssociatedTypeBinding, GenericArgs, ImportAlias, ModPath, Path, PathKind}, | 34 | path::{path, AssociatedTypeBinding, GenericArgs, ImportAlias, ModPath, Path, PathKind}, |
34 | type_ref::{Mutability, TraitRef, TypeBound, TypeRef}, | 35 | type_ref::{Mutability, TraitRef, TypeBound, TypeRef}, |
35 | visibility::RawVisibility, | 36 | visibility::RawVisibility, |
@@ -146,8 +147,6 @@ impl ItemTree { | |||
146 | macro_defs, | 147 | macro_defs, |
147 | vis, | 148 | vis, |
148 | generics, | 149 | generics, |
149 | type_refs, | ||
150 | trait_refs, | ||
151 | inner_items, | 150 | inner_items, |
152 | } = &mut **data; | 151 | } = &mut **data; |
153 | 152 | ||
@@ -172,9 +171,6 @@ impl ItemTree { | |||
172 | 171 | ||
173 | vis.arena.shrink_to_fit(); | 172 | vis.arena.shrink_to_fit(); |
174 | generics.arena.shrink_to_fit(); | 173 | generics.arena.shrink_to_fit(); |
175 | type_refs.arena.shrink_to_fit(); | ||
176 | type_refs.map.shrink_to_fit(); | ||
177 | trait_refs.map.shrink_to_fit(); | ||
178 | 174 | ||
179 | inner_items.shrink_to_fit(); | 175 | inner_items.shrink_to_fit(); |
180 | } | 176 | } |
@@ -271,58 +267,6 @@ static EMPTY_GENERICS: GenericParams = GenericParams { | |||
271 | where_predicates: Vec::new(), | 267 | where_predicates: Vec::new(), |
272 | }; | 268 | }; |
273 | 269 | ||
274 | /// `TypeRef` interner. | ||
275 | #[derive(Default, Debug, Eq, PartialEq)] | ||
276 | struct TypeRefStorage { | ||
277 | arena: Arena<Arc<TypeRef>>, | ||
278 | map: FxHashMap<Arc<TypeRef>, Idx<Arc<TypeRef>>>, | ||
279 | } | ||
280 | |||
281 | impl TypeRefStorage { | ||
282 | // Note: We lie about the `Idx<TypeRef>` to hide the interner details. | ||
283 | |||
284 | fn intern(&mut self, ty: TypeRef) -> Idx<TypeRef> { | ||
285 | if let Some(id) = self.map.get(&ty) { | ||
286 | return Idx::from_raw(id.into_raw()); | ||
287 | } | ||
288 | |||
289 | let ty = Arc::new(ty); | ||
290 | let idx = self.arena.alloc(ty.clone()); | ||
291 | self.map.insert(ty, idx); | ||
292 | Idx::from_raw(idx.into_raw()) | ||
293 | } | ||
294 | |||
295 | fn lookup(&self, id: Idx<TypeRef>) -> &TypeRef { | ||
296 | &self.arena[Idx::from_raw(id.into_raw())] | ||
297 | } | ||
298 | } | ||
299 | |||
300 | /// `TraitRef` interner. | ||
301 | #[derive(Default, Debug, Eq, PartialEq)] | ||
302 | struct TraitRefStorage { | ||
303 | arena: Arena<Arc<TraitRef>>, | ||
304 | map: FxHashMap<Arc<TraitRef>, Idx<Arc<TraitRef>>>, | ||
305 | } | ||
306 | |||
307 | impl TraitRefStorage { | ||
308 | // Note: We lie about the `Idx<TraitRef>` to hide the interner details. | ||
309 | |||
310 | fn intern(&mut self, ty: TraitRef) -> Idx<TraitRef> { | ||
311 | if let Some(id) = self.map.get(&ty) { | ||
312 | return Idx::from_raw(id.into_raw()); | ||
313 | } | ||
314 | |||
315 | let ty = Arc::new(ty); | ||
316 | let idx = self.arena.alloc(ty.clone()); | ||
317 | self.map.insert(ty, idx); | ||
318 | Idx::from_raw(idx.into_raw()) | ||
319 | } | ||
320 | |||
321 | fn lookup(&self, id: Idx<TraitRef>) -> &TraitRef { | ||
322 | &self.arena[Idx::from_raw(id.into_raw())] | ||
323 | } | ||
324 | } | ||
325 | |||
326 | #[derive(Default, Debug, Eq, PartialEq)] | 270 | #[derive(Default, Debug, Eq, PartialEq)] |
327 | struct ItemTreeData { | 271 | struct ItemTreeData { |
328 | imports: Arena<Import>, | 272 | imports: Arena<Import>, |
@@ -346,8 +290,6 @@ struct ItemTreeData { | |||
346 | 290 | ||
347 | vis: ItemVisibilities, | 291 | vis: ItemVisibilities, |
348 | generics: GenericParamsStorage, | 292 | generics: GenericParamsStorage, |
349 | type_refs: TypeRefStorage, | ||
350 | trait_refs: TraitRefStorage, | ||
351 | 293 | ||
352 | inner_items: FxHashMap<FileAstId<ast::BlockExpr>, SmallVec<[ModItem; 1]>>, | 294 | inner_items: FxHashMap<FileAstId<ast::BlockExpr>, SmallVec<[ModItem; 1]>>, |
353 | } | 295 | } |
@@ -577,22 +519,6 @@ impl Index<GenericParamsId> for ItemTree { | |||
577 | } | 519 | } |
578 | } | 520 | } |
579 | 521 | ||
580 | impl Index<Idx<TypeRef>> for ItemTree { | ||
581 | type Output = TypeRef; | ||
582 | |||
583 | fn index(&self, id: Idx<TypeRef>) -> &Self::Output { | ||
584 | self.data().type_refs.lookup(id) | ||
585 | } | ||
586 | } | ||
587 | |||
588 | impl Index<Idx<TraitRef>> for ItemTree { | ||
589 | type Output = TraitRef; | ||
590 | |||
591 | fn index(&self, id: Idx<TraitRef>) -> &Self::Output { | ||
592 | self.data().trait_refs.lookup(id) | ||
593 | } | ||
594 | } | ||
595 | |||
596 | impl<N: ItemTreeNode> Index<FileItemTreeId<N>> for ItemTree { | 522 | impl<N: ItemTreeNode> Index<FileItemTreeId<N>> for ItemTree { |
597 | type Output = N; | 523 | type Output = N; |
598 | fn index(&self, id: FileItemTreeId<N>) -> &N { | 524 | fn index(&self, id: FileItemTreeId<N>) -> &N { |
@@ -637,13 +563,13 @@ pub struct Function { | |||
637 | /// `extern "abi" fn`). | 563 | /// `extern "abi" fn`). |
638 | pub is_in_extern_block: bool, | 564 | pub is_in_extern_block: bool, |
639 | pub params: IdRange<Param>, | 565 | pub params: IdRange<Param>, |
640 | pub ret_type: Idx<TypeRef>, | 566 | pub ret_type: Interned<TypeRef>, |
641 | pub ast_id: FileAstId<ast::Fn>, | 567 | pub ast_id: FileAstId<ast::Fn>, |
642 | } | 568 | } |
643 | 569 | ||
644 | #[derive(Debug, Clone, Eq, PartialEq)] | 570 | #[derive(Debug, Clone, Eq, PartialEq)] |
645 | pub enum Param { | 571 | pub enum Param { |
646 | Normal(Idx<TypeRef>), | 572 | Normal(Interned<TypeRef>), |
647 | Varargs, | 573 | Varargs, |
648 | } | 574 | } |
649 | 575 | ||
@@ -699,7 +625,7 @@ pub struct Const { | |||
699 | /// const _: () = (); | 625 | /// const _: () = (); |
700 | pub name: Option<Name>, | 626 | pub name: Option<Name>, |
701 | pub visibility: RawVisibilityId, | 627 | pub visibility: RawVisibilityId, |
702 | pub type_ref: Idx<TypeRef>, | 628 | pub type_ref: Interned<TypeRef>, |
703 | pub ast_id: FileAstId<ast::Const>, | 629 | pub ast_id: FileAstId<ast::Const>, |
704 | } | 630 | } |
705 | 631 | ||
@@ -710,7 +636,7 @@ pub struct Static { | |||
710 | pub mutable: bool, | 636 | pub mutable: bool, |
711 | /// Whether the static is in an `extern` block. | 637 | /// Whether the static is in an `extern` block. |
712 | pub is_extern: bool, | 638 | pub is_extern: bool, |
713 | pub type_ref: Idx<TypeRef>, | 639 | pub type_ref: Interned<TypeRef>, |
714 | pub ast_id: FileAstId<ast::Static>, | 640 | pub ast_id: FileAstId<ast::Static>, |
715 | } | 641 | } |
716 | 642 | ||
@@ -729,8 +655,8 @@ pub struct Trait { | |||
729 | #[derive(Debug, Clone, Eq, PartialEq)] | 655 | #[derive(Debug, Clone, Eq, PartialEq)] |
730 | pub struct Impl { | 656 | pub struct Impl { |
731 | pub generic_params: GenericParamsId, | 657 | pub generic_params: GenericParamsId, |
732 | pub target_trait: Option<Idx<TraitRef>>, | 658 | pub target_trait: Option<Interned<TraitRef>>, |
733 | pub self_ty: Idx<TypeRef>, | 659 | pub self_ty: Interned<TypeRef>, |
734 | pub is_negative: bool, | 660 | pub is_negative: bool, |
735 | pub items: Box<[AssocItem]>, | 661 | pub items: Box<[AssocItem]>, |
736 | pub ast_id: FileAstId<ast::Impl>, | 662 | pub ast_id: FileAstId<ast::Impl>, |
@@ -743,7 +669,7 @@ pub struct TypeAlias { | |||
743 | /// Bounds on the type alias itself. Only valid in trait declarations, eg. `type Assoc: Copy;`. | 669 | /// Bounds on the type alias itself. Only valid in trait declarations, eg. `type Assoc: Copy;`. |
744 | pub bounds: Box<[TypeBound]>, | 670 | pub bounds: Box<[TypeBound]>, |
745 | pub generic_params: GenericParamsId, | 671 | pub generic_params: GenericParamsId, |
746 | pub type_ref: Option<Idx<TypeRef>>, | 672 | pub type_ref: Option<Interned<TypeRef>>, |
747 | pub is_extern: bool, | 673 | pub is_extern: bool, |
748 | pub ast_id: FileAstId<ast::TypeAlias>, | 674 | pub ast_id: FileAstId<ast::TypeAlias>, |
749 | } | 675 | } |
@@ -933,6 +859,6 @@ pub enum Fields { | |||
933 | #[derive(Debug, Clone, PartialEq, Eq)] | 859 | #[derive(Debug, Clone, PartialEq, Eq)] |
934 | pub struct Field { | 860 | pub struct Field { |
935 | pub name: Name, | 861 | pub name: Name, |
936 | pub type_ref: Idx<TypeRef>, | 862 | pub type_ref: Interned<TypeRef>, |
937 | pub visibility: RawVisibilityId, | 863 | pub visibility: RawVisibilityId, |
938 | } | 864 | } |
diff --git a/crates/hir_def/src/item_tree/lower.rs b/crates/hir_def/src/item_tree/lower.rs index 124dcc866..23d3dea7b 100644 --- a/crates/hir_def/src/item_tree/lower.rs +++ b/crates/hir_def/src/item_tree/lower.rs | |||
@@ -362,7 +362,7 @@ impl Ctx { | |||
362 | } | 362 | } |
363 | } | 363 | } |
364 | }; | 364 | }; |
365 | let ty = self.data().type_refs.intern(self_type); | 365 | let ty = Interned::new(self_type); |
366 | let idx = self.data().params.alloc(Param::Normal(ty)); | 366 | let idx = self.data().params.alloc(Param::Normal(ty)); |
367 | self.add_attrs(idx.into(), RawAttrs::new(&self_param, &self.hygiene)); | 367 | self.add_attrs(idx.into(), RawAttrs::new(&self_param, &self.hygiene)); |
368 | has_self_param = true; | 368 | has_self_param = true; |
@@ -372,7 +372,7 @@ impl Ctx { | |||
372 | Some(_) => self.data().params.alloc(Param::Varargs), | 372 | Some(_) => self.data().params.alloc(Param::Varargs), |
373 | None => { | 373 | None => { |
374 | let type_ref = TypeRef::from_ast_opt(&self.body_ctx, param.ty()); | 374 | let type_ref = TypeRef::from_ast_opt(&self.body_ctx, param.ty()); |
375 | let ty = self.data().type_refs.intern(type_ref); | 375 | let ty = Interned::new(type_ref); |
376 | self.data().params.alloc(Param::Normal(ty)) | 376 | self.data().params.alloc(Param::Normal(ty)) |
377 | } | 377 | } |
378 | }; | 378 | }; |
@@ -395,8 +395,6 @@ impl Ctx { | |||
395 | ret_type | 395 | ret_type |
396 | }; | 396 | }; |
397 | 397 | ||
398 | let ret_type = self.data().type_refs.intern(ret_type); | ||
399 | |||
400 | let has_body = func.body().is_some(); | 398 | let has_body = func.body().is_some(); |
401 | 399 | ||
402 | let ast_id = self.source_ast_id_map.ast_id(func); | 400 | let ast_id = self.source_ast_id_map.ast_id(func); |
@@ -428,7 +426,7 @@ impl Ctx { | |||
428 | qualifier, | 426 | qualifier, |
429 | is_in_extern_block: false, | 427 | is_in_extern_block: false, |
430 | params, | 428 | params, |
431 | ret_type, | 429 | ret_type: Interned::new(ret_type), |
432 | ast_id, | 430 | ast_id, |
433 | }; | 431 | }; |
434 | res.generic_params = self.lower_generic_params(GenericsOwner::Function(&res), func); | 432 | res.generic_params = self.lower_generic_params(GenericsOwner::Function(&res), func); |
@@ -694,8 +692,7 @@ impl Ctx { | |||
694 | generics.fill(&self.body_ctx, sm, node); | 692 | generics.fill(&self.body_ctx, sm, node); |
695 | // lower `impl Trait` in arguments | 693 | // lower `impl Trait` in arguments |
696 | for id in func.params.clone() { | 694 | for id in func.params.clone() { |
697 | if let Param::Normal(ty) = self.data().params[id] { | 695 | if let Param::Normal(ty) = &self.data().params[id] { |
698 | let ty = self.data().type_refs.lookup(ty); | ||
699 | generics.fill_implicit_impl_trait_args(ty); | 696 | generics.fill_implicit_impl_trait_args(ty); |
700 | } | 697 | } |
701 | } | 698 | } |
@@ -749,20 +746,20 @@ impl Ctx { | |||
749 | self.data().vis.alloc(vis) | 746 | self.data().vis.alloc(vis) |
750 | } | 747 | } |
751 | 748 | ||
752 | fn lower_trait_ref(&mut self, trait_ref: &ast::Type) -> Option<Idx<TraitRef>> { | 749 | fn lower_trait_ref(&mut self, trait_ref: &ast::Type) -> Option<Interned<TraitRef>> { |
753 | let trait_ref = TraitRef::from_ast(&self.body_ctx, trait_ref.clone())?; | 750 | let trait_ref = TraitRef::from_ast(&self.body_ctx, trait_ref.clone())?; |
754 | Some(self.data().trait_refs.intern(trait_ref)) | 751 | Some(Interned::new(trait_ref)) |
755 | } | 752 | } |
756 | 753 | ||
757 | fn lower_type_ref(&mut self, type_ref: &ast::Type) -> Idx<TypeRef> { | 754 | fn lower_type_ref(&mut self, type_ref: &ast::Type) -> Interned<TypeRef> { |
758 | let tyref = TypeRef::from_ast(&self.body_ctx, type_ref.clone()); | 755 | let tyref = TypeRef::from_ast(&self.body_ctx, type_ref.clone()); |
759 | self.data().type_refs.intern(tyref) | 756 | Interned::new(tyref) |
760 | } | 757 | } |
761 | 758 | ||
762 | fn lower_type_ref_opt(&mut self, type_ref: Option<ast::Type>) -> Idx<TypeRef> { | 759 | fn lower_type_ref_opt(&mut self, type_ref: Option<ast::Type>) -> Interned<TypeRef> { |
763 | match type_ref.map(|ty| self.lower_type_ref(&ty)) { | 760 | match type_ref.map(|ty| self.lower_type_ref(&ty)) { |
764 | Some(it) => it, | 761 | Some(it) => it, |
765 | None => self.data().type_refs.intern(TypeRef::Error), | 762 | None => Interned::new(TypeRef::Error), |
766 | } | 763 | } |
767 | } | 764 | } |
768 | 765 | ||
diff --git a/crates/hir_def/src/lib.rs b/crates/hir_def/src/lib.rs index c9e07de86..f408e510a 100644 --- a/crates/hir_def/src/lib.rs +++ b/crates/hir_def/src/lib.rs | |||
@@ -49,6 +49,7 @@ pub mod import_map; | |||
49 | 49 | ||
50 | #[cfg(test)] | 50 | #[cfg(test)] |
51 | mod test_db; | 51 | mod test_db; |
52 | mod intern; | ||
52 | 53 | ||
53 | use std::{ | 54 | use std::{ |
54 | hash::{Hash, Hasher}, | 55 | hash::{Hash, Hasher}, |
diff --git a/crates/hir_ty/src/lower.rs b/crates/hir_ty/src/lower.rs index afbfa12d5..a08f694d9 100644 --- a/crates/hir_ty/src/lower.rs +++ b/crates/hir_ty/src/lower.rs | |||
@@ -1157,7 +1157,7 @@ fn type_for_type_alias(db: &dyn HirDatabase, t: TypeAliasId) -> Binders<Ty> { | |||
1157 | Binders::new(0, TyKind::ForeignType(crate::to_foreign_def_id(t)).intern(&Interner)) | 1157 | Binders::new(0, TyKind::ForeignType(crate::to_foreign_def_id(t)).intern(&Interner)) |
1158 | } else { | 1158 | } else { |
1159 | let type_ref = &db.type_alias_data(t).type_ref; | 1159 | let type_ref = &db.type_alias_data(t).type_ref; |
1160 | let inner = ctx.lower_ty(type_ref.as_ref().unwrap_or(&TypeRef::Error)); | 1160 | let inner = ctx.lower_ty(type_ref.as_deref().unwrap_or(&TypeRef::Error)); |
1161 | Binders::new(generics.len(), inner) | 1161 | Binders::new(generics.len(), inner) |
1162 | } | 1162 | } |
1163 | } | 1163 | } |