aboutsummaryrefslogtreecommitdiff
path: root/crates/hir_def
diff options
context:
space:
mode:
Diffstat (limited to 'crates/hir_def')
-rw-r--r--crates/hir_def/Cargo.toml1
-rw-r--r--crates/hir_def/src/adt.rs9
-rw-r--r--crates/hir_def/src/attr.rs7
-rw-r--r--crates/hir_def/src/data.rs29
-rw-r--r--crates/hir_def/src/intern.rs163
-rw-r--r--crates/hir_def/src/item_tree.rs94
-rw-r--r--crates/hir_def/src/item_tree/lower.rs25
-rw-r--r--crates/hir_def/src/lib.rs1
-rw-r--r--crates/hir_def/src/nameres/collector.rs2
-rw-r--r--crates/hir_def/src/path.rs14
-rw-r--r--crates/hir_def/src/path/lower.rs8
11 files changed, 223 insertions, 130 deletions
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/attr.rs b/crates/hir_def/src/attr.rs
index 52a2bce9b..2bab121d9 100644
--- a/crates/hir_def/src/attr.rs
+++ b/crates/hir_def/src/attr.rs
@@ -18,6 +18,7 @@ use tt::Subtree;
18 18
19use crate::{ 19use crate::{
20 db::DefDatabase, 20 db::DefDatabase,
21 intern::Interned,
21 item_tree::{ItemTreeId, ItemTreeNode}, 22 item_tree::{ItemTreeId, ItemTreeNode},
22 nameres::ModuleSource, 23 nameres::ModuleSource,
23 path::{ModPath, PathKind}, 24 path::{ModPath, PathKind},
@@ -98,7 +99,7 @@ impl RawAttrs {
98 Either::Right(comment) => comment.doc_comment().map(|doc| Attr { 99 Either::Right(comment) => comment.doc_comment().map(|doc| Attr {
99 index: i as u32, 100 index: i as u32,
100 input: Some(AttrInput::Literal(SmolStr::new(doc))), 101 input: Some(AttrInput::Literal(SmolStr::new(doc))),
101 path: ModPath::from(hir_expand::name!(doc)), 102 path: Interned::new(ModPath::from(hir_expand::name!(doc))),
102 }), 103 }),
103 }) 104 })
104 .collect::<Arc<_>>(); 105 .collect::<Arc<_>>();
@@ -510,7 +511,7 @@ impl AttrSourceMap {
510#[derive(Debug, Clone, PartialEq, Eq)] 511#[derive(Debug, Clone, PartialEq, Eq)]
511pub struct Attr { 512pub struct Attr {
512 index: u32, 513 index: u32,
513 pub(crate) path: ModPath, 514 pub(crate) path: Interned<ModPath>,
514 pub(crate) input: Option<AttrInput>, 515 pub(crate) input: Option<AttrInput>,
515} 516}
516 517
@@ -524,7 +525,7 @@ pub enum AttrInput {
524 525
525impl Attr { 526impl Attr {
526 fn from_src(ast: ast::Attr, hygiene: &Hygiene, index: u32) -> Option<Attr> { 527 fn from_src(ast: ast::Attr, hygiene: &Hygiene, index: u32) -> Option<Attr> {
527 let path = ModPath::from_src(ast.path()?, hygiene)?; 528 let path = Interned::new(ModPath::from_src(ast.path()?, hygiene)?);
528 let input = if let Some(ast::Expr::Literal(lit)) = ast.expr() { 529 let input = if let Some(ast::Expr::Literal(lit)) = ast.expr() {
529 let value = match lit.kind() { 530 let value = match lit.kind() {
530 ast::LiteralKind::String(string) => string.value()?.into(), 531 ast::LiteralKind::String(string) => string.value()?.into(),
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..cc0b5d350
--- /dev/null
+++ b/crates/hir_def/src/intern.rs
@@ -0,0 +1,163 @@
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
18#[derive(Hash)]
19pub struct Interned<T: Internable + ?Sized> {
20 arc: Arc<T>,
21}
22
23impl<T: Internable> Interned<T> {
24 pub fn new(obj: T) -> Self {
25 let storage = T::storage().get();
26 let shard_idx = storage.determine_map(&obj);
27 let shard = &storage.shards()[shard_idx];
28 let shard = shard.upgradeable_read();
29
30 // Atomically,
31 // - check if `obj` is already in the map
32 // - if so, clone its `Arc` and return it
33 // - if not, box it up, insert it, and return a clone
34 // This needs to be atomic (locking the shard) to avoid races with other thread, which could
35 // insert the same object between us looking it up and inserting it.
36
37 // FIXME: avoid double lookup by using raw entry API (once stable, or when hashbrown can be
38 // plugged into dashmap)
39 if let Some((arc, _)) = shard.get_key_value(&obj) {
40 return Self { arc: arc.clone() };
41 }
42
43 let arc = Arc::new(obj);
44 let arc2 = arc.clone();
45
46 {
47 let mut shard = shard.upgrade();
48 shard.insert(arc2, SharedValue::new(()));
49 }
50
51 Self { arc }
52 }
53}
54
55impl<T: Internable + ?Sized> Drop for Interned<T> {
56 #[inline]
57 fn drop(&mut self) {
58 // When the last `Ref` is dropped, remove the object from the global map.
59 if Arc::strong_count(&self.arc) == 2 {
60 // Only `self` and the global map point to the object.
61
62 self.drop_slow();
63 }
64 }
65}
66
67impl<T: Internable + ?Sized> Interned<T> {
68 #[cold]
69 fn drop_slow(&mut self) {
70 let storage = T::storage().get();
71 let shard_idx = storage.determine_map(&self.arc);
72 let shard = &storage.shards()[shard_idx];
73 let mut shard = shard.write();
74
75 // FIXME: avoid double lookup
76 let (arc, _) = shard.get_key_value(&self.arc).expect("interned value removed prematurely");
77
78 if Arc::strong_count(arc) != 2 {
79 // Another thread has interned another copy
80 return;
81 }
82
83 shard.remove(&self.arc);
84
85 // Shrink the backing storage if the shard is less than 50% occupied.
86 if shard.len() * 2 < shard.capacity() {
87 shard.shrink_to_fit();
88 }
89 }
90}
91
92/// Compares interned `Ref`s using pointer equality.
93impl<T: Internable> PartialEq for Interned<T> {
94 // NOTE: No `?Sized` because `ptr_eq` doesn't work right with trait objects.
95
96 #[inline]
97 fn eq(&self, other: &Self) -> bool {
98 Arc::ptr_eq(&self.arc, &other.arc)
99 }
100}
101
102impl<T: Internable> Eq for Interned<T> {}
103
104impl<T: Internable + ?Sized> AsRef<T> for Interned<T> {
105 #[inline]
106 fn as_ref(&self) -> &T {
107 &self.arc
108 }
109}
110
111impl<T: Internable + ?Sized> Deref for Interned<T> {
112 type Target = T;
113
114 #[inline]
115 fn deref(&self) -> &Self::Target {
116 &self.arc
117 }
118}
119
120impl<T: Internable + ?Sized> Clone for Interned<T> {
121 fn clone(&self) -> Self {
122 Self { arc: self.arc.clone() }
123 }
124}
125
126impl<T: Debug + Internable + ?Sized> Debug for Interned<T> {
127 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
128 (*self.arc).fmt(f)
129 }
130}
131
132pub struct InternStorage<T: ?Sized> {
133 map: OnceCell<InternMap<T>>,
134}
135
136impl<T: ?Sized> InternStorage<T> {
137 pub const fn new() -> Self {
138 Self { map: OnceCell::new() }
139 }
140}
141
142impl<T: Internable + ?Sized> InternStorage<T> {
143 fn get(&self) -> &InternMap<T> {
144 self.map.get_or_init(DashMap::default)
145 }
146}
147
148pub trait Internable: Hash + Eq + 'static {
149 fn storage() -> &'static InternStorage<Self>;
150}
151
152macro_rules! impl_internable {
153 ( $($t:path),+ $(,)? ) => { $(
154 impl Internable for $t {
155 fn storage() -> &'static InternStorage<Self> {
156 static STORAGE: InternStorage<$t> = InternStorage::new();
157 &STORAGE
158 }
159 }
160 )+ };
161}
162
163impl_internable!(crate::type_ref::TypeRef, crate::type_ref::TraitRef, crate::path::ModPath);
diff --git a/crates/hir_def/src/item_tree.rs b/crates/hir_def/src/item_tree.rs
index 5449bbf5d..69a313c7e 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}
@@ -768,7 +694,7 @@ pub enum ModKind {
768#[derive(Debug, Clone, Eq, PartialEq)] 694#[derive(Debug, Clone, Eq, PartialEq)]
769pub struct MacroCall { 695pub struct MacroCall {
770 /// Path to the called macro. 696 /// Path to the called macro.
771 pub path: ModPath, 697 pub path: Interned<ModPath>,
772 pub ast_id: FileAstId<ast::MacroCall>, 698 pub ast_id: FileAstId<ast::MacroCall>,
773} 699}
774 700
@@ -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..5247379c5 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);
@@ -608,7 +606,7 @@ impl Ctx {
608 } 606 }
609 607
610 fn lower_macro_call(&mut self, m: &ast::MacroCall) -> Option<FileItemTreeId<MacroCall>> { 608 fn lower_macro_call(&mut self, m: &ast::MacroCall) -> Option<FileItemTreeId<MacroCall>> {
611 let path = ModPath::from_src(m.path()?, &self.hygiene)?; 609 let path = Interned::new(ModPath::from_src(m.path()?, &self.hygiene)?);
612 let ast_id = self.source_ast_id_map.ast_id(m); 610 let ast_id = self.source_ast_id_map.ast_id(m);
613 let res = MacroCall { path, ast_id }; 611 let res = MacroCall { path, ast_id };
614 Some(id(self.data().macro_calls.alloc(res))) 612 Some(id(self.data().macro_calls.alloc(res)))
@@ -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_def/src/nameres/collector.rs b/crates/hir_def/src/nameres/collector.rs
index d58135ec9..5badefabf 100644
--- a/crates/hir_def/src/nameres/collector.rs
+++ b/crates/hir_def/src/nameres/collector.rs
@@ -1464,7 +1464,7 @@ impl ModCollector<'_, '_> {
1464 } 1464 }
1465 1465
1466 fn collect_macro_call(&mut self, mac: &MacroCall) { 1466 fn collect_macro_call(&mut self, mac: &MacroCall) {
1467 let mut ast_id = AstIdWithPath::new(self.file_id, mac.ast_id, mac.path.clone()); 1467 let mut ast_id = AstIdWithPath::new(self.file_id, mac.ast_id, (*mac.path).clone());
1468 1468
1469 // Case 1: try to resolve in legacy scope and expand macro_rules 1469 // Case 1: try to resolve in legacy scope and expand macro_rules
1470 let mut error = None; 1470 let mut error = None;
diff --git a/crates/hir_def/src/path.rs b/crates/hir_def/src/path.rs
index 8c923bb7b..a3e83e2cf 100644
--- a/crates/hir_def/src/path.rs
+++ b/crates/hir_def/src/path.rs
@@ -7,7 +7,7 @@ use std::{
7 sync::Arc, 7 sync::Arc,
8}; 8};
9 9
10use crate::{body::LowerCtx, type_ref::LifetimeRef}; 10use crate::{body::LowerCtx, intern::Interned, type_ref::LifetimeRef};
11use base_db::CrateId; 11use base_db::CrateId;
12use hir_expand::{ 12use hir_expand::{
13 hygiene::Hygiene, 13 hygiene::Hygiene,
@@ -48,7 +48,7 @@ pub enum ImportAlias {
48 48
49impl ModPath { 49impl ModPath {
50 pub fn from_src(path: ast::Path, hygiene: &Hygiene) -> Option<ModPath> { 50 pub fn from_src(path: ast::Path, hygiene: &Hygiene) -> Option<ModPath> {
51 lower::lower_path(path, hygiene).map(|it| it.mod_path) 51 lower::lower_path(path, hygiene).map(|it| (*it.mod_path).clone())
52 } 52 }
53 53
54 pub fn from_segments(kind: PathKind, segments: impl IntoIterator<Item = Name>) -> ModPath { 54 pub fn from_segments(kind: PathKind, segments: impl IntoIterator<Item = Name>) -> ModPath {
@@ -123,7 +123,7 @@ pub struct Path {
123 /// Type based path like `<T>::foo`. 123 /// Type based path like `<T>::foo`.
124 /// Note that paths like `<Type as Trait>::foo` are desugard to `Trait::<Self=Type>::foo`. 124 /// Note that paths like `<Type as Trait>::foo` are desugard to `Trait::<Self=Type>::foo`.
125 type_anchor: Option<Box<TypeRef>>, 125 type_anchor: Option<Box<TypeRef>>,
126 mod_path: ModPath, 126 mod_path: Interned<ModPath>,
127 /// Invariant: the same len as `self.mod_path.segments` 127 /// Invariant: the same len as `self.mod_path.segments`
128 generic_args: Vec<Option<Arc<GenericArgs>>>, 128 generic_args: Vec<Option<Arc<GenericArgs>>>,
129} 129}
@@ -176,7 +176,7 @@ impl Path {
176 path: ModPath, 176 path: ModPath,
177 generic_args: Vec<Option<Arc<GenericArgs>>>, 177 generic_args: Vec<Option<Arc<GenericArgs>>>,
178 ) -> Path { 178 ) -> Path {
179 Path { type_anchor: None, mod_path: path, generic_args } 179 Path { type_anchor: None, mod_path: Interned::new(path), generic_args }
180 } 180 }
181 181
182 pub fn kind(&self) -> &PathKind { 182 pub fn kind(&self) -> &PathKind {
@@ -204,10 +204,10 @@ impl Path {
204 } 204 }
205 let res = Path { 205 let res = Path {
206 type_anchor: self.type_anchor.clone(), 206 type_anchor: self.type_anchor.clone(),
207 mod_path: ModPath::from_segments( 207 mod_path: Interned::new(ModPath::from_segments(
208 self.mod_path.kind.clone(), 208 self.mod_path.kind.clone(),
209 self.mod_path.segments[..self.mod_path.segments.len() - 1].iter().cloned(), 209 self.mod_path.segments[..self.mod_path.segments.len() - 1].iter().cloned(),
210 ), 210 )),
211 generic_args: self.generic_args[..self.generic_args.len() - 1].to_vec(), 211 generic_args: self.generic_args[..self.generic_args.len() - 1].to_vec(),
212 }; 212 };
213 Some(res) 213 Some(res)
@@ -283,7 +283,7 @@ impl From<Name> for Path {
283 fn from(name: Name) -> Path { 283 fn from(name: Name) -> Path {
284 Path { 284 Path {
285 type_anchor: None, 285 type_anchor: None,
286 mod_path: ModPath::from_segments(PathKind::Plain, iter::once(name)), 286 mod_path: Interned::new(ModPath::from_segments(PathKind::Plain, iter::once(name))),
287 generic_args: vec![None], 287 generic_args: vec![None],
288 } 288 }
289 } 289 }
diff --git a/crates/hir_def/src/path/lower.rs b/crates/hir_def/src/path/lower.rs
index 4de951fd3..28f6244da 100644
--- a/crates/hir_def/src/path/lower.rs
+++ b/crates/hir_def/src/path/lower.rs
@@ -2,6 +2,7 @@
2 2
3mod lower_use; 3mod lower_use;
4 4
5use crate::intern::Interned;
5use std::sync::Arc; 6use std::sync::Arc;
6 7
7use either::Either; 8use either::Either;
@@ -74,10 +75,11 @@ pub(super) fn lower_path(mut path: ast::Path, hygiene: &Hygiene) -> Option<Path>
74 // <T as Trait<A>>::Foo desugars to Trait<Self=T, A>::Foo 75 // <T as Trait<A>>::Foo desugars to Trait<Self=T, A>::Foo
75 Some(trait_ref) => { 76 Some(trait_ref) => {
76 let path = Path::from_src(trait_ref.path()?, hygiene)?; 77 let path = Path::from_src(trait_ref.path()?, hygiene)?;
78 let mod_path = (*path.mod_path).clone();
77 let num_segments = path.mod_path.segments.len(); 79 let num_segments = path.mod_path.segments.len();
78 kind = path.mod_path.kind; 80 kind = mod_path.kind;
79 81
80 let mut prefix_segments = path.mod_path.segments; 82 let mut prefix_segments = mod_path.segments;
81 prefix_segments.reverse(); 83 prefix_segments.reverse();
82 segments.extend(prefix_segments); 84 segments.extend(prefix_segments);
83 85
@@ -140,7 +142,7 @@ pub(super) fn lower_path(mut path: ast::Path, hygiene: &Hygiene) -> Option<Path>
140 } 142 }
141 } 143 }
142 144
143 let mod_path = ModPath::from_segments(kind, segments); 145 let mod_path = Interned::new(ModPath::from_segments(kind, segments));
144 return Some(Path { type_anchor, mod_path, generic_args }); 146 return Some(Path { type_anchor, mod_path, generic_args });
145 147
146 fn qualifier(path: &ast::Path) -> Option<ast::Path> { 148 fn qualifier(path: &ast::Path) -> Option<ast::Path> {