Skip to content

Commit 3e70d0f

Browse files
bors[bot]Jonas Schievink
andauthored
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]>
2 parents 6a73d54 + 7c9b3d1 commit 3e70d0f

File tree

2 files changed

+73
-44
lines changed

2 files changed

+73
-44
lines changed

crates/ra_hir_def/src/item_scope.rs

Lines changed: 70 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
//! Describes items defined or visible (ie, imported) in a certain scope.
22
//! This is shared between modules and blocks.
33
4+
use std::collections::hash_map::Entry;
5+
46
use hir_expand::name::Name;
57
use once_cell::sync::Lazy;
68
use ra_db::CrateId;
@@ -27,7 +29,11 @@ pub struct PerNsGlobImports {
2729

2830
#[derive(Debug, Default, PartialEq, Eq)]
2931
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+
3137
defs: Vec<ModuleDefId>,
3238
impls: Vec<ImplId>,
3339
/// Macros visible in current module in legacy textual scope
@@ -65,14 +71,16 @@ pub(crate) enum BuiltinShadowMode {
6571
/// Other methods will only resolve values, types and module scoped macros only.
6672
impl ItemScope {
6773
pub fn entries<'a>(&'a self) -> impl Iterator<Item = (&'a Name, PerNs)> + 'a {
68-
//FIXME: shadowing
69-
self.visible.iter().map(|(n, def)| (n, *def))
70-
}
71-
72-
pub fn entries_without_primitives<'a>(
73-
&'a self,
74-
) -> impl Iterator<Item = (&'a Name, PerNs)> + 'a {
75-
self.visible.iter().map(|(n, def)| (n, *def))
74+
// FIXME: shadowing
75+
let keys: FxHashSet<_> = self
76+
.types
77+
.keys()
78+
.chain(self.values.keys())
79+
.chain(self.macros.keys())
80+
.chain(self.unresolved.iter())
81+
.collect();
82+
83+
keys.into_iter().map(move |name| (name, self.get(name)))
7684
}
7785

7886
pub fn declarations(&self) -> impl Iterator<Item = ModuleDefId> + '_ {
@@ -91,7 +99,7 @@ impl ItemScope {
9199

92100
/// Iterate over all module scoped macros
93101
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_)))
95103
}
96104

97105
/// Iterate over all legacy textual scoped macros visible at the end of the module
@@ -101,21 +109,25 @@ impl ItemScope {
101109

102110
/// Get a name from current module scope, legacy macros are not included
103111
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+
}
105117
}
106118

107119
pub(crate) fn name_of(&self, item: ItemInNs) -> Option<(&Name, Visibility)> {
108-
for (name, per_ns) in &self.visible {
109-
if let Some(vis) = item.match_with(*per_ns) {
120+
for (name, per_ns) in self.entries() {
121+
if let Some(vis) = item.match_with(per_ns) {
110122
return Some((name, vis));
111123
}
112124
}
113125
None
114126
}
115127

116128
pub(crate) fn traits<'a>(&'a self) -> impl Iterator<Item = TraitId> + 'a {
117-
self.visible.values().filter_map(|def| match def.take_types() {
118-
Some(ModuleDefId::TraitId(t)) => Some(t),
129+
self.types.values().filter_map(|(def, _)| match def {
130+
ModuleDefId::TraitId(t) => Some(*t),
119131
_ => None,
120132
})
121133
}
@@ -138,21 +150,30 @@ impl ItemScope {
138150

139151
pub(crate) fn push_res(&mut self, name: Name, def: PerNs) -> bool {
140152
let mut changed = false;
141-
let existing = self.visible.entry(name).or_default();
142153

143-
if existing.types.is_none() && def.types.is_some() {
144-
existing.types = def.types;
145-
changed = true;
154+
if let Some(types) = def.types {
155+
self.types.entry(name.clone()).or_insert_with(|| {
156+
changed = true;
157+
types
158+
});
146159
}
147-
148-
if existing.values.is_none() && def.values.is_some() {
149-
existing.values = def.values;
150-
changed = true;
160+
if let Some(values) = def.values {
161+
self.values.entry(name.clone()).or_insert_with(|| {
162+
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+
});
151171
}
152172

153-
if existing.macros.is_none() && def.macros.is_some() {
154-
existing.macros = def.macros;
155-
changed = true;
173+
if def.is_none() {
174+
if self.unresolved.insert(name) {
175+
changed = true;
176+
}
156177
}
157178

158179
changed
@@ -166,17 +187,17 @@ impl ItemScope {
166187
def_import_type: ImportType,
167188
) -> bool {
168189
let mut changed = false;
169-
let existing = self.visible.entry(lookup.1.clone()).or_default();
170190

171191
macro_rules! check_changed {
172192
(
173193
$changed:ident,
174-
( $existing:ident / $def:ident ) . $field:ident,
194+
( $this:ident / $def:ident ) . $field:ident,
175195
$glob_imports:ident [ $lookup:ident ],
176196
$def_import_type:ident
177-
) => {
178-
match ($existing.$field, $def.$field) {
179-
(None, Some(_)) => {
197+
) => {{
198+
let existing = $this.$field.entry($lookup.1.clone());
199+
match (existing, $def.$field) {
200+
(Entry::Vacant(entry), Some(_)) => {
180201
match $def_import_type {
181202
ImportType::Glob => {
182203
$glob_imports.$field.insert($lookup.clone());
@@ -186,32 +207,42 @@ impl ItemScope {
186207
}
187208
}
188209

189-
$existing.$field = $def.$field;
210+
if let Some(fld) = $def.$field {
211+
entry.insert(fld);
212+
}
190213
$changed = true;
191214
}
192-
(Some(_), Some(_))
215+
(Entry::Occupied(mut entry), Some(_))
193216
if $glob_imports.$field.contains(&$lookup)
194217
&& matches!($def_import_type, ImportType::Named) =>
195218
{
196219
mark::hit!(import_shadowed);
197220
$glob_imports.$field.remove(&$lookup);
198-
$existing.$field = $def.$field;
221+
if let Some(fld) = $def.$field {
222+
entry.insert(fld);
223+
}
199224
$changed = true;
200225
}
201226
_ => {}
202227
}
203-
};
228+
}};
204229
}
205230

206-
check_changed!(changed, (existing / def).types, glob_imports[lookup], def_import_type);
207-
check_changed!(changed, (existing / def).values, glob_imports[lookup], def_import_type);
208-
check_changed!(changed, (existing / def).macros, glob_imports[lookup], def_import_type);
231+
check_changed!(changed, (self / def).types, glob_imports[lookup], def_import_type);
232+
check_changed!(changed, (self / def).values, 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+
}
209240

210241
changed
211242
}
212243

213244
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))
215246
}
216247

217248
pub(crate) fn collect_legacy_macros(&self) -> FxHashMap<Name, MacroDefId> {

crates/ra_hir_def/src/resolver.rs

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -511,11 +511,9 @@ impl Scope {
511511
});
512512
}
513513
}
514-
Scope::LocalItemsScope(body) => {
515-
body.item_scope.entries_without_primitives().for_each(|(name, def)| {
516-
f(name.clone(), ScopeDef::PerNs(def));
517-
})
518-
}
514+
Scope::LocalItemsScope(body) => body.item_scope.entries().for_each(|(name, def)| {
515+
f(name.clone(), ScopeDef::PerNs(def));
516+
}),
519517
Scope::GenericParams { params, def } => {
520518
for (local_id, param) in params.types.iter() {
521519
if let Some(name) = &param.name {

0 commit comments

Comments
 (0)