@@ -61,7 +61,7 @@ impl ModuleScope {
61
61
62
62
/// `Resolution` is basically `DefId` atm, but it should account for stuff like
63
63
/// multiple namespaces, ambiguity and errors.
64
- #[ derive( Debug , Clone , PartialEq , Eq ) ]
64
+ #[ derive( Debug , Clone , PartialEq , Eq , Default ) ]
65
65
pub struct Resolution {
66
66
/// None for unresolved
67
67
pub def : PerNs < ModuleDef > ,
@@ -154,6 +154,8 @@ struct Resolver<'a, DB> {
154
154
krate : Crate ,
155
155
module_tree : Arc < ModuleTree > ,
156
156
processed_imports : FxHashSet < ( ModuleId , ImportId ) > ,
157
+ /// If module `a` has `use b::*`, then this contains the mapping b -> a (and the import)
158
+ glob_imports : FxHashMap < ModuleId , Vec < ( ModuleId , ImportId ) > > ,
157
159
result : ItemMap ,
158
160
}
159
161
@@ -173,6 +175,7 @@ where
173
175
krate,
174
176
module_tree,
175
177
processed_imports : FxHashSet :: default ( ) ,
178
+ glob_imports : FxHashMap :: default ( ) ,
176
179
result : ItemMap :: default ( ) ,
177
180
}
178
181
}
@@ -264,14 +267,72 @@ where
264
267
import : & ImportData ,
265
268
) -> ReachedFixedPoint {
266
269
log:: debug!( "resolving import: {:?}" , import) ;
267
- if import. is_glob {
268
- return ReachedFixedPoint :: Yes ;
269
- } ;
270
270
let original_module = Module { krate : self . krate , module_id } ;
271
271
let ( def, reached_fixedpoint) =
272
272
self . result . resolve_path_fp ( self . db , original_module, & import. path ) ;
273
273
274
- if reached_fixedpoint == ReachedFixedPoint :: Yes {
274
+ if reached_fixedpoint != ReachedFixedPoint :: Yes {
275
+ return reached_fixedpoint;
276
+ }
277
+
278
+ if import. is_glob {
279
+ log:: debug!( "glob import: {:?}" , import) ;
280
+ match def. take_types ( ) {
281
+ Some ( ModuleDef :: Module ( m) ) => {
282
+ if m. krate != self . krate {
283
+ tested_by ! ( glob_across_crates) ;
284
+ // glob import from other crate => we can just import everything once
285
+ let item_map = self . db . item_map ( m. krate ) ;
286
+ let scope = & item_map[ m. module_id ] ;
287
+ let items = scope
288
+ . items
289
+ . iter ( )
290
+ . map ( |( name, res) | ( name. clone ( ) , res. clone ( ) ) )
291
+ . collect :: < Vec < _ > > ( ) ;
292
+ self . update ( module_id, Some ( import_id) , & items) ;
293
+ } else {
294
+ // glob import from same crate => we do an initial
295
+ // import, and then need to propagate any further
296
+ // additions
297
+ let scope = & self . result [ m. module_id ] ;
298
+ let items = scope
299
+ . items
300
+ . iter ( )
301
+ . map ( |( name, res) | ( name. clone ( ) , res. clone ( ) ) )
302
+ . collect :: < Vec < _ > > ( ) ;
303
+ self . update ( module_id, Some ( import_id) , & items) ;
304
+ // record the glob import in case we add further items
305
+ self . glob_imports
306
+ . entry ( m. module_id )
307
+ . or_default ( )
308
+ . push ( ( module_id, import_id) ) ;
309
+ }
310
+ }
311
+ Some ( ModuleDef :: Enum ( e) ) => {
312
+ tested_by ! ( glob_enum) ;
313
+ // glob import from enum => just import all the variants
314
+ let variants = e. variants ( self . db ) ;
315
+ let resolutions = variants
316
+ . into_iter ( )
317
+ . filter_map ( |variant| {
318
+ let res = Resolution {
319
+ def : PerNs :: both ( variant. into ( ) , e. into ( ) ) ,
320
+ import : Some ( import_id) ,
321
+ } ;
322
+ let name = variant. name ( self . db ) ?;
323
+ Some ( ( name, res) )
324
+ } )
325
+ . collect :: < Vec < _ > > ( ) ;
326
+ self . update ( module_id, Some ( import_id) , & resolutions) ;
327
+ }
328
+ Some ( d) => {
329
+ log:: debug!( "glob import {:?} from non-module/enum {:?}" , import, d) ;
330
+ }
331
+ None => {
332
+ log:: debug!( "glob import {:?} didn't resolve as type" , import) ;
333
+ }
334
+ }
335
+ } else {
275
336
let last_segment = import. path . segments . last ( ) . unwrap ( ) ;
276
337
let name = import. alias . clone ( ) . unwrap_or_else ( || last_segment. name . clone ( ) ) ;
277
338
log:: debug!( "resolved import {:?} ({:?}) to {:?}" , name, import, def) ;
@@ -284,17 +345,61 @@ where
284
345
}
285
346
}
286
347
}
287
- self . update ( module_id, |items| {
288
- let res = Resolution { def, import : Some ( import_id) } ;
289
- items. items . insert ( name, res) ;
290
- } ) ;
348
+ let resolution = Resolution { def, import : Some ( import_id) } ;
349
+ self . update ( module_id, None , & [ ( name, resolution) ] ) ;
291
350
}
292
351
reached_fixedpoint
293
352
}
294
353
295
- fn update ( & mut self , module_id : ModuleId , f : impl FnOnce ( & mut ModuleScope ) ) {
354
+ fn update (
355
+ & mut self ,
356
+ module_id : ModuleId ,
357
+ import : Option < ImportId > ,
358
+ resolutions : & [ ( Name , Resolution ) ] ,
359
+ ) {
360
+ self . update_recursive ( module_id, import, resolutions, 0 )
361
+ }
362
+
363
+ fn update_recursive (
364
+ & mut self ,
365
+ module_id : ModuleId ,
366
+ import : Option < ImportId > ,
367
+ resolutions : & [ ( Name , Resolution ) ] ,
368
+ depth : usize ,
369
+ ) {
370
+ if depth > 100 {
371
+ // prevent stack overflows (but this shouldn't be possible)
372
+ panic ! ( "infinite recursion in glob imports!" ) ;
373
+ }
296
374
let module_items = self . result . per_module . get_mut ( module_id) . unwrap ( ) ;
297
- f ( module_items)
375
+ let mut changed = false ;
376
+ for ( name, res) in resolutions {
377
+ let existing = module_items. items . entry ( name. clone ( ) ) . or_default ( ) ;
378
+ if existing. def . types . is_none ( ) && res. def . types . is_some ( ) {
379
+ existing. def . types = res. def . types ;
380
+ existing. import = import. or ( res. import ) ;
381
+ changed = true ;
382
+ }
383
+ if existing. def . values . is_none ( ) && res. def . values . is_some ( ) {
384
+ existing. def . values = res. def . values ;
385
+ existing. import = import. or ( res. import ) ;
386
+ changed = true ;
387
+ }
388
+ }
389
+ if !changed {
390
+ return ;
391
+ }
392
+ let glob_imports = self
393
+ . glob_imports
394
+ . get ( & module_id)
395
+ . into_iter ( )
396
+ . flat_map ( |v| v. iter ( ) )
397
+ . cloned ( )
398
+ . collect :: < Vec < _ > > ( ) ;
399
+ for ( glob_importing_module, glob_import) in glob_imports {
400
+ // We pass the glob import so that the tracked import in those modules is that glob import
401
+ self . update_recursive ( glob_importing_module, Some ( glob_import) , resolutions, depth + 1 ) ;
402
+ }
298
403
}
299
404
}
300
405
0 commit comments