diff options
Diffstat (limited to 'crates/ra_hir_def')
-rw-r--r-- | crates/ra_hir_def/src/nameres.rs | 270 | ||||
-rw-r--r-- | crates/ra_hir_def/src/nameres/collector.rs | 10 | ||||
-rw-r--r-- | crates/ra_hir_def/src/nameres/mod_resolution.rs | 12 | ||||
-rw-r--r-- | crates/ra_hir_def/src/nameres/path_resolution.rs | 261 | ||||
-rw-r--r-- | crates/ra_hir_def/src/nameres/per_ns.rs | 8 | ||||
-rw-r--r-- | crates/ra_hir_def/src/nameres/raw.rs | 48 |
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 | ||
51 | pub mod raw; | 50 | pub mod raw; |
52 | pub mod per_ns; | 51 | pub mod per_ns; |
53 | pub mod collector; | 52 | mod collector; |
54 | pub mod mod_resolution; | 53 | mod mod_resolution; |
54 | mod path_resolution; | ||
55 | 55 | ||
56 | #[cfg(test)] | 56 | #[cfg(test)] |
57 | mod tests; | 57 | mod tests; |
@@ -65,14 +65,15 @@ use ra_db::{CrateId, Edition, FileId}; | |||
65 | use ra_prof::profile; | 65 | use ra_prof::profile; |
66 | use ra_syntax::ast; | 66 | use ra_syntax::ast; |
67 | use rustc_hash::{FxHashMap, FxHashSet}; | 67 | use rustc_hash::{FxHashMap, FxHashSet}; |
68 | use test_utils::tested_by; | ||
69 | 68 | ||
70 | use crate::{ | 69 | use 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 | ||
198 | impl 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)] | ||
205 | struct ResolvePathResult { | ||
206 | resolved_def: PerNs, | ||
207 | segment_index: Option<usize>, | ||
208 | reached_fixedpoint: ReachedFixedPoint, | ||
209 | } | ||
210 | |||
211 | impl 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)] | ||
226 | enum ResolveMode { | ||
227 | Import, | ||
228 | Other, | ||
229 | } | ||
230 | |||
231 | #[derive(Debug, Clone, Copy, PartialEq, Eq)] | ||
232 | enum ReachedFixedPoint { | ||
233 | Yes, | ||
234 | No, | ||
235 | } | ||
236 | |||
237 | impl CrateDefMap { | 199 | impl 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 | ||
505 | mod diagnostics { | 263 | mod 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; | |||
6 | use crate::{db::DefDatabase2, HirFileId}; | 6 | use crate::{db::DefDatabase2, HirFileId}; |
7 | 7 | ||
8 | #[derive(Clone, Debug)] | 8 | #[derive(Clone, Debug)] |
9 | pub struct ModDir { | 9 | pub(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 | ||
18 | impl ModDir { | 18 | impl 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 | |||
13 | use hir_expand::name::Name; | ||
14 | use ra_db::Edition; | ||
15 | use test_utils::tested_by; | ||
16 | |||
17 | use 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)] | ||
25 | pub(super) enum ResolveMode { | ||
26 | Import, | ||
27 | Other, | ||
28 | } | ||
29 | |||
30 | #[derive(Debug, Clone, Copy, PartialEq, Eq)] | ||
31 | pub(super) enum ReachedFixedPoint { | ||
32 | Yes, | ||
33 | No, | ||
34 | } | ||
35 | |||
36 | #[derive(Debug, Clone)] | ||
37 | pub(super) struct ResolvePathResult { | ||
38 | pub(super) resolved_def: PerNs, | ||
39 | pub(super) segment_index: Option<usize>, | ||
40 | pub(super) reached_fixedpoint: ReachedFixedPoint, | ||
41 | } | ||
42 | |||
43 | impl 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 | |||
57 | impl 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 | ||
5 | use crate::ModuleDefId; | 5 | use crate::ModuleDefId; |
6 | 6 | ||
7 | #[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)] | ||
8 | pub 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)] |
16 | pub struct PerNs { | 8 | pub 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 { | |||
125 | type Attrs = Option<Arc<[Attr]>>; | 125 | type Attrs = Option<Arc<[Attr]>>; |
126 | 126 | ||
127 | #[derive(Debug, PartialEq, Eq, Clone)] | 127 | #[derive(Debug, PartialEq, Eq, Clone)] |
128 | pub struct RawItem { | 128 | pub(super) struct RawItem { |
129 | attrs: Attrs, | 129 | attrs: Attrs, |
130 | pub kind: RawItemKind, | 130 | pub(super) kind: RawItemKind, |
131 | } | 131 | } |
132 | 132 | ||
133 | impl RawItem { | 133 | impl 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)] |
140 | pub enum RawItemKind { | 140 | pub(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)] |
148 | pub struct Module(RawId); | 148 | pub(super) struct Module(RawId); |
149 | impl_arena_id!(Module); | 149 | impl_arena_id!(Module); |
150 | 150 | ||
151 | #[derive(Debug, PartialEq, Eq)] | 151 | #[derive(Debug, PartialEq, Eq)] |
152 | pub enum ModuleData { | 152 | pub(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)] |
162 | pub struct ImportData { | 162 | pub 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)] |
172 | pub struct Def(RawId); | 172 | pub(super) struct Def(RawId); |
173 | impl_arena_id!(Def); | 173 | impl_arena_id!(Def); |
174 | 174 | ||
175 | #[derive(Debug, PartialEq, Eq)] | 175 | #[derive(Debug, PartialEq, Eq)] |
176 | pub struct DefData { | 176 | pub(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)] |
182 | pub enum DefKind { | 182 | pub(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)] |
194 | pub struct Macro(RawId); | 194 | pub(super) struct Macro(RawId); |
195 | impl_arena_id!(Macro); | 195 | impl_arena_id!(Macro); |
196 | 196 | ||
197 | #[derive(Debug, PartialEq, Eq)] | 197 | #[derive(Debug, PartialEq, Eq)] |
198 | pub struct MacroData { | 198 | pub(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 | ||
205 | struct RawItemsCollector { | 205 | struct RawItemsCollector { |