diff options
Diffstat (limited to 'crates/hir_def/src/nameres.rs')
-rw-r--r-- | crates/hir_def/src/nameres.rs | 242 |
1 files changed, 190 insertions, 52 deletions
diff --git a/crates/hir_def/src/nameres.rs b/crates/hir_def/src/nameres.rs index 50acc3f54..003d668ca 100644 --- a/crates/hir_def/src/nameres.rs +++ b/crates/hir_def/src/nameres.rs | |||
@@ -59,6 +59,7 @@ use std::sync::Arc; | |||
59 | use base_db::{CrateId, Edition, FileId}; | 59 | use base_db::{CrateId, Edition, FileId}; |
60 | use hir_expand::{diagnostics::DiagnosticSink, name::Name, InFile}; | 60 | use hir_expand::{diagnostics::DiagnosticSink, name::Name, InFile}; |
61 | use la_arena::Arena; | 61 | use la_arena::Arena; |
62 | use profile::Count; | ||
62 | use rustc_hash::FxHashMap; | 63 | use rustc_hash::FxHashMap; |
63 | use stdx::format_to; | 64 | use stdx::format_to; |
64 | use syntax::ast; | 65 | use syntax::ast; |
@@ -69,26 +70,45 @@ use crate::{ | |||
69 | nameres::{diagnostics::DefDiagnostic, path_resolution::ResolveMode}, | 70 | nameres::{diagnostics::DefDiagnostic, path_resolution::ResolveMode}, |
70 | path::ModPath, | 71 | path::ModPath, |
71 | per_ns::PerNs, | 72 | per_ns::PerNs, |
72 | AstId, LocalModuleId, ModuleDefId, ModuleId, | 73 | AstId, BlockId, BlockLoc, LocalModuleId, ModuleDefId, ModuleId, |
73 | }; | 74 | }; |
74 | 75 | ||
75 | /// 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. | ||
76 | #[derive(Debug, PartialEq, Eq)] | 85 | #[derive(Debug, PartialEq, Eq)] |
77 | pub struct CrateDefMap { | 86 | pub struct DefMap { |
78 | pub root: LocalModuleId, | 87 | _c: Count<Self>, |
79 | pub modules: Arena<ModuleData>, | 88 | block: Option<BlockInfo>, |
80 | pub(crate) krate: CrateId, | 89 | root: LocalModuleId, |
90 | modules: Arena<ModuleData>, | ||
91 | krate: CrateId, | ||
81 | /// The prelude module for this crate. This either comes from an import | 92 | /// The prelude module for this crate. This either comes from an import |
82 | /// marked with the `prelude_import` attribute, or (in the normal case) from | 93 | /// marked with the `prelude_import` attribute, or (in the normal case) from |
83 | /// a dependency (`std` or `core`). | 94 | /// a dependency (`std` or `core`). |
84 | pub(crate) prelude: Option<ModuleId>, | 95 | prelude: Option<ModuleId>, |
85 | pub(crate) extern_prelude: FxHashMap<Name, ModuleDefId>, | 96 | extern_prelude: FxHashMap<Name, ModuleDefId>, |
86 | 97 | ||
87 | edition: Edition, | 98 | edition: Edition, |
88 | diagnostics: Vec<DefDiagnostic>, | 99 | diagnostics: Vec<DefDiagnostic>, |
89 | } | 100 | } |
90 | 101 | ||
91 | impl std::ops::Index<LocalModuleId> for CrateDefMap { | 102 | /// For `DefMap`s computed for a block expression, this stores its location in the parent map. |
103 | #[derive(Debug, PartialEq, Eq, Clone, Copy)] | ||
104 | struct BlockInfo { | ||
105 | /// The `BlockId` this `DefMap` was created from. | ||
106 | block: BlockId, | ||
107 | /// The containing module. | ||
108 | parent: ModuleId, | ||
109 | } | ||
110 | |||
111 | impl std::ops::Index<LocalModuleId> for DefMap { | ||
92 | type Output = ModuleData; | 112 | type Output = ModuleData; |
93 | fn index(&self, id: LocalModuleId) -> &ModuleData { | 113 | fn index(&self, id: LocalModuleId) -> &ModuleData { |
94 | &self.modules[id] | 114 | &self.modules[id] |
@@ -109,6 +129,10 @@ pub enum ModuleOrigin { | |||
109 | Inline { | 129 | Inline { |
110 | definition: AstId<ast::Module>, | 130 | definition: AstId<ast::Module>, |
111 | }, | 131 | }, |
132 | /// Pseudo-module introduced by a block scope (contains only inner items). | ||
133 | BlockExpr { | ||
134 | block: AstId<ast::BlockExpr>, | ||
135 | }, | ||
112 | } | 136 | } |
113 | 137 | ||
114 | impl Default for ModuleOrigin { | 138 | impl Default for ModuleOrigin { |
@@ -122,7 +146,7 @@ impl ModuleOrigin { | |||
122 | match self { | 146 | match self { |
123 | ModuleOrigin::File { declaration: module, .. } | 147 | ModuleOrigin::File { declaration: module, .. } |
124 | | ModuleOrigin::Inline { definition: module, .. } => Some(*module), | 148 | | ModuleOrigin::Inline { definition: module, .. } => Some(*module), |
125 | ModuleOrigin::CrateRoot { .. } => None, | 149 | ModuleOrigin::CrateRoot { .. } | ModuleOrigin::BlockExpr { .. } => None, |
126 | } | 150 | } |
127 | } | 151 | } |
128 | 152 | ||
@@ -137,7 +161,7 @@ impl ModuleOrigin { | |||
137 | 161 | ||
138 | pub fn is_inline(&self) -> bool { | 162 | pub fn is_inline(&self) -> bool { |
139 | match self { | 163 | match self { |
140 | ModuleOrigin::Inline { .. } => true, | 164 | ModuleOrigin::Inline { .. } | ModuleOrigin::BlockExpr { .. } => true, |
141 | ModuleOrigin::CrateRoot { .. } | ModuleOrigin::File { .. } => false, | 165 | ModuleOrigin::CrateRoot { .. } | ModuleOrigin::File { .. } => false, |
142 | } | 166 | } |
143 | } | 167 | } |
@@ -155,6 +179,9 @@ impl ModuleOrigin { | |||
155 | definition.file_id, | 179 | definition.file_id, |
156 | ModuleSource::Module(definition.to_node(db.upcast())), | 180 | ModuleSource::Module(definition.to_node(db.upcast())), |
157 | ), | 181 | ), |
182 | ModuleOrigin::BlockExpr { block } => { | ||
183 | InFile::new(block.file_id, ModuleSource::BlockExpr(block.to_node(db.upcast()))) | ||
184 | } | ||
158 | } | 185 | } |
159 | } | 186 | } |
160 | } | 187 | } |
@@ -169,29 +196,54 @@ pub struct ModuleData { | |||
169 | pub origin: ModuleOrigin, | 196 | pub origin: ModuleOrigin, |
170 | } | 197 | } |
171 | 198 | ||
172 | impl CrateDefMap { | 199 | impl DefMap { |
173 | pub(crate) fn crate_def_map_query(db: &dyn DefDatabase, krate: CrateId) -> Arc<CrateDefMap> { | 200 | pub(crate) fn crate_def_map_query(db: &dyn DefDatabase, krate: CrateId) -> Arc<DefMap> { |
174 | let _p = profile::span("crate_def_map_query").detail(|| { | 201 | let _p = profile::span("crate_def_map_query").detail(|| { |
175 | db.crate_graph()[krate].display_name.as_deref().unwrap_or_default().to_string() | 202 | db.crate_graph()[krate].display_name.as_deref().unwrap_or_default().to_string() |
176 | }); | 203 | }); |
177 | let def_map = { | 204 | let edition = db.crate_graph()[krate].edition; |
178 | let edition = db.crate_graph()[krate].edition; | 205 | let def_map = DefMap::empty(krate, edition); |
179 | let mut modules: Arena<ModuleData> = Arena::default(); | 206 | let def_map = collector::collect_defs(db, def_map, None); |
180 | let root = modules.alloc(ModuleData::default()); | ||
181 | CrateDefMap { | ||
182 | krate, | ||
183 | edition, | ||
184 | extern_prelude: FxHashMap::default(), | ||
185 | prelude: None, | ||
186 | root, | ||
187 | modules, | ||
188 | diagnostics: Vec::new(), | ||
189 | } | ||
190 | }; | ||
191 | let def_map = collector::collect_defs(db, def_map); | ||
192 | Arc::new(def_map) | 207 | Arc::new(def_map) |
193 | } | 208 | } |
194 | 209 | ||
210 | pub(crate) fn block_def_map_query( | ||
211 | db: &dyn DefDatabase, | ||
212 | block_id: BlockId, | ||
213 | ) -> Option<Arc<DefMap>> { | ||
214 | let block: BlockLoc = db.lookup_intern_block(block_id); | ||
215 | |||
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() { | ||
218 | return None; | ||
219 | } | ||
220 | |||
221 | let block_info = BlockInfo { block: block_id, parent: block.module }; | ||
222 | |||
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); | ||
226 | |||
227 | let def_map = collector::collect_defs(db, def_map, Some(block.ast_id)); | ||
228 | Some(Arc::new(def_map)) | ||
229 | } | ||
230 | |||
231 | fn empty(krate: CrateId, edition: Edition) -> DefMap { | ||
232 | let mut modules: Arena<ModuleData> = Arena::default(); | ||
233 | let root = modules.alloc(ModuleData::default()); | ||
234 | DefMap { | ||
235 | _c: Count::new(), | ||
236 | block: None, | ||
237 | krate, | ||
238 | edition, | ||
239 | extern_prelude: FxHashMap::default(), | ||
240 | prelude: None, | ||
241 | root, | ||
242 | modules, | ||
243 | diagnostics: Vec::new(), | ||
244 | } | ||
245 | } | ||
246 | |||
195 | pub fn add_diagnostics( | 247 | pub fn add_diagnostics( |
196 | &self, | 248 | &self, |
197 | db: &dyn DefDatabase, | 249 | db: &dyn DefDatabase, |
@@ -208,6 +260,46 @@ impl CrateDefMap { | |||
208 | .map(|(id, _data)| id) | 260 | .map(|(id, _data)| id) |
209 | } | 261 | } |
210 | 262 | ||
263 | pub fn modules(&self) -> impl Iterator<Item = (LocalModuleId, &ModuleData)> + '_ { | ||
264 | self.modules.iter() | ||
265 | } | ||
266 | |||
267 | pub fn root(&self) -> LocalModuleId { | ||
268 | self.root | ||
269 | } | ||
270 | |||
271 | pub(crate) fn krate(&self) -> CrateId { | ||
272 | self.krate | ||
273 | } | ||
274 | |||
275 | pub(crate) fn block_id(&self) -> Option<BlockId> { | ||
276 | self.block.as_ref().map(|block| block.block) | ||
277 | } | ||
278 | |||
279 | pub(crate) fn prelude(&self) -> Option<ModuleId> { | ||
280 | self.prelude | ||
281 | } | ||
282 | |||
283 | pub(crate) fn extern_prelude(&self) -> impl Iterator<Item = (&Name, &ModuleDefId)> + '_ { | ||
284 | self.extern_prelude.iter() | ||
285 | } | ||
286 | |||
287 | pub fn module_id(&self, local_id: LocalModuleId) -> ModuleId { | ||
288 | let block = self.block.as_ref().map(|b| b.block); | ||
289 | ModuleId { krate: self.krate, local_id, block } | ||
290 | } | ||
291 | |||
292 | pub(crate) fn crate_root(&self, db: &dyn DefDatabase) -> ModuleId { | ||
293 | self.with_ancestor_maps(db, self.root, &mut |def_map, _module| { | ||
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") | ||
301 | } | ||
302 | |||
211 | pub(crate) fn resolve_path( | 303 | pub(crate) fn resolve_path( |
212 | &self, | 304 | &self, |
213 | db: &dyn DefDatabase, | 305 | db: &dyn DefDatabase, |
@@ -220,37 +312,68 @@ impl CrateDefMap { | |||
220 | (res.resolved_def, res.segment_index) | 312 | (res.resolved_def, res.segment_index) |
221 | } | 313 | } |
222 | 314 | ||
315 | /// Ascends the `DefMap` hierarchy and calls `f` with every `DefMap` and containing module. | ||
316 | /// | ||
317 | /// If `f` returns `Some(val)`, iteration is stopped and `Some(val)` is returned. If `f` returns | ||
318 | /// `None`, iteration continues. | ||
319 | pub fn with_ancestor_maps<T>( | ||
320 | &self, | ||
321 | db: &dyn DefDatabase, | ||
322 | local_mod: LocalModuleId, | ||
323 | f: &mut dyn FnMut(&DefMap, LocalModuleId) -> Option<T>, | ||
324 | ) -> Option<T> { | ||
325 | if let Some(it) = f(self, local_mod) { | ||
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 | ||
338 | } | ||
339 | |||
340 | /// If this `DefMap` is for a block expression, returns the module containing the block (which | ||
341 | /// might again be a block, or a module inside a block). | ||
342 | pub fn parent(&self) -> Option<ModuleId> { | ||
343 | Some(self.block?.parent) | ||
344 | } | ||
345 | |||
346 | /// Returns the module containing `local_mod`, either the parent `mod`, or the module containing | ||
347 | /// the block, if `self` corresponds to a block expression. | ||
348 | pub fn containing_module(&self, local_mod: LocalModuleId) -> Option<ModuleId> { | ||
349 | match &self[local_mod].parent { | ||
350 | Some(parent) => Some(self.module_id(*parent)), | ||
351 | None => match &self.block { | ||
352 | Some(block) => Some(block.parent), | ||
353 | None => None, | ||
354 | }, | ||
355 | } | ||
356 | } | ||
357 | |||
223 | // FIXME: this can use some more human-readable format (ideally, an IR | 358 | // FIXME: this can use some more human-readable format (ideally, an IR |
224 | // even), as this should be a great debugging aid. | 359 | // even), as this should be a great debugging aid. |
225 | pub fn dump(&self) -> String { | 360 | pub fn dump(&self, db: &dyn DefDatabase) -> String { |
226 | let mut buf = String::new(); | 361 | let mut buf = String::new(); |
227 | go(&mut buf, self, "crate", self.root); | 362 | let mut arc; |
363 | let mut current_map = self; | ||
364 | while let Some(block) = ¤t_map.block { | ||
365 | go(&mut buf, current_map, "block scope", current_map.root); | ||
366 | buf.push('\n'); | ||
367 | arc = block.parent.def_map(db); | ||
368 | current_map = &*arc; | ||
369 | } | ||
370 | go(&mut buf, current_map, "crate", current_map.root); | ||
228 | return buf; | 371 | return buf; |
229 | 372 | ||
230 | fn go(buf: &mut String, map: &CrateDefMap, path: &str, module: LocalModuleId) { | 373 | fn go(buf: &mut String, map: &DefMap, path: &str, module: LocalModuleId) { |
231 | format_to!(buf, "{}\n", path); | 374 | format_to!(buf, "{}\n", path); |
232 | 375 | ||
233 | let mut entries: Vec<_> = map.modules[module].scope.resolutions().collect(); | 376 | map.modules[module].scope.dump(buf); |
234 | entries.sort_by_key(|(name, _)| name.clone()); | ||
235 | |||
236 | for (name, def) in entries { | ||
237 | format_to!(buf, "{}:", name.map_or("_".to_string(), |name| name.to_string())); | ||
238 | |||
239 | if def.types.is_some() { | ||
240 | buf.push_str(" t"); | ||
241 | } | ||
242 | if def.values.is_some() { | ||
243 | buf.push_str(" v"); | ||
244 | } | ||
245 | if def.macros.is_some() { | ||
246 | buf.push_str(" m"); | ||
247 | } | ||
248 | if def.is_none() { | ||
249 | buf.push_str(" _"); | ||
250 | } | ||
251 | |||
252 | buf.push('\n'); | ||
253 | } | ||
254 | 377 | ||
255 | for (name, child) in map.modules[module].children.iter() { | 378 | for (name, child) in map.modules[module].children.iter() { |
256 | let path = format!("{}::{}", path, name); | 379 | let path = format!("{}::{}", path, name); |
@@ -280,6 +403,7 @@ impl ModuleData { | |||
280 | pub enum ModuleSource { | 403 | pub enum ModuleSource { |
281 | SourceFile(ast::SourceFile), | 404 | SourceFile(ast::SourceFile), |
282 | Module(ast::Module), | 405 | Module(ast::Module), |
406 | BlockExpr(ast::BlockExpr), | ||
283 | } | 407 | } |
284 | 408 | ||
285 | mod diagnostics { | 409 | mod diagnostics { |
@@ -305,6 +429,8 @@ mod diagnostics { | |||
305 | 429 | ||
306 | UnresolvedProcMacro { ast: MacroCallKind }, | 430 | UnresolvedProcMacro { ast: MacroCallKind }, |
307 | 431 | ||
432 | UnresolvedMacroCall { ast: AstId<ast::MacroCall> }, | ||
433 | |||
308 | MacroError { ast: MacroCallKind, message: String }, | 434 | MacroError { ast: MacroCallKind, message: String }, |
309 | } | 435 | } |
310 | 436 | ||
@@ -365,6 +491,13 @@ mod diagnostics { | |||
365 | Self { in_module: container, kind: DiagnosticKind::MacroError { ast, message } } | 491 | Self { in_module: container, kind: DiagnosticKind::MacroError { ast, message } } |
366 | } | 492 | } |
367 | 493 | ||
494 | pub(super) fn unresolved_macro_call( | ||
495 | container: LocalModuleId, | ||
496 | ast: AstId<ast::MacroCall>, | ||
497 | ) -> Self { | ||
498 | Self { in_module: container, kind: DiagnosticKind::UnresolvedMacroCall { ast } } | ||
499 | } | ||
500 | |||
368 | pub(super) fn add_to( | 501 | pub(super) fn add_to( |
369 | &self, | 502 | &self, |
370 | db: &dyn DefDatabase, | 503 | db: &dyn DefDatabase, |
@@ -477,6 +610,11 @@ mod diagnostics { | |||
477 | }); | 610 | }); |
478 | } | 611 | } |
479 | 612 | ||
613 | DiagnosticKind::UnresolvedMacroCall { ast } => { | ||
614 | let node = ast.to_node(db.upcast()); | ||
615 | sink.push(UnresolvedMacroCall { file: ast.file_id, node: AstPtr::new(&node) }); | ||
616 | } | ||
617 | |||
480 | DiagnosticKind::MacroError { ast, message } => { | 618 | DiagnosticKind::MacroError { ast, message } => { |
481 | let (file, ast) = match ast { | 619 | let (file, ast) = match ast { |
482 | MacroCallKind::FnLike(ast) => { | 620 | MacroCallKind::FnLike(ast) => { |