aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_hir_def
diff options
context:
space:
mode:
Diffstat (limited to 'crates/ra_hir_def')
-rw-r--r--crates/ra_hir_def/src/nameres.rs270
-rw-r--r--crates/ra_hir_def/src/nameres/collector.rs10
-rw-r--r--crates/ra_hir_def/src/nameres/mod_resolution.rs12
-rw-r--r--crates/ra_hir_def/src/nameres/path_resolution.rs261
-rw-r--r--crates/ra_hir_def/src/nameres/per_ns.rs8
-rw-r--r--crates/ra_hir_def/src/nameres/raw.rs48
6 files changed, 314 insertions, 295 deletions
diff --git a/crates/ra_hir_def/src/nameres.rs b/crates/ra_hir_def/src/nameres.rs
index 433bdde48..d3ecabb9b 100644
--- a/crates/ra_hir_def/src/nameres.rs
+++ b/crates/ra_hir_def/src/nameres.rs
@@ -14,10 +14,10 @@
14//! 14//!
15//! ## Collecting RawItems 15//! ## Collecting RawItems
16//! 16//!
17//! This happens in the `raw` module, which parses a single source file into a 17//! This happens in the `raw` module, which parses a single source file into a
18//! set of top-level items. Nested imports are desugared to flat imports in 18//! set of top-level items. Nested imports are desugared to flat imports in this
19//! this phase. Macro calls are represented as a triple of (Path, Option<Name>, 19//! phase. Macro calls are represented as a triple of (Path, Option<Name>,
20//! TokenTree). 20//! TokenTree).
21//! 21//!
22//! ## Collecting Modules 22//! ## Collecting Modules
23//! 23//!
@@ -44,14 +44,14 @@
44//! Macros from other crates (including proc-macros) can be used with 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 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 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 47//! path and, upon success, we run macro expansion and "collect module" phase on
48//! on the result 48//! the result
49 49
50// FIXME: review privacy of submodules
51pub mod raw; 50pub mod raw;
52pub mod per_ns; 51pub mod per_ns;
53pub mod collector; 52mod collector;
54pub mod mod_resolution; 53mod mod_resolution;
54mod path_resolution;
55 55
56#[cfg(test)] 56#[cfg(test)]
57mod tests; 57mod tests;
@@ -65,14 +65,15 @@ use ra_db::{CrateId, Edition, FileId};
65use ra_prof::profile; 65use ra_prof::profile;
66use ra_syntax::ast; 66use ra_syntax::ast;
67use rustc_hash::{FxHashMap, FxHashSet}; 67use rustc_hash::{FxHashMap, FxHashSet};
68use test_utils::tested_by;
69 68
70use crate::{ 69use crate::{
71 builtin_type::BuiltinType, 70 builtin_type::BuiltinType,
72 db::DefDatabase2, 71 db::DefDatabase2,
73 nameres::{diagnostics::DefDiagnostic, per_ns::PerNs, raw::ImportId}, 72 nameres::{
74 path::{Path, PathKind}, 73 diagnostics::DefDiagnostic, path_resolution::ResolveMode, per_ns::PerNs, raw::ImportId,
75 AdtId, AstId, CrateModuleId, EnumVariantId, ModuleDefId, ModuleId, TraitId, 74 },
75 path::Path,
76 AstId, CrateModuleId, ModuleDefId, ModuleId, TraitId,
76}; 77};
77 78
78/// Contains all top-level defs from a macro-expanded crate 79/// Contains all top-level defs from a macro-expanded crate
@@ -195,45 +196,6 @@ pub struct Resolution {
195 pub import: Option<ImportId>, 196 pub import: Option<ImportId>,
196} 197}
197 198
198impl Resolution {
199 pub(crate) fn from_macro(macro_: MacroDefId) -> Self {
200 Resolution { def: PerNs::macros(macro_), import: None }
201 }
202}
203
204#[derive(Debug, Clone)]
205struct ResolvePathResult {
206 resolved_def: PerNs,
207 segment_index: Option<usize>,
208 reached_fixedpoint: ReachedFixedPoint,
209}
210
211impl ResolvePathResult {
212 fn empty(reached_fixedpoint: ReachedFixedPoint) -> ResolvePathResult {
213 ResolvePathResult::with(PerNs::none(), reached_fixedpoint, None)
214 }
215
216 fn with(
217 resolved_def: PerNs,
218 reached_fixedpoint: ReachedFixedPoint,
219 segment_index: Option<usize>,
220 ) -> ResolvePathResult {
221 ResolvePathResult { resolved_def, reached_fixedpoint, segment_index }
222 }
223}
224
225#[derive(Debug, Clone, Copy, PartialEq, Eq)]
226enum ResolveMode {
227 Import,
228 Other,
229}
230
231#[derive(Debug, Clone, Copy, PartialEq, Eq)]
232enum ReachedFixedPoint {
233 Yes,
234 No,
235}
236
237impl CrateDefMap { 199impl CrateDefMap {
238 pub(crate) fn crate_def_map_query( 200 pub(crate) fn crate_def_map_query(
239 // Note that this doesn't have `+ AstDatabase`! 201 // Note that this doesn't have `+ AstDatabase`!
@@ -296,210 +258,6 @@ impl CrateDefMap {
296 let res = self.resolve_path_fp_with_macro(db, ResolveMode::Other, original_module, path); 258 let res = self.resolve_path_fp_with_macro(db, ResolveMode::Other, original_module, path);
297 (res.resolved_def, res.segment_index) 259 (res.resolved_def, res.segment_index)
298 } 260 }
299
300 // Returns Yes if we are sure that additions to `ItemMap` wouldn't change
301 // the result.
302 fn resolve_path_fp_with_macro(
303 &self,
304 db: &impl DefDatabase2,
305 mode: ResolveMode,
306 original_module: CrateModuleId,
307 path: &Path,
308 ) -> ResolvePathResult {
309 let mut segments = path.segments.iter().enumerate();
310 let mut curr_per_ns: PerNs = match path.kind {
311 PathKind::DollarCrate(krate) => {
312 if krate == self.krate {
313 tested_by!(macro_dollar_crate_self);
314 PerNs::types(ModuleId { krate: self.krate, module_id: self.root }.into())
315 } else {
316 let def_map = db.crate_def_map(krate);
317 let module = ModuleId { krate, module_id: def_map.root };
318 tested_by!(macro_dollar_crate_other);
319 PerNs::types(module.into())
320 }
321 }
322 PathKind::Crate => {
323 PerNs::types(ModuleId { krate: self.krate, module_id: self.root }.into())
324 }
325 PathKind::Self_ => {
326 PerNs::types(ModuleId { krate: self.krate, module_id: original_module }.into())
327 }
328 // plain import or absolute path in 2015: crate-relative with
329 // fallback to extern prelude (with the simplification in
330 // rust-lang/rust#57745)
331 // FIXME there must be a nicer way to write this condition
332 PathKind::Plain | PathKind::Abs
333 if self.edition == Edition::Edition2015
334 && (path.kind == PathKind::Abs || mode == ResolveMode::Import) =>
335 {
336 let segment = match segments.next() {
337 Some((_, segment)) => segment,
338 None => return ResolvePathResult::empty(ReachedFixedPoint::Yes),
339 };
340 log::debug!("resolving {:?} in crate root (+ extern prelude)", segment);
341 self.resolve_name_in_crate_root_or_extern_prelude(&segment.name)
342 }
343 PathKind::Plain => {
344 let segment = match segments.next() {
345 Some((_, segment)) => segment,
346 None => return ResolvePathResult::empty(ReachedFixedPoint::Yes),
347 };
348 log::debug!("resolving {:?} in module", segment);
349 self.resolve_name_in_module(db, original_module, &segment.name)
350 }
351 PathKind::Super => {
352 if let Some(p) = self.modules[original_module].parent {
353 PerNs::types(ModuleId { krate: self.krate, module_id: p }.into())
354 } else {
355 log::debug!("super path in root module");
356 return ResolvePathResult::empty(ReachedFixedPoint::Yes);
357 }
358 }
359 PathKind::Abs => {
360 // 2018-style absolute path -- only extern prelude
361 let segment = match segments.next() {
362 Some((_, segment)) => segment,
363 None => return ResolvePathResult::empty(ReachedFixedPoint::Yes),
364 };
365 if let Some(def) = self.extern_prelude.get(&segment.name) {
366 log::debug!("absolute path {:?} resolved to crate {:?}", path, def);
367 PerNs::types(*def)
368 } else {
369 return ResolvePathResult::empty(ReachedFixedPoint::No); // extern crate declarations can add to the extern prelude
370 }
371 }
372 PathKind::Type(_) => {
373 // This is handled in `infer::infer_path_expr`
374 // The result returned here does not matter
375 return ResolvePathResult::empty(ReachedFixedPoint::Yes);
376 }
377 };
378
379 for (i, segment) in segments {
380 let curr = match curr_per_ns.take_types() {
381 Some(r) => r,
382 None => {
383 // we still have path segments left, but the path so far
384 // didn't resolve in the types namespace => no resolution
385 // (don't break here because `curr_per_ns` might contain
386 // something in the value namespace, and it would be wrong
387 // to return that)
388 return ResolvePathResult::empty(ReachedFixedPoint::No);
389 }
390 };
391 // resolve segment in curr
392
393 curr_per_ns = match curr {
394 ModuleDefId::ModuleId(module) => {
395 if module.krate != self.krate {
396 let path =
397 Path { segments: path.segments[i..].to_vec(), kind: PathKind::Self_ };
398 log::debug!("resolving {:?} in other crate", path);
399 let defp_map = db.crate_def_map(module.krate);
400 let (def, s) = defp_map.resolve_path(db, module.module_id, &path);
401 return ResolvePathResult::with(
402 def,
403 ReachedFixedPoint::Yes,
404 s.map(|s| s + i),
405 );
406 }
407
408 // Since it is a qualified path here, it should not contains legacy macros
409 match self[module.module_id].scope.get(&segment.name) {
410 Some(res) => res.def,
411 _ => {
412 log::debug!("path segment {:?} not found", segment.name);
413 return ResolvePathResult::empty(ReachedFixedPoint::No);
414 }
415 }
416 }
417 ModuleDefId::AdtId(AdtId::EnumId(e)) => {
418 // enum variant
419 tested_by!(can_import_enum_variant);
420 let enum_data = db.enum_data(e);
421 match enum_data.variant(&segment.name) {
422 Some(local_id) => {
423 let variant = EnumVariantId { parent: e, local_id };
424 PerNs::both(variant.into(), variant.into())
425 }
426 None => {
427 return ResolvePathResult::with(
428 PerNs::types(e.into()),
429 ReachedFixedPoint::Yes,
430 Some(i),
431 );
432 }
433 }
434 }
435 s => {
436 // could be an inherent method call in UFCS form
437 // (`Struct::method`), or some other kind of associated item
438 log::debug!(
439 "path segment {:?} resolved to non-module {:?}, but is not last",
440 segment.name,
441 curr,
442 );
443
444 return ResolvePathResult::with(
445 PerNs::types(s),
446 ReachedFixedPoint::Yes,
447 Some(i),
448 );
449 }
450 };
451 }
452 ResolvePathResult::with(curr_per_ns, ReachedFixedPoint::Yes, None)
453 }
454
455 fn resolve_name_in_crate_root_or_extern_prelude(&self, name: &Name) -> PerNs {
456 let from_crate_root =
457 self[self.root].scope.get(name).map_or_else(PerNs::none, |res| res.def);
458 let from_extern_prelude = self.resolve_name_in_extern_prelude(name);
459
460 from_crate_root.or(from_extern_prelude)
461 }
462
463 pub(crate) fn resolve_name_in_module(
464 &self,
465 db: &impl DefDatabase2,
466 module: CrateModuleId,
467 name: &Name,
468 ) -> PerNs {
469 // Resolve in:
470 // - legacy scope of macro
471 // - current module / scope
472 // - extern prelude
473 // - std prelude
474 let from_legacy_macro =
475 self[module].scope.get_legacy_macro(name).map_or_else(PerNs::none, PerNs::macros);
476 let from_scope = self[module].scope.get(name).map_or_else(PerNs::none, |res| res.def);
477 let from_extern_prelude =
478 self.extern_prelude.get(name).map_or(PerNs::none(), |&it| PerNs::types(it));
479 let from_prelude = self.resolve_in_prelude(db, name);
480
481 from_legacy_macro.or(from_scope).or(from_extern_prelude).or(from_prelude)
482 }
483
484 fn resolve_name_in_extern_prelude(&self, name: &Name) -> PerNs {
485 self.extern_prelude.get(name).map_or(PerNs::none(), |&it| PerNs::types(it))
486 }
487
488 fn resolve_in_prelude(&self, db: &impl DefDatabase2, name: &Name) -> PerNs {
489 if let Some(prelude) = self.prelude {
490 let keep;
491 let def_map = if prelude.krate == self.krate {
492 self
493 } else {
494 // Extend lifetime
495 keep = db.crate_def_map(prelude.krate);
496 &keep
497 };
498 def_map[prelude.module_id].scope.get(name).map_or_else(PerNs::none, |res| res.def)
499 } else {
500 PerNs::none()
501 }
502 }
503} 261}
504 262
505mod diagnostics { 263mod diagnostics {
diff --git a/crates/ra_hir_def/src/nameres/collector.rs b/crates/ra_hir_def/src/nameres/collector.rs
index 3b61d9895..aacd50df8 100644
--- a/crates/ra_hir_def/src/nameres/collector.rs
+++ b/crates/ra_hir_def/src/nameres/collector.rs
@@ -14,8 +14,8 @@ use crate::{
14 attr::Attr, 14 attr::Attr,
15 db::DefDatabase2, 15 db::DefDatabase2,
16 nameres::{ 16 nameres::{
17 diagnostics::DefDiagnostic, mod_resolution::ModDir, per_ns::PerNs, raw, CrateDefMap, 17 diagnostics::DefDiagnostic, mod_resolution::ModDir, path_resolution::ReachedFixedPoint,
18 ModuleData, ReachedFixedPoint, Resolution, ResolveMode, 18 per_ns::PerNs, raw, CrateDefMap, ModuleData, Resolution, ResolveMode,
19 }, 19 },
20 path::{Path, PathKind}, 20 path::{Path, PathKind},
21 AdtId, AstId, AstItemDef, ConstId, CrateModuleId, EnumId, EnumVariantId, FunctionId, 21 AdtId, AstId, AstItemDef, ConstId, CrateModuleId, EnumId, EnumVariantId, FunctionId,
@@ -182,7 +182,11 @@ where
182 // In Rust, `#[macro_export]` macros are unconditionally visible at the 182 // In Rust, `#[macro_export]` macros are unconditionally visible at the
183 // crate root, even if the parent modules is **not** visible. 183 // crate root, even if the parent modules is **not** visible.
184 if export { 184 if export {
185 self.update(self.def_map.root, None, &[(name, Resolution::from_macro(macro_))]); 185 self.update(
186 self.def_map.root,
187 None,
188 &[(name, Resolution { def: PerNs::macros(macro_), import: None })],
189 );
186 } 190 }
187 } 191 }
188 192
diff --git a/crates/ra_hir_def/src/nameres/mod_resolution.rs b/crates/ra_hir_def/src/nameres/mod_resolution.rs
index f6b0b8fb1..b3b1379d0 100644
--- a/crates/ra_hir_def/src/nameres/mod_resolution.rs
+++ b/crates/ra_hir_def/src/nameres/mod_resolution.rs
@@ -6,7 +6,7 @@ use ra_syntax::SmolStr;
6use crate::{db::DefDatabase2, HirFileId}; 6use crate::{db::DefDatabase2, HirFileId};
7 7
8#[derive(Clone, Debug)] 8#[derive(Clone, Debug)]
9pub struct ModDir { 9pub(super) struct ModDir {
10 /// `.` for `mod.rs`, `lib.rs` 10 /// `.` for `mod.rs`, `lib.rs`
11 /// `./foo` for `foo.rs` 11 /// `./foo` for `foo.rs`
12 /// `./foo/bar` for `mod bar { mod x; }` nested in `foo.rs` 12 /// `./foo/bar` for `mod bar { mod x; }` nested in `foo.rs`
@@ -16,11 +16,15 @@ pub struct ModDir {
16} 16}
17 17
18impl ModDir { 18impl ModDir {
19 pub fn root() -> ModDir { 19 pub(super) fn root() -> ModDir {
20 ModDir { path: RelativePathBuf::default(), root_non_dir_owner: false } 20 ModDir { path: RelativePathBuf::default(), root_non_dir_owner: false }
21 } 21 }
22 22
23 pub fn descend_into_definition(&self, name: &Name, attr_path: Option<&SmolStr>) -> ModDir { 23 pub(super) fn descend_into_definition(
24 &self,
25 name: &Name,
26 attr_path: Option<&SmolStr>,
27 ) -> ModDir {
24 let mut path = self.path.clone(); 28 let mut path = self.path.clone();
25 match attr_to_path(attr_path) { 29 match attr_to_path(attr_path) {
26 None => path.push(&name.to_string()), 30 None => path.push(&name.to_string()),
@@ -34,7 +38,7 @@ impl ModDir {
34 ModDir { path, root_non_dir_owner: false } 38 ModDir { path, root_non_dir_owner: false }
35 } 39 }
36 40
37 pub fn resolve_declaration( 41 pub(super) fn resolve_declaration(
38 &self, 42 &self,
39 db: &impl DefDatabase2, 43 db: &impl DefDatabase2,
40 file_id: HirFileId, 44 file_id: HirFileId,
diff --git a/crates/ra_hir_def/src/nameres/path_resolution.rs b/crates/ra_hir_def/src/nameres/path_resolution.rs
new file mode 100644
index 000000000..95692f826
--- /dev/null
+++ b/crates/ra_hir_def/src/nameres/path_resolution.rs
@@ -0,0 +1,261 @@
1//! This modules implements a function to resolve a path `foo::bar::baz` to a
2//! def, which is used within the name resolution.
3//!
4//! When name resolution is finished, the result of resolving a path is either
5//! `Some(def)` or `None`. However, when we are in process of resolving imports
6//! or macros, there's a third possibility:
7//!
8//! I can't resolve this path right now, but I might be resolve this path
9//! later, when more macros are expanded.
10//!
11//! `ReachedFixedPoint` signals about this.
12
13use hir_expand::name::Name;
14use ra_db::Edition;
15use test_utils::tested_by;
16
17use crate::{
18 db::DefDatabase2,
19 nameres::{per_ns::PerNs, CrateDefMap},
20 path::{Path, PathKind},
21 AdtId, CrateModuleId, EnumVariantId, ModuleDefId, ModuleId,
22};
23
24#[derive(Debug, Clone, Copy, PartialEq, Eq)]
25pub(super) enum ResolveMode {
26 Import,
27 Other,
28}
29
30#[derive(Debug, Clone, Copy, PartialEq, Eq)]
31pub(super) enum ReachedFixedPoint {
32 Yes,
33 No,
34}
35
36#[derive(Debug, Clone)]
37pub(super) struct ResolvePathResult {
38 pub(super) resolved_def: PerNs,
39 pub(super) segment_index: Option<usize>,
40 pub(super) reached_fixedpoint: ReachedFixedPoint,
41}
42
43impl ResolvePathResult {
44 fn empty(reached_fixedpoint: ReachedFixedPoint) -> ResolvePathResult {
45 ResolvePathResult::with(PerNs::none(), reached_fixedpoint, None)
46 }
47
48 fn with(
49 resolved_def: PerNs,
50 reached_fixedpoint: ReachedFixedPoint,
51 segment_index: Option<usize>,
52 ) -> ResolvePathResult {
53 ResolvePathResult { resolved_def, reached_fixedpoint, segment_index }
54 }
55}
56
57impl CrateDefMap {
58 pub(super) fn resolve_name_in_extern_prelude(&self, name: &Name) -> PerNs {
59 self.extern_prelude.get(name).map_or(PerNs::none(), |&it| PerNs::types(it))
60 }
61
62 // Returns Yes if we are sure that additions to `ItemMap` wouldn't change
63 // the result.
64 pub(super) fn resolve_path_fp_with_macro(
65 &self,
66 db: &impl DefDatabase2,
67 mode: ResolveMode,
68 original_module: CrateModuleId,
69 path: &Path,
70 ) -> ResolvePathResult {
71 let mut segments = path.segments.iter().enumerate();
72 let mut curr_per_ns: PerNs = match path.kind {
73 PathKind::DollarCrate(krate) => {
74 if krate == self.krate {
75 tested_by!(macro_dollar_crate_self);
76 PerNs::types(ModuleId { krate: self.krate, module_id: self.root }.into())
77 } else {
78 let def_map = db.crate_def_map(krate);
79 let module = ModuleId { krate, module_id: def_map.root };
80 tested_by!(macro_dollar_crate_other);
81 PerNs::types(module.into())
82 }
83 }
84 PathKind::Crate => {
85 PerNs::types(ModuleId { krate: self.krate, module_id: self.root }.into())
86 }
87 PathKind::Self_ => {
88 PerNs::types(ModuleId { krate: self.krate, module_id: original_module }.into())
89 }
90 // plain import or absolute path in 2015: crate-relative with
91 // fallback to extern prelude (with the simplification in
92 // rust-lang/rust#57745)
93 // FIXME there must be a nicer way to write this condition
94 PathKind::Plain | PathKind::Abs
95 if self.edition == Edition::Edition2015
96 && (path.kind == PathKind::Abs || mode == ResolveMode::Import) =>
97 {
98 let segment = match segments.next() {
99 Some((_, segment)) => segment,
100 None => return ResolvePathResult::empty(ReachedFixedPoint::Yes),
101 };
102 log::debug!("resolving {:?} in crate root (+ extern prelude)", segment);
103 self.resolve_name_in_crate_root_or_extern_prelude(&segment.name)
104 }
105 PathKind::Plain => {
106 let segment = match segments.next() {
107 Some((_, segment)) => segment,
108 None => return ResolvePathResult::empty(ReachedFixedPoint::Yes),
109 };
110 log::debug!("resolving {:?} in module", segment);
111 self.resolve_name_in_module(db, original_module, &segment.name)
112 }
113 PathKind::Super => {
114 if let Some(p) = self.modules[original_module].parent {
115 PerNs::types(ModuleId { krate: self.krate, module_id: p }.into())
116 } else {
117 log::debug!("super path in root module");
118 return ResolvePathResult::empty(ReachedFixedPoint::Yes);
119 }
120 }
121 PathKind::Abs => {
122 // 2018-style absolute path -- only extern prelude
123 let segment = match segments.next() {
124 Some((_, segment)) => segment,
125 None => return ResolvePathResult::empty(ReachedFixedPoint::Yes),
126 };
127 if let Some(def) = self.extern_prelude.get(&segment.name) {
128 log::debug!("absolute path {:?} resolved to crate {:?}", path, def);
129 PerNs::types(*def)
130 } else {
131 return ResolvePathResult::empty(ReachedFixedPoint::No); // extern crate declarations can add to the extern prelude
132 }
133 }
134 PathKind::Type(_) => {
135 // This is handled in `infer::infer_path_expr`
136 // The result returned here does not matter
137 return ResolvePathResult::empty(ReachedFixedPoint::Yes);
138 }
139 };
140
141 for (i, segment) in segments {
142 let curr = match curr_per_ns.take_types() {
143 Some(r) => r,
144 None => {
145 // we still have path segments left, but the path so far
146 // didn't resolve in the types namespace => no resolution
147 // (don't break here because `curr_per_ns` might contain
148 // something in the value namespace, and it would be wrong
149 // to return that)
150 return ResolvePathResult::empty(ReachedFixedPoint::No);
151 }
152 };
153 // resolve segment in curr
154
155 curr_per_ns = match curr {
156 ModuleDefId::ModuleId(module) => {
157 if module.krate != self.krate {
158 let path =
159 Path { segments: path.segments[i..].to_vec(), kind: PathKind::Self_ };
160 log::debug!("resolving {:?} in other crate", path);
161 let defp_map = db.crate_def_map(module.krate);
162 let (def, s) = defp_map.resolve_path(db, module.module_id, &path);
163 return ResolvePathResult::with(
164 def,
165 ReachedFixedPoint::Yes,
166 s.map(|s| s + i),
167 );
168 }
169
170 // Since it is a qualified path here, it should not contains legacy macros
171 match self[module.module_id].scope.get(&segment.name) {
172 Some(res) => res.def,
173 _ => {
174 log::debug!("path segment {:?} not found", segment.name);
175 return ResolvePathResult::empty(ReachedFixedPoint::No);
176 }
177 }
178 }
179 ModuleDefId::AdtId(AdtId::EnumId(e)) => {
180 // enum variant
181 tested_by!(can_import_enum_variant);
182 let enum_data = db.enum_data(e);
183 match enum_data.variant(&segment.name) {
184 Some(local_id) => {
185 let variant = EnumVariantId { parent: e, local_id };
186 PerNs::both(variant.into(), variant.into())
187 }
188 None => {
189 return ResolvePathResult::with(
190 PerNs::types(e.into()),
191 ReachedFixedPoint::Yes,
192 Some(i),
193 );
194 }
195 }
196 }
197 s => {
198 // could be an inherent method call in UFCS form
199 // (`Struct::method`), or some other kind of associated item
200 log::debug!(
201 "path segment {:?} resolved to non-module {:?}, but is not last",
202 segment.name,
203 curr,
204 );
205
206 return ResolvePathResult::with(
207 PerNs::types(s),
208 ReachedFixedPoint::Yes,
209 Some(i),
210 );
211 }
212 };
213 }
214 ResolvePathResult::with(curr_per_ns, ReachedFixedPoint::Yes, None)
215 }
216
217 fn resolve_name_in_module(
218 &self,
219 db: &impl DefDatabase2,
220 module: CrateModuleId,
221 name: &Name,
222 ) -> PerNs {
223 // Resolve in:
224 // - legacy scope of macro
225 // - current module / scope
226 // - extern prelude
227 // - std prelude
228 let from_legacy_macro =
229 self[module].scope.get_legacy_macro(name).map_or_else(PerNs::none, PerNs::macros);
230 let from_scope = self[module].scope.get(name).map_or_else(PerNs::none, |res| res.def);
231 let from_extern_prelude =
232 self.extern_prelude.get(name).map_or(PerNs::none(), |&it| PerNs::types(it));
233 let from_prelude = self.resolve_in_prelude(db, name);
234
235 from_legacy_macro.or(from_scope).or(from_extern_prelude).or(from_prelude)
236 }
237
238 fn resolve_name_in_crate_root_or_extern_prelude(&self, name: &Name) -> PerNs {
239 let from_crate_root =
240 self[self.root].scope.get(name).map_or_else(PerNs::none, |res| res.def);
241 let from_extern_prelude = self.resolve_name_in_extern_prelude(name);
242
243 from_crate_root.or(from_extern_prelude)
244 }
245
246 fn resolve_in_prelude(&self, db: &impl DefDatabase2, name: &Name) -> PerNs {
247 if let Some(prelude) = self.prelude {
248 let keep;
249 let def_map = if prelude.krate == self.krate {
250 self
251 } else {
252 // Extend lifetime
253 keep = db.crate_def_map(prelude.krate);
254 &keep
255 };
256 def_map[prelude.module_id].scope.get(name).map_or_else(PerNs::none, |res| res.def)
257 } else {
258 PerNs::none()
259 }
260 }
261}
diff --git a/crates/ra_hir_def/src/nameres/per_ns.rs b/crates/ra_hir_def/src/nameres/per_ns.rs
index 298b0b0c7..717ed1ef9 100644
--- a/crates/ra_hir_def/src/nameres/per_ns.rs
+++ b/crates/ra_hir_def/src/nameres/per_ns.rs
@@ -4,14 +4,6 @@ use hir_expand::MacroDefId;
4 4
5use crate::ModuleDefId; 5use crate::ModuleDefId;
6 6
7#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
8pub enum Namespace {
9 Types,
10 Values,
11 // Note that only type inference uses this enum, and it doesn't care about macros.
12 // Macro,
13}
14
15#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] 7#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
16pub struct PerNs { 8pub struct PerNs {
17 pub types: Option<ModuleDefId>, 9 pub types: Option<ModuleDefId>,
diff --git a/crates/ra_hir_def/src/nameres/raw.rs b/crates/ra_hir_def/src/nameres/raw.rs
index cb47fa317..369376f30 100644
--- a/crates/ra_hir_def/src/nameres/raw.rs
+++ b/crates/ra_hir_def/src/nameres/raw.rs
@@ -88,7 +88,7 @@ impl RawItems {
88 (Arc::new(collector.raw_items), Arc::new(collector.source_map)) 88 (Arc::new(collector.raw_items), Arc::new(collector.source_map))
89 } 89 }
90 90
91 pub fn items(&self) -> &[RawItem] { 91 pub(super) fn items(&self) -> &[RawItem] {
92 &self.items 92 &self.items
93 } 93 }
94} 94}
@@ -125,19 +125,19 @@ impl Index<Macro> for RawItems {
125type Attrs = Option<Arc<[Attr]>>; 125type Attrs = Option<Arc<[Attr]>>;
126 126
127#[derive(Debug, PartialEq, Eq, Clone)] 127#[derive(Debug, PartialEq, Eq, Clone)]
128pub struct RawItem { 128pub(super) struct RawItem {
129 attrs: Attrs, 129 attrs: Attrs,
130 pub kind: RawItemKind, 130 pub(super) kind: RawItemKind,
131} 131}
132 132
133impl RawItem { 133impl RawItem {
134 pub fn attrs(&self) -> &[Attr] { 134 pub(super) fn attrs(&self) -> &[Attr] {
135 self.attrs.as_ref().map_or(&[], |it| &*it) 135 self.attrs.as_ref().map_or(&[], |it| &*it)
136 } 136 }
137} 137}
138 138
139#[derive(Debug, PartialEq, Eq, Clone, Copy)] 139#[derive(Debug, PartialEq, Eq, Clone, Copy)]
140pub enum RawItemKind { 140pub(super) enum RawItemKind {
141 Module(Module), 141 Module(Module),
142 Import(ImportId), 142 Import(ImportId),
143 Def(Def), 143 Def(Def),
@@ -145,11 +145,11 @@ pub enum RawItemKind {
145} 145}
146 146
147#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] 147#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
148pub struct Module(RawId); 148pub(super) struct Module(RawId);
149impl_arena_id!(Module); 149impl_arena_id!(Module);
150 150
151#[derive(Debug, PartialEq, Eq)] 151#[derive(Debug, PartialEq, Eq)]
152pub enum ModuleData { 152pub(super) enum ModuleData {
153 Declaration { name: Name, ast_id: FileAstId<ast::Module> }, 153 Declaration { name: Name, ast_id: FileAstId<ast::Module> },
154 Definition { name: Name, ast_id: FileAstId<ast::Module>, items: Vec<RawItem> }, 154 Definition { name: Name, ast_id: FileAstId<ast::Module>, items: Vec<RawItem> },
155} 155}
@@ -160,26 +160,26 @@ impl_arena_id!(ImportId);
160 160
161#[derive(Debug, Clone, PartialEq, Eq)] 161#[derive(Debug, Clone, PartialEq, Eq)]
162pub struct ImportData { 162pub struct ImportData {
163 pub path: Path, 163 pub(super) path: Path,
164 pub alias: Option<Name>, 164 pub(super) alias: Option<Name>,
165 pub is_glob: bool, 165 pub(super) is_glob: bool,
166 pub is_prelude: bool, 166 pub(super) is_prelude: bool,
167 pub is_extern_crate: bool, 167 pub(super) is_extern_crate: bool,
168 pub is_macro_use: bool, 168 pub(super) is_macro_use: bool,
169} 169}
170 170
171#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] 171#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
172pub struct Def(RawId); 172pub(super) struct Def(RawId);
173impl_arena_id!(Def); 173impl_arena_id!(Def);
174 174
175#[derive(Debug, PartialEq, Eq)] 175#[derive(Debug, PartialEq, Eq)]
176pub struct DefData { 176pub(super) struct DefData {
177 pub name: Name, 177 pub(super) name: Name,
178 pub kind: DefKind, 178 pub(super) kind: DefKind,
179} 179}
180 180
181#[derive(Debug, PartialEq, Eq, Clone, Copy)] 181#[derive(Debug, PartialEq, Eq, Clone, Copy)]
182pub enum DefKind { 182pub(super) enum DefKind {
183 Function(FileAstId<ast::FnDef>), 183 Function(FileAstId<ast::FnDef>),
184 Struct(FileAstId<ast::StructDef>), 184 Struct(FileAstId<ast::StructDef>),
185 Union(FileAstId<ast::StructDef>), 185 Union(FileAstId<ast::StructDef>),
@@ -191,15 +191,15 @@ pub enum DefKind {
191} 191}
192 192
193#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] 193#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
194pub struct Macro(RawId); 194pub(super) struct Macro(RawId);
195impl_arena_id!(Macro); 195impl_arena_id!(Macro);
196 196
197#[derive(Debug, PartialEq, Eq)] 197#[derive(Debug, PartialEq, Eq)]
198pub struct MacroData { 198pub(super) struct MacroData {
199 pub ast_id: FileAstId<ast::MacroCall>, 199 pub(super) ast_id: FileAstId<ast::MacroCall>,
200 pub path: Path, 200 pub(super) path: Path,
201 pub name: Option<Name>, 201 pub(super) name: Option<Name>,
202 pub export: bool, 202 pub(super) export: bool,
203} 203}
204 204
205struct RawItemsCollector { 205struct RawItemsCollector {