|
12 | 12 |
|
13 | 13 | use base_db::Edition;
|
14 | 14 | use hir_expand::name::Name;
|
| 15 | +use triomphe::Arc; |
15 | 16 |
|
16 | 17 | use crate::{
|
17 | 18 | db::DefDatabase,
|
18 | 19 | item_scope::BUILTIN_SCOPE,
|
19 |
| - nameres::{sub_namespace_match, BuiltinShadowMode, DefMap, MacroSubNs}, |
| 20 | + nameres::{sub_namespace_match, BlockInfo, BuiltinShadowMode, DefMap, MacroSubNs}, |
20 | 21 | path::{ModPath, PathKind},
|
21 | 22 | per_ns::PerNs,
|
22 | 23 | visibility::{RawVisibility, Visibility},
|
@@ -159,13 +160,15 @@ impl DefMap {
|
159 | 160 | (None, new) => new,
|
160 | 161 | };
|
161 | 162 |
|
162 |
| - match ¤t_map.block { |
163 |
| - Some(block) => { |
| 163 | + match current_map.block { |
| 164 | + Some(block) if original_module == Self::ROOT => { |
| 165 | + // Block modules "inherit" names from its parent module. |
164 | 166 | original_module = block.parent.local_id;
|
165 | 167 | arc = block.parent.def_map(db, current_map.krate);
|
166 |
| - current_map = &*arc; |
| 168 | + current_map = &arc; |
167 | 169 | }
|
168 |
| - None => return result, |
| 170 | + // Proper (non-block) modules, including those in block `DefMap`s, don't. |
| 171 | + _ => return result, |
169 | 172 | }
|
170 | 173 | }
|
171 | 174 | }
|
@@ -241,51 +244,54 @@ impl DefMap {
|
241 | 244 | )
|
242 | 245 | }
|
243 | 246 | PathKind::Super(lvl) => {
|
244 |
| - let mut module = original_module; |
245 |
| - for i in 0..lvl { |
246 |
| - match self.modules[module].parent { |
247 |
| - Some(it) => module = it, |
248 |
| - None => match &self.block { |
249 |
| - Some(block) => { |
250 |
| - // Look up remaining path in parent `DefMap` |
251 |
| - let new_path = ModPath::from_segments( |
252 |
| - PathKind::Super(lvl - i), |
253 |
| - path.segments().to_vec(), |
254 |
| - ); |
255 |
| - tracing::debug!( |
256 |
| - "`super` path: {} -> {} in parent map", |
257 |
| - path.display(db.upcast()), |
258 |
| - new_path.display(db.upcast()) |
259 |
| - ); |
260 |
| - return block |
261 |
| - .parent |
262 |
| - .def_map(db, self.krate) |
263 |
| - .resolve_path_fp_with_macro( |
264 |
| - db, |
265 |
| - mode, |
266 |
| - block.parent.local_id, |
267 |
| - &new_path, |
268 |
| - shadow, |
269 |
| - expected_macro_subns, |
270 |
| - ); |
271 |
| - } |
272 |
| - None => { |
273 |
| - tracing::debug!("super path in root module"); |
274 |
| - return ResolvePathResult::empty(ReachedFixedPoint::Yes); |
275 |
| - } |
276 |
| - }, |
277 |
| - } |
| 247 | + let mut local_id = original_module; |
| 248 | + let mut ext; |
| 249 | + let mut def_map = self; |
| 250 | + |
| 251 | + // Adjust `local_id` to `self`, i.e. the nearest non-block module. |
| 252 | + if def_map.module_id(local_id).is_block_module() { |
| 253 | + (ext, local_id) = adjust_to_nearest_non_block_module(db, def_map, local_id); |
| 254 | + def_map = &ext; |
278 | 255 | }
|
279 | 256 |
|
280 |
| - // Resolve `self` to the containing crate-rooted module if we're a block |
281 |
| - self.with_ancestor_maps(db, module, &mut |def_map, module| { |
282 |
| - if def_map.block.is_some() { |
283 |
| - None // keep ascending |
| 257 | + // Go up the module tree but skip block modules as `super` always refers to the |
| 258 | + // nearest non-block module. |
| 259 | + for _ in 0..lvl { |
| 260 | + // Loop invariant: at the beginning of each loop, `local_id` must refer to a |
| 261 | + // non-block module. |
| 262 | + if let Some(parent) = def_map.modules[local_id].parent { |
| 263 | + local_id = parent; |
| 264 | + if def_map.module_id(local_id).is_block_module() { |
| 265 | + (ext, local_id) = |
| 266 | + adjust_to_nearest_non_block_module(db, def_map, local_id); |
| 267 | + def_map = &ext; |
| 268 | + } |
284 | 269 | } else {
|
285 |
| - Some(PerNs::types(def_map.module_id(module).into(), Visibility::Public)) |
| 270 | + stdx::always!(def_map.block.is_none()); |
| 271 | + tracing::debug!("super path in root module"); |
| 272 | + return ResolvePathResult::empty(ReachedFixedPoint::Yes); |
286 | 273 | }
|
287 |
| - }) |
288 |
| - .expect("block DefMap not rooted in crate DefMap") |
| 274 | + } |
| 275 | + |
| 276 | + let module = def_map.module_id(local_id); |
| 277 | + stdx::never!(module.is_block_module()); |
| 278 | + |
| 279 | + if self.block != def_map.block { |
| 280 | + // If we have a different `DefMap` from `self` (the orignal `DefMap` we started |
| 281 | + // with), resolve the remaining path segments in that `DefMap`. |
| 282 | + let path = |
| 283 | + ModPath::from_segments(PathKind::Super(0), path.segments().iter().cloned()); |
| 284 | + return def_map.resolve_path_fp_with_macro( |
| 285 | + db, |
| 286 | + mode, |
| 287 | + local_id, |
| 288 | + &path, |
| 289 | + shadow, |
| 290 | + expected_macro_subns, |
| 291 | + ); |
| 292 | + } |
| 293 | + |
| 294 | + PerNs::types(module.into(), Visibility::Public) |
289 | 295 | }
|
290 | 296 | PathKind::Abs => {
|
291 | 297 | // 2018-style absolute path -- only extern prelude
|
@@ -508,3 +514,27 @@ impl DefMap {
|
508 | 514 | }
|
509 | 515 | }
|
510 | 516 | }
|
| 517 | + |
| 518 | +/// Given a block module, returns its nearest non-block module and the `DefMap` it blongs to. |
| 519 | +fn adjust_to_nearest_non_block_module( |
| 520 | + db: &dyn DefDatabase, |
| 521 | + def_map: &DefMap, |
| 522 | + mut local_id: LocalModuleId, |
| 523 | +) -> (Arc<DefMap>, LocalModuleId) { |
| 524 | + // INVARIANT: `local_id` in `def_map` must be a block module. |
| 525 | + stdx::always!(def_map.module_id(local_id).is_block_module()); |
| 526 | + |
| 527 | + let mut ext; |
| 528 | + // This needs to be a local variable due to our mighty lifetime. |
| 529 | + let mut def_map = def_map; |
| 530 | + loop { |
| 531 | + let BlockInfo { parent, .. } = def_map.block.expect("block module without parent module"); |
| 532 | + |
| 533 | + ext = parent.def_map(db, def_map.krate); |
| 534 | + def_map = &ext; |
| 535 | + local_id = parent.local_id; |
| 536 | + if !parent.is_block_module() { |
| 537 | + return (ext, local_id); |
| 538 | + } |
| 539 | + } |
| 540 | +} |
0 commit comments