@@ -13,7 +13,7 @@ use rustc_hash::FxHashSet;
1313use crate :: {
1414 db:: DefDatabase ,
1515 item_scope:: ItemInNs ,
16- nameres:: DefMap ,
16+ nameres:: { DefMap , ModuleData } ,
1717 path:: { ModPath , PathKind } ,
1818 visibility:: { Visibility , VisibilityExplicitness } ,
1919 ImportPathConfig , ModuleDefId , ModuleId ,
@@ -161,7 +161,7 @@ fn find_path_inner(ctx: &FindPathCtx<'_>, item: ItemInNs, max_len: usize) -> Opt
161161#[ tracing:: instrument( skip_all) ]
162162fn find_path_for_module (
163163 ctx : & FindPathCtx < ' _ > ,
164- visited_modules : & mut FxHashSet < ModuleId > ,
164+ visited_modules : & mut FxHashSet < ( ItemInNs , ModuleId ) > ,
165165 module_id : ModuleId ,
166166 maybe_extern : bool ,
167167 max_len : usize ,
@@ -338,7 +338,7 @@ fn is_kw_kind_relative_to_from(
338338#[ tracing:: instrument( skip_all) ]
339339fn calculate_best_path (
340340 ctx : & FindPathCtx < ' _ > ,
341- visited_modules : & mut FxHashSet < ModuleId > ,
341+ visited_modules : & mut FxHashSet < ( ItemInNs , ModuleId ) > ,
342342 item : ItemInNs ,
343343 max_len : usize ,
344344 best_choice : & mut Option < Choice > ,
@@ -445,28 +445,32 @@ fn calculate_best_path(
445445
446446fn calculate_best_path_local (
447447 ctx : & FindPathCtx < ' _ > ,
448- visited_modules : & mut FxHashSet < ModuleId > ,
448+ visited_modules : & mut FxHashSet < ( ItemInNs , ModuleId ) > ,
449449 item : ItemInNs ,
450450 max_len : usize ,
451451 best_choice : & mut Option < Choice > ,
452452) {
453453 // FIXME: cache the `find_local_import_locations` output?
454- find_local_import_locations ( ctx. db , item, ctx. from , ctx. from_def_map , |name, module_id| {
455- if !visited_modules. insert ( module_id) {
456- return ;
457- }
458- // we are looking for paths of length up to best_path_len, any longer will make it be
459- // less optimal. The -1 is due to us pushing name onto it afterwards.
460- if let Some ( choice) = find_path_for_module (
461- ctx,
462- visited_modules,
463- module_id,
464- false ,
465- best_choice. as_ref ( ) . map_or ( max_len, |it| it. path . len ( ) ) - 1 ,
466- ) {
467- Choice :: try_select ( best_choice, choice, ctx. cfg . prefer_prelude , name. clone ( ) ) ;
468- }
469- } ) ;
454+ find_local_import_locations (
455+ ctx. db ,
456+ item,
457+ ctx. from ,
458+ ctx. from_def_map ,
459+ visited_modules,
460+ |visited_modules, name, module_id| {
461+ // we are looking for paths of length up to best_path_len, any longer will make it be
462+ // less optimal. The -1 is due to us pushing name onto it afterwards.
463+ if let Some ( choice) = find_path_for_module (
464+ ctx,
465+ visited_modules,
466+ module_id,
467+ false ,
468+ best_choice. as_ref ( ) . map_or ( max_len, |it| it. path . len ( ) ) - 1 ,
469+ ) {
470+ Choice :: try_select ( best_choice, choice, ctx. cfg . prefer_prelude , name. clone ( ) ) ;
471+ }
472+ } ,
473+ ) ;
470474}
471475
472476struct Choice {
@@ -551,7 +555,8 @@ fn find_local_import_locations(
551555 item : ItemInNs ,
552556 from : ModuleId ,
553557 def_map : & DefMap ,
554- mut cb : impl FnMut ( & Name , ModuleId ) ,
558+ visited_modules : & mut FxHashSet < ( ItemInNs , ModuleId ) > ,
559+ mut cb : impl FnMut ( & mut FxHashSet < ( ItemInNs , ModuleId ) > , & Name , ModuleId ) ,
555560) {
556561 let _p = tracing:: info_span!( "find_local_import_locations" ) . entered ( ) ;
557562
@@ -564,32 +569,29 @@ fn find_local_import_locations(
564569 let mut worklist = def_map[ from. local_id ]
565570 . children
566571 . values ( )
567- . map ( |child| def_map. module_id ( * child) )
568- // FIXME: do we need to traverse out of block expressions here?
572+ . map ( |& child| def_map. module_id ( child) )
569573 . chain ( iter:: successors ( from. containing_module ( db) , |m| m. containing_module ( db) ) )
574+ . zip ( iter:: repeat ( false ) )
570575 . collect :: < Vec < _ > > ( ) ;
571- let mut seen: FxHashSet < _ > = FxHashSet :: default ( ) ;
572576
573577 let def_map = def_map. crate_root ( ) . def_map ( db) ;
574-
575- while let Some ( module) = worklist. pop ( ) {
576- if !seen. insert ( module) {
577- continue ; // already processed this module
578+ let mut block_def_map;
579+ let mut cursor = 0 ;
580+
581+ while let Some ( & mut ( module, ref mut processed) ) = worklist. get_mut ( cursor) {
582+ cursor += 1 ;
583+ if !visited_modules. insert ( ( item, module) ) {
584+ // already processed this module
585+ continue ;
578586 }
579- let ext_def_map;
580- let data = if module. krate == from. krate {
581- if module. block . is_some ( ) {
582- // Re-query the block's DefMap
583- ext_def_map = module. def_map ( db) ;
584- & ext_def_map[ module. local_id ]
585- } else {
586- // Reuse the root DefMap
587- & def_map[ module. local_id ]
588- }
587+ * processed = true ;
588+ let data = if module. block . is_some ( ) {
589+ // Re-query the block's DefMap
590+ block_def_map = module. def_map ( db) ;
591+ & block_def_map[ module. local_id ]
589592 } else {
590- // The crate might reexport a module defined in another crate.
591- ext_def_map = module. def_map ( db) ;
592- & ext_def_map[ module. local_id ]
593+ // Reuse the root DefMap
594+ & def_map[ module. local_id ]
593595 } ;
594596
595597 if let Some ( ( name, vis, declared) ) = data. scope . name_of ( item) {
@@ -612,18 +614,30 @@ fn find_local_import_locations(
612614 // the item and we're a submodule of it, so can we.
613615 // Also this keeps the cached data smaller.
614616 if declared || is_pub_or_explicit {
615- cb ( name, module) ;
617+ cb ( visited_modules , name, module) ;
616618 }
617619 }
618620 }
619621
620622 // Descend into all modules visible from `from`.
621623 for ( module, vis) in data. scope . modules_in_scope ( ) {
624+ if module. krate != from. krate {
625+ // We don't need to look at modules from other crates as our item has to be in the
626+ // current crate
627+ continue ;
628+ }
629+ if visited_modules. contains ( & ( item, module) ) {
630+ continue ;
631+ }
632+
622633 if vis. is_visible_from ( db, from) {
623- worklist. push ( module) ;
634+ worklist. push ( ( module, false ) ) ;
624635 }
625636 }
626637 }
638+ worklist. into_iter ( ) . filter ( |& ( _, processed) | processed) . for_each ( |( module, _) | {
639+ visited_modules. remove ( & ( item, module) ) ;
640+ } ) ;
627641}
628642
629643#[ cfg( test) ]
@@ -1591,8 +1605,6 @@ fn main() {
15911605
15921606 #[ test]
15931607 fn from_inside_module ( ) {
1594- // This worked correctly, but the test suite logic was broken.
1595- cov_mark:: check!( submodule_in_testdb) ;
15961608 check_found_path (
15971609 r#"
15981610mod baz {
@@ -1617,6 +1629,35 @@ mod bar {
16171629 )
16181630 }
16191631
1632+ #[ test]
1633+ fn from_inside_module2 ( ) {
1634+ check_found_path (
1635+ r#"
1636+ mod qux {
1637+ pub mod baz {
1638+ pub struct Foo {}
1639+ }
1640+
1641+ mod bar {
1642+ fn bar() {
1643+ $0;
1644+ }
1645+ }
1646+ }
1647+
1648+ "# ,
1649+ "crate::qux::baz::Foo" ,
1650+ expect ! [ [ r#"
1651+ Plain (imports ✔): super::baz::Foo
1652+ Plain (imports ✖): super::baz::Foo
1653+ ByCrate(imports ✔): crate::qux::baz::Foo
1654+ ByCrate(imports ✖): crate::qux::baz::Foo
1655+ BySelf (imports ✔): super::baz::Foo
1656+ BySelf (imports ✖): super::baz::Foo
1657+ "# ] ] ,
1658+ )
1659+ }
1660+
16201661 #[ test]
16211662 fn from_inside_module_with_inner_items ( ) {
16221663 check_found_path (
0 commit comments