diff options
Diffstat (limited to 'crates/hir_def/src/nameres.rs')
-rw-r--r-- | crates/hir_def/src/nameres.rs | 60 |
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)] |
104 | struct BlockInfo { | 104 | struct 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 | ||
110 | impl std::ops::Index<LocalModuleId> for DefMap { | 111 | impl 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) = ¤t_map.block { | 346 | while let Some(block) = ¤t_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; |