1use either::Either;
14use hir_expand::{
15 mod_path::{ModPath, PathKind},
16 name::Name,
17};
18use span::Edition;
19use stdx::TupleExt;
20
21use crate::{
22 AdtId, LocalModuleId, ModuleDefId,
23 db::DefDatabase,
24 item_scope::{BUILTIN_SCOPE, ImportOrExternCrate},
25 item_tree::FieldsShape,
26 nameres::{
27 BlockInfo, BuiltinShadowMode, DefMap, LocalDefMap, MacroSubNs, assoc::TraitItems,
28 crate_def_map, sub_namespace_match,
29 },
30 per_ns::PerNs,
31 visibility::{RawVisibility, Visibility},
32};
33
34#[derive(Debug, Clone, Copy, PartialEq, Eq)]
35pub(super) enum ResolveMode {
36 Import,
37 Other,
38}
39
40#[derive(Debug, Clone, Copy, PartialEq, Eq)]
41pub(super) enum ReachedFixedPoint {
42 Yes,
43 No,
44}
45
46#[derive(Debug, Clone)]
47pub(super) struct ResolvePathResult {
48 pub(super) resolved_def: PerNs,
49 pub(super) segment_index: Option<usize>,
51 pub(super) reached_fixedpoint: ReachedFixedPoint,
52 pub(super) prefix_info: ResolvePathResultPrefixInfo,
53}
54
55#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
56pub struct ResolvePathResultPrefixInfo {
57 pub(crate) differing_crate: bool,
58 pub enum_variant: bool,
60}
61
62impl ResolvePathResult {
63 fn empty(reached_fixedpoint: ReachedFixedPoint) -> ResolvePathResult {
64 ResolvePathResult::new(
65 PerNs::none(),
66 reached_fixedpoint,
67 None,
68 ResolvePathResultPrefixInfo::default(),
69 )
70 }
71
72 fn new(
73 resolved_def: PerNs,
74 reached_fixedpoint: ReachedFixedPoint,
75 segment_index: Option<usize>,
76 prefix_info: ResolvePathResultPrefixInfo,
77 ) -> ResolvePathResult {
78 ResolvePathResult { resolved_def, segment_index, reached_fixedpoint, prefix_info }
79 }
80}
81
82impl PerNs {
83 pub(super) fn filter_macro(
84 mut self,
85 db: &dyn DefDatabase,
86 expected: Option<MacroSubNs>,
87 ) -> Self {
88 self.macros = self.macros.filter(|def| {
89 let this = MacroSubNs::from_id(db, def.def);
90 sub_namespace_match(Some(this), expected)
91 });
92
93 self
94 }
95}
96
97impl DefMap {
98 pub(crate) fn resolve_visibility(
99 &self,
100 local_def_map: &LocalDefMap,
101 db: &dyn DefDatabase,
102 original_module: LocalModuleId,
104 visibility: &RawVisibility,
107 within_impl: bool,
108 ) -> Option<Visibility> {
109 let vis = match visibility {
110 RawVisibility::Module(path, explicitness) => {
111 let (result, remaining) = self.resolve_path(
112 local_def_map,
113 db,
114 original_module,
115 path,
116 BuiltinShadowMode::Module,
117 None,
118 );
119 if remaining.is_some() {
120 return None;
121 }
122 let types = result.take_types()?;
123 let mut vis = match types {
124 ModuleDefId::ModuleId(m) => Visibility::Module(m, *explicitness),
125 _ => {
127 return None;
128 }
129 };
130
131 if let Visibility::Module(m, mv) = vis {
135 if self.block_id() != m.block && !within_impl {
137 vis = Visibility::Module(self.module_id(Self::ROOT), mv);
138 tracing::debug!(
139 "visibility {:?} points outside DefMap, adjusting to {:?}",
140 m,
141 vis
142 );
143 }
144 }
145 vis
146 }
147 RawVisibility::PubSelf(explicitness) => {
148 Visibility::Module(self.module_id(original_module), *explicitness)
149 }
150 RawVisibility::Public => Visibility::Public,
151 RawVisibility::PubCrate => Visibility::PubCrate(self.krate),
152 };
153 Some(vis)
154 }
155
156 pub(super) fn resolve_path_fp_with_macro(
159 &self,
160 local_def_map: &LocalDefMap,
161 db: &dyn DefDatabase,
162 mode: ResolveMode,
163 mut original_module: LocalModuleId,
165 path: &ModPath,
166 shadow: BuiltinShadowMode,
167 expected_macro_subns: Option<MacroSubNs>,
170 ) -> ResolvePathResult {
171 let mut result = self.resolve_path_fp_with_macro_single(
172 local_def_map,
173 db,
174 mode,
175 original_module,
176 path,
177 shadow,
178 expected_macro_subns,
179 );
180
181 if self.block.is_none() {
182 return result;
184 }
185
186 let mut current_map = self;
187
188 let mut merge = |new: ResolvePathResult| {
189 result.resolved_def = result.resolved_def.or(new.resolved_def);
190 if result.reached_fixedpoint == ReachedFixedPoint::No {
191 result.reached_fixedpoint = new.reached_fixedpoint;
192 }
193 result.prefix_info.differing_crate |= new.prefix_info.differing_crate;
194 result.prefix_info.enum_variant |= new.prefix_info.enum_variant;
195 result.segment_index = match (result.segment_index, new.segment_index) {
196 (Some(idx), None) => Some(idx),
197 (Some(old), Some(new)) => Some(old.max(new)),
198 (None, new) => new,
199 };
200 };
201
202 loop {
203 match current_map.block {
204 Some(block) if original_module == Self::ROOT => {
205 original_module = block.parent.local_id;
207 current_map = block.parent.def_map(db, current_map.krate);
208 }
209 _ => {
211 if original_module != Self::ROOT && current_map.block.is_some() {
212 original_module = Self::ROOT;
215 current_map = crate_def_map(db, self.krate);
216
217 let new = current_map.resolve_path_fp_in_all_preludes(
218 local_def_map,
219 db,
220 mode,
221 original_module,
222 path,
223 shadow,
224 );
225 merge(new);
226 }
227
228 return result;
229 }
230 }
231
232 let new = current_map.resolve_path_fp_with_macro_single(
233 local_def_map,
234 db,
235 mode,
236 original_module,
237 path,
238 shadow,
239 expected_macro_subns,
240 );
241
242 merge(new);
243 }
244 }
245
246 pub(super) fn resolve_path_fp_with_macro_single(
247 &self,
248 local_def_map: &LocalDefMap,
249 db: &dyn DefDatabase,
250 mode: ResolveMode,
251 original_module: LocalModuleId,
252 path: &ModPath,
253 shadow: BuiltinShadowMode,
254 expected_macro_subns: Option<MacroSubNs>,
255 ) -> ResolvePathResult {
256 let mut segments = path.segments().iter().enumerate();
257 let curr_per_ns = match path.kind {
258 PathKind::DollarCrate(krate) => {
259 if krate == self.krate {
260 cov_mark::hit!(macro_dollar_crate_self);
261 PerNs::types(self.crate_root().into(), Visibility::Public, None)
262 } else {
263 let def_map = crate_def_map(db, krate);
264 let module = def_map.module_id(Self::ROOT);
265 cov_mark::hit!(macro_dollar_crate_other);
266 PerNs::types(module.into(), Visibility::Public, None)
267 }
268 }
269 PathKind::Crate => PerNs::types(self.crate_root().into(), Visibility::Public, None),
270 PathKind::Plain | PathKind::Abs
275 if self.data.edition == Edition::Edition2015
276 && (path.kind == PathKind::Abs || mode == ResolveMode::Import) =>
277 {
278 let (_, segment) = match segments.next() {
279 Some((idx, segment)) => (idx, segment),
280 None => return ResolvePathResult::empty(ReachedFixedPoint::Yes),
281 };
282 tracing::debug!("resolving {:?} in crate root (+ extern prelude)", segment);
283 self.resolve_name_in_crate_root_or_extern_prelude(
284 local_def_map,
285 db,
286 original_module,
287 segment,
288 )
289 }
290 PathKind::Plain => {
291 let (_, segment) = match segments.next() {
292 Some((idx, segment)) => (idx, segment),
293 None => return ResolvePathResult::empty(ReachedFixedPoint::Yes),
294 };
295 let prefer_module =
302 if path.segments().len() == 1 { shadow } else { BuiltinShadowMode::Module };
303
304 tracing::debug!("resolving {:?} in module", segment);
305 self.resolve_name_in_module(
306 local_def_map,
307 db,
308 original_module,
309 segment,
310 prefer_module,
311 expected_macro_subns,
312 )
313 }
314 PathKind::Super(lvl) => {
315 let mut local_id = original_module;
316 let mut ext;
317 let mut def_map = self;
318
319 if def_map.module_id(local_id).is_block_module() {
321 (ext, local_id) = adjust_to_nearest_non_block_module(db, def_map, local_id);
322 def_map = ext;
323 }
324
325 for _ in 0..lvl {
328 if let Some(parent) = def_map.modules[local_id].parent {
331 local_id = parent;
332 if def_map.module_id(local_id).is_block_module() {
333 (ext, local_id) =
334 adjust_to_nearest_non_block_module(db, def_map, local_id);
335 def_map = ext;
336 }
337 } else {
338 stdx::always!(def_map.block.is_none());
339 tracing::debug!("super path in root module");
340 return ResolvePathResult::empty(ReachedFixedPoint::Yes);
341 }
342 }
343
344 let module = def_map.module_id(local_id);
345 stdx::never!(module.is_block_module());
346
347 if self.block != def_map.block {
348 let path =
351 ModPath::from_segments(PathKind::SELF, path.segments().iter().cloned());
352 return def_map.resolve_path_fp_with_macro(
354 local_def_map,
355 db,
356 mode,
357 local_id,
358 &path,
359 shadow,
360 expected_macro_subns,
361 );
362 }
363
364 PerNs::types(module.into(), Visibility::Public, None)
365 }
366 PathKind::Abs => match self.resolve_path_abs(local_def_map, &mut segments, path) {
367 Either::Left(it) => it,
368 Either::Right(reached_fixed_point) => {
369 return ResolvePathResult::empty(reached_fixed_point);
370 }
371 },
372 };
373
374 self.resolve_remaining_segments(
375 db,
376 mode,
377 segments,
378 curr_per_ns,
379 path,
380 shadow,
381 original_module,
382 )
383 }
384
385 pub(super) fn resolve_path_fp_in_all_preludes(
387 &self,
388 local_def_map: &LocalDefMap,
389 db: &dyn DefDatabase,
390 mode: ResolveMode,
391 original_module: LocalModuleId,
392 path: &ModPath,
393 shadow: BuiltinShadowMode,
394 ) -> ResolvePathResult {
395 let mut segments = path.segments().iter().enumerate();
396 let curr_per_ns = match path.kind {
397 PathKind::Plain | PathKind::Abs
402 if self.data.edition == Edition::Edition2015
403 && (path.kind == PathKind::Abs || mode == ResolveMode::Import) =>
404 {
405 let (_, segment) = match segments.next() {
406 Some((idx, segment)) => (idx, segment),
407 None => return ResolvePathResult::empty(ReachedFixedPoint::Yes),
408 };
409 tracing::debug!("resolving {:?} in crate root (+ extern prelude)", segment);
410 self.resolve_name_in_extern_prelude(local_def_map, segment)
411 }
412 PathKind::Plain => {
413 let (_, segment) = match segments.next() {
414 Some((idx, segment)) => (idx, segment),
415 None => return ResolvePathResult::empty(ReachedFixedPoint::Yes),
416 };
417 tracing::debug!("resolving {:?} in module", segment);
418 self.resolve_name_in_all_preludes(local_def_map, db, segment)
419 }
420 PathKind::Abs => match self.resolve_path_abs(local_def_map, &mut segments, path) {
421 Either::Left(it) => it,
422 Either::Right(reached_fixed_point) => {
423 return ResolvePathResult::empty(reached_fixed_point);
424 }
425 },
426 PathKind::DollarCrate(_) | PathKind::Crate | PathKind::Super(_) => {
427 return ResolvePathResult::empty(ReachedFixedPoint::Yes);
428 }
429 };
430
431 self.resolve_remaining_segments(
432 db,
433 mode,
434 segments,
435 curr_per_ns,
436 path,
437 shadow,
438 original_module,
439 )
440 }
441
442 fn resolve_path_abs<'a>(
444 &self,
445 local_def_map: &LocalDefMap,
446 segments: &mut impl Iterator<Item = (usize, &'a Name)>,
447 path: &ModPath,
448 ) -> Either<PerNs, ReachedFixedPoint> {
449 let segment = match segments.next() {
450 Some((_, segment)) => segment,
451 None => return Either::Right(ReachedFixedPoint::Yes),
452 };
453 if let Some(&(def, extern_crate)) = local_def_map.extern_prelude.get(segment) {
454 tracing::debug!("absolute path {:?} resolved to crate {:?}", path, def);
455 Either::Left(PerNs::types(
456 def.into(),
457 Visibility::Public,
458 extern_crate.map(ImportOrExternCrate::ExternCrate),
459 ))
460 } else {
461 Either::Right(ReachedFixedPoint::No) }
463 }
464
465 fn resolve_remaining_segments<'a>(
466 &self,
467 db: &dyn DefDatabase,
468 mode: ResolveMode,
469 mut segments: impl Iterator<Item = (usize, &'a Name)>,
470 mut curr_per_ns: PerNs,
471 path: &ModPath,
472 shadow: BuiltinShadowMode,
473 original_module: LocalModuleId,
474 ) -> ResolvePathResult {
475 while let Some((i, segment)) = segments.next() {
476 let curr = match curr_per_ns.take_types_full() {
477 Some(r) => r,
478 None => {
479 return ResolvePathResult::empty(ReachedFixedPoint::No);
485 }
486 };
487 curr_per_ns = match curr.def {
490 ModuleDefId::ModuleId(module) => {
491 if module.krate != self.krate {
492 let path = ModPath::from_segments(
494 PathKind::SELF,
495 path.segments()[i..].iter().cloned(),
496 );
497 tracing::debug!("resolving {:?} in other crate", path);
498 let defp_map = module.def_map(db);
499 let resolution = defp_map.resolve_path_fp_with_macro(
504 LocalDefMap::EMPTY,
505 db,
506 mode,
507 module.local_id,
508 &path,
509 shadow,
510 None,
511 );
512 return ResolvePathResult::new(
513 resolution.resolved_def,
514 ReachedFixedPoint::Yes,
515 resolution.segment_index.map(|s| s + i),
516 ResolvePathResultPrefixInfo {
517 differing_crate: true,
518 enum_variant: resolution.prefix_info.enum_variant,
519 },
520 );
521 }
522
523 let def_map;
524 let module_data = if module.block == self.block_id() {
525 &self[module.local_id]
526 } else {
527 def_map = module.def_map(db);
528 &def_map[module.local_id]
529 };
530
531 module_data.scope.get(segment)
533 }
534 ModuleDefId::AdtId(AdtId::EnumId(e)) => {
535 cov_mark::hit!(can_import_enum_variant);
537
538 let res = e
539 .enum_variants(db)
540 .variants
541 .iter()
542 .find(|(_, name, _)| name == segment)
543 .map(|&(variant, _, shape)| match shape {
544 FieldsShape::Record => {
545 PerNs::types(variant.into(), Visibility::Public, None)
546 }
547 FieldsShape::Tuple | FieldsShape::Unit => PerNs::both(
548 variant.into(),
549 variant.into(),
550 Visibility::Public,
551 None,
552 ),
553 });
554 return match res {
556 Some(res) => {
557 if segments.next().is_some() {
558 ResolvePathResult::empty(ReachedFixedPoint::No)
560 } else {
561 ResolvePathResult::new(
562 res,
563 ReachedFixedPoint::Yes,
564 None,
565 ResolvePathResultPrefixInfo {
566 enum_variant: true,
567 ..ResolvePathResultPrefixInfo::default()
568 },
569 )
570 }
571 }
572 None => ResolvePathResult::new(
573 PerNs::types(e.into(), curr.vis, curr.import),
574 ReachedFixedPoint::Yes,
575 Some(i),
576 ResolvePathResultPrefixInfo::default(),
577 ),
578 };
579 }
580 def @ ModuleDefId::TraitId(t) if mode == ResolveMode::Import => {
581 let item = if true {
588 None
589 } else {
590 TraitItems::query(db, t).assoc_item_by_name(segment)
591 };
592 return match item {
593 Some(item) => ResolvePathResult::new(
594 match item {
595 crate::AssocItemId::FunctionId(function_id) => PerNs::values(
596 function_id.into(),
597 curr.vis,
598 curr.import.and_then(|it| it.import_or_glob()),
599 ),
600 crate::AssocItemId::ConstId(const_id) => PerNs::values(
601 const_id.into(),
602 curr.vis,
603 curr.import.and_then(|it| it.import_or_glob()),
604 ),
605 crate::AssocItemId::TypeAliasId(type_alias_id) => {
606 PerNs::types(type_alias_id.into(), curr.vis, curr.import)
607 }
608 },
609 ReachedFixedPoint::Yes,
610 segments.next().map(TupleExt::head),
611 ResolvePathResultPrefixInfo::default(),
612 ),
613 None => ResolvePathResult::new(
614 PerNs::types(def, curr.vis, curr.import),
615 ReachedFixedPoint::Yes,
616 Some(i),
617 ResolvePathResultPrefixInfo::default(),
618 ),
619 };
620 }
621 s => {
622 tracing::debug!(
625 "path segment {:?} resolved to non-module {:?}, but is not last",
626 segment,
627 curr,
628 );
629
630 return ResolvePathResult::new(
631 PerNs::types(s, curr.vis, curr.import),
632 ReachedFixedPoint::Yes,
633 Some(i),
634 ResolvePathResultPrefixInfo::default(),
635 );
636 }
637 };
638
639 curr_per_ns = curr_per_ns
640 .filter_visibility(|vis| vis.is_visible_from_def_map(db, self, original_module));
641 }
642
643 ResolvePathResult::new(
644 curr_per_ns,
645 ReachedFixedPoint::Yes,
646 None,
647 ResolvePathResultPrefixInfo::default(),
648 )
649 }
650
651 fn resolve_name_in_module(
652 &self,
653 local_def_map: &LocalDefMap,
654 db: &dyn DefDatabase,
655 module: LocalModuleId,
656 name: &Name,
657 shadow: BuiltinShadowMode,
658 expected_macro_subns: Option<MacroSubNs>,
659 ) -> PerNs {
660 let from_legacy_macro = self[module]
666 .scope
667 .get_legacy_macro(name)
668 .and_then(|it| it.last())
670 .copied()
671 .filter(|&id| {
672 sub_namespace_match(Some(MacroSubNs::from_id(db, id)), expected_macro_subns)
673 })
674 .map_or_else(PerNs::none, |m| PerNs::macros(m, Visibility::Public, None));
675 let from_scope = self[module].scope.get(name).filter_macro(db, expected_macro_subns);
676 let from_builtin = match self.block {
677 Some(_) => {
678 PerNs::none()
680 }
681 None => BUILTIN_SCOPE.get(name).copied().unwrap_or_else(PerNs::none),
682 };
683 let from_scope_or_builtin = match shadow {
684 BuiltinShadowMode::Module => from_scope.or(from_builtin),
685 BuiltinShadowMode::Other => match from_scope.take_types() {
686 Some(ModuleDefId::ModuleId(_)) => from_builtin.or(from_scope),
687 Some(_) | None => from_scope.or(from_builtin),
688 },
689 };
690
691 let extern_prelude = || {
692 if self.block.is_some() && module == DefMap::ROOT {
693 return PerNs::none();
696 }
697 self.resolve_name_in_extern_prelude(local_def_map, name)
698 };
699 let macro_use_prelude = || self.resolve_in_macro_use_prelude(name);
700 let prelude = || {
701 if self.block.is_some() && module == DefMap::ROOT {
702 return PerNs::none();
703 }
704 self.resolve_in_prelude(db, name)
705 };
706
707 from_legacy_macro
708 .or(from_scope_or_builtin)
709 .or_else(extern_prelude)
710 .or_else(macro_use_prelude)
711 .or_else(prelude)
712 }
713
714 fn resolve_name_in_all_preludes(
715 &self,
716 local_def_map: &LocalDefMap,
717 db: &dyn DefDatabase,
718 name: &Name,
719 ) -> PerNs {
720 let extern_prelude = self.resolve_name_in_extern_prelude(local_def_map, name);
724 let macro_use_prelude = || self.resolve_in_macro_use_prelude(name);
725 let prelude = || self.resolve_in_prelude(db, name);
726
727 extern_prelude.or_else(macro_use_prelude).or_else(prelude)
728 }
729
730 fn resolve_name_in_extern_prelude(&self, local_def_map: &LocalDefMap, name: &Name) -> PerNs {
731 local_def_map.extern_prelude.get(name).map_or(PerNs::none(), |&(it, extern_crate)| {
732 PerNs::types(
733 it.into(),
734 Visibility::Public,
735 extern_crate.map(ImportOrExternCrate::ExternCrate),
736 )
737 })
738 }
739
740 fn resolve_in_macro_use_prelude(&self, name: &Name) -> PerNs {
741 self.macro_use_prelude.get(name).map_or(PerNs::none(), |&(it, extern_crate)| {
742 PerNs::macros(
743 it,
744 Visibility::Public,
745 extern_crate.map(ImportOrExternCrate::ExternCrate),
746 )
747 })
748 }
749
750 fn resolve_name_in_crate_root_or_extern_prelude(
751 &self,
752 local_def_map: &LocalDefMap,
753 db: &dyn DefDatabase,
754 module: LocalModuleId,
755 name: &Name,
756 ) -> PerNs {
757 let from_crate_root = match self.block {
758 Some(_) => {
759 let def_map = self.crate_root().def_map(db);
760 def_map[Self::ROOT].scope.get(name)
761 }
762 None => self[Self::ROOT].scope.get(name),
763 };
764 let from_extern_prelude = || {
765 if self.block.is_some() && module == DefMap::ROOT {
766 return PerNs::none();
768 }
769 self.resolve_name_in_extern_prelude(local_def_map, name)
770 };
771
772 from_crate_root.or_else(from_extern_prelude)
773 }
774
775 fn resolve_in_prelude(&self, db: &dyn DefDatabase, name: &Name) -> PerNs {
776 if let Some((prelude, _use)) = self.prelude {
777 let keep;
778 let def_map = if prelude.krate == self.krate {
779 self
780 } else {
781 keep = prelude.def_map(db);
783 keep
784 };
785 def_map[prelude.local_id].scope.get(name)
786 } else {
787 PerNs::none()
788 }
789 }
790}
791
792fn adjust_to_nearest_non_block_module<'db>(
794 db: &'db dyn DefDatabase,
795 def_map: &'db DefMap,
796 mut local_id: LocalModuleId,
797) -> (&'db DefMap, LocalModuleId) {
798 stdx::always!(def_map.module_id(local_id).is_block_module());
800
801 let mut def_map = def_map;
803 loop {
804 let BlockInfo { parent, .. } = def_map.block.expect("block module without parent module");
805
806 def_map = parent.def_map(db, def_map.krate);
807 local_id = parent.local_id;
808 if !parent.is_block_module() {
809 return (def_map, local_id);
810 }
811 }
812}