diff options
author | bors[bot] <26634292+bors[bot]@users.noreply.github.com> | 2020-06-30 13:10:21 +0100 |
---|---|---|
committer | GitHub <[email protected]> | 2020-06-30 13:10:21 +0100 |
commit | 3e70d0f30802472ee40c9fc37b8ead69e137a1a1 (patch) | |
tree | f64b342534df07401f86435ddfd578f7ceca0c72 | |
parent | 6a73d544f4117b942b300afb8bda98216fc92356 (diff) | |
parent | 7c9b3d154c4d826d4623891c69a60d1a69031e5b (diff) |
Merge #5136
5136: Split namespace maps in `ItemScope` r=jonas-schievink a=jonas-schievink
Reduces memory usage of the CrateDefMap query by ~130 MB (50%) on r-a.
I was also looking into handling glob imports more efficiently (storing scope chains instead of always duplicating everything into the glob-importing module's scope), but it seems that this already gives the most significant wins.
Co-authored-by: Jonas Schievink <[email protected]>
-rw-r--r-- | crates/ra_hir_def/src/item_scope.rs | 109 | ||||
-rw-r--r-- | crates/ra_hir_def/src/resolver.rs | 8 |
2 files changed, 73 insertions, 44 deletions
diff --git a/crates/ra_hir_def/src/item_scope.rs b/crates/ra_hir_def/src/item_scope.rs index 4d446c707..beeb98559 100644 --- a/crates/ra_hir_def/src/item_scope.rs +++ b/crates/ra_hir_def/src/item_scope.rs | |||
@@ -1,6 +1,8 @@ | |||
1 | //! Describes items defined or visible (ie, imported) in a certain scope. | 1 | //! Describes items defined or visible (ie, imported) in a certain scope. |
2 | //! This is shared between modules and blocks. | 2 | //! This is shared between modules and blocks. |
3 | 3 | ||
4 | use std::collections::hash_map::Entry; | ||
5 | |||
4 | use hir_expand::name::Name; | 6 | use hir_expand::name::Name; |
5 | use once_cell::sync::Lazy; | 7 | use once_cell::sync::Lazy; |
6 | use ra_db::CrateId; | 8 | use ra_db::CrateId; |
@@ -27,7 +29,11 @@ pub struct PerNsGlobImports { | |||
27 | 29 | ||
28 | #[derive(Debug, Default, PartialEq, Eq)] | 30 | #[derive(Debug, Default, PartialEq, Eq)] |
29 | pub struct ItemScope { | 31 | pub struct ItemScope { |
30 | visible: FxHashMap<Name, PerNs>, | 32 | types: FxHashMap<Name, (ModuleDefId, Visibility)>, |
33 | values: FxHashMap<Name, (ModuleDefId, Visibility)>, | ||
34 | macros: FxHashMap<Name, (MacroDefId, Visibility)>, | ||
35 | unresolved: FxHashSet<Name>, | ||
36 | |||
31 | defs: Vec<ModuleDefId>, | 37 | defs: Vec<ModuleDefId>, |
32 | impls: Vec<ImplId>, | 38 | impls: Vec<ImplId>, |
33 | /// Macros visible in current module in legacy textual scope | 39 | /// Macros visible in current module in legacy textual scope |
@@ -65,14 +71,16 @@ pub(crate) enum BuiltinShadowMode { | |||
65 | /// Other methods will only resolve values, types and module scoped macros only. | 71 | /// Other methods will only resolve values, types and module scoped macros only. |
66 | impl ItemScope { | 72 | impl ItemScope { |
67 | pub fn entries<'a>(&'a self) -> impl Iterator<Item = (&'a Name, PerNs)> + 'a { | 73 | pub fn entries<'a>(&'a self) -> impl Iterator<Item = (&'a Name, PerNs)> + 'a { |
68 | //FIXME: shadowing | 74 | // FIXME: shadowing |
69 | self.visible.iter().map(|(n, def)| (n, *def)) | 75 | let keys: FxHashSet<_> = self |
70 | } | 76 | .types |
71 | 77 | .keys() | |
72 | pub fn entries_without_primitives<'a>( | 78 | .chain(self.values.keys()) |
73 | &'a self, | 79 | .chain(self.macros.keys()) |
74 | ) -> impl Iterator<Item = (&'a Name, PerNs)> + 'a { | 80 | .chain(self.unresolved.iter()) |
75 | self.visible.iter().map(|(n, def)| (n, *def)) | 81 | .collect(); |
82 | |||
83 | keys.into_iter().map(move |name| (name, self.get(name))) | ||
76 | } | 84 | } |
77 | 85 | ||
78 | pub fn declarations(&self) -> impl Iterator<Item = ModuleDefId> + '_ { | 86 | pub fn declarations(&self) -> impl Iterator<Item = ModuleDefId> + '_ { |
@@ -91,7 +99,7 @@ impl ItemScope { | |||
91 | 99 | ||
92 | /// Iterate over all module scoped macros | 100 | /// Iterate over all module scoped macros |
93 | pub(crate) fn macros<'a>(&'a self) -> impl Iterator<Item = (&'a Name, MacroDefId)> + 'a { | 101 | pub(crate) fn macros<'a>(&'a self) -> impl Iterator<Item = (&'a Name, MacroDefId)> + 'a { |
94 | self.visible.iter().filter_map(|(name, def)| def.take_macros().map(|macro_| (name, macro_))) | 102 | self.entries().filter_map(|(name, def)| def.take_macros().map(|macro_| (name, macro_))) |
95 | } | 103 | } |
96 | 104 | ||
97 | /// Iterate over all legacy textual scoped macros visible at the end of the module | 105 | /// Iterate over all legacy textual scoped macros visible at the end of the module |
@@ -101,12 +109,16 @@ impl ItemScope { | |||
101 | 109 | ||
102 | /// Get a name from current module scope, legacy macros are not included | 110 | /// Get a name from current module scope, legacy macros are not included |
103 | pub(crate) fn get(&self, name: &Name) -> PerNs { | 111 | pub(crate) fn get(&self, name: &Name) -> PerNs { |
104 | self.visible.get(name).copied().unwrap_or_else(PerNs::none) | 112 | PerNs { |
113 | types: self.types.get(name).copied(), | ||
114 | values: self.values.get(name).copied(), | ||
115 | macros: self.macros.get(name).copied(), | ||
116 | } | ||
105 | } | 117 | } |
106 | 118 | ||
107 | pub(crate) fn name_of(&self, item: ItemInNs) -> Option<(&Name, Visibility)> { | 119 | pub(crate) fn name_of(&self, item: ItemInNs) -> Option<(&Name, Visibility)> { |
108 | for (name, per_ns) in &self.visible { | 120 | for (name, per_ns) in self.entries() { |
109 | if let Some(vis) = item.match_with(*per_ns) { | 121 | if let Some(vis) = item.match_with(per_ns) { |
110 | return Some((name, vis)); | 122 | return Some((name, vis)); |
111 | } | 123 | } |
112 | } | 124 | } |
@@ -114,8 +126,8 @@ impl ItemScope { | |||
114 | } | 126 | } |
115 | 127 | ||
116 | pub(crate) fn traits<'a>(&'a self) -> impl Iterator<Item = TraitId> + 'a { | 128 | pub(crate) fn traits<'a>(&'a self) -> impl Iterator<Item = TraitId> + 'a { |
117 | self.visible.values().filter_map(|def| match def.take_types() { | 129 | self.types.values().filter_map(|(def, _)| match def { |
118 | Some(ModuleDefId::TraitId(t)) => Some(t), | 130 | ModuleDefId::TraitId(t) => Some(*t), |
119 | _ => None, | 131 | _ => None, |
120 | }) | 132 | }) |
121 | } | 133 | } |
@@ -138,21 +150,30 @@ impl ItemScope { | |||
138 | 150 | ||
139 | pub(crate) fn push_res(&mut self, name: Name, def: PerNs) -> bool { | 151 | pub(crate) fn push_res(&mut self, name: Name, def: PerNs) -> bool { |
140 | let mut changed = false; | 152 | let mut changed = false; |
141 | let existing = self.visible.entry(name).or_default(); | ||
142 | 153 | ||
143 | if existing.types.is_none() && def.types.is_some() { | 154 | if let Some(types) = def.types { |
144 | existing.types = def.types; | 155 | self.types.entry(name.clone()).or_insert_with(|| { |
145 | changed = true; | 156 | changed = true; |
157 | types | ||
158 | }); | ||
146 | } | 159 | } |
147 | 160 | if let Some(values) = def.values { | |
148 | if existing.values.is_none() && def.values.is_some() { | 161 | self.values.entry(name.clone()).or_insert_with(|| { |
149 | existing.values = def.values; | 162 | changed = true; |
150 | changed = true; | 163 | values |
164 | }); | ||
165 | } | ||
166 | if let Some(macros) = def.macros { | ||
167 | self.macros.entry(name.clone()).or_insert_with(|| { | ||
168 | changed = true; | ||
169 | macros | ||
170 | }); | ||
151 | } | 171 | } |
152 | 172 | ||
153 | if existing.macros.is_none() && def.macros.is_some() { | 173 | if def.is_none() { |
154 | existing.macros = def.macros; | 174 | if self.unresolved.insert(name) { |
155 | changed = true; | 175 | changed = true; |
176 | } | ||
156 | } | 177 | } |
157 | 178 | ||
158 | changed | 179 | changed |
@@ -166,17 +187,17 @@ impl ItemScope { | |||
166 | def_import_type: ImportType, | 187 | def_import_type: ImportType, |
167 | ) -> bool { | 188 | ) -> bool { |
168 | let mut changed = false; | 189 | let mut changed = false; |
169 | let existing = self.visible.entry(lookup.1.clone()).or_default(); | ||
170 | 190 | ||
171 | macro_rules! check_changed { | 191 | macro_rules! check_changed { |
172 | ( | 192 | ( |
173 | $changed:ident, | 193 | $changed:ident, |
174 | ( $existing:ident / $def:ident ) . $field:ident, | 194 | ( $this:ident / $def:ident ) . $field:ident, |
175 | $glob_imports:ident [ $lookup:ident ], | 195 | $glob_imports:ident [ $lookup:ident ], |
176 | $def_import_type:ident | 196 | $def_import_type:ident |
177 | ) => { | 197 | ) => {{ |
178 | match ($existing.$field, $def.$field) { | 198 | let existing = $this.$field.entry($lookup.1.clone()); |
179 | (None, Some(_)) => { | 199 | match (existing, $def.$field) { |
200 | (Entry::Vacant(entry), Some(_)) => { | ||
180 | match $def_import_type { | 201 | match $def_import_type { |
181 | ImportType::Glob => { | 202 | ImportType::Glob => { |
182 | $glob_imports.$field.insert($lookup.clone()); | 203 | $glob_imports.$field.insert($lookup.clone()); |
@@ -186,32 +207,42 @@ impl ItemScope { | |||
186 | } | 207 | } |
187 | } | 208 | } |
188 | 209 | ||
189 | $existing.$field = $def.$field; | 210 | if let Some(fld) = $def.$field { |
211 | entry.insert(fld); | ||
212 | } | ||
190 | $changed = true; | 213 | $changed = true; |
191 | } | 214 | } |
192 | (Some(_), Some(_)) | 215 | (Entry::Occupied(mut entry), Some(_)) |
193 | if $glob_imports.$field.contains(&$lookup) | 216 | if $glob_imports.$field.contains(&$lookup) |
194 | && matches!($def_import_type, ImportType::Named) => | 217 | && matches!($def_import_type, ImportType::Named) => |
195 | { | 218 | { |
196 | mark::hit!(import_shadowed); | 219 | mark::hit!(import_shadowed); |
197 | $glob_imports.$field.remove(&$lookup); | 220 | $glob_imports.$field.remove(&$lookup); |
198 | $existing.$field = $def.$field; | 221 | if let Some(fld) = $def.$field { |
222 | entry.insert(fld); | ||
223 | } | ||
199 | $changed = true; | 224 | $changed = true; |
200 | } | 225 | } |
201 | _ => {} | 226 | _ => {} |
202 | } | 227 | } |
203 | }; | 228 | }}; |
204 | } | 229 | } |
205 | 230 | ||
206 | check_changed!(changed, (existing / def).types, glob_imports[lookup], def_import_type); | 231 | check_changed!(changed, (self / def).types, glob_imports[lookup], def_import_type); |
207 | check_changed!(changed, (existing / def).values, glob_imports[lookup], def_import_type); | 232 | check_changed!(changed, (self / def).values, glob_imports[lookup], def_import_type); |
208 | check_changed!(changed, (existing / def).macros, glob_imports[lookup], def_import_type); | 233 | check_changed!(changed, (self / def).macros, glob_imports[lookup], def_import_type); |
234 | |||
235 | if def.is_none() { | ||
236 | if self.unresolved.insert(lookup.1) { | ||
237 | changed = true; | ||
238 | } | ||
239 | } | ||
209 | 240 | ||
210 | changed | 241 | changed |
211 | } | 242 | } |
212 | 243 | ||
213 | pub(crate) fn resolutions<'a>(&'a self) -> impl Iterator<Item = (Name, PerNs)> + 'a { | 244 | pub(crate) fn resolutions<'a>(&'a self) -> impl Iterator<Item = (Name, PerNs)> + 'a { |
214 | self.visible.iter().map(|(name, res)| (name.clone(), *res)) | 245 | self.entries().map(|(name, res)| (name.clone(), res)) |
215 | } | 246 | } |
216 | 247 | ||
217 | pub(crate) fn collect_legacy_macros(&self) -> FxHashMap<Name, MacroDefId> { | 248 | pub(crate) fn collect_legacy_macros(&self) -> FxHashMap<Name, MacroDefId> { |
diff --git a/crates/ra_hir_def/src/resolver.rs b/crates/ra_hir_def/src/resolver.rs index 15fdd9019..0bf51eb7b 100644 --- a/crates/ra_hir_def/src/resolver.rs +++ b/crates/ra_hir_def/src/resolver.rs | |||
@@ -511,11 +511,9 @@ impl Scope { | |||
511 | }); | 511 | }); |
512 | } | 512 | } |
513 | } | 513 | } |
514 | Scope::LocalItemsScope(body) => { | 514 | Scope::LocalItemsScope(body) => body.item_scope.entries().for_each(|(name, def)| { |
515 | body.item_scope.entries_without_primitives().for_each(|(name, def)| { | 515 | f(name.clone(), ScopeDef::PerNs(def)); |
516 | f(name.clone(), ScopeDef::PerNs(def)); | 516 | }), |
517 | }) | ||
518 | } | ||
519 | Scope::GenericParams { params, def } => { | 517 | Scope::GenericParams { params, def } => { |
520 | for (local_id, param) in params.types.iter() { | 518 | for (local_id, param) in params.types.iter() { |
521 | if let Some(name) = ¶m.name { | 519 | if let Some(name) = ¶m.name { |