@@ -2426,17 +2426,96 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
24262426
24272427 match binding. kind {
24282428 DeclKind :: Import { source_decl, import, .. } => {
2429- // Don't include `{{root}}` in suggestions - it's an internal symbol
2430- // that should never be shown to users.
2431- let path = import
2432- . module_path
2433- . iter ( )
2434- . filter ( |seg| seg. ident . name != kw:: PathRoot )
2435- . map ( |seg| seg. ident . clone ( ) )
2436- . chain ( std:: iter:: once ( ident) )
2437- . collect :: < Vec < _ > > ( ) ;
24382429 let through_reexport = !matches ! ( source_decl. kind, DeclKind :: Def ( _) ) ;
2439- sugg_paths. push ( ( path, through_reexport) ) ;
2430+ let uses_relative_path = import
2431+ . module_path
2432+ . first ( )
2433+ . is_some_and ( |seg| matches ! ( seg. ident. name, kw:: SelfLower | kw:: Super ) ) ;
2434+ let res_def_id = res. opt_def_id ( ) ;
2435+ let path = if uses_relative_path {
2436+ // A path recovered from `self`/`super` is only useful if both the
2437+ // target and every module segment can be named from the failing use site.
2438+ let module_path = if let Some ( ModuleOrUniformRoot :: Module ( module) ) =
2439+ import. imported_module . get ( )
2440+ && module. is_local ( )
2441+ && let Some ( module_path) = self . module_path_names ( module)
2442+ && let Some ( mut def_id) = module. opt_def_id ( )
2443+ && res_def_id. is_none_or ( |def_id| {
2444+ self . is_accessible_from (
2445+ self . tcx . visibility ( def_id) ,
2446+ parent_scope. module ,
2447+ )
2448+ } ) {
2449+ // `module_path_names` tells us the resolved module's canonical path.
2450+ // Before suggesting that path from the failing use site, make sure
2451+ // every segment in it can actually be named from there.
2452+ let mut visible_from_use_site = true ;
2453+ while let Some ( parent) = self . tcx . opt_parent ( def_id) {
2454+ if !self . is_accessible_from (
2455+ self . tcx . visibility ( def_id) ,
2456+ parent_scope. module ,
2457+ ) {
2458+ visible_from_use_site = false ;
2459+ break ;
2460+ }
2461+ if parent. is_top_level_module ( ) {
2462+ break ;
2463+ }
2464+ def_id = parent;
2465+ }
2466+ if visible_from_use_site { Some ( module_path) } else { None }
2467+ } else {
2468+ None
2469+ } ;
2470+
2471+ if let Some ( module_path) = module_path {
2472+ // `import.module_path` is relative to the import's module, not to the
2473+ // failing use site.
2474+ let mut suggestion = ImportSuggestion {
2475+ did : res_def_id,
2476+ descr : "" ,
2477+ path : Path {
2478+ span : ident. span ,
2479+ segments : module_path
2480+ . into_iter ( )
2481+ . chain ( std:: iter:: once ( ident. name ) )
2482+ . map ( |name| {
2483+ ast:: PathSegment :: from_ident ( Ident :: with_dummy_span (
2484+ name,
2485+ ) )
2486+ } )
2487+ . collect ( ) ,
2488+ tokens : None ,
2489+ } ,
2490+ accessible : true ,
2491+ doc_visible : true ,
2492+ via_import : false ,
2493+ note : None ,
2494+ is_stable : true ,
2495+ } ;
2496+ // Reuse the existing relative shortening policy. The fields above
2497+ // other than `did` and `path` are not used by this helper.
2498+ self . shorten_candidate_path ( & mut suggestion, parent_scope. module ) ;
2499+ Some ( suggestion. path . segments . iter ( ) . map ( |seg| seg. ident ) . collect ( ) )
2500+ } else {
2501+ None
2502+ }
2503+ } else {
2504+ // Don't include `{{root}}` in suggestions - it's an internal symbol
2505+ // that should never be shown to users.
2506+ Some (
2507+ import
2508+ . module_path
2509+ . iter ( )
2510+ . filter ( |seg| seg. ident . name != kw:: PathRoot )
2511+ . map ( |seg| seg. ident . clone ( ) )
2512+ . chain ( std:: iter:: once ( ident) )
2513+ . collect :: < Vec < _ > > ( ) ,
2514+ )
2515+ } ;
2516+ if let Some ( path) = path {
2517+ sugg_paths. push ( ( path, through_reexport) ) ;
2518+ }
24402519 }
24412520 DeclKind :: Def ( _) => { }
24422521 }
0 commit comments