diff options
Diffstat (limited to 'crates/hir_def/src/nameres/path_resolution.rs')
-rw-r--r-- | crates/hir_def/src/nameres/path_resolution.rs | 163 |
1 files changed, 126 insertions, 37 deletions
diff --git a/crates/hir_def/src/nameres/path_resolution.rs b/crates/hir_def/src/nameres/path_resolution.rs index 88e10574e..dd1db0094 100644 --- a/crates/hir_def/src/nameres/path_resolution.rs +++ b/crates/hir_def/src/nameres/path_resolution.rs | |||
@@ -10,20 +10,19 @@ | |||
10 | //! | 10 | //! |
11 | //! `ReachedFixedPoint` signals about this. | 11 | //! `ReachedFixedPoint` signals about this. |
12 | 12 | ||
13 | use std::iter::successors; | ||
14 | |||
15 | use base_db::Edition; | 13 | use base_db::Edition; |
14 | use hir_expand::name; | ||
16 | use hir_expand::name::Name; | 15 | use hir_expand::name::Name; |
17 | use test_utils::mark; | 16 | use test_utils::mark; |
18 | 17 | ||
19 | use crate::{ | 18 | use crate::{ |
20 | db::DefDatabase, | 19 | db::DefDatabase, |
21 | item_scope::BUILTIN_SCOPE, | 20 | item_scope::BUILTIN_SCOPE, |
22 | nameres::{BuiltinShadowMode, CrateDefMap}, | 21 | nameres::{BuiltinShadowMode, DefMap}, |
23 | path::{ModPath, PathKind}, | 22 | path::{ModPath, PathKind}, |
24 | per_ns::PerNs, | 23 | per_ns::PerNs, |
25 | visibility::{RawVisibility, Visibility}, | 24 | visibility::{RawVisibility, Visibility}, |
26 | AdtId, CrateId, EnumVariantId, LocalModuleId, ModuleDefId, ModuleId, | 25 | AdtId, CrateId, EnumVariantId, LocalModuleId, ModuleDefId, |
27 | }; | 26 | }; |
28 | 27 | ||
29 | #[derive(Debug, Clone, Copy, PartialEq, Eq)] | 28 | #[derive(Debug, Clone, Copy, PartialEq, Eq)] |
@@ -61,8 +60,12 @@ impl ResolvePathResult { | |||
61 | } | 60 | } |
62 | } | 61 | } |
63 | 62 | ||
64 | impl CrateDefMap { | 63 | impl DefMap { |
65 | pub(super) fn resolve_name_in_extern_prelude(&self, name: &Name) -> PerNs { | 64 | pub(super) fn resolve_name_in_extern_prelude(&self, name: &Name) -> PerNs { |
65 | if name == &name!(self) { | ||
66 | mark::hit!(extern_crate_self_as); | ||
67 | return PerNs::types(self.module_id(self.root).into(), Visibility::Public); | ||
68 | } | ||
66 | self.extern_prelude | 69 | self.extern_prelude |
67 | .get(name) | 70 | .get(name) |
68 | .map_or(PerNs::none(), |&it| PerNs::types(it, Visibility::Public)) | 71 | .map_or(PerNs::none(), |&it| PerNs::types(it, Visibility::Public)) |
@@ -74,7 +77,7 @@ impl CrateDefMap { | |||
74 | original_module: LocalModuleId, | 77 | original_module: LocalModuleId, |
75 | visibility: &RawVisibility, | 78 | visibility: &RawVisibility, |
76 | ) -> Option<Visibility> { | 79 | ) -> Option<Visibility> { |
77 | match visibility { | 80 | let mut vis = match visibility { |
78 | RawVisibility::Module(path) => { | 81 | RawVisibility::Module(path) => { |
79 | let (result, remaining) = | 82 | let (result, remaining) = |
80 | self.resolve_path(db, original_module, &path, BuiltinShadowMode::Module); | 83 | self.resolve_path(db, original_module, &path, BuiltinShadowMode::Module); |
@@ -83,15 +86,28 @@ impl CrateDefMap { | |||
83 | } | 86 | } |
84 | let types = result.take_types()?; | 87 | let types = result.take_types()?; |
85 | match types { | 88 | match types { |
86 | ModuleDefId::ModuleId(m) => Some(Visibility::Module(m)), | 89 | ModuleDefId::ModuleId(m) => Visibility::Module(m), |
87 | _ => { | 90 | _ => { |
88 | // error: visibility needs to refer to module | 91 | // error: visibility needs to refer to module |
89 | None | 92 | return None; |
90 | } | 93 | } |
91 | } | 94 | } |
92 | } | 95 | } |
93 | RawVisibility::Public => Some(Visibility::Public), | 96 | RawVisibility::Public => Visibility::Public, |
97 | }; | ||
98 | |||
99 | // In block expressions, `self` normally refers to the containing non-block module, and | ||
100 | // `super` to its parent (etc.). However, visibilities must only refer to a module in the | ||
101 | // DefMap they're written in, so we restrict them when that happens. | ||
102 | if let Visibility::Module(m) = vis { | ||
103 | if self.block_id() != m.block { | ||
104 | mark::hit!(adjust_vis_in_block_def_map); | ||
105 | vis = Visibility::Module(self.module_id(self.root())); | ||
106 | log::debug!("visibility {:?} points outside DefMap, adjusting to {:?}", m, vis); | ||
107 | } | ||
94 | } | 108 | } |
109 | |||
110 | Some(vis) | ||
95 | } | 111 | } |
96 | 112 | ||
97 | // Returns Yes if we are sure that additions to `ItemMap` wouldn't change | 113 | // Returns Yes if we are sure that additions to `ItemMap` wouldn't change |
@@ -100,30 +116,69 @@ impl CrateDefMap { | |||
100 | &self, | 116 | &self, |
101 | db: &dyn DefDatabase, | 117 | db: &dyn DefDatabase, |
102 | mode: ResolveMode, | 118 | mode: ResolveMode, |
119 | mut original_module: LocalModuleId, | ||
120 | path: &ModPath, | ||
121 | shadow: BuiltinShadowMode, | ||
122 | ) -> ResolvePathResult { | ||
123 | let mut result = ResolvePathResult::empty(ReachedFixedPoint::No); | ||
124 | |||
125 | let mut arc; | ||
126 | let mut current_map = self; | ||
127 | loop { | ||
128 | let new = current_map.resolve_path_fp_with_macro_single( | ||
129 | db, | ||
130 | mode, | ||
131 | original_module, | ||
132 | path, | ||
133 | shadow, | ||
134 | ); | ||
135 | |||
136 | // Merge `new` into `result`. | ||
137 | result.resolved_def = result.resolved_def.or(new.resolved_def); | ||
138 | if result.reached_fixedpoint == ReachedFixedPoint::No { | ||
139 | result.reached_fixedpoint = new.reached_fixedpoint; | ||
140 | } | ||
141 | // FIXME: this doesn't seem right; what if the different namespace resolutions come from different crates? | ||
142 | result.krate = result.krate.or(new.krate); | ||
143 | result.segment_index = match (result.segment_index, new.segment_index) { | ||
144 | (Some(idx), None) => Some(idx), | ||
145 | (Some(old), Some(new)) => Some(old.max(new)), | ||
146 | (None, new) => new, | ||
147 | }; | ||
148 | |||
149 | match ¤t_map.block { | ||
150 | Some(block) => { | ||
151 | original_module = block.parent.local_id; | ||
152 | arc = block.parent.def_map(db); | ||
153 | current_map = &*arc; | ||
154 | } | ||
155 | None => return result, | ||
156 | } | ||
157 | } | ||
158 | } | ||
159 | |||
160 | pub(super) fn resolve_path_fp_with_macro_single( | ||
161 | &self, | ||
162 | db: &dyn DefDatabase, | ||
163 | mode: ResolveMode, | ||
103 | original_module: LocalModuleId, | 164 | original_module: LocalModuleId, |
104 | path: &ModPath, | 165 | path: &ModPath, |
105 | shadow: BuiltinShadowMode, | 166 | shadow: BuiltinShadowMode, |
106 | ) -> ResolvePathResult { | 167 | ) -> ResolvePathResult { |
107 | let mut segments = path.segments.iter().enumerate(); | 168 | let mut segments = path.segments().iter().enumerate(); |
108 | let mut curr_per_ns: PerNs = match path.kind { | 169 | let mut curr_per_ns: PerNs = match path.kind { |
109 | PathKind::DollarCrate(krate) => { | 170 | PathKind::DollarCrate(krate) => { |
110 | if krate == self.krate { | 171 | if krate == self.krate { |
111 | mark::hit!(macro_dollar_crate_self); | 172 | mark::hit!(macro_dollar_crate_self); |
112 | PerNs::types( | 173 | PerNs::types(self.crate_root(db).into(), Visibility::Public) |
113 | ModuleId { krate: self.krate, local_id: self.root }.into(), | ||
114 | Visibility::Public, | ||
115 | ) | ||
116 | } else { | 174 | } else { |
117 | let def_map = db.crate_def_map(krate); | 175 | let def_map = db.crate_def_map(krate); |
118 | let module = ModuleId { krate, local_id: def_map.root }; | 176 | let module = def_map.module_id(def_map.root); |
119 | mark::hit!(macro_dollar_crate_other); | 177 | mark::hit!(macro_dollar_crate_other); |
120 | PerNs::types(module.into(), Visibility::Public) | 178 | PerNs::types(module.into(), Visibility::Public) |
121 | } | 179 | } |
122 | } | 180 | } |
123 | PathKind::Crate => PerNs::types( | 181 | PathKind::Crate => PerNs::types(self.crate_root(db).into(), Visibility::Public), |
124 | ModuleId { krate: self.krate, local_id: self.root }.into(), | ||
125 | Visibility::Public, | ||
126 | ), | ||
127 | // plain import or absolute path in 2015: crate-relative with | 182 | // plain import or absolute path in 2015: crate-relative with |
128 | // fallback to extern prelude (with the simplification in | 183 | // fallback to extern prelude (with the simplification in |
129 | // rust-lang/rust#57745) | 184 | // rust-lang/rust#57745) |
@@ -151,23 +206,49 @@ impl CrateDefMap { | |||
151 | // BuiltinShadowMode wasn't Module, then we need to try | 206 | // BuiltinShadowMode wasn't Module, then we need to try |
152 | // resolving it as a builtin. | 207 | // resolving it as a builtin. |
153 | let prefer_module = | 208 | let prefer_module = |
154 | if path.segments.len() == 1 { shadow } else { BuiltinShadowMode::Module }; | 209 | if path.segments().len() == 1 { shadow } else { BuiltinShadowMode::Module }; |
155 | 210 | ||
156 | log::debug!("resolving {:?} in module", segment); | 211 | log::debug!("resolving {:?} in module", segment); |
157 | self.resolve_name_in_module(db, original_module, &segment, prefer_module) | 212 | self.resolve_name_in_module(db, original_module, &segment, prefer_module) |
158 | } | 213 | } |
159 | PathKind::Super(lvl) => { | 214 | PathKind::Super(lvl) => { |
160 | let m = successors(Some(original_module), |m| self.modules[*m].parent) | 215 | let mut module = original_module; |
161 | .nth(lvl as usize); | 216 | for i in 0..lvl { |
162 | if let Some(local_id) = m { | 217 | match self.modules[module].parent { |
163 | PerNs::types( | 218 | Some(it) => module = it, |
164 | ModuleId { krate: self.krate, local_id }.into(), | 219 | None => match &self.block { |
165 | Visibility::Public, | 220 | Some(block) => { |
166 | ) | 221 | // Look up remaining path in parent `DefMap` |
167 | } else { | 222 | let new_path = ModPath::from_segments( |
168 | log::debug!("super path in root module"); | 223 | PathKind::Super(lvl - i), |
169 | return ResolvePathResult::empty(ReachedFixedPoint::Yes); | 224 | path.segments().to_vec(), |
225 | ); | ||
226 | log::debug!("`super` path: {} -> {} in parent map", path, new_path); | ||
227 | return block.parent.def_map(db).resolve_path_fp_with_macro( | ||
228 | db, | ||
229 | mode, | ||
230 | block.parent.local_id, | ||
231 | &new_path, | ||
232 | shadow, | ||
233 | ); | ||
234 | } | ||
235 | None => { | ||
236 | log::debug!("super path in root module"); | ||
237 | return ResolvePathResult::empty(ReachedFixedPoint::Yes); | ||
238 | } | ||
239 | }, | ||
240 | } | ||
170 | } | 241 | } |
242 | |||
243 | // Resolve `self` to the containing crate-rooted module if we're a block | ||
244 | self.with_ancestor_maps(db, module, &mut |def_map, module| { | ||
245 | if def_map.block.is_some() { | ||
246 | None // keep ascending | ||
247 | } else { | ||
248 | Some(PerNs::types(def_map.module_id(module).into(), Visibility::Public)) | ||
249 | } | ||
250 | }) | ||
251 | .expect("block DefMap not rooted in crate DefMap") | ||
171 | } | 252 | } |
172 | PathKind::Abs => { | 253 | PathKind::Abs => { |
173 | // 2018-style absolute path -- only extern prelude | 254 | // 2018-style absolute path -- only extern prelude |
@@ -201,12 +282,12 @@ impl CrateDefMap { | |||
201 | curr_per_ns = match curr { | 282 | curr_per_ns = match curr { |
202 | ModuleDefId::ModuleId(module) => { | 283 | ModuleDefId::ModuleId(module) => { |
203 | if module.krate != self.krate { | 284 | if module.krate != self.krate { |
204 | let path = ModPath { | 285 | let path = ModPath::from_segments( |
205 | segments: path.segments[i..].to_vec(), | 286 | PathKind::Super(0), |
206 | kind: PathKind::Super(0), | 287 | path.segments()[i..].iter().cloned(), |
207 | }; | 288 | ); |
208 | log::debug!("resolving {:?} in other crate", path); | 289 | log::debug!("resolving {:?} in other crate", path); |
209 | let defp_map = db.crate_def_map(module.krate); | 290 | let defp_map = module.def_map(db); |
210 | let (def, s) = defp_map.resolve_path(db, module.local_id, &path, shadow); | 291 | let (def, s) = defp_map.resolve_path(db, module.local_id, &path, shadow); |
211 | return ResolvePathResult::with( | 292 | return ResolvePathResult::with( |
212 | def, | 293 | def, |
@@ -216,8 +297,16 @@ impl CrateDefMap { | |||
216 | ); | 297 | ); |
217 | } | 298 | } |
218 | 299 | ||
300 | let def_map; | ||
301 | let module_data = if module.block == self.block_id() { | ||
302 | &self[module.local_id] | ||
303 | } else { | ||
304 | def_map = module.def_map(db); | ||
305 | &def_map[module.local_id] | ||
306 | }; | ||
307 | |||
219 | // Since it is a qualified path here, it should not contains legacy macros | 308 | // Since it is a qualified path here, it should not contains legacy macros |
220 | self[module.local_id].scope.get(&segment) | 309 | module_data.scope.get(&segment) |
221 | } | 310 | } |
222 | ModuleDefId::AdtId(AdtId::EnumId(e)) => { | 311 | ModuleDefId::AdtId(AdtId::EnumId(e)) => { |
223 | // enum variant | 312 | // enum variant |
@@ -319,7 +408,7 @@ impl CrateDefMap { | |||
319 | self | 408 | self |
320 | } else { | 409 | } else { |
321 | // Extend lifetime | 410 | // Extend lifetime |
322 | keep = db.crate_def_map(prelude.krate); | 411 | keep = prelude.def_map(db); |
323 | &keep | 412 | &keep |
324 | }; | 413 | }; |
325 | def_map[prelude.local_id].scope.get(name) | 414 | def_map[prelude.local_id].scope.get(name) |