mun_hir/name_resolution/
path_resolution.rs1use crate::{
2 ids::{ItemDefinitionId, ModuleId},
3 item_scope::BUILTIN_SCOPE,
4 module_tree::LocalModuleId,
5 package_defs::PackageDefs,
6 DefDatabase, Name, PackageId, Path, PathKind, PerNs, Visibility,
7};
8use std::iter::successors;
9
10#[derive(Debug, Clone, Copy, PartialEq, Eq)]
14pub enum ReachedFixedPoint {
15 Yes,
16 No,
17}
18
19#[derive(Debug, Clone)]
22pub(crate) struct ResolvePathResult {
23 pub(crate) resolved_def: PerNs<(ItemDefinitionId, Visibility)>,
24 pub(crate) segment_index: Option<usize>,
25 pub(crate) reached_fixedpoint: ReachedFixedPoint,
26 pub(crate) package: Option<PackageId>,
27}
28
29impl ResolvePathResult {
30 fn empty(reached_fixedpoint: ReachedFixedPoint) -> ResolvePathResult {
32 ResolvePathResult::with(PerNs::none(), reached_fixedpoint, None, None)
33 }
34
35 fn with(
37 resolved_def: PerNs<(ItemDefinitionId, Visibility)>,
38 reached_fixedpoint: ReachedFixedPoint,
39 segment_index: Option<usize>,
40 package: Option<PackageId>,
41 ) -> ResolvePathResult {
42 ResolvePathResult {
43 resolved_def,
44 segment_index,
45 reached_fixedpoint,
46 package,
47 }
48 }
49}
50
51impl PackageDefs {
52 pub(crate) fn resolve_path_in_module(
56 &self,
57 db: &dyn DefDatabase,
58 module: LocalModuleId,
59 path: &Path,
60 ) -> (PerNs<(ItemDefinitionId, Visibility)>, Option<usize>) {
61 let res = self.resolve_path_with_fixedpoint(db, module, path);
62 (res.resolved_def, res.segment_index)
63 }
64
65 fn resolve_name_in_module(
67 &self,
68 _db: &dyn DefDatabase,
69 module: LocalModuleId,
70 name: &Name,
71 ) -> PerNs<(ItemDefinitionId, Visibility)> {
72 self[module]
73 .get(name)
74 .or(BUILTIN_SCOPE.get(name).copied().unwrap_or_else(PerNs::none))
75 }
76
77 pub(crate) fn resolve_path_with_fixedpoint(
81 &self,
82 db: &dyn DefDatabase,
83 original_module: LocalModuleId,
84 path: &Path,
85 ) -> ResolvePathResult {
86 let mut segments = path.segments.iter().enumerate();
87 let mut curr_per_ns: PerNs<(ItemDefinitionId, Visibility)> = match path.kind {
88 PathKind::Plain => {
89 let (_, segment) = match segments.next() {
90 Some((idx, segment)) => (idx, segment),
91 None => return ResolvePathResult::empty(ReachedFixedPoint::Yes),
92 };
93 self.resolve_name_in_module(db, original_module, segment)
94 }
95 PathKind::Super(lvl) => {
96 let m = successors(Some(original_module), |m| self.module_tree[*m].parent)
97 .nth(lvl as usize);
98 if let Some(local_id) = m {
99 PerNs::types((
100 ModuleId {
101 package: self.module_tree.package,
102 local_id,
103 }
104 .into(),
105 Visibility::Public,
106 ))
107 } else {
108 return ResolvePathResult::empty(ReachedFixedPoint::Yes);
109 }
110 }
111 PathKind::Package => PerNs::types((
112 ModuleId {
113 package: self.module_tree.package,
114 local_id: self.module_tree.root,
115 }
116 .into(),
117 Visibility::Public,
118 )),
119 };
120
121 for (i, segment) in segments {
122 let (curr, vis) = match curr_per_ns.take_types() {
123 Some(r) => r,
124 None => {
125 return ResolvePathResult::empty(ReachedFixedPoint::No);
126 }
127 };
128
129 curr_per_ns = match curr {
130 ItemDefinitionId::ModuleId(module) => self[module.local_id].get(segment),
131 s => {
133 return ResolvePathResult::with(
134 PerNs::types((s, vis)),
135 ReachedFixedPoint::Yes,
136 Some(i),
137 Some(self.module_tree.package),
138 );
139 }
140 };
141 }
142
143 ResolvePathResult::with(
144 curr_per_ns,
145 ReachedFixedPoint::Yes,
146 None,
147 Some(self.module_tree.package),
148 )
149 }
150}