aboutsummaryrefslogtreecommitdiff
path: root/crates
diff options
context:
space:
mode:
authorJonas Schievink <[email protected]>2021-04-01 18:46:43 +0100
committerJonas Schievink <[email protected]>2021-04-01 18:46:43 +0100
commitb00266b79f0e2c2a5e332b30f7e6aba83b5e6e5a (patch)
treec7e591ec8a1ec6b401a8a7ea00115120a4789db5 /crates
parent25201b2dad7b4b0d41494e238ebf643ad7ad8cd6 (diff)
Global TypeRef/TraitRef interning
Diffstat (limited to 'crates')
-rw-r--r--crates/hir/src/display.rs2
-rw-r--r--crates/hir/src/lib.rs8
-rw-r--r--crates/hir_def/Cargo.toml1
-rw-r--r--crates/hir_def/src/adt.rs9
-rw-r--r--crates/hir_def/src/data.rs29
-rw-r--r--crates/hir_def/src/intern.rs157
-rw-r--r--crates/hir_def/src/item_tree.rs92
-rw-r--r--crates/hir_def/src/item_tree/lower.rs23
-rw-r--r--crates/hir_def/src/lib.rs1
-rw-r--r--crates/hir_ty/src/lower.rs2
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]
13cov-mark = { version = "1.1", features = ["thread-local"] } 13cov-mark = { version = "1.1", features = ["thread-local"] }
14dashmap = { version = "4.0.2", features = ["raw-api"] }
14log = "0.4.8" 15log = "0.4.8"
15once_cell = "1.3.1" 16once_cell = "1.3.1"
16rustc-hash = "1.1.0" 17rustc-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};
15use crate::{ 15use 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)]
59pub struct FieldData { 60pub 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)]
20pub struct FunctionData { 21pub 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)]
77pub struct TypeAliasData { 78pub 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)]
158pub struct ImplData { 159pub 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 {
195pub struct ConstData { 196pub 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)]
217pub struct StaticData { 218pub 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
5use std::{
6 fmt::{self, Debug},
7 hash::{BuildHasherDefault, Hash},
8 ops::Deref,
9 sync::Arc,
10};
11
12use dashmap::{DashMap, SharedValue};
13use once_cell::sync::OnceCell;
14use rustc_hash::FxHasher;
15
16type InternMap<T> = DashMap<Arc<T>, (), BuildHasherDefault<FxHasher>>;
17
18pub struct Interned<T: Internable> {
19 arc: Arc<T>,
20}
21
22impl<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
54impl<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.
85impl<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
92impl<T: Internable> Eq for Interned<T> {}
93
94impl<T: Internable> AsRef<T> for Interned<T> {
95 #[inline]
96 fn as_ref(&self) -> &T {
97 &self.arc
98 }
99}
100
101impl<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
110impl<T: Internable> Clone for Interned<T> {
111 fn clone(&self) -> Self {
112 Self { arc: self.arc.clone() }
113 }
114}
115
116impl<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
122pub struct InternStorage<T> {
123 map: OnceCell<InternMap<T>>,
124}
125
126impl<T> InternStorage<T> {
127 pub const fn new() -> Self {
128 Self { map: OnceCell::new() }
129 }
130}
131
132impl<T: Internable> InternStorage<T> {
133 fn get(&self) -> &InternMap<T> {
134 self.map.get_or_init(DashMap::default)
135 }
136}
137
138pub trait Internable: Hash + Eq + Sized + 'static {
139 fn storage() -> &'static InternStorage<Self>;
140}
141
142// region:`Internable` implementations
143
144macro_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
155impl_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)]
276struct TypeRefStorage {
277 arena: Arena<Arc<TypeRef>>,
278 map: FxHashMap<Arc<TypeRef>, Idx<Arc<TypeRef>>>,
279}
280
281impl 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)]
302struct TraitRefStorage {
303 arena: Arena<Arc<TraitRef>>,
304 map: FxHashMap<Arc<TraitRef>, Idx<Arc<TraitRef>>>,
305}
306
307impl 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)]
327struct ItemTreeData { 271struct 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
580impl 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
588impl 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
596impl<N: ItemTreeNode> Index<FileItemTreeId<N>> for ItemTree { 522impl<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)]
645pub enum Param { 571pub 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)]
730pub struct Impl { 656pub 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)]
934pub struct Field { 860pub 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)]
51mod test_db; 51mod test_db;
52mod intern;
52 53
53use std::{ 54use 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}