diff options
Diffstat (limited to 'crates/hir_def/src/nameres.rs')
-rw-r--r-- | crates/hir_def/src/nameres.rs | 150 |
1 files changed, 121 insertions, 29 deletions
diff --git a/crates/hir_def/src/nameres.rs b/crates/hir_def/src/nameres.rs index 50acc3f54..bd3ea9b8b 100644 --- a/crates/hir_def/src/nameres.rs +++ b/crates/hir_def/src/nameres.rs | |||
@@ -59,9 +59,10 @@ 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, AstNode}; |
65 | 66 | ||
66 | use crate::{ | 67 | use crate::{ |
67 | db::DefDatabase, | 68 | db::DefDatabase, |
@@ -74,21 +75,23 @@ use crate::{ | |||
74 | 75 | ||
75 | /// Contains all top-level defs from a macro-expanded crate | 76 | /// Contains all top-level defs from a macro-expanded crate |
76 | #[derive(Debug, PartialEq, Eq)] | 77 | #[derive(Debug, PartialEq, Eq)] |
77 | pub struct CrateDefMap { | 78 | pub struct DefMap { |
78 | pub root: LocalModuleId, | 79 | _c: Count<Self>, |
79 | pub modules: Arena<ModuleData>, | 80 | parent: Option<Arc<DefMap>>, |
80 | pub(crate) krate: CrateId, | 81 | root: LocalModuleId, |
82 | modules: Arena<ModuleData>, | ||
83 | krate: CrateId, | ||
81 | /// The prelude module for this crate. This either comes from an import | 84 | /// 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 | 85 | /// marked with the `prelude_import` attribute, or (in the normal case) from |
83 | /// a dependency (`std` or `core`). | 86 | /// a dependency (`std` or `core`). |
84 | pub(crate) prelude: Option<ModuleId>, | 87 | prelude: Option<ModuleId>, |
85 | pub(crate) extern_prelude: FxHashMap<Name, ModuleDefId>, | 88 | extern_prelude: FxHashMap<Name, ModuleDefId>, |
86 | 89 | ||
87 | edition: Edition, | 90 | edition: Edition, |
88 | diagnostics: Vec<DefDiagnostic>, | 91 | diagnostics: Vec<DefDiagnostic>, |
89 | } | 92 | } |
90 | 93 | ||
91 | impl std::ops::Index<LocalModuleId> for CrateDefMap { | 94 | impl std::ops::Index<LocalModuleId> for DefMap { |
92 | type Output = ModuleData; | 95 | type Output = ModuleData; |
93 | fn index(&self, id: LocalModuleId) -> &ModuleData { | 96 | fn index(&self, id: LocalModuleId) -> &ModuleData { |
94 | &self.modules[id] | 97 | &self.modules[id] |
@@ -109,6 +112,10 @@ pub enum ModuleOrigin { | |||
109 | Inline { | 112 | Inline { |
110 | definition: AstId<ast::Module>, | 113 | definition: AstId<ast::Module>, |
111 | }, | 114 | }, |
115 | /// Pseudo-module introduced by a block scope (contains only inner items). | ||
116 | BlockExpr { | ||
117 | block: AstId<ast::BlockExpr>, | ||
118 | }, | ||
112 | } | 119 | } |
113 | 120 | ||
114 | impl Default for ModuleOrigin { | 121 | impl Default for ModuleOrigin { |
@@ -122,7 +129,7 @@ impl ModuleOrigin { | |||
122 | match self { | 129 | match self { |
123 | ModuleOrigin::File { declaration: module, .. } | 130 | ModuleOrigin::File { declaration: module, .. } |
124 | | ModuleOrigin::Inline { definition: module, .. } => Some(*module), | 131 | | ModuleOrigin::Inline { definition: module, .. } => Some(*module), |
125 | ModuleOrigin::CrateRoot { .. } => None, | 132 | ModuleOrigin::CrateRoot { .. } | ModuleOrigin::BlockExpr { .. } => None, |
126 | } | 133 | } |
127 | } | 134 | } |
128 | 135 | ||
@@ -137,7 +144,7 @@ impl ModuleOrigin { | |||
137 | 144 | ||
138 | pub fn is_inline(&self) -> bool { | 145 | pub fn is_inline(&self) -> bool { |
139 | match self { | 146 | match self { |
140 | ModuleOrigin::Inline { .. } => true, | 147 | ModuleOrigin::Inline { .. } | ModuleOrigin::BlockExpr { .. } => true, |
141 | ModuleOrigin::CrateRoot { .. } | ModuleOrigin::File { .. } => false, | 148 | ModuleOrigin::CrateRoot { .. } | ModuleOrigin::File { .. } => false, |
142 | } | 149 | } |
143 | } | 150 | } |
@@ -155,6 +162,9 @@ impl ModuleOrigin { | |||
155 | definition.file_id, | 162 | definition.file_id, |
156 | ModuleSource::Module(definition.to_node(db.upcast())), | 163 | ModuleSource::Module(definition.to_node(db.upcast())), |
157 | ), | 164 | ), |
165 | ModuleOrigin::BlockExpr { block } => { | ||
166 | InFile::new(block.file_id, ModuleSource::BlockExpr(block.to_node(db.upcast()))) | ||
167 | } | ||
158 | } | 168 | } |
159 | } | 169 | } |
160 | } | 170 | } |
@@ -169,29 +179,56 @@ pub struct ModuleData { | |||
169 | pub origin: ModuleOrigin, | 179 | pub origin: ModuleOrigin, |
170 | } | 180 | } |
171 | 181 | ||
172 | impl CrateDefMap { | 182 | impl DefMap { |
173 | pub(crate) fn crate_def_map_query(db: &dyn DefDatabase, krate: CrateId) -> Arc<CrateDefMap> { | 183 | pub(crate) fn crate_def_map_query(db: &dyn DefDatabase, krate: CrateId) -> Arc<DefMap> { |
174 | let _p = profile::span("crate_def_map_query").detail(|| { | 184 | let _p = profile::span("crate_def_map_query").detail(|| { |
175 | db.crate_graph()[krate].display_name.as_deref().unwrap_or_default().to_string() | 185 | db.crate_graph()[krate].display_name.as_deref().unwrap_or_default().to_string() |
176 | }); | 186 | }); |
177 | let def_map = { | 187 | let edition = db.crate_graph()[krate].edition; |
178 | let edition = db.crate_graph()[krate].edition; | 188 | let def_map = DefMap::empty(krate, edition); |
179 | let mut modules: Arena<ModuleData> = Arena::default(); | 189 | 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) | 190 | Arc::new(def_map) |
193 | } | 191 | } |
194 | 192 | ||
193 | pub(crate) fn block_def_map_query( | ||
194 | db: &dyn DefDatabase, | ||
195 | krate: CrateId, | ||
196 | block: AstId<ast::BlockExpr>, | ||
197 | ) -> Arc<DefMap> { | ||
198 | let item_tree = db.item_tree(block.file_id); | ||
199 | let block_items = item_tree.inner_items_of_block(block.value); | ||
200 | |||
201 | let parent = parent_def_map(db, krate, block); | ||
202 | |||
203 | if block_items.is_empty() { | ||
204 | // If there are no inner items, nothing new is brought into scope, so we can just return | ||
205 | // the parent DefMap. This keeps DefMap parent chains short. | ||
206 | return parent; | ||
207 | } | ||
208 | |||
209 | let mut def_map = DefMap::empty(krate, parent.edition); | ||
210 | def_map.parent = Some(parent); | ||
211 | |||
212 | let def_map = collector::collect_defs(db, def_map, Some(block.value)); | ||
213 | Arc::new(def_map) | ||
214 | } | ||
215 | |||
216 | fn empty(krate: CrateId, edition: Edition) -> DefMap { | ||
217 | let mut modules: Arena<ModuleData> = Arena::default(); | ||
218 | let root = modules.alloc(ModuleData::default()); | ||
219 | DefMap { | ||
220 | _c: Count::new(), | ||
221 | parent: None, | ||
222 | krate, | ||
223 | edition, | ||
224 | extern_prelude: FxHashMap::default(), | ||
225 | prelude: None, | ||
226 | root, | ||
227 | modules, | ||
228 | diagnostics: Vec::new(), | ||
229 | } | ||
230 | } | ||
231 | |||
195 | pub fn add_diagnostics( | 232 | pub fn add_diagnostics( |
196 | &self, | 233 | &self, |
197 | db: &dyn DefDatabase, | 234 | db: &dyn DefDatabase, |
@@ -208,6 +245,26 @@ impl CrateDefMap { | |||
208 | .map(|(id, _data)| id) | 245 | .map(|(id, _data)| id) |
209 | } | 246 | } |
210 | 247 | ||
248 | pub fn modules(&self) -> impl Iterator<Item = (LocalModuleId, &ModuleData)> + '_ { | ||
249 | self.modules.iter() | ||
250 | } | ||
251 | |||
252 | pub fn root(&self) -> LocalModuleId { | ||
253 | self.root | ||
254 | } | ||
255 | |||
256 | pub(crate) fn krate(&self) -> CrateId { | ||
257 | self.krate | ||
258 | } | ||
259 | |||
260 | pub(crate) fn prelude(&self) -> Option<ModuleId> { | ||
261 | self.prelude | ||
262 | } | ||
263 | |||
264 | pub(crate) fn extern_prelude(&self) -> impl Iterator<Item = (&Name, &ModuleDefId)> + '_ { | ||
265 | self.extern_prelude.iter() | ||
266 | } | ||
267 | |||
211 | pub(crate) fn resolve_path( | 268 | pub(crate) fn resolve_path( |
212 | &self, | 269 | &self, |
213 | db: &dyn DefDatabase, | 270 | db: &dyn DefDatabase, |
@@ -224,10 +281,15 @@ impl CrateDefMap { | |||
224 | // even), as this should be a great debugging aid. | 281 | // even), as this should be a great debugging aid. |
225 | pub fn dump(&self) -> String { | 282 | pub fn dump(&self) -> String { |
226 | let mut buf = String::new(); | 283 | let mut buf = String::new(); |
227 | go(&mut buf, self, "crate", self.root); | 284 | let mut current_map = self; |
285 | while let Some(parent) = ¤t_map.parent { | ||
286 | go(&mut buf, current_map, "block scope", current_map.root); | ||
287 | current_map = &**parent; | ||
288 | } | ||
289 | go(&mut buf, current_map, "crate", current_map.root); | ||
228 | return buf; | 290 | return buf; |
229 | 291 | ||
230 | fn go(buf: &mut String, map: &CrateDefMap, path: &str, module: LocalModuleId) { | 292 | fn go(buf: &mut String, map: &DefMap, path: &str, module: LocalModuleId) { |
231 | format_to!(buf, "{}\n", path); | 293 | format_to!(buf, "{}\n", path); |
232 | 294 | ||
233 | let mut entries: Vec<_> = map.modules[module].scope.resolutions().collect(); | 295 | let mut entries: Vec<_> = map.modules[module].scope.resolutions().collect(); |
@@ -276,10 +338,40 @@ impl ModuleData { | |||
276 | } | 338 | } |
277 | } | 339 | } |
278 | 340 | ||
341 | fn parent_def_map( | ||
342 | db: &dyn DefDatabase, | ||
343 | krate: CrateId, | ||
344 | block: AstId<ast::BlockExpr>, | ||
345 | ) -> Arc<DefMap> { | ||
346 | // FIXME: store this info in the item tree instead of reparsing here | ||
347 | let ast_id_map = db.ast_id_map(block.file_id); | ||
348 | let block_ptr = ast_id_map.get(block.value); | ||
349 | let root = match db.parse_or_expand(block.file_id) { | ||
350 | Some(it) => it, | ||
351 | None => { | ||
352 | return Arc::new(DefMap::empty(krate, Edition::Edition2018)); | ||
353 | } | ||
354 | }; | ||
355 | let ast = block_ptr.to_node(&root); | ||
356 | |||
357 | for ancestor in ast.syntax().ancestors().skip(1) { | ||
358 | if let Some(block_expr) = ast::BlockExpr::cast(ancestor) { | ||
359 | let ancestor_id = ast_id_map.ast_id(&block_expr); | ||
360 | let ast_id = InFile::new(block.file_id, ancestor_id); | ||
361 | let parent_map = db.block_def_map(krate, ast_id); | ||
362 | return parent_map; | ||
363 | } | ||
364 | } | ||
365 | |||
366 | // No enclosing block scope, so the parent is the crate-level DefMap. | ||
367 | db.crate_def_map(krate) | ||
368 | } | ||
369 | |||
279 | #[derive(Debug, Clone, PartialEq, Eq)] | 370 | #[derive(Debug, Clone, PartialEq, Eq)] |
280 | pub enum ModuleSource { | 371 | pub enum ModuleSource { |
281 | SourceFile(ast::SourceFile), | 372 | SourceFile(ast::SourceFile), |
282 | Module(ast::Module), | 373 | Module(ast::Module), |
374 | BlockExpr(ast::BlockExpr), | ||
283 | } | 375 | } |
284 | 376 | ||
285 | mod diagnostics { | 377 | mod diagnostics { |