diff options
author | bors[bot] <26634292+bors[bot]@users.noreply.github.com> | 2021-04-02 17:43:16 +0100 |
---|---|---|
committer | GitHub <[email protected]> | 2021-04-02 17:43:16 +0100 |
commit | f4d56989b657b15aec6675cf1ba697e3f87eb088 (patch) | |
tree | 23e4d8265444257f2e4018a003659a711fde0414 /crates | |
parent | 9bcdbefc7b657f34704439d068113180b14359dc (diff) | |
parent | 6e227b80a7686a7ea5bc039d54c307fda29c99ba (diff) |
Merge #8284
8284: Reduce memory usage by using global `Arc`-based interning r=jonas-schievink a=jonas-schievink
This saves around 50 mb when running `analysis-stats` on r-a itself. Not a lot, but this infra can be easily reused to intern more stuff.
Co-authored-by: Jonas Schievink <[email protected]>
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/attr.rs | 7 | ||||
-rw-r--r-- | crates/hir_def/src/data.rs | 29 | ||||
-rw-r--r-- | crates/hir_def/src/intern.rs | 163 | ||||
-rw-r--r-- | crates/hir_def/src/item_tree.rs | 94 | ||||
-rw-r--r-- | crates/hir_def/src/item_tree/lower.rs | 25 | ||||
-rw-r--r-- | crates/hir_def/src/lib.rs | 1 | ||||
-rw-r--r-- | crates/hir_def/src/nameres/collector.rs | 2 | ||||
-rw-r--r-- | crates/hir_def/src/path.rs | 14 | ||||
-rw-r--r-- | crates/hir_def/src/path/lower.rs | 8 | ||||
-rw-r--r-- | crates/hir_ty/src/lower.rs | 2 |
14 files changed, 229 insertions, 136 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/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 | ||
19 | use crate::{ | 19 | use 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)] |
511 | pub struct Attr { | 512 | pub 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 | ||
525 | impl Attr { | 526 | impl 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)] |
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..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 | |||
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 | #[derive(Hash)] | ||
19 | pub struct Interned<T: Internable + ?Sized> { | ||
20 | arc: Arc<T>, | ||
21 | } | ||
22 | |||
23 | impl<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 | |||
55 | impl<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 | |||
67 | impl<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. | ||
93 | impl<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 | |||
102 | impl<T: Internable> Eq for Interned<T> {} | ||
103 | |||
104 | impl<T: Internable + ?Sized> AsRef<T> for Interned<T> { | ||
105 | #[inline] | ||
106 | fn as_ref(&self) -> &T { | ||
107 | &self.arc | ||
108 | } | ||
109 | } | ||
110 | |||
111 | impl<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 | |||
120 | impl<T: Internable + ?Sized> Clone for Interned<T> { | ||
121 | fn clone(&self) -> Self { | ||
122 | Self { arc: self.arc.clone() } | ||
123 | } | ||
124 | } | ||
125 | |||
126 | impl<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 | |||
132 | pub struct InternStorage<T: ?Sized> { | ||
133 | map: OnceCell<InternMap<T>>, | ||
134 | } | ||
135 | |||
136 | impl<T: ?Sized> InternStorage<T> { | ||
137 | pub const fn new() -> Self { | ||
138 | Self { map: OnceCell::new() } | ||
139 | } | ||
140 | } | ||
141 | |||
142 | impl<T: Internable + ?Sized> InternStorage<T> { | ||
143 | fn get(&self) -> &InternMap<T> { | ||
144 | self.map.get_or_init(DashMap::default) | ||
145 | } | ||
146 | } | ||
147 | |||
148 | pub trait Internable: Hash + Eq + 'static { | ||
149 | fn storage() -> &'static InternStorage<Self>; | ||
150 | } | ||
151 | |||
152 | macro_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 | |||
163 | impl_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)] | ||
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 | } |
@@ -768,7 +694,7 @@ pub enum ModKind { | |||
768 | #[derive(Debug, Clone, Eq, PartialEq)] | 694 | #[derive(Debug, Clone, Eq, PartialEq)] |
769 | pub struct MacroCall { | 695 | pub 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)] |
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..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)] |
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_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 | ||
10 | use crate::{body::LowerCtx, type_ref::LifetimeRef}; | 10 | use crate::{body::LowerCtx, intern::Interned, type_ref::LifetimeRef}; |
11 | use base_db::CrateId; | 11 | use base_db::CrateId; |
12 | use hir_expand::{ | 12 | use hir_expand::{ |
13 | hygiene::Hygiene, | 13 | hygiene::Hygiene, |
@@ -48,7 +48,7 @@ pub enum ImportAlias { | |||
48 | 48 | ||
49 | impl ModPath { | 49 | impl 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 | ||
3 | mod lower_use; | 3 | mod lower_use; |
4 | 4 | ||
5 | use crate::intern::Interned; | ||
5 | use std::sync::Arc; | 6 | use std::sync::Arc; |
6 | 7 | ||
7 | use either::Either; | 8 | use 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> { |
diff --git a/crates/hir_ty/src/lower.rs b/crates/hir_ty/src/lower.rs index 018621131..72ee060e0 100644 --- a/crates/hir_ty/src/lower.rs +++ b/crates/hir_ty/src/lower.rs | |||
@@ -1154,7 +1154,7 @@ fn type_for_type_alias(db: &dyn HirDatabase, t: TypeAliasId) -> Binders<Ty> { | |||
1154 | Binders::new(0, TyKind::ForeignType(crate::to_foreign_def_id(t)).intern(&Interner)) | 1154 | Binders::new(0, TyKind::ForeignType(crate::to_foreign_def_id(t)).intern(&Interner)) |
1155 | } else { | 1155 | } else { |
1156 | let type_ref = &db.type_alias_data(t).type_ref; | 1156 | let type_ref = &db.type_alias_data(t).type_ref; |
1157 | let inner = ctx.lower_ty(type_ref.as_ref().unwrap_or(&TypeRef::Error)); | 1157 | let inner = ctx.lower_ty(type_ref.as_deref().unwrap_or(&TypeRef::Error)); |
1158 | Binders::new(generics.len(), inner) | 1158 | Binders::new(generics.len(), inner) |
1159 | } | 1159 | } |
1160 | } | 1160 | } |