diff options
Diffstat (limited to 'crates/hir_def/src/nameres.rs')
-rw-r--r-- | crates/hir_def/src/nameres.rs | 107 |
1 files changed, 62 insertions, 45 deletions
diff --git a/crates/hir_def/src/nameres.rs b/crates/hir_def/src/nameres.rs index 0a15fc470..ad2e9bcac 100644 --- a/crates/hir_def/src/nameres.rs +++ b/crates/hir_def/src/nameres.rs | |||
@@ -73,7 +73,15 @@ use crate::{ | |||
73 | AstId, BlockId, BlockLoc, LocalModuleId, ModuleDefId, ModuleId, | 73 | AstId, BlockId, BlockLoc, LocalModuleId, ModuleDefId, ModuleId, |
74 | }; | 74 | }; |
75 | 75 | ||
76 | /// Contains all top-level defs from a macro-expanded crate | 76 | /// Contains the results of (early) name resolution. |
77 | /// | ||
78 | /// A `DefMap` stores the module tree and the definitions that are in scope in every module after | ||
79 | /// item-level macros have been expanded. | ||
80 | /// | ||
81 | /// Every crate has a primary `DefMap` whose root is the crate's main file (`main.rs`/`lib.rs`), | ||
82 | /// computed by the `crate_def_map` query. Additionally, every block expression introduces the | ||
83 | /// opportunity to write arbitrary item and module hierarchies, and thus gets its own `DefMap` that | ||
84 | /// is computed by the `block_def_map` query. | ||
77 | #[derive(Debug, PartialEq, Eq)] | 85 | #[derive(Debug, PartialEq, Eq)] |
78 | pub struct DefMap { | 86 | pub struct DefMap { |
79 | _c: Count<Self>, | 87 | _c: Count<Self>, |
@@ -91,11 +99,13 @@ pub struct DefMap { | |||
91 | diagnostics: Vec<DefDiagnostic>, | 99 | diagnostics: Vec<DefDiagnostic>, |
92 | } | 100 | } |
93 | 101 | ||
94 | #[derive(Debug, PartialEq, Eq)] | 102 | /// For `DefMap`s computed for a block expression, this stores its location in the parent map. |
103 | #[derive(Debug, PartialEq, Eq, Clone, Copy)] | ||
95 | struct BlockInfo { | 104 | struct BlockInfo { |
105 | /// The `BlockId` this `DefMap` was created from. | ||
96 | block: BlockId, | 106 | block: BlockId, |
97 | parent: Arc<DefMap>, | 107 | /// The containing module. |
98 | parent_module: LocalModuleId, | 108 | parent: ModuleId, |
99 | } | 109 | } |
100 | 110 | ||
101 | impl std::ops::Index<LocalModuleId> for DefMap { | 111 | impl std::ops::Index<LocalModuleId> for DefMap { |
@@ -197,21 +207,25 @@ impl DefMap { | |||
197 | Arc::new(def_map) | 207 | Arc::new(def_map) |
198 | } | 208 | } |
199 | 209 | ||
200 | pub(crate) fn block_def_map_query(db: &dyn DefDatabase, block_id: BlockId) -> Arc<DefMap> { | 210 | pub(crate) fn block_def_map_query( |
211 | db: &dyn DefDatabase, | ||
212 | block_id: BlockId, | ||
213 | ) -> Option<Arc<DefMap>> { | ||
201 | let block: BlockLoc = db.lookup_intern_block(block_id); | 214 | let block: BlockLoc = db.lookup_intern_block(block_id); |
202 | let parent = block.module.def_map(db); | ||
203 | 215 | ||
204 | // FIXME: It would be good to just return the parent map when the block has no items, but | 216 | let item_tree = db.item_tree(block.ast_id.file_id); |
205 | // we rely on `def_map.block` in a few places, which is `Some` for the inner `DefMap`. | 217 | if item_tree.inner_items_of_block(block.ast_id.value).is_empty() { |
218 | return None; | ||
219 | } | ||
206 | 220 | ||
207 | let block_info = | 221 | let block_info = BlockInfo { block: block_id, parent: block.module }; |
208 | BlockInfo { block: block_id, parent, parent_module: block.module.local_id }; | ||
209 | 222 | ||
210 | 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); | ||
211 | def_map.block = Some(block_info); | 225 | def_map.block = Some(block_info); |
212 | 226 | ||
213 | 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)); |
214 | Arc::new(def_map) | 228 | Some(Arc::new(def_map)) |
215 | } | 229 | } |
216 | 230 | ||
217 | fn empty(krate: CrateId, edition: Edition) -> DefMap { | 231 | fn empty(krate: CrateId, edition: Edition) -> DefMap { |
@@ -275,9 +289,15 @@ impl DefMap { | |||
275 | ModuleId { krate: self.krate, local_id, block } | 289 | ModuleId { krate: self.krate, local_id, block } |
276 | } | 290 | } |
277 | 291 | ||
278 | pub(crate) fn crate_root(&self) -> ModuleId { | 292 | pub(crate) fn crate_root(&self, db: &dyn DefDatabase) -> ModuleId { |
279 | let (root_map, _) = self.ancestor_maps(self.root).last().unwrap(); | 293 | self.with_ancestor_maps(db, self.root, &mut |def_map, _module| { |
280 | 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") | ||
281 | } | 301 | } |
282 | 302 | ||
283 | pub(crate) fn resolve_path( | 303 | pub(crate) fn resolve_path( |
@@ -292,25 +312,42 @@ impl DefMap { | |||
292 | (res.resolved_def, res.segment_index) | 312 | (res.resolved_def, res.segment_index) |
293 | } | 313 | } |
294 | 314 | ||
295 | /// 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. |
296 | /// expression. | 316 | /// |
297 | 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>( | ||
298 | &self, | 320 | &self, |
321 | db: &dyn DefDatabase, | ||
299 | local_mod: LocalModuleId, | 322 | local_mod: LocalModuleId, |
300 | ) -> impl Iterator<Item = (&DefMap, LocalModuleId)> { | 323 | f: &mut dyn FnMut(&DefMap, LocalModuleId) -> Option<T>, |
301 | std::iter::successors(Some((self, local_mod)), |(map, _)| { | 324 | ) -> Option<T> { |
302 | map.block.as_ref().map(|block| (&*block.parent, block.parent_module)) | 325 | if let Some(it) = f(self, local_mod) { |
303 | }) | 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 | ||
304 | } | 338 | } |
305 | 339 | ||
306 | // 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 |
307 | // even), as this should be a great debugging aid. | 341 | // even), as this should be a great debugging aid. |
308 | pub fn dump(&self) -> String { | 342 | pub fn dump(&self, db: &dyn DefDatabase) -> String { |
309 | let mut buf = String::new(); | 343 | let mut buf = String::new(); |
344 | let mut arc; | ||
310 | let mut current_map = self; | 345 | let mut current_map = self; |
311 | while let Some(block) = ¤t_map.block { | 346 | while let Some(block) = ¤t_map.block { |
312 | go(&mut buf, current_map, "block scope", current_map.root); | 347 | go(&mut buf, current_map, "block scope", current_map.root); |
313 | current_map = &*block.parent; | 348 | buf.push('\n'); |
349 | arc = block.parent.def_map(db); | ||
350 | current_map = &*arc; | ||
314 | } | 351 | } |
315 | go(&mut buf, current_map, "crate", current_map.root); | 352 | go(&mut buf, current_map, "crate", current_map.root); |
316 | return buf; | 353 | return buf; |
@@ -318,27 +355,7 @@ impl DefMap { | |||
318 | fn go(buf: &mut String, map: &DefMap, path: &str, module: LocalModuleId) { | 355 | fn go(buf: &mut String, map: &DefMap, path: &str, module: LocalModuleId) { |
319 | format_to!(buf, "{}\n", path); | 356 | format_to!(buf, "{}\n", path); |
320 | 357 | ||
321 | let mut entries: Vec<_> = map.modules[module].scope.resolutions().collect(); | 358 | map.modules[module].scope.dump(buf); |
322 | entries.sort_by_key(|(name, _)| name.clone()); | ||
323 | |||
324 | for (name, def) in entries { | ||
325 | format_to!(buf, "{}:", name.map_or("_".to_string(), |name| name.to_string())); | ||
326 | |||
327 | if def.types.is_some() { | ||
328 | buf.push_str(" t"); | ||
329 | } | ||
330 | if def.values.is_some() { | ||
331 | buf.push_str(" v"); | ||
332 | } | ||
333 | if def.macros.is_some() { | ||
334 | buf.push_str(" m"); | ||
335 | } | ||
336 | if def.is_none() { | ||
337 | buf.push_str(" _"); | ||
338 | } | ||
339 | |||
340 | buf.push('\n'); | ||
341 | } | ||
342 | 359 | ||
343 | for (name, child) in map.modules[module].children.iter() { | 360 | for (name, child) in map.modules[module].children.iter() { |
344 | let path = format!("{}::{}", path, name); | 361 | let path = format!("{}::{}", path, name); |