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 & current_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
}
@@ -189,7 +192,7 @@ impl DefMap {
189
192
) ) ;
190
193
191
194
let mut segments = path. segments ( ) . iter ( ) . enumerate ( ) ;
192
- let mut curr_per_ns: PerNs = match path. kind {
195
+ let mut curr_per_ns = match path. kind {
193
196
PathKind :: DollarCrate ( krate) => {
194
197
if krate == self . krate {
195
198
cov_mark:: hit!( macro_dollar_crate_self) ;
@@ -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