diff options
author | Aleksey Kladov <[email protected]> | 2019-03-14 09:54:03 +0000 |
---|---|---|
committer | Aleksey Kladov <[email protected]> | 2019-03-17 09:52:05 +0000 |
commit | c7259a899c1709753dcda0fb117e2f7cc30a4d6e (patch) | |
tree | 410be0a8db17aca2d9878b0b2ac36d1921660990 /crates | |
parent | 71e5adf694a4b253bc5bb48be96bb6ba08002d8c (diff) |
remove ItemMap
Diffstat (limited to 'crates')
-rw-r--r-- | crates/ra_hir/src/code_model_api.rs | 6 | ||||
-rw-r--r-- | crates/ra_hir/src/db.rs | 5 | ||||
-rw-r--r-- | crates/ra_hir/src/lib.rs | 2 | ||||
-rw-r--r-- | crates/ra_hir/src/nameres.rs | 539 | ||||
-rw-r--r-- | crates/ra_hir/src/nameres/crate_def_map.rs | 30 | ||||
-rw-r--r-- | crates/ra_hir/src/nameres/crate_def_map/collector.rs | 10 | ||||
-rw-r--r-- | crates/ra_hir/src/resolve.rs | 36 |
7 files changed, 59 insertions, 569 deletions
diff --git a/crates/ra_hir/src/code_model_api.rs b/crates/ra_hir/src/code_model_api.rs index ef69ef96a..86c26f1d8 100644 --- a/crates/ra_hir/src/code_model_api.rs +++ b/crates/ra_hir/src/code_model_api.rs | |||
@@ -173,7 +173,7 @@ impl Module { | |||
173 | 173 | ||
174 | /// Returns a `ModuleScope`: a set of items, visible in this module. | 174 | /// Returns a `ModuleScope`: a set of items, visible in this module. |
175 | pub fn scope(&self, db: &impl HirDatabase) -> ModuleScope { | 175 | pub fn scope(&self, db: &impl HirDatabase) -> ModuleScope { |
176 | db.item_map(self.krate)[self.module_id].clone() | 176 | db.crate_def_map(self.krate)[self.module_id].scope.clone() |
177 | } | 177 | } |
178 | 178 | ||
179 | pub fn problems(&self, db: &impl HirDatabase) -> Vec<(TreeArc<SyntaxNode>, Problem)> { | 179 | pub fn problems(&self, db: &impl HirDatabase) -> Vec<(TreeArc<SyntaxNode>, Problem)> { |
@@ -181,8 +181,8 @@ impl Module { | |||
181 | } | 181 | } |
182 | 182 | ||
183 | pub fn resolver(&self, db: &impl HirDatabase) -> Resolver { | 183 | pub fn resolver(&self, db: &impl HirDatabase) -> Resolver { |
184 | let item_map = db.item_map(self.krate); | 184 | let def_map = db.crate_def_map(self.krate); |
185 | Resolver::default().push_module_scope(item_map, *self) | 185 | Resolver::default().push_module_scope(def_map, self.module_id) |
186 | } | 186 | } |
187 | 187 | ||
188 | pub fn declarations(self, db: &impl HirDatabase) -> Vec<ModuleDef> { | 188 | pub fn declarations(self, db: &impl HirDatabase) -> Vec<ModuleDef> { |
diff --git a/crates/ra_hir/src/db.rs b/crates/ra_hir/src/db.rs index 423922a57..0190f4987 100644 --- a/crates/ra_hir/src/db.rs +++ b/crates/ra_hir/src/db.rs | |||
@@ -10,7 +10,7 @@ use crate::{ | |||
10 | Struct, Enum, StructField, | 10 | Struct, Enum, StructField, |
11 | Const, ConstSignature, Static, | 11 | Const, ConstSignature, Static, |
12 | macros::MacroExpansion, | 12 | macros::MacroExpansion, |
13 | nameres::{Namespace, ItemMap, lower::{LoweredModule, ImportSourceMap}, crate_def_map::{RawItems, CrateDefMap}}, | 13 | nameres::{Namespace, lower::{LoweredModule, ImportSourceMap}, crate_def_map::{RawItems, CrateDefMap}}, |
14 | ty::{InferenceResult, Ty, method_resolution::CrateImplBlocks, TypableDef, CallableDef, FnSig}, | 14 | ty::{InferenceResult, Ty, method_resolution::CrateImplBlocks, TypableDef, CallableDef, FnSig}, |
15 | adt::{StructData, EnumData}, | 15 | adt::{StructData, EnumData}, |
16 | impl_block::{ModuleImplBlocks, ImplSourceMap}, | 16 | impl_block::{ModuleImplBlocks, ImplSourceMap}, |
@@ -50,9 +50,6 @@ pub trait PersistentHirDatabase: SourceDatabase + AsRef<HirInterner> { | |||
50 | #[salsa::invoke(RawItems::raw_items_query)] | 50 | #[salsa::invoke(RawItems::raw_items_query)] |
51 | fn raw_items(&self, file_id: FileId) -> Arc<RawItems>; | 51 | fn raw_items(&self, file_id: FileId) -> Arc<RawItems>; |
52 | 52 | ||
53 | #[salsa::invoke(crate::nameres::ItemMap::item_map_query)] | ||
54 | fn item_map(&self, krate: Crate) -> Arc<ItemMap>; | ||
55 | |||
56 | #[salsa::invoke(CrateDefMap::crate_def_map_query)] | 53 | #[salsa::invoke(CrateDefMap::crate_def_map_query)] |
57 | fn crate_def_map(&self, krate: Crate) -> Arc<CrateDefMap>; | 54 | fn crate_def_map(&self, krate: Crate) -> Arc<CrateDefMap>; |
58 | 55 | ||
diff --git a/crates/ra_hir/src/lib.rs b/crates/ra_hir/src/lib.rs index 61db4f6cc..a188a3cc8 100644 --- a/crates/ra_hir/src/lib.rs +++ b/crates/ra_hir/src/lib.rs | |||
@@ -54,7 +54,7 @@ pub use self::{ | |||
54 | name::Name, | 54 | name::Name, |
55 | ids::{HirFileId, MacroCallId, MacroCallLoc, HirInterner}, | 55 | ids::{HirFileId, MacroCallId, MacroCallLoc, HirInterner}, |
56 | macros::{MacroDef, MacroInput, MacroExpansion}, | 56 | macros::{MacroDef, MacroInput, MacroExpansion}, |
57 | nameres::{ItemMap, PerNs, Namespace}, | 57 | nameres::{PerNs, Namespace}, |
58 | ty::{Ty, Substs, display::HirDisplay}, | 58 | ty::{Ty, Substs, display::HirDisplay}, |
59 | impl_block::{ImplBlock, ImplItem}, | 59 | impl_block::{ImplBlock, ImplItem}, |
60 | docs::{Docs, Documentation}, | 60 | docs::{Docs, Documentation}, |
diff --git a/crates/ra_hir/src/nameres.rs b/crates/ra_hir/src/nameres.rs index 59297425e..2248842de 100644 --- a/crates/ra_hir/src/nameres.rs +++ b/crates/ra_hir/src/nameres.rs | |||
@@ -17,43 +17,15 @@ | |||
17 | pub(crate) mod lower; | 17 | pub(crate) mod lower; |
18 | pub(crate) mod crate_def_map; | 18 | pub(crate) mod crate_def_map; |
19 | 19 | ||
20 | use std::{time, sync::Arc}; | 20 | use rustc_hash::FxHashMap; |
21 | |||
22 | use rustc_hash::{FxHashMap, FxHashSet}; | ||
23 | |||
24 | use ra_arena::map::ArenaMap; | ||
25 | use ra_db::Edition; | 21 | use ra_db::Edition; |
26 | use test_utils::tested_by; | ||
27 | 22 | ||
28 | use crate::{ | 23 | use crate::{ |
29 | Module, ModuleDef, | 24 | ModuleDef, Name, |
30 | Path, PathKind, PersistentHirDatabase, | 25 | nameres::lower::ImportId, |
31 | Crate, Name, | ||
32 | nameres::{ | ||
33 | crate_def_map::{CrateDefMap, ModuleId}, | ||
34 | lower::{ImportId, LoweredModule, ImportData} | ||
35 | }, | ||
36 | }; | 26 | }; |
37 | 27 | ||
38 | /// `ItemMap` is the result of module name resolution. It contains, for each | 28 | pub(crate) use self::crate_def_map::{CrateDefMap, ModuleId}; |
39 | /// module, the set of visible items. | ||
40 | #[derive(Debug, PartialEq, Eq)] | ||
41 | pub struct ItemMap { | ||
42 | edition: Edition, | ||
43 | /// The prelude module for this crate. This either comes from an import | ||
44 | /// marked with the `prelude_import` attribute, or (in the normal case) from | ||
45 | /// a dependency (`std` or `core`). | ||
46 | pub(crate) prelude: Option<Module>, | ||
47 | pub(crate) extern_prelude: FxHashMap<Name, ModuleDef>, | ||
48 | per_module: ArenaMap<ModuleId, ModuleScope>, | ||
49 | } | ||
50 | |||
51 | impl std::ops::Index<ModuleId> for ItemMap { | ||
52 | type Output = ModuleScope; | ||
53 | fn index(&self, id: ModuleId) -> &ModuleScope { | ||
54 | &self.per_module[id] | ||
55 | } | ||
56 | } | ||
57 | 29 | ||
58 | #[derive(Debug, Default, PartialEq, Eq, Clone)] | 30 | #[derive(Debug, Default, PartialEq, Eq, Clone)] |
59 | pub struct ModuleScope { | 31 | pub struct ModuleScope { |
@@ -158,292 +130,6 @@ impl<T> PerNs<T> { | |||
158 | } | 130 | } |
159 | } | 131 | } |
160 | 132 | ||
161 | struct Resolver<'a, DB> { | ||
162 | db: &'a DB, | ||
163 | input: &'a FxHashMap<ModuleId, Arc<LoweredModule>>, | ||
164 | krate: Crate, | ||
165 | def_map: Arc<CrateDefMap>, | ||
166 | processed_imports: FxHashSet<(ModuleId, ImportId)>, | ||
167 | /// If module `a` has `use b::*`, then this contains the mapping b -> a (and the import) | ||
168 | glob_imports: FxHashMap<ModuleId, Vec<(ModuleId, ImportId)>>, | ||
169 | result: ItemMap, | ||
170 | } | ||
171 | |||
172 | impl<'a, DB> Resolver<'a, DB> | ||
173 | where | ||
174 | DB: PersistentHirDatabase, | ||
175 | { | ||
176 | fn new( | ||
177 | db: &'a DB, | ||
178 | input: &'a FxHashMap<ModuleId, Arc<LoweredModule>>, | ||
179 | krate: Crate, | ||
180 | ) -> Resolver<'a, DB> { | ||
181 | Resolver { | ||
182 | db, | ||
183 | input, | ||
184 | krate, | ||
185 | def_map: db.crate_def_map(krate), | ||
186 | processed_imports: FxHashSet::default(), | ||
187 | glob_imports: FxHashMap::default(), | ||
188 | result: ItemMap { | ||
189 | edition: krate.edition(db), | ||
190 | prelude: None, | ||
191 | extern_prelude: FxHashMap::default(), | ||
192 | per_module: ArenaMap::default(), | ||
193 | }, | ||
194 | } | ||
195 | } | ||
196 | |||
197 | pub(crate) fn resolve(mut self) -> ItemMap { | ||
198 | self.populate_extern_prelude(); | ||
199 | for (&module_id, items) in self.input.iter() { | ||
200 | self.populate_module(module_id, Arc::clone(items)); | ||
201 | } | ||
202 | |||
203 | let mut iter = 0; | ||
204 | loop { | ||
205 | iter += 1; | ||
206 | if iter > 1000 { | ||
207 | panic!("failed to reach fixedpoint after 1000 iters") | ||
208 | } | ||
209 | let processed_imports_count = self.processed_imports.len(); | ||
210 | for &module_id in self.input.keys() { | ||
211 | self.db.check_canceled(); | ||
212 | self.resolve_imports(module_id); | ||
213 | } | ||
214 | if processed_imports_count == self.processed_imports.len() { | ||
215 | // no new imports resolved | ||
216 | break; | ||
217 | } | ||
218 | } | ||
219 | self.result | ||
220 | } | ||
221 | |||
222 | fn populate_extern_prelude(&mut self) { | ||
223 | for dep in self.krate.dependencies(self.db) { | ||
224 | log::debug!("crate dep {:?} -> {:?}", dep.name, dep.krate); | ||
225 | if let Some(module) = dep.krate.root_module(self.db) { | ||
226 | self.result.extern_prelude.insert(dep.name.clone(), module.into()); | ||
227 | } | ||
228 | // look for the prelude | ||
229 | if self.result.prelude.is_none() { | ||
230 | let item_map = self.db.item_map(dep.krate); | ||
231 | if item_map.prelude.is_some() { | ||
232 | self.result.prelude = item_map.prelude; | ||
233 | } | ||
234 | } | ||
235 | } | ||
236 | } | ||
237 | |||
238 | fn populate_module(&mut self, module_id: ModuleId, input: Arc<LoweredModule>) { | ||
239 | let mut module_items = ModuleScope::default(); | ||
240 | for (import_id, import_data) in input.imports.iter() { | ||
241 | if let Some(last_segment) = import_data.path.segments.iter().last() { | ||
242 | if !import_data.is_glob { | ||
243 | let name = | ||
244 | import_data.alias.clone().unwrap_or_else(|| last_segment.name.clone()); | ||
245 | module_items | ||
246 | .items | ||
247 | .insert(name, Resolution { def: PerNs::none(), import: Some(import_id) }); | ||
248 | } | ||
249 | } | ||
250 | } | ||
251 | // Populate explicitly declared items, except modules | ||
252 | for (name, &def) in input.declarations.iter() { | ||
253 | let resolution = Resolution { def, import: None }; | ||
254 | module_items.items.insert(name.clone(), resolution); | ||
255 | } | ||
256 | |||
257 | // Populate modules | ||
258 | for (name, module_id) in self.def_map[module_id].children.iter() { | ||
259 | let module = Module { module_id: *module_id, krate: self.krate }; | ||
260 | self.add_module_item(&mut module_items, name.clone(), PerNs::types(module.into())); | ||
261 | } | ||
262 | |||
263 | self.result.per_module.insert(module_id, module_items); | ||
264 | } | ||
265 | |||
266 | fn add_module_item(&self, module_items: &mut ModuleScope, name: Name, def: PerNs<ModuleDef>) { | ||
267 | let resolution = Resolution { def, import: None }; | ||
268 | module_items.items.insert(name, resolution); | ||
269 | } | ||
270 | |||
271 | fn resolve_imports(&mut self, module_id: ModuleId) { | ||
272 | for (import_id, import_data) in self.input[&module_id].imports.iter() { | ||
273 | if self.processed_imports.contains(&(module_id, import_id)) { | ||
274 | // already done | ||
275 | continue; | ||
276 | } | ||
277 | if self.resolve_import(module_id, import_id, import_data) == ReachedFixedPoint::Yes { | ||
278 | log::debug!("import {:?} resolved (or definite error)", import_id); | ||
279 | self.processed_imports.insert((module_id, import_id)); | ||
280 | } | ||
281 | } | ||
282 | } | ||
283 | |||
284 | fn resolve_import( | ||
285 | &mut self, | ||
286 | module_id: ModuleId, | ||
287 | import_id: ImportId, | ||
288 | import: &ImportData, | ||
289 | ) -> ReachedFixedPoint { | ||
290 | log::debug!("resolving import: {:?} ({:?})", import, self.result.edition); | ||
291 | let original_module = Module { krate: self.krate, module_id }; | ||
292 | |||
293 | let (def, reached_fixedpoint) = if import.is_extern_crate { | ||
294 | let res = self.result.resolve_name_in_extern_prelude( | ||
295 | &import | ||
296 | .path | ||
297 | .as_ident() | ||
298 | .expect("extern crate should have been desugared to one-element path"), | ||
299 | ); | ||
300 | (res, if res.is_none() { ReachedFixedPoint::No } else { ReachedFixedPoint::Yes }) | ||
301 | } else { | ||
302 | let res = self.result.resolve_path_fp( | ||
303 | self.db, | ||
304 | ResolveMode::Import, | ||
305 | original_module, | ||
306 | &import.path, | ||
307 | ); | ||
308 | |||
309 | (res.resolved_def, res.reached_fixedpoint) | ||
310 | }; | ||
311 | |||
312 | if reached_fixedpoint != ReachedFixedPoint::Yes { | ||
313 | return reached_fixedpoint; | ||
314 | } | ||
315 | |||
316 | if import.is_glob { | ||
317 | log::debug!("glob import: {:?}", import); | ||
318 | match def.take_types() { | ||
319 | Some(ModuleDef::Module(m)) => { | ||
320 | if import.is_prelude { | ||
321 | tested_by!(std_prelude); | ||
322 | self.result.prelude = Some(m); | ||
323 | } else if m.krate != self.krate { | ||
324 | tested_by!(glob_across_crates); | ||
325 | // glob import from other crate => we can just import everything once | ||
326 | let item_map = self.db.item_map(m.krate); | ||
327 | let scope = &item_map[m.module_id]; | ||
328 | let items = scope | ||
329 | .items | ||
330 | .iter() | ||
331 | .map(|(name, res)| (name.clone(), res.clone())) | ||
332 | .collect::<Vec<_>>(); | ||
333 | self.update(module_id, Some(import_id), &items); | ||
334 | } else { | ||
335 | // glob import from same crate => we do an initial | ||
336 | // import, and then need to propagate any further | ||
337 | // additions | ||
338 | let scope = &self.result[m.module_id]; | ||
339 | let items = scope | ||
340 | .items | ||
341 | .iter() | ||
342 | .map(|(name, res)| (name.clone(), res.clone())) | ||
343 | .collect::<Vec<_>>(); | ||
344 | self.update(module_id, Some(import_id), &items); | ||
345 | // record the glob import in case we add further items | ||
346 | self.glob_imports | ||
347 | .entry(m.module_id) | ||
348 | .or_default() | ||
349 | .push((module_id, import_id)); | ||
350 | } | ||
351 | } | ||
352 | Some(ModuleDef::Enum(e)) => { | ||
353 | tested_by!(glob_enum); | ||
354 | // glob import from enum => just import all the variants | ||
355 | let variants = e.variants(self.db); | ||
356 | let resolutions = variants | ||
357 | .into_iter() | ||
358 | .filter_map(|variant| { | ||
359 | let res = Resolution { | ||
360 | def: PerNs::both(variant.into(), variant.into()), | ||
361 | import: Some(import_id), | ||
362 | }; | ||
363 | let name = variant.name(self.db)?; | ||
364 | Some((name, res)) | ||
365 | }) | ||
366 | .collect::<Vec<_>>(); | ||
367 | self.update(module_id, Some(import_id), &resolutions); | ||
368 | } | ||
369 | Some(d) => { | ||
370 | log::debug!("glob import {:?} from non-module/enum {:?}", import, d); | ||
371 | } | ||
372 | None => { | ||
373 | log::debug!("glob import {:?} didn't resolve as type", import); | ||
374 | } | ||
375 | } | ||
376 | } else { | ||
377 | let last_segment = import.path.segments.last().unwrap(); | ||
378 | let name = import.alias.clone().unwrap_or_else(|| last_segment.name.clone()); | ||
379 | log::debug!("resolved import {:?} ({:?}) to {:?}", name, import, def); | ||
380 | |||
381 | // extern crates in the crate root are special-cased to insert entries into the extern prelude: rust-lang/rust#54658 | ||
382 | if let Some(root_module) = self.krate.root_module(self.db) { | ||
383 | if import.is_extern_crate && module_id == root_module.module_id { | ||
384 | if let Some(def) = def.take_types() { | ||
385 | self.result.extern_prelude.insert(name.clone(), def); | ||
386 | } | ||
387 | } | ||
388 | } | ||
389 | let resolution = Resolution { def, import: Some(import_id) }; | ||
390 | self.update(module_id, None, &[(name, resolution)]); | ||
391 | } | ||
392 | reached_fixedpoint | ||
393 | } | ||
394 | |||
395 | fn update( | ||
396 | &mut self, | ||
397 | module_id: ModuleId, | ||
398 | import: Option<ImportId>, | ||
399 | resolutions: &[(Name, Resolution)], | ||
400 | ) { | ||
401 | self.update_recursive(module_id, import, resolutions, 0) | ||
402 | } | ||
403 | |||
404 | fn update_recursive( | ||
405 | &mut self, | ||
406 | module_id: ModuleId, | ||
407 | import: Option<ImportId>, | ||
408 | resolutions: &[(Name, Resolution)], | ||
409 | depth: usize, | ||
410 | ) { | ||
411 | if depth > 100 { | ||
412 | // prevent stack overflows (but this shouldn't be possible) | ||
413 | panic!("infinite recursion in glob imports!"); | ||
414 | } | ||
415 | let module_items = self.result.per_module.get_mut(module_id).unwrap(); | ||
416 | let mut changed = false; | ||
417 | for (name, res) in resolutions { | ||
418 | let existing = module_items.items.entry(name.clone()).or_default(); | ||
419 | if existing.def.types.is_none() && res.def.types.is_some() { | ||
420 | existing.def.types = res.def.types; | ||
421 | existing.import = import.or(res.import); | ||
422 | changed = true; | ||
423 | } | ||
424 | if existing.def.values.is_none() && res.def.values.is_some() { | ||
425 | existing.def.values = res.def.values; | ||
426 | existing.import = import.or(res.import); | ||
427 | changed = true; | ||
428 | } | ||
429 | } | ||
430 | if !changed { | ||
431 | return; | ||
432 | } | ||
433 | let glob_imports = self | ||
434 | .glob_imports | ||
435 | .get(&module_id) | ||
436 | .into_iter() | ||
437 | .flat_map(|v| v.iter()) | ||
438 | .cloned() | ||
439 | .collect::<Vec<_>>(); | ||
440 | for (glob_importing_module, glob_import) in glob_imports { | ||
441 | // We pass the glob import so that the tracked import in those modules is that glob import | ||
442 | self.update_recursive(glob_importing_module, Some(glob_import), resolutions, depth + 1); | ||
443 | } | ||
444 | } | ||
445 | } | ||
446 | |||
447 | #[derive(Debug, Clone)] | 133 | #[derive(Debug, Clone)] |
448 | struct ResolvePathResult { | 134 | struct ResolvePathResult { |
449 | resolved_def: PerNs<ModuleDef>, | 135 | resolved_def: PerNs<ModuleDef>, |
@@ -476,220 +162,3 @@ enum ReachedFixedPoint { | |||
476 | Yes, | 162 | Yes, |
477 | No, | 163 | No, |
478 | } | 164 | } |
479 | |||
480 | impl ItemMap { | ||
481 | pub(crate) fn item_map_query(db: &impl PersistentHirDatabase, krate: Crate) -> Arc<ItemMap> { | ||
482 | let start = time::Instant::now(); | ||
483 | let def_map = db.crate_def_map(krate); | ||
484 | let input = def_map | ||
485 | .modules() | ||
486 | .map(|module_id| (module_id, db.lower_module(Module { krate, module_id }))) | ||
487 | .collect::<FxHashMap<_, _>>(); | ||
488 | |||
489 | let resolver = Resolver::new(db, &input, krate); | ||
490 | let res = resolver.resolve(); | ||
491 | let elapsed = start.elapsed(); | ||
492 | log::info!("item_map: {:?}", elapsed); | ||
493 | Arc::new(res) | ||
494 | } | ||
495 | |||
496 | pub(crate) fn resolve_path( | ||
497 | &self, | ||
498 | db: &impl PersistentHirDatabase, | ||
499 | original_module: Module, | ||
500 | path: &Path, | ||
501 | ) -> (PerNs<ModuleDef>, Option<usize>) { | ||
502 | let res = self.resolve_path_fp(db, ResolveMode::Other, original_module, path); | ||
503 | (res.resolved_def, res.segment_index) | ||
504 | } | ||
505 | |||
506 | fn resolve_in_prelude( | ||
507 | &self, | ||
508 | db: &impl PersistentHirDatabase, | ||
509 | original_module: Module, | ||
510 | name: &Name, | ||
511 | ) -> PerNs<ModuleDef> { | ||
512 | if let Some(prelude) = self.prelude { | ||
513 | let resolution = if prelude.krate == original_module.krate { | ||
514 | self[prelude.module_id].items.get(name).cloned() | ||
515 | } else { | ||
516 | db.item_map(prelude.krate)[prelude.module_id].items.get(name).cloned() | ||
517 | }; | ||
518 | resolution.map(|r| r.def).unwrap_or_else(PerNs::none) | ||
519 | } else { | ||
520 | PerNs::none() | ||
521 | } | ||
522 | } | ||
523 | |||
524 | pub(crate) fn resolve_name_in_module( | ||
525 | &self, | ||
526 | db: &impl PersistentHirDatabase, | ||
527 | module: Module, | ||
528 | name: &Name, | ||
529 | ) -> PerNs<ModuleDef> { | ||
530 | // Resolve in: | ||
531 | // - current module / scope | ||
532 | // - extern prelude | ||
533 | // - std prelude | ||
534 | let from_scope = self[module.module_id].items.get(name).map_or(PerNs::none(), |it| it.def); | ||
535 | let from_extern_prelude = | ||
536 | self.extern_prelude.get(name).map_or(PerNs::none(), |&it| PerNs::types(it)); | ||
537 | let from_prelude = self.resolve_in_prelude(db, module, name); | ||
538 | |||
539 | from_scope.or(from_extern_prelude).or(from_prelude) | ||
540 | } | ||
541 | |||
542 | fn resolve_name_in_extern_prelude(&self, name: &Name) -> PerNs<ModuleDef> { | ||
543 | self.extern_prelude.get(name).map_or(PerNs::none(), |&it| PerNs::types(it)) | ||
544 | } | ||
545 | |||
546 | fn resolve_name_in_crate_root_or_extern_prelude( | ||
547 | &self, | ||
548 | db: &impl PersistentHirDatabase, | ||
549 | module: Module, | ||
550 | name: &Name, | ||
551 | ) -> PerNs<ModuleDef> { | ||
552 | let crate_root = module.crate_root(db); | ||
553 | let from_crate_root = | ||
554 | self[crate_root.module_id].items.get(name).map_or(PerNs::none(), |it| it.def); | ||
555 | let from_extern_prelude = self.resolve_name_in_extern_prelude(name); | ||
556 | |||
557 | from_crate_root.or(from_extern_prelude) | ||
558 | } | ||
559 | |||
560 | // Returns Yes if we are sure that additions to `ItemMap` wouldn't change | ||
561 | // the result. | ||
562 | fn resolve_path_fp( | ||
563 | &self, | ||
564 | db: &impl PersistentHirDatabase, | ||
565 | mode: ResolveMode, | ||
566 | original_module: Module, | ||
567 | path: &Path, | ||
568 | ) -> ResolvePathResult { | ||
569 | let mut segments = path.segments.iter().enumerate(); | ||
570 | let mut curr_per_ns: PerNs<ModuleDef> = match path.kind { | ||
571 | PathKind::Crate => PerNs::types(original_module.crate_root(db).into()), | ||
572 | PathKind::Self_ => PerNs::types(original_module.into()), | ||
573 | // plain import or absolute path in 2015: crate-relative with | ||
574 | // fallback to extern prelude (with the simplification in | ||
575 | // rust-lang/rust#57745) | ||
576 | // TODO there must be a nicer way to write this condition | ||
577 | PathKind::Plain | PathKind::Abs | ||
578 | if self.edition == Edition::Edition2015 | ||
579 | && (path.kind == PathKind::Abs || mode == ResolveMode::Import) => | ||
580 | { | ||
581 | let segment = match segments.next() { | ||
582 | Some((_, segment)) => segment, | ||
583 | None => return ResolvePathResult::empty(ReachedFixedPoint::Yes), | ||
584 | }; | ||
585 | log::debug!("resolving {:?} in crate root (+ extern prelude)", segment); | ||
586 | self.resolve_name_in_crate_root_or_extern_prelude( | ||
587 | db, | ||
588 | original_module, | ||
589 | &segment.name, | ||
590 | ) | ||
591 | } | ||
592 | PathKind::Plain => { | ||
593 | let segment = match segments.next() { | ||
594 | Some((_, segment)) => segment, | ||
595 | None => return ResolvePathResult::empty(ReachedFixedPoint::Yes), | ||
596 | }; | ||
597 | log::debug!("resolving {:?} in module", segment); | ||
598 | self.resolve_name_in_module(db, original_module, &segment.name) | ||
599 | } | ||
600 | PathKind::Super => { | ||
601 | if let Some(p) = original_module.parent(db) { | ||
602 | PerNs::types(p.into()) | ||
603 | } else { | ||
604 | log::debug!("super path in root module"); | ||
605 | return ResolvePathResult::empty(ReachedFixedPoint::Yes); | ||
606 | } | ||
607 | } | ||
608 | PathKind::Abs => { | ||
609 | // 2018-style absolute path -- only extern prelude | ||
610 | let segment = match segments.next() { | ||
611 | Some((_, segment)) => segment, | ||
612 | None => return ResolvePathResult::empty(ReachedFixedPoint::Yes), | ||
613 | }; | ||
614 | if let Some(def) = self.extern_prelude.get(&segment.name) { | ||
615 | log::debug!("absolute path {:?} resolved to crate {:?}", path, def); | ||
616 | PerNs::types(*def) | ||
617 | } else { | ||
618 | return ResolvePathResult::empty(ReachedFixedPoint::No); // extern crate declarations can add to the extern prelude | ||
619 | } | ||
620 | } | ||
621 | }; | ||
622 | |||
623 | for (i, segment) in segments { | ||
624 | let curr = match curr_per_ns.as_ref().take_types() { | ||
625 | Some(r) => r, | ||
626 | None => { | ||
627 | // we still have path segments left, but the path so far | ||
628 | // didn't resolve in the types namespace => no resolution | ||
629 | // (don't break here because `curr_per_ns` might contain | ||
630 | // something in the value namespace, and it would be wrong | ||
631 | // to return that) | ||
632 | return ResolvePathResult::empty(ReachedFixedPoint::No); | ||
633 | } | ||
634 | }; | ||
635 | // resolve segment in curr | ||
636 | |||
637 | curr_per_ns = match curr { | ||
638 | ModuleDef::Module(module) => { | ||
639 | if module.krate != original_module.krate { | ||
640 | let path = Path { | ||
641 | segments: path.segments[i..].iter().cloned().collect(), | ||
642 | kind: PathKind::Self_, | ||
643 | }; | ||
644 | log::debug!("resolving {:?} in other crate", path); | ||
645 | let item_map = db.item_map(module.krate); | ||
646 | let (def, s) = item_map.resolve_path(db, *module, &path); | ||
647 | return ResolvePathResult::with( | ||
648 | def, | ||
649 | ReachedFixedPoint::Yes, | ||
650 | s.map(|s| s + i), | ||
651 | ); | ||
652 | } | ||
653 | |||
654 | match self[module.module_id].items.get(&segment.name) { | ||
655 | Some(res) if !res.def.is_none() => res.def, | ||
656 | _ => { | ||
657 | log::debug!("path segment {:?} not found", segment.name); | ||
658 | return ResolvePathResult::empty(ReachedFixedPoint::No); | ||
659 | } | ||
660 | } | ||
661 | } | ||
662 | ModuleDef::Enum(e) => { | ||
663 | // enum variant | ||
664 | tested_by!(can_import_enum_variant); | ||
665 | match e.variant(db, &segment.name) { | ||
666 | Some(variant) => PerNs::both(variant.into(), variant.into()), | ||
667 | None => { | ||
668 | return ResolvePathResult::with( | ||
669 | PerNs::types((*e).into()), | ||
670 | ReachedFixedPoint::Yes, | ||
671 | Some(i), | ||
672 | ); | ||
673 | } | ||
674 | } | ||
675 | } | ||
676 | s => { | ||
677 | // could be an inherent method call in UFCS form | ||
678 | // (`Struct::method`), or some other kind of associated item | ||
679 | log::debug!( | ||
680 | "path segment {:?} resolved to non-module {:?}, but is not last", | ||
681 | segment.name, | ||
682 | curr, | ||
683 | ); | ||
684 | |||
685 | return ResolvePathResult::with( | ||
686 | PerNs::types((*s).into()), | ||
687 | ReachedFixedPoint::Yes, | ||
688 | Some(i), | ||
689 | ); | ||
690 | } | ||
691 | }; | ||
692 | } | ||
693 | ResolvePathResult::with(curr_per_ns, ReachedFixedPoint::Yes, None) | ||
694 | } | ||
695 | } | ||
diff --git a/crates/ra_hir/src/nameres/crate_def_map.rs b/crates/ra_hir/src/nameres/crate_def_map.rs index 37b36719f..cc4955053 100644 --- a/crates/ra_hir/src/nameres/crate_def_map.rs +++ b/crates/ra_hir/src/nameres/crate_def_map.rs | |||
@@ -149,8 +149,16 @@ impl CrateDefMap { | |||
149 | &self.problems | 149 | &self.problems |
150 | } | 150 | } |
151 | 151 | ||
152 | pub(crate) fn modules<'a>(&'a self) -> impl Iterator<Item = ModuleId> + 'a { | 152 | pub(crate) fn mk_module(&self, module_id: ModuleId) -> Module { |
153 | self.modules.iter().map(|(id, _data)| id) | 153 | Module { krate: self.krate, module_id } |
154 | } | ||
155 | |||
156 | pub(crate) fn prelude(&self) -> Option<Module> { | ||
157 | self.prelude | ||
158 | } | ||
159 | |||
160 | pub(crate) fn extern_prelude(&self) -> &FxHashMap<Name, ModuleDef> { | ||
161 | &self.extern_prelude | ||
154 | } | 162 | } |
155 | 163 | ||
156 | pub(crate) fn find_module_by_source( | 164 | pub(crate) fn find_module_by_source( |
@@ -169,6 +177,16 @@ impl CrateDefMap { | |||
169 | Some(module_id) | 177 | Some(module_id) |
170 | } | 178 | } |
171 | 179 | ||
180 | pub(crate) fn resolve_path( | ||
181 | &self, | ||
182 | db: &impl PersistentHirDatabase, | ||
183 | original_module: ModuleId, | ||
184 | path: &Path, | ||
185 | ) -> (PerNs<ModuleDef>, Option<usize>) { | ||
186 | let res = self.resolve_path_fp(db, ResolveMode::Other, original_module, path); | ||
187 | (res.resolved_def, res.segment_index) | ||
188 | } | ||
189 | |||
172 | // Returns Yes if we are sure that additions to `ItemMap` wouldn't change | 190 | // Returns Yes if we are sure that additions to `ItemMap` wouldn't change |
173 | // the result. | 191 | // the result. |
174 | fn resolve_path_fp( | 192 | fn resolve_path_fp( |
@@ -254,8 +272,8 @@ impl CrateDefMap { | |||
254 | kind: PathKind::Self_, | 272 | kind: PathKind::Self_, |
255 | }; | 273 | }; |
256 | log::debug!("resolving {:?} in other crate", path); | 274 | log::debug!("resolving {:?} in other crate", path); |
257 | let item_map = db.item_map(module.krate); | 275 | let defp_map = db.crate_def_map(module.krate); |
258 | let (def, s) = item_map.resolve_path(db, *module, &path); | 276 | let (def, s) = defp_map.resolve_path(db, module.module_id, &path); |
259 | return ResolvePathResult::with( | 277 | return ResolvePathResult::with( |
260 | def, | 278 | def, |
261 | ReachedFixedPoint::Yes, | 279 | ReachedFixedPoint::Yes, |
@@ -313,7 +331,7 @@ impl CrateDefMap { | |||
313 | from_crate_root.or(from_extern_prelude) | 331 | from_crate_root.or(from_extern_prelude) |
314 | } | 332 | } |
315 | 333 | ||
316 | fn resolve_name_in_module( | 334 | pub(crate) fn resolve_name_in_module( |
317 | &self, | 335 | &self, |
318 | db: &impl PersistentHirDatabase, | 336 | db: &impl PersistentHirDatabase, |
319 | module: ModuleId, | 337 | module: ModuleId, |
@@ -340,7 +358,7 @@ impl CrateDefMap { | |||
340 | let resolution = if prelude.krate == self.krate { | 358 | let resolution = if prelude.krate == self.krate { |
341 | self[prelude.module_id].scope.items.get(name).cloned() | 359 | self[prelude.module_id].scope.items.get(name).cloned() |
342 | } else { | 360 | } else { |
343 | db.item_map(prelude.krate)[prelude.module_id].items.get(name).cloned() | 361 | db.crate_def_map(prelude.krate)[prelude.module_id].scope.items.get(name).cloned() |
344 | }; | 362 | }; |
345 | resolution.map(|r| r.def).unwrap_or_else(PerNs::none) | 363 | resolution.map(|r| r.def).unwrap_or_else(PerNs::none) |
346 | } else { | 364 | } else { |
diff --git a/crates/ra_hir/src/nameres/crate_def_map/collector.rs b/crates/ra_hir/src/nameres/crate_def_map/collector.rs index 68f74b866..8b727e2c9 100644 --- a/crates/ra_hir/src/nameres/crate_def_map/collector.rs +++ b/crates/ra_hir/src/nameres/crate_def_map/collector.rs | |||
@@ -26,9 +26,9 @@ pub(super) fn collect_defs( | |||
26 | } | 26 | } |
27 | // look for the prelude | 27 | // look for the prelude |
28 | if def_map.prelude.is_none() { | 28 | if def_map.prelude.is_none() { |
29 | let item_map = db.item_map(dep.krate); | 29 | let map = db.crate_def_map(dep.krate); |
30 | if item_map.prelude.is_some() { | 30 | if map.prelude.is_some() { |
31 | def_map.prelude = item_map.prelude; | 31 | def_map.prelude = map.prelude; |
32 | } | 32 | } |
33 | } | 33 | } |
34 | } | 34 | } |
@@ -162,8 +162,8 @@ where | |||
162 | } else if m.krate != self.def_map.krate { | 162 | } else if m.krate != self.def_map.krate { |
163 | tested_by!(glob_across_crates); | 163 | tested_by!(glob_across_crates); |
164 | // glob import from other crate => we can just import everything once | 164 | // glob import from other crate => we can just import everything once |
165 | let item_map = self.db.item_map(m.krate); | 165 | let item_map = self.db.crate_def_map(m.krate); |
166 | let scope = &item_map[m.module_id]; | 166 | let scope = &item_map[m.module_id].scope; |
167 | let items = scope | 167 | let items = scope |
168 | .items | 168 | .items |
169 | .iter() | 169 | .iter() |
diff --git a/crates/ra_hir/src/resolve.rs b/crates/ra_hir/src/resolve.rs index 57e7d0b9a..e85447eeb 100644 --- a/crates/ra_hir/src/resolve.rs +++ b/crates/ra_hir/src/resolve.rs | |||
@@ -4,10 +4,10 @@ use std::sync::Arc; | |||
4 | use rustc_hash::FxHashMap; | 4 | use rustc_hash::FxHashMap; |
5 | 5 | ||
6 | use crate::{ | 6 | use crate::{ |
7 | ModuleDef, Module, | 7 | ModuleDef, |
8 | db::HirDatabase, | 8 | db::HirDatabase, |
9 | name::{Name, KnownName}, | 9 | name::{Name, KnownName}, |
10 | nameres::{PerNs, ItemMap}, | 10 | nameres::{PerNs, CrateDefMap, ModuleId}, |
11 | generics::GenericParams, | 11 | generics::GenericParams, |
12 | expr::{scope::{ExprScopes, ScopeId}, PatId, Body}, | 12 | expr::{scope::{ExprScopes, ScopeId}, PatId, Body}, |
13 | impl_block::ImplBlock, | 13 | impl_block::ImplBlock, |
@@ -22,8 +22,8 @@ pub struct Resolver { | |||
22 | // TODO how to store these best | 22 | // TODO how to store these best |
23 | #[derive(Debug, Clone)] | 23 | #[derive(Debug, Clone)] |
24 | pub(crate) struct ModuleItemMap { | 24 | pub(crate) struct ModuleItemMap { |
25 | item_map: Arc<ItemMap>, | 25 | crate_def_map: Arc<CrateDefMap>, |
26 | module: Module, | 26 | module_id: ModuleId, |
27 | } | 27 | } |
28 | 28 | ||
29 | #[derive(Debug, Clone)] | 29 | #[derive(Debug, Clone)] |
@@ -175,9 +175,9 @@ impl Resolver { | |||
175 | names | 175 | names |
176 | } | 176 | } |
177 | 177 | ||
178 | fn module(&self) -> Option<(&ItemMap, Module)> { | 178 | fn module(&self) -> Option<(&CrateDefMap, ModuleId)> { |
179 | self.scopes.iter().rev().find_map(|scope| match scope { | 179 | self.scopes.iter().rev().find_map(|scope| match scope { |
180 | Scope::ModuleScope(m) => Some((&*m.item_map, m.module.clone())), | 180 | Scope::ModuleScope(m) => Some((&*m.crate_def_map, m.module_id)), |
181 | 181 | ||
182 | _ => None, | 182 | _ => None, |
183 | }) | 183 | }) |
@@ -206,8 +206,12 @@ impl Resolver { | |||
206 | self.push_scope(Scope::ImplBlockScope(impl_block)) | 206 | self.push_scope(Scope::ImplBlockScope(impl_block)) |
207 | } | 207 | } |
208 | 208 | ||
209 | pub(crate) fn push_module_scope(self, item_map: Arc<ItemMap>, module: Module) -> Resolver { | 209 | pub(crate) fn push_module_scope( |
210 | self.push_scope(Scope::ModuleScope(ModuleItemMap { item_map, module })) | 210 | self, |
211 | crate_def_map: Arc<CrateDefMap>, | ||
212 | module_id: ModuleId, | ||
213 | ) -> Resolver { | ||
214 | self.push_scope(Scope::ModuleScope(ModuleItemMap { crate_def_map, module_id })) | ||
211 | } | 215 | } |
212 | 216 | ||
213 | pub(crate) fn push_expr_scope( | 217 | pub(crate) fn push_expr_scope( |
@@ -224,9 +228,11 @@ impl Scope { | |||
224 | match self { | 228 | match self { |
225 | Scope::ModuleScope(m) => { | 229 | Scope::ModuleScope(m) => { |
226 | if let Some(KnownName::SelfParam) = name.as_known_name() { | 230 | if let Some(KnownName::SelfParam) = name.as_known_name() { |
227 | PerNs::types(Resolution::Def(m.module.into())) | 231 | PerNs::types(Resolution::Def(m.crate_def_map.mk_module(m.module_id).into())) |
228 | } else { | 232 | } else { |
229 | m.item_map.resolve_name_in_module(db, m.module, name).map(Resolution::Def) | 233 | m.crate_def_map |
234 | .resolve_name_in_module(db, m.module_id, name) | ||
235 | .map(Resolution::Def) | ||
230 | } | 236 | } |
231 | } | 237 | } |
232 | Scope::GenericParams(gp) => match gp.find_by_name(name) { | 238 | Scope::GenericParams(gp) => match gp.find_by_name(name) { |
@@ -261,15 +267,15 @@ impl Scope { | |||
261 | // def: m.module.into(), | 267 | // def: m.module.into(), |
262 | // }), | 268 | // }), |
263 | // ); | 269 | // ); |
264 | m.item_map[m.module.module_id].entries().for_each(|(name, res)| { | 270 | m.crate_def_map[m.module_id].scope.entries().for_each(|(name, res)| { |
265 | f(name.clone(), res.def.map(Resolution::Def)); | 271 | f(name.clone(), res.def.map(Resolution::Def)); |
266 | }); | 272 | }); |
267 | m.item_map.extern_prelude.iter().for_each(|(name, def)| { | 273 | m.crate_def_map.extern_prelude().iter().for_each(|(name, def)| { |
268 | f(name.clone(), PerNs::types(Resolution::Def(*def))); | 274 | f(name.clone(), PerNs::types(Resolution::Def(*def))); |
269 | }); | 275 | }); |
270 | if let Some(prelude) = m.item_map.prelude { | 276 | if let Some(prelude) = m.crate_def_map.prelude() { |
271 | let prelude_item_map = db.item_map(prelude.krate); | 277 | let prelude_def_map = db.crate_def_map(prelude.krate); |
272 | prelude_item_map[prelude.module_id].entries().for_each(|(name, res)| { | 278 | prelude_def_map[prelude.module_id].scope.entries().for_each(|(name, res)| { |
273 | f(name.clone(), res.def.map(Resolution::Def)); | 279 | f(name.clone(), res.def.map(Resolution::Def)); |
274 | }); | 280 | }); |
275 | } | 281 | } |