@@ -34,6 +34,7 @@ use crate::{
34
34
/// module, the set of visible items.
35
35
#[ derive( Default , Debug , PartialEq , Eq ) ]
36
36
pub struct ItemMap {
37
+ pub ( crate ) extern_prelude : FxHashMap < Name , ModuleDef > ,
37
38
per_module : ArenaMap < ModuleId , ModuleScope > ,
38
39
}
39
40
@@ -204,6 +205,7 @@ where
204
205
}
205
206
206
207
pub ( crate ) fn resolve ( mut self ) -> ItemMap {
208
+ self . populate_extern_prelude ( ) ;
207
209
for ( & module_id, items) in self . input . iter ( ) {
208
210
self . populate_module ( module_id, Arc :: clone ( items) ) ;
209
211
}
@@ -227,29 +229,19 @@ where
227
229
self . result
228
230
}
229
231
232
+ fn populate_extern_prelude ( & mut self ) {
233
+ for dep in self . krate . dependencies ( self . db ) {
234
+ log:: debug!( "crate dep {:?} -> {:?}" , dep. name, dep. krate) ;
235
+ if let Some ( module) = dep. krate . root_module ( self . db ) {
236
+ self . result
237
+ . extern_prelude
238
+ . insert ( dep. name . clone ( ) , module. into ( ) ) ;
239
+ }
240
+ }
241
+ }
242
+
230
243
fn populate_module ( & mut self , module_id : ModuleId , input : Arc < LoweredModule > ) {
231
244
let mut module_items = ModuleScope :: default ( ) ;
232
-
233
- // Populate extern crates prelude
234
- {
235
- let root_id = module_id. crate_root ( & self . module_tree ) ;
236
- let file_id = root_id. file_id ( & self . module_tree ) ;
237
- let crate_graph = self . db . crate_graph ( ) ;
238
- if let Some ( crate_id) = crate_graph. crate_id_for_crate_root ( file_id. as_original_file ( ) )
239
- {
240
- let krate = Crate { crate_id } ;
241
- for dep in krate. dependencies ( self . db ) {
242
- if let Some ( module) = dep. krate . root_module ( self . db ) {
243
- let def = module. into ( ) ;
244
- self . add_module_item (
245
- & mut module_items,
246
- dep. name . clone ( ) ,
247
- PerNs :: types ( def) ,
248
- ) ;
249
- }
250
- }
251
- } ;
252
- }
253
245
for ( import_id, import_data) in input. imports . iter ( ) {
254
246
if let Some ( last_segment) = import_data. path . segments . iter ( ) . last ( ) {
255
247
if !import_data. is_glob {
@@ -327,7 +319,16 @@ where
327
319
. alias
328
320
. clone ( )
329
321
. unwrap_or_else ( || last_segment. name . clone ( ) ) ;
330
- log:: debug!( "resolved import {:?} ({:?}) to {:?}" , name, import, def, ) ;
322
+ log:: debug!( "resolved import {:?} ({:?}) to {:?}" , name, import, def) ;
323
+
324
+ // extern crates in the crate root are special-cased to insert entries into the extern prelude: rust-lang/rust#54658
325
+ if let Some ( root_module) = self . krate . root_module ( self . db ) {
326
+ if import. is_extern_crate && module_id == root_module. module_id {
327
+ if let Some ( def) = def. take_types ( ) {
328
+ self . result . extern_prelude . insert ( name. clone ( ) , def) ;
329
+ }
330
+ }
331
+ }
331
332
self . update ( module_id, |items| {
332
333
let res = Resolution {
333
334
def,
@@ -389,24 +390,53 @@ impl ItemMap {
389
390
original_module : Module ,
390
391
path : & Path ,
391
392
) -> ( PerNs < ModuleDef > , ReachedFixedPoint ) {
392
- let mut curr_per_ns: PerNs < ModuleDef > = PerNs :: types ( match path. kind {
393
- PathKind :: Crate => original_module. crate_root ( db) . into ( ) ,
394
- PathKind :: Self_ | PathKind :: Plain => original_module. into ( ) ,
393
+ let mut segments = path. segments . iter ( ) . enumerate ( ) ;
394
+ let mut curr_per_ns: PerNs < ModuleDef > = match path. kind {
395
+ PathKind :: Crate => PerNs :: types ( original_module. crate_root ( db) . into ( ) ) ,
396
+ PathKind :: Self_ => PerNs :: types ( original_module. into ( ) ) ,
397
+ PathKind :: Plain => {
398
+ let segment = match segments. next ( ) {
399
+ Some ( ( _, segment) ) => segment,
400
+ None => return ( PerNs :: none ( ) , ReachedFixedPoint :: Yes ) ,
401
+ } ;
402
+ // Resolve in:
403
+ // - current module / scope
404
+ // - extern prelude
405
+ match self [ original_module. module_id ] . items . get ( & segment. name ) {
406
+ Some ( res) if !res. def . is_none ( ) => res. def ,
407
+ _ => {
408
+ if let Some ( def) = self . extern_prelude . get ( & segment. name ) {
409
+ PerNs :: types ( * def)
410
+ } else {
411
+ return ( PerNs :: none ( ) , ReachedFixedPoint :: No ) ;
412
+ }
413
+ }
414
+ }
415
+ }
395
416
PathKind :: Super => {
396
417
if let Some ( p) = original_module. parent ( db) {
397
- p. into ( )
418
+ PerNs :: types ( p. into ( ) )
398
419
} else {
399
420
log:: debug!( "super path in root module" ) ;
400
421
return ( PerNs :: none ( ) , ReachedFixedPoint :: Yes ) ;
401
422
}
402
423
}
403
424
PathKind :: Abs => {
404
- // TODO: absolute use is not supported
405
- return ( PerNs :: none ( ) , ReachedFixedPoint :: Yes ) ;
425
+ // 2018-style absolute path -- only extern prelude
426
+ let segment = match segments. next ( ) {
427
+ Some ( ( _, segment) ) => segment,
428
+ None => return ( PerNs :: none ( ) , ReachedFixedPoint :: Yes ) ,
429
+ } ;
430
+ if let Some ( def) = self . extern_prelude . get ( & segment. name ) {
431
+ log:: debug!( "absolute path {:?} resolved to crate {:?}" , path, def) ;
432
+ PerNs :: types ( * def)
433
+ } else {
434
+ return ( PerNs :: none ( ) , ReachedFixedPoint :: No ) ; // extern crate declarations can add to the extern prelude
435
+ }
406
436
}
407
- } ) ;
437
+ } ;
408
438
409
- for ( i, segment) in path . segments . iter ( ) . enumerate ( ) {
439
+ for ( i, segment) in segments {
410
440
let curr = match curr_per_ns. as_ref ( ) . take_types ( ) {
411
441
Some ( r) => r,
412
442
None => {
0 commit comments