aboutsummaryrefslogtreecommitdiff
path: root/crates/hir_def/src/nameres.rs
diff options
context:
space:
mode:
authorJonas Schievink <[email protected]>2021-02-04 12:44:54 +0000
committerJonas Schievink <[email protected]>2021-02-04 12:44:54 +0000
commit26a2a2433c7bae1533d07a38a6003e6f40fa97d9 (patch)
treec1a3bbed8832b554c6991802f728d99ea6ced088 /crates/hir_def/src/nameres.rs
parent01bc1fdff8b04d373e794af29b18243eb9d15e34 (diff)
Don't keep the parent DefMap alive via Arc
This seems like it could easily leak a lot of memory since we don't currently run GC
Diffstat (limited to 'crates/hir_def/src/nameres.rs')
-rw-r--r--crates/hir_def/src/nameres.rs60
1 files changed, 41 insertions, 19 deletions
diff --git a/crates/hir_def/src/nameres.rs b/crates/hir_def/src/nameres.rs
index 68998c121..ad2e9bcac 100644
--- a/crates/hir_def/src/nameres.rs
+++ b/crates/hir_def/src/nameres.rs
@@ -100,11 +100,12 @@ pub struct DefMap {
100} 100}
101 101
102/// For `DefMap`s computed for a block expression, this stores its location in the parent map. 102/// For `DefMap`s computed for a block expression, this stores its location in the parent map.
103#[derive(Debug, PartialEq, Eq)] 103#[derive(Debug, PartialEq, Eq, Clone, Copy)]
104struct BlockInfo { 104struct BlockInfo {
105 /// The `BlockId` this `DefMap` was created from.
105 block: BlockId, 106 block: BlockId,
106 parent: Arc<DefMap>, 107 /// The containing module.
107 parent_module: LocalModuleId, 108 parent: ModuleId,
108} 109}
109 110
110impl std::ops::Index<LocalModuleId> for DefMap { 111impl std::ops::Index<LocalModuleId> for DefMap {
@@ -211,17 +212,16 @@ impl DefMap {
211 block_id: BlockId, 212 block_id: BlockId,
212 ) -> Option<Arc<DefMap>> { 213 ) -> Option<Arc<DefMap>> {
213 let block: BlockLoc = db.lookup_intern_block(block_id); 214 let block: BlockLoc = db.lookup_intern_block(block_id);
214 let parent = block.module.def_map(db);
215 215
216 let item_tree = db.item_tree(block.ast_id.file_id); 216 let item_tree = db.item_tree(block.ast_id.file_id);
217 if item_tree.inner_items_of_block(block.ast_id.value).is_empty() { 217 if item_tree.inner_items_of_block(block.ast_id.value).is_empty() {
218 return None; 218 return None;
219 } 219 }
220 220
221 let block_info = 221 let block_info = BlockInfo { block: block_id, parent: block.module };
222 BlockInfo { block: block_id, parent, parent_module: block.module.local_id };
223 222
224 let mut def_map = DefMap::empty(block.module.krate, block_info.parent.edition); 223 let parent_map = block.module.def_map(db);
224 let mut def_map = DefMap::empty(block.module.krate, parent_map.edition);
225 def_map.block = Some(block_info); 225 def_map.block = Some(block_info);
226 226
227 let def_map = collector::collect_defs(db, def_map, Some(block.ast_id)); 227 let def_map = collector::collect_defs(db, def_map, Some(block.ast_id));
@@ -289,9 +289,15 @@ impl DefMap {
289 ModuleId { krate: self.krate, local_id, block } 289 ModuleId { krate: self.krate, local_id, block }
290 } 290 }
291 291
292 pub(crate) fn crate_root(&self) -> ModuleId { 292 pub(crate) fn crate_root(&self, db: &dyn DefDatabase) -> ModuleId {
293 let (root_map, _) = self.ancestor_maps(self.root).last().unwrap(); 293 self.with_ancestor_maps(db, self.root, &mut |def_map, _module| {
294 root_map.module_id(root_map.root) 294 if def_map.block.is_none() {
295 Some(def_map.module_id(def_map.root))
296 } else {
297 None
298 }
299 })
300 .expect("DefMap chain without root")
295 } 301 }
296 302
297 pub(crate) fn resolve_path( 303 pub(crate) fn resolve_path(
@@ -306,26 +312,42 @@ impl DefMap {
306 (res.resolved_def, res.segment_index) 312 (res.resolved_def, res.segment_index)
307 } 313 }
308 314
309 /// Iterates over the containing `DefMap`s, if `self` is a `DefMap` corresponding to a block 315 /// Ascends the `DefMap` hierarchy and calls `f` with every `DefMap` and containing module.
310 /// expression. 316 ///
311 fn ancestor_maps( 317 /// If `f` returns `Some(val)`, iteration is stopped and `Some(val)` is returned. If `f` returns
318 /// `None`, iteration continues.
319 fn with_ancestor_maps<T>(
312 &self, 320 &self,
321 db: &dyn DefDatabase,
313 local_mod: LocalModuleId, 322 local_mod: LocalModuleId,
314 ) -> impl Iterator<Item = (&DefMap, LocalModuleId)> { 323 f: &mut dyn FnMut(&DefMap, LocalModuleId) -> Option<T>,
315 std::iter::successors(Some((self, local_mod)), |(map, _)| { 324 ) -> Option<T> {
316 map.block.as_ref().map(|block| (&*block.parent, block.parent_module)) 325 if let Some(it) = f(self, local_mod) {
317 }) 326 return Some(it);
327 }
328 let mut block = self.block;
329 while let Some(block_info) = block {
330 let parent = block_info.parent.def_map(db);
331 if let Some(it) = f(&parent, block_info.parent.local_id) {
332 return Some(it);
333 }
334 block = parent.block;
335 }
336
337 None
318 } 338 }
319 339
320 // FIXME: this can use some more human-readable format (ideally, an IR 340 // FIXME: this can use some more human-readable format (ideally, an IR
321 // even), as this should be a great debugging aid. 341 // even), as this should be a great debugging aid.
322 pub fn dump(&self) -> String { 342 pub fn dump(&self, db: &dyn DefDatabase) -> String {
323 let mut buf = String::new(); 343 let mut buf = String::new();
344 let mut arc;
324 let mut current_map = self; 345 let mut current_map = self;
325 while let Some(block) = &current_map.block { 346 while let Some(block) = &current_map.block {
326 go(&mut buf, current_map, "block scope", current_map.root); 347 go(&mut buf, current_map, "block scope", current_map.root);
327 buf.push('\n'); 348 buf.push('\n');
328 current_map = &*block.parent; 349 arc = block.parent.def_map(db);
350 current_map = &*arc;
329 } 351 }
330 go(&mut buf, current_map, "crate", current_map.root); 352 go(&mut buf, current_map, "crate", current_map.root);
331 return buf; 353 return buf;