aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorbors[bot] <26634292+bors[bot]@users.noreply.github.com>2020-06-30 13:10:21 +0100
committerGitHub <[email protected]>2020-06-30 13:10:21 +0100
commit3e70d0f30802472ee40c9fc37b8ead69e137a1a1 (patch)
treef64b342534df07401f86435ddfd578f7ceca0c72
parent6a73d544f4117b942b300afb8bda98216fc92356 (diff)
parent7c9b3d154c4d826d4623891c69a60d1a69031e5b (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.rs109
-rw-r--r--crates/ra_hir_def/src/resolver.rs8
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
4use std::collections::hash_map::Entry;
5
4use hir_expand::name::Name; 6use hir_expand::name::Name;
5use once_cell::sync::Lazy; 7use once_cell::sync::Lazy;
6use ra_db::CrateId; 8use ra_db::CrateId;
@@ -27,7 +29,11 @@ pub struct PerNsGlobImports {
27 29
28#[derive(Debug, Default, PartialEq, Eq)] 30#[derive(Debug, Default, PartialEq, Eq)]
29pub struct ItemScope { 31pub 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.
66impl ItemScope { 72impl 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) = &param.name { 519 if let Some(name) = &param.name {