aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_hir/src/nameres.rs
diff options
context:
space:
mode:
Diffstat (limited to 'crates/ra_hir/src/nameres.rs')
-rw-r--r--crates/ra_hir/src/nameres.rs743
1 files changed, 252 insertions, 491 deletions
diff --git a/crates/ra_hir/src/nameres.rs b/crates/ra_hir/src/nameres.rs
index 73919ee37..edd2f25f7 100644
--- a/crates/ra_hir/src/nameres.rs
+++ b/crates/ra_hir/src/nameres.rs
@@ -1,60 +1,148 @@
1//! Name resolution algorithm. The end result of the algorithm is an `ItemMap`: 1/// This module implements import-resolution/macro expansion algorithm.
2//! a map which maps each module to its scope: the set of items visible in the 2///
3//! module. That is, we only resolve imports here, name resolution of item 3/// The result of this module is `CrateDefMap`: a datastructure which contains:
4//! bodies will be done in a separate step. 4///
5//! 5/// * a tree of modules for the crate
6//! Like Rustc, we use an interactive per-crate algorithm: we start with scopes 6/// * for each module, a set of items visible in the module (directly declared
7//! containing only directly defined items, and then iteratively resolve 7/// or imported)
8//! imports. 8///
9//! 9/// Note that `CrateDefMap` contains fully macro expanded code.
10//! To make this work nicely in the IDE scenario, we place `InputModuleItems` 10///
11//! in between raw syntax and name resolution. `InputModuleItems` are computed 11/// Computing `CrateDefMap` can be partitioned into several logically
12//! using only the module's syntax, and it is all directly defined items plus 12/// independent "phases". The phases are mutually recursive though, there's no
13//! imports. The plan is to make `InputModuleItems` independent of local 13/// strict ordering.
14//! modifications (that is, typing inside a function should not change IMIs), 14///
15//! so that the results of name resolution can be preserved unless the module 15/// ## Collecting RawItems
16//! structure itself is modified. 16///
17pub(crate) mod lower; 17/// This happens in the `raw` module, which parses a single source file into a
18 18/// set of top-level items. Nested imports are desugared to flat imports in
19use std::{time, sync::Arc}; 19/// this phase. Macro calls are represented as a triple of (Path, Option<Name>,
20 20/// TokenTree).
21use rustc_hash::{FxHashMap, FxHashSet}; 21///
22 22/// ## Collecting Modules
23use ra_arena::map::ArenaMap; 23///
24use ra_db::Edition; 24/// This happens in the `collector` module. In this phase, we recursively walk
25/// tree of modules, collect raw items from submodules, populate module scopes
26/// with defined items (so, we assign item ids in this phase) and record the set
27/// of unresolved imports and macros.
28///
29/// While we walk tree of modules, we also record macro_rules definitions and
30/// expand calls to macro_rules defined macros.
31///
32/// ## Resolving Imports
33///
34/// We maintain a list of currently unresolved imports. On every iteration, we
35/// try to resolve some imports from this list. If the import is resolved, we
36/// record it, by adding an item to current module scope and, if necessary, by
37/// recursively populating glob imports.
38///
39/// ## Resolving Macros
40///
41/// macro_rules from the same crate use a global mutable namespace. We expand
42/// them immediately, when we collect modules.
43///
44/// Macros from other crates (including proc-macros) can be used with
45/// `foo::bar!` syntax. We handle them similarly to imports. There's a list of
46/// unexpanded macros. On every iteration, we try to resolve each macro call
47/// path and, upon success, we run macro expansion and "collect module" phase
48/// on the result
49
50mod per_ns;
51mod raw;
52mod collector;
53#[cfg(test)]
54mod tests;
55
56use std::sync::Arc;
57
58use rustc_hash::FxHashMap;
59use ra_arena::{Arena, RawId, impl_arena_id};
60use ra_db::{FileId, Edition};
25use test_utils::tested_by; 61use test_utils::tested_by;
26 62
27use crate::{ 63use crate::{
28 Module, ModuleDef, 64 ModuleDef, Name, Crate, Module, Problem,
29 Path, PathKind, PersistentHirDatabase, 65 PersistentHirDatabase, Path, PathKind, HirFileId,
30 Crate, Name, 66 ids::{SourceItemId, SourceFileItemId, MacroCallId},
31 module_tree::{ModuleId, ModuleTree},
32 nameres::lower::{ImportId, LoweredModule, ImportData},
33}; 67};
34 68
35/// `ItemMap` is the result of module name resolution. It contains, for each 69pub(crate) use self::raw::{RawItems, ImportId, ImportSourceMap};
36/// module, the set of visible items. 70
71pub use self::per_ns::{PerNs, Namespace};
72
73/// Contans all top-level defs from a macro-expanded crate
37#[derive(Debug, PartialEq, Eq)] 74#[derive(Debug, PartialEq, Eq)]
38pub struct ItemMap { 75pub struct CrateDefMap {
76 krate: Crate,
39 edition: Edition, 77 edition: Edition,
40 /// The prelude module for this crate. This either comes from an import 78 /// The prelude module for this crate. This either comes from an import
41 /// marked with the `prelude_import` attribute, or (in the normal case) from 79 /// marked with the `prelude_import` attribute, or (in the normal case) from
42 /// a dependency (`std` or `core`). 80 /// a dependency (`std` or `core`).
43 pub(crate) prelude: Option<Module>, 81 prelude: Option<Module>,
44 pub(crate) extern_prelude: FxHashMap<Name, ModuleDef>, 82 extern_prelude: FxHashMap<Name, ModuleDef>,
45 per_module: ArenaMap<ModuleId, ModuleScope>, 83 root: CrateModuleId,
84 modules: Arena<CrateModuleId, ModuleData>,
85 macros: Arena<CrateMacroId, mbe::MacroRules>,
86 public_macros: FxHashMap<Name, CrateMacroId>,
87 macro_resolutions: FxHashMap<MacroCallId, (Crate, CrateMacroId)>,
88 problems: CrateDefMapProblems,
89}
90
91impl std::ops::Index<CrateModuleId> for CrateDefMap {
92 type Output = ModuleData;
93 fn index(&self, id: CrateModuleId) -> &ModuleData {
94 &self.modules[id]
95 }
96}
97
98impl std::ops::Index<CrateMacroId> for CrateDefMap {
99 type Output = mbe::MacroRules;
100 fn index(&self, id: CrateMacroId) -> &mbe::MacroRules {
101 &self.macros[id]
102 }
103}
104
105/// An ID of a macro, **local** to a specific crate
106#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
107pub(crate) struct CrateMacroId(RawId);
108impl_arena_id!(CrateMacroId);
109
110/// An ID of a module, **local** to a specific crate
111#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
112pub(crate) struct CrateModuleId(RawId);
113impl_arena_id!(CrateModuleId);
114
115#[derive(Default, Debug, PartialEq, Eq)]
116pub(crate) struct ModuleData {
117 pub(crate) parent: Option<CrateModuleId>,
118 pub(crate) children: FxHashMap<Name, CrateModuleId>,
119 pub(crate) scope: ModuleScope,
120 /// None for root
121 pub(crate) declaration: Option<SourceItemId>,
122 /// None for inline modules.
123 ///
124 /// Note that non-inline modules, by definition, live inside non-macro file.
125 pub(crate) definition: Option<FileId>,
126}
127
128#[derive(Default, Debug, PartialEq, Eq)]
129pub(crate) struct CrateDefMapProblems {
130 problems: Vec<(SourceItemId, Problem)>,
46} 131}
47 132
48impl std::ops::Index<ModuleId> for ItemMap { 133impl CrateDefMapProblems {
49 type Output = ModuleScope; 134 fn add(&mut self, source_item_id: SourceItemId, problem: Problem) {
50 fn index(&self, id: ModuleId) -> &ModuleScope { 135 self.problems.push((source_item_id, problem))
51 &self.per_module[id] 136 }
137
138 pub(crate) fn iter<'a>(&'a self) -> impl Iterator<Item = (&'a SourceItemId, &'a Problem)> + 'a {
139 self.problems.iter().map(|(s, p)| (s, p))
52 } 140 }
53} 141}
54 142
55#[derive(Debug, Default, PartialEq, Eq, Clone)] 143#[derive(Debug, Default, PartialEq, Eq, Clone)]
56pub struct ModuleScope { 144pub struct ModuleScope {
57 pub(crate) items: FxHashMap<Name, Resolution>, 145 items: FxHashMap<Name, Resolution>,
58} 146}
59 147
60impl ModuleScope { 148impl ModuleScope {
@@ -66,8 +154,6 @@ impl ModuleScope {
66 } 154 }
67} 155}
68 156
69/// `Resolution` is basically `DefId` atm, but it should account for stuff like
70/// multiple namespaces, ambiguity and errors.
71#[derive(Debug, Clone, PartialEq, Eq, Default)] 157#[derive(Debug, Clone, PartialEq, Eq, Default)]
72pub struct Resolution { 158pub struct Resolution {
73 /// None for unresolved 159 /// None for unresolved
@@ -76,372 +162,6 @@ pub struct Resolution {
76 pub import: Option<ImportId>, 162 pub import: Option<ImportId>,
77} 163}
78 164
79#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
80pub enum Namespace {
81 Types,
82 Values,
83}
84
85#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
86pub struct PerNs<T> {
87 pub types: Option<T>,
88 pub values: Option<T>,
89}
90
91impl<T> Default for PerNs<T> {
92 fn default() -> Self {
93 PerNs { types: None, values: None }
94 }
95}
96
97impl<T> PerNs<T> {
98 pub fn none() -> PerNs<T> {
99 PerNs { types: None, values: None }
100 }
101
102 pub fn values(t: T) -> PerNs<T> {
103 PerNs { types: None, values: Some(t) }
104 }
105
106 pub fn types(t: T) -> PerNs<T> {
107 PerNs { types: Some(t), values: None }
108 }
109
110 pub fn both(types: T, values: T) -> PerNs<T> {
111 PerNs { types: Some(types), values: Some(values) }
112 }
113
114 pub fn is_none(&self) -> bool {
115 self.types.is_none() && self.values.is_none()
116 }
117
118 pub fn is_both(&self) -> bool {
119 self.types.is_some() && self.values.is_some()
120 }
121
122 pub fn take(self, namespace: Namespace) -> Option<T> {
123 match namespace {
124 Namespace::Types => self.types,
125 Namespace::Values => self.values,
126 }
127 }
128
129 pub fn take_types(self) -> Option<T> {
130 self.take(Namespace::Types)
131 }
132
133 pub fn take_values(self) -> Option<T> {
134 self.take(Namespace::Values)
135 }
136
137 pub fn get(&self, namespace: Namespace) -> Option<&T> {
138 self.as_ref().take(namespace)
139 }
140
141 pub fn as_ref(&self) -> PerNs<&T> {
142 PerNs { types: self.types.as_ref(), values: self.values.as_ref() }
143 }
144
145 pub fn or(self, other: PerNs<T>) -> PerNs<T> {
146 PerNs { types: self.types.or(other.types), values: self.values.or(other.values) }
147 }
148
149 pub fn and_then<U>(self, f: impl Fn(T) -> Option<U>) -> PerNs<U> {
150 PerNs { types: self.types.and_then(&f), values: self.values.and_then(&f) }
151 }
152
153 pub fn map<U>(self, f: impl Fn(T) -> U) -> PerNs<U> {
154 PerNs { types: self.types.map(&f), values: self.values.map(&f) }
155 }
156}
157
158struct Resolver<'a, DB> {
159 db: &'a DB,
160 input: &'a FxHashMap<ModuleId, Arc<LoweredModule>>,
161 krate: Crate,
162 module_tree: Arc<ModuleTree>,
163 processed_imports: FxHashSet<(ModuleId, ImportId)>,
164 /// If module `a` has `use b::*`, then this contains the mapping b -> a (and the import)
165 glob_imports: FxHashMap<ModuleId, Vec<(ModuleId, ImportId)>>,
166 result: ItemMap,
167}
168
169impl<'a, DB> Resolver<'a, DB>
170where
171 DB: PersistentHirDatabase,
172{
173 fn new(
174 db: &'a DB,
175 input: &'a FxHashMap<ModuleId, Arc<LoweredModule>>,
176 krate: Crate,
177 ) -> Resolver<'a, DB> {
178 let module_tree = db.module_tree(krate);
179 Resolver {
180 db,
181 input,
182 krate,
183 module_tree,
184 processed_imports: FxHashSet::default(),
185 glob_imports: FxHashMap::default(),
186 result: ItemMap {
187 edition: krate.edition(db),
188 prelude: None,
189 extern_prelude: FxHashMap::default(),
190 per_module: ArenaMap::default(),
191 },
192 }
193 }
194
195 pub(crate) fn resolve(mut self) -> ItemMap {
196 self.populate_extern_prelude();
197 for (&module_id, items) in self.input.iter() {
198 self.populate_module(module_id, Arc::clone(items));
199 }
200
201 let mut iter = 0;
202 loop {
203 iter += 1;
204 if iter > 1000 {
205 panic!("failed to reach fixedpoint after 1000 iters")
206 }
207 let processed_imports_count = self.processed_imports.len();
208 for &module_id in self.input.keys() {
209 self.db.check_canceled();
210 self.resolve_imports(module_id);
211 }
212 if processed_imports_count == self.processed_imports.len() {
213 // no new imports resolved
214 break;
215 }
216 }
217 self.result
218 }
219
220 fn populate_extern_prelude(&mut self) {
221 for dep in self.krate.dependencies(self.db) {
222 log::debug!("crate dep {:?} -> {:?}", dep.name, dep.krate);
223 if let Some(module) = dep.krate.root_module(self.db) {
224 self.result.extern_prelude.insert(dep.name.clone(), module.into());
225 }
226 // look for the prelude
227 if self.result.prelude.is_none() {
228 let item_map = self.db.item_map(dep.krate);
229 if item_map.prelude.is_some() {
230 self.result.prelude = item_map.prelude;
231 }
232 }
233 }
234 }
235
236 fn populate_module(&mut self, module_id: ModuleId, input: Arc<LoweredModule>) {
237 let mut module_items = ModuleScope::default();
238 for (import_id, import_data) in input.imports.iter() {
239 if let Some(last_segment) = import_data.path.segments.iter().last() {
240 if !import_data.is_glob {
241 let name =
242 import_data.alias.clone().unwrap_or_else(|| last_segment.name.clone());
243 module_items
244 .items
245 .insert(name, Resolution { def: PerNs::none(), import: Some(import_id) });
246 }
247 }
248 }
249 // Populate explicitly declared items, except modules
250 for (name, &def) in input.declarations.iter() {
251 let resolution = Resolution { def, import: None };
252 module_items.items.insert(name.clone(), resolution);
253 }
254
255 // Populate modules
256 for (name, module_id) in module_id.children(&self.module_tree) {
257 let module = Module { module_id, krate: self.krate };
258 self.add_module_item(&mut module_items, name, PerNs::types(module.into()));
259 }
260
261 self.result.per_module.insert(module_id, module_items);
262 }
263
264 fn add_module_item(&self, module_items: &mut ModuleScope, name: Name, def: PerNs<ModuleDef>) {
265 let resolution = Resolution { def, import: None };
266 module_items.items.insert(name, resolution);
267 }
268
269 fn resolve_imports(&mut self, module_id: ModuleId) {
270 for (import_id, import_data) in self.input[&module_id].imports.iter() {
271 if self.processed_imports.contains(&(module_id, import_id)) {
272 // already done
273 continue;
274 }
275 if self.resolve_import(module_id, import_id, import_data) == ReachedFixedPoint::Yes {
276 log::debug!("import {:?} resolved (or definite error)", import_id);
277 self.processed_imports.insert((module_id, import_id));
278 }
279 }
280 }
281
282 fn resolve_import(
283 &mut self,
284 module_id: ModuleId,
285 import_id: ImportId,
286 import: &ImportData,
287 ) -> ReachedFixedPoint {
288 log::debug!("resolving import: {:?} ({:?})", import, self.result.edition);
289 let original_module = Module { krate: self.krate, module_id };
290
291 let (def, reached_fixedpoint) = if import.is_extern_crate {
292 let res = self.result.resolve_name_in_extern_prelude(
293 &import
294 .path
295 .as_ident()
296 .expect("extern crate should have been desugared to one-element path"),
297 );
298 (res, if res.is_none() { ReachedFixedPoint::No } else { ReachedFixedPoint::Yes })
299 } else {
300 let res = self.result.resolve_path_fp(
301 self.db,
302 ResolveMode::Import,
303 original_module,
304 &import.path,
305 );
306
307 (res.resolved_def, res.reached_fixedpoint)
308 };
309
310 if reached_fixedpoint != ReachedFixedPoint::Yes {
311 return reached_fixedpoint;
312 }
313
314 if import.is_glob {
315 log::debug!("glob import: {:?}", import);
316 match def.take_types() {
317 Some(ModuleDef::Module(m)) => {
318 if import.is_prelude {
319 tested_by!(std_prelude);
320 self.result.prelude = Some(m);
321 } else if m.krate != self.krate {
322 tested_by!(glob_across_crates);
323 // glob import from other crate => we can just import everything once
324 let item_map = self.db.item_map(m.krate);
325 let scope = &item_map[m.module_id];
326 let items = scope
327 .items
328 .iter()
329 .map(|(name, res)| (name.clone(), res.clone()))
330 .collect::<Vec<_>>();
331 self.update(module_id, Some(import_id), &items);
332 } else {
333 // glob import from same crate => we do an initial
334 // import, and then need to propagate any further
335 // additions
336 let scope = &self.result[m.module_id];
337 let items = scope
338 .items
339 .iter()
340 .map(|(name, res)| (name.clone(), res.clone()))
341 .collect::<Vec<_>>();
342 self.update(module_id, Some(import_id), &items);
343 // record the glob import in case we add further items
344 self.glob_imports
345 .entry(m.module_id)
346 .or_default()
347 .push((module_id, import_id));
348 }
349 }
350 Some(ModuleDef::Enum(e)) => {
351 tested_by!(glob_enum);
352 // glob import from enum => just import all the variants
353 let variants = e.variants(self.db);
354 let resolutions = variants
355 .into_iter()
356 .filter_map(|variant| {
357 let res = Resolution {
358 def: PerNs::both(variant.into(), variant.into()),
359 import: Some(import_id),
360 };
361 let name = variant.name(self.db)?;
362 Some((name, res))
363 })
364 .collect::<Vec<_>>();
365 self.update(module_id, Some(import_id), &resolutions);
366 }
367 Some(d) => {
368 log::debug!("glob import {:?} from non-module/enum {:?}", import, d);
369 }
370 None => {
371 log::debug!("glob import {:?} didn't resolve as type", import);
372 }
373 }
374 } else {
375 let last_segment = import.path.segments.last().unwrap();
376 let name = import.alias.clone().unwrap_or_else(|| last_segment.name.clone());
377 log::debug!("resolved import {:?} ({:?}) to {:?}", name, import, def);
378
379 // extern crates in the crate root are special-cased to insert entries into the extern prelude: rust-lang/rust#54658
380 if let Some(root_module) = self.krate.root_module(self.db) {
381 if import.is_extern_crate && module_id == root_module.module_id {
382 if let Some(def) = def.take_types() {
383 self.result.extern_prelude.insert(name.clone(), def);
384 }
385 }
386 }
387 let resolution = Resolution { def, import: Some(import_id) };
388 self.update(module_id, None, &[(name, resolution)]);
389 }
390 reached_fixedpoint
391 }
392
393 fn update(
394 &mut self,
395 module_id: ModuleId,
396 import: Option<ImportId>,
397 resolutions: &[(Name, Resolution)],
398 ) {
399 self.update_recursive(module_id, import, resolutions, 0)
400 }
401
402 fn update_recursive(
403 &mut self,
404 module_id: ModuleId,
405 import: Option<ImportId>,
406 resolutions: &[(Name, Resolution)],
407 depth: usize,
408 ) {
409 if depth > 100 {
410 // prevent stack overflows (but this shouldn't be possible)
411 panic!("infinite recursion in glob imports!");
412 }
413 let module_items = self.result.per_module.get_mut(module_id).unwrap();
414 let mut changed = false;
415 for (name, res) in resolutions {
416 let existing = module_items.items.entry(name.clone()).or_default();
417 if existing.def.types.is_none() && res.def.types.is_some() {
418 existing.def.types = res.def.types;
419 existing.import = import.or(res.import);
420 changed = true;
421 }
422 if existing.def.values.is_none() && res.def.values.is_some() {
423 existing.def.values = res.def.values;
424 existing.import = import.or(res.import);
425 changed = true;
426 }
427 }
428 if !changed {
429 return;
430 }
431 let glob_imports = self
432 .glob_imports
433 .get(&module_id)
434 .into_iter()
435 .flat_map(|v| v.iter())
436 .cloned()
437 .collect::<Vec<_>>();
438 for (glob_importing_module, glob_import) in glob_imports {
439 // We pass the glob import so that the tracked import in those modules is that glob import
440 self.update_recursive(glob_importing_module, Some(glob_import), resolutions, depth + 1);
441 }
442 }
443}
444
445#[derive(Debug, Clone)] 165#[derive(Debug, Clone)]
446struct ResolvePathResult { 166struct ResolvePathResult {
447 resolved_def: PerNs<ModuleDef>, 167 resolved_def: PerNs<ModuleDef>,
@@ -475,84 +195,85 @@ enum ReachedFixedPoint {
475 No, 195 No,
476} 196}
477 197
478impl ItemMap { 198impl CrateDefMap {
479 pub(crate) fn item_map_query(db: &impl PersistentHirDatabase, krate: Crate) -> Arc<ItemMap> { 199 pub(crate) fn crate_def_map_query(
480 let start = time::Instant::now(); 200 db: &impl PersistentHirDatabase,
481 let module_tree = db.module_tree(krate); 201 krate: Crate,
482 let input = module_tree 202 ) -> Arc<CrateDefMap> {
483 .modules() 203 let start = std::time::Instant::now();
484 .map(|module_id| (module_id, db.lower_module(Module { krate, module_id }))) 204 let def_map = {
485 .collect::<FxHashMap<_, _>>(); 205 let edition = krate.edition(db);
486 206 let mut modules: Arena<CrateModuleId, ModuleData> = Arena::default();
487 let resolver = Resolver::new(db, &input, krate); 207 let root = modules.alloc(ModuleData::default());
488 let res = resolver.resolve(); 208 CrateDefMap {
489 let elapsed = start.elapsed(); 209 krate,
490 log::info!("item_map: {:?}", elapsed); 210 edition,
491 Arc::new(res) 211 extern_prelude: FxHashMap::default(),
212 prelude: None,
213 root,
214 modules,
215 macros: Arena::default(),
216 public_macros: FxHashMap::default(),
217 macro_resolutions: FxHashMap::default(),
218 problems: CrateDefMapProblems::default(),
219 }
220 };
221 let def_map = collector::collect_defs(db, def_map);
222 log::info!("crate_def_map_query: {:?}", start.elapsed());
223 Arc::new(def_map)
492 } 224 }
493 225
494 pub(crate) fn resolve_path( 226 pub(crate) fn root(&self) -> CrateModuleId {
495 &self, 227 self.root
496 db: &impl PersistentHirDatabase,
497 original_module: Module,
498 path: &Path,
499 ) -> (PerNs<ModuleDef>, Option<usize>) {
500 let res = self.resolve_path_fp(db, ResolveMode::Other, original_module, path);
501 (res.resolved_def, res.segment_index)
502 } 228 }
503 229
504 fn resolve_in_prelude( 230 pub(crate) fn problems(&self) -> &CrateDefMapProblems {
505 &self, 231 &self.problems
506 db: &impl PersistentHirDatabase,
507 original_module: Module,
508 name: &Name,
509 ) -> PerNs<ModuleDef> {
510 if let Some(prelude) = self.prelude {
511 let resolution = if prelude.krate == original_module.krate {
512 self[prelude.module_id].items.get(name).cloned()
513 } else {
514 db.item_map(prelude.krate)[prelude.module_id].items.get(name).cloned()
515 };
516 resolution.map(|r| r.def).unwrap_or_else(PerNs::none)
517 } else {
518 PerNs::none()
519 }
520 } 232 }
521 233
522 pub(crate) fn resolve_name_in_module( 234 pub(crate) fn mk_module(&self, module_id: CrateModuleId) -> Module {
523 &self, 235 Module { krate: self.krate, module_id }
524 db: &impl PersistentHirDatabase, 236 }
525 module: Module,
526 name: &Name,
527 ) -> PerNs<ModuleDef> {
528 // Resolve in:
529 // - current module / scope
530 // - extern prelude
531 // - std prelude
532 let from_scope = self[module.module_id].items.get(name).map_or(PerNs::none(), |it| it.def);
533 let from_extern_prelude =
534 self.extern_prelude.get(name).map_or(PerNs::none(), |&it| PerNs::types(it));
535 let from_prelude = self.resolve_in_prelude(db, module, name);
536 237
537 from_scope.or(from_extern_prelude).or(from_prelude) 238 pub(crate) fn prelude(&self) -> Option<Module> {
239 self.prelude
538 } 240 }
539 241
540 fn resolve_name_in_extern_prelude(&self, name: &Name) -> PerNs<ModuleDef> { 242 pub(crate) fn extern_prelude(&self) -> &FxHashMap<Name, ModuleDef> {
541 self.extern_prelude.get(name).map_or(PerNs::none(), |&it| PerNs::types(it)) 243 &self.extern_prelude
542 } 244 }
543 245
544 fn resolve_name_in_crate_root_or_extern_prelude( 246 pub(crate) fn resolve_macro(
545 &self, 247 &self,
546 db: &impl PersistentHirDatabase, 248 macro_call_id: MacroCallId,
547 module: Module, 249 ) -> Option<(Crate, CrateMacroId)> {
548 name: &Name, 250 self.macro_resolutions.get(&macro_call_id).map(|&it| it)
549 ) -> PerNs<ModuleDef> { 251 }
550 let crate_root = module.crate_root(db);
551 let from_crate_root =
552 self[crate_root.module_id].items.get(name).map_or(PerNs::none(), |it| it.def);
553 let from_extern_prelude = self.resolve_name_in_extern_prelude(name);
554 252
555 from_crate_root.or(from_extern_prelude) 253 pub(crate) fn find_module_by_source(
254 &self,
255 file_id: HirFileId,
256 decl_id: Option<SourceFileItemId>,
257 ) -> Option<CrateModuleId> {
258 let decl_id = decl_id.map(|it| it.with_file_id(file_id));
259 let (module_id, _module_data) = self.modules.iter().find(|(_module_id, module_data)| {
260 if decl_id.is_some() {
261 module_data.declaration == decl_id
262 } else {
263 module_data.definition.map(|it| it.into()) == Some(file_id)
264 }
265 })?;
266 Some(module_id)
267 }
268
269 pub(crate) fn resolve_path(
270 &self,
271 db: &impl PersistentHirDatabase,
272 original_module: CrateModuleId,
273 path: &Path,
274 ) -> (PerNs<ModuleDef>, Option<usize>) {
275 let res = self.resolve_path_fp(db, ResolveMode::Other, original_module, path);
276 (res.resolved_def, res.segment_index)
556 } 277 }
557 278
558 // Returns Yes if we are sure that additions to `ItemMap` wouldn't change 279 // Returns Yes if we are sure that additions to `ItemMap` wouldn't change
@@ -561,13 +282,17 @@ impl ItemMap {
561 &self, 282 &self,
562 db: &impl PersistentHirDatabase, 283 db: &impl PersistentHirDatabase,
563 mode: ResolveMode, 284 mode: ResolveMode,
564 original_module: Module, 285 original_module: CrateModuleId,
565 path: &Path, 286 path: &Path,
566 ) -> ResolvePathResult { 287 ) -> ResolvePathResult {
567 let mut segments = path.segments.iter().enumerate(); 288 let mut segments = path.segments.iter().enumerate();
568 let mut curr_per_ns: PerNs<ModuleDef> = match path.kind { 289 let mut curr_per_ns: PerNs<ModuleDef> = match path.kind {
569 PathKind::Crate => PerNs::types(original_module.crate_root(db).into()), 290 PathKind::Crate => {
570 PathKind::Self_ => PerNs::types(original_module.into()), 291 PerNs::types(Module { krate: self.krate, module_id: self.root }.into())
292 }
293 PathKind::Self_ => {
294 PerNs::types(Module { krate: self.krate, module_id: original_module }.into())
295 }
571 // plain import or absolute path in 2015: crate-relative with 296 // plain import or absolute path in 2015: crate-relative with
572 // fallback to extern prelude (with the simplification in 297 // fallback to extern prelude (with the simplification in
573 // rust-lang/rust#57745) 298 // rust-lang/rust#57745)
@@ -581,11 +306,7 @@ impl ItemMap {
581 None => return ResolvePathResult::empty(ReachedFixedPoint::Yes), 306 None => return ResolvePathResult::empty(ReachedFixedPoint::Yes),
582 }; 307 };
583 log::debug!("resolving {:?} in crate root (+ extern prelude)", segment); 308 log::debug!("resolving {:?} in crate root (+ extern prelude)", segment);
584 self.resolve_name_in_crate_root_or_extern_prelude( 309 self.resolve_name_in_crate_root_or_extern_prelude(&segment.name)
585 db,
586 original_module,
587 &segment.name,
588 )
589 } 310 }
590 PathKind::Plain => { 311 PathKind::Plain => {
591 let segment = match segments.next() { 312 let segment = match segments.next() {
@@ -596,8 +317,8 @@ impl ItemMap {
596 self.resolve_name_in_module(db, original_module, &segment.name) 317 self.resolve_name_in_module(db, original_module, &segment.name)
597 } 318 }
598 PathKind::Super => { 319 PathKind::Super => {
599 if let Some(p) = original_module.parent(db) { 320 if let Some(p) = self.modules[original_module].parent {
600 PerNs::types(p.into()) 321 PerNs::types(Module { krate: self.krate, module_id: p }.into())
601 } else { 322 } else {
602 log::debug!("super path in root module"); 323 log::debug!("super path in root module");
603 return ResolvePathResult::empty(ReachedFixedPoint::Yes); 324 return ResolvePathResult::empty(ReachedFixedPoint::Yes);
@@ -634,14 +355,14 @@ impl ItemMap {
634 355
635 curr_per_ns = match curr { 356 curr_per_ns = match curr {
636 ModuleDef::Module(module) => { 357 ModuleDef::Module(module) => {
637 if module.krate != original_module.krate { 358 if module.krate != self.krate {
638 let path = Path { 359 let path = Path {
639 segments: path.segments[i..].iter().cloned().collect(), 360 segments: path.segments[i..].iter().cloned().collect(),
640 kind: PathKind::Self_, 361 kind: PathKind::Self_,
641 }; 362 };
642 log::debug!("resolving {:?} in other crate", path); 363 log::debug!("resolving {:?} in other crate", path);
643 let item_map = db.item_map(module.krate); 364 let defp_map = db.crate_def_map(module.krate);
644 let (def, s) = item_map.resolve_path(db, *module, &path); 365 let (def, s) = defp_map.resolve_path(db, module.module_id, &path);
645 return ResolvePathResult::with( 366 return ResolvePathResult::with(
646 def, 367 def,
647 ReachedFixedPoint::Yes, 368 ReachedFixedPoint::Yes,
@@ -649,7 +370,7 @@ impl ItemMap {
649 ); 370 );
650 } 371 }
651 372
652 match self[module.module_id].items.get(&segment.name) { 373 match self[module.module_id].scope.items.get(&segment.name) {
653 Some(res) if !res.def.is_none() => res.def, 374 Some(res) if !res.def.is_none() => res.def,
654 _ => { 375 _ => {
655 log::debug!("path segment {:?} not found", segment.name); 376 log::debug!("path segment {:?} not found", segment.name);
@@ -659,7 +380,7 @@ impl ItemMap {
659 } 380 }
660 ModuleDef::Enum(e) => { 381 ModuleDef::Enum(e) => {
661 // enum variant 382 // enum variant
662 tested_by!(item_map_enum_importing); 383 tested_by!(can_import_enum_variant);
663 match e.variant(db, &segment.name) { 384 match e.variant(db, &segment.name) {
664 Some(variant) => PerNs::both(variant.into(), variant.into()), 385 Some(variant) => PerNs::both(variant.into(), variant.into()),
665 None => { 386 None => {
@@ -690,7 +411,47 @@ impl ItemMap {
690 } 411 }
691 ResolvePathResult::with(curr_per_ns, ReachedFixedPoint::Yes, None) 412 ResolvePathResult::with(curr_per_ns, ReachedFixedPoint::Yes, None)
692 } 413 }
693}
694 414
695#[cfg(test)] 415 fn resolve_name_in_crate_root_or_extern_prelude(&self, name: &Name) -> PerNs<ModuleDef> {
696mod tests; 416 let from_crate_root =
417 self[self.root].scope.items.get(name).map_or(PerNs::none(), |it| it.def);
418 let from_extern_prelude = self.resolve_name_in_extern_prelude(name);
419
420 from_crate_root.or(from_extern_prelude)
421 }
422
423 pub(crate) fn resolve_name_in_module(
424 &self,
425 db: &impl PersistentHirDatabase,
426 module: CrateModuleId,
427 name: &Name,
428 ) -> PerNs<ModuleDef> {
429 // Resolve in:
430 // - current module / scope
431 // - extern prelude
432 // - std prelude
433 let from_scope = self[module].scope.items.get(name).map_or(PerNs::none(), |it| it.def);
434 let from_extern_prelude =
435 self.extern_prelude.get(name).map_or(PerNs::none(), |&it| PerNs::types(it));
436 let from_prelude = self.resolve_in_prelude(db, name);
437
438 from_scope.or(from_extern_prelude).or(from_prelude)
439 }
440
441 fn resolve_name_in_extern_prelude(&self, name: &Name) -> PerNs<ModuleDef> {
442 self.extern_prelude.get(name).map_or(PerNs::none(), |&it| PerNs::types(it))
443 }
444
445 fn resolve_in_prelude(&self, db: &impl PersistentHirDatabase, name: &Name) -> PerNs<ModuleDef> {
446 if let Some(prelude) = self.prelude {
447 let resolution = if prelude.krate == self.krate {
448 self[prelude.module_id].scope.items.get(name).cloned()
449 } else {
450 db.crate_def_map(prelude.krate)[prelude.module_id].scope.items.get(name).cloned()
451 };
452 resolution.map(|r| r.def).unwrap_or_else(PerNs::none)
453 } else {
454 PerNs::none()
455 }
456 }
457}