@@ -2472,17 +2472,96 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
24722472
24732473 match binding. kind {
24742474 DeclKind :: Import { source_decl, import, .. } => {
2475- // Don't include `{{root}}` in suggestions - it's an internal symbol
2476- // that should never be shown to users.
2477- let path = import
2478- . module_path
2479- . iter ( )
2480- . filter ( |seg| seg. ident . name != kw:: PathRoot )
2481- . map ( |seg| seg. ident . clone ( ) )
2482- . chain ( std:: iter:: once ( ident) )
2483- . collect :: < Vec < _ > > ( ) ;
24842475 let through_reexport = !matches ! ( source_decl. kind, DeclKind :: Def ( _) ) ;
2485- sugg_paths. push ( ( path, through_reexport) ) ;
2476+ let uses_relative_path = import
2477+ . module_path
2478+ . first ( )
2479+ . is_some_and ( |seg| matches ! ( seg. ident. name, kw:: SelfLower | kw:: Super ) ) ;
2480+ let res_def_id = res. opt_def_id ( ) ;
2481+ let path = if uses_relative_path {
2482+ // A path recovered from `self`/`super` is only useful if both the
2483+ // target and every module segment can be named from the failing use site.
2484+ let module_path = if let Some ( ModuleOrUniformRoot :: Module ( module) ) =
2485+ import. imported_module . get ( )
2486+ && module. is_local ( )
2487+ && let Some ( module_path) = self . module_path_names ( module)
2488+ && let Some ( mut def_id) = module. opt_def_id ( )
2489+ && res_def_id. is_none_or ( |def_id| {
2490+ self . is_accessible_from (
2491+ self . tcx . visibility ( def_id) ,
2492+ parent_scope. module ,
2493+ )
2494+ } ) {
2495+ // `module_path_names` tells us the resolved module's canonical path.
2496+ // Before suggesting that path from the failing use site, make sure
2497+ // every segment in it can actually be named from there.
2498+ let mut visible_from_use_site = true ;
2499+ while let Some ( parent) = self . tcx . opt_parent ( def_id) {
2500+ if !self . is_accessible_from (
2501+ self . tcx . visibility ( def_id) ,
2502+ parent_scope. module ,
2503+ ) {
2504+ visible_from_use_site = false ;
2505+ break ;
2506+ }
2507+ if parent. is_top_level_module ( ) {
2508+ break ;
2509+ }
2510+ def_id = parent;
2511+ }
2512+ if visible_from_use_site { Some ( module_path) } else { None }
2513+ } else {
2514+ None
2515+ } ;
2516+
2517+ if let Some ( module_path) = module_path {
2518+ // `import.module_path` is relative to the import's module, not to the
2519+ // failing use site.
2520+ let mut suggestion = ImportSuggestion {
2521+ did : res_def_id,
2522+ descr : "" ,
2523+ path : Path {
2524+ span : ident. span ,
2525+ segments : module_path
2526+ . into_iter ( )
2527+ . chain ( std:: iter:: once ( ident. name ) )
2528+ . map ( |name| {
2529+ ast:: PathSegment :: from_ident ( Ident :: with_dummy_span (
2530+ name,
2531+ ) )
2532+ } )
2533+ . collect ( ) ,
2534+ tokens : None ,
2535+ } ,
2536+ accessible : true ,
2537+ doc_visible : true ,
2538+ via_import : false ,
2539+ note : None ,
2540+ is_stable : true ,
2541+ } ;
2542+ // Reuse the existing relative shortening policy. The fields above
2543+ // other than `did` and `path` are not used by this helper.
2544+ self . shorten_candidate_path ( & mut suggestion, parent_scope. module ) ;
2545+ Some ( suggestion. path . segments . iter ( ) . map ( |seg| seg. ident ) . collect ( ) )
2546+ } else {
2547+ None
2548+ }
2549+ } else {
2550+ // Don't include `{{root}}` in suggestions - it's an internal symbol
2551+ // that should never be shown to users.
2552+ Some (
2553+ import
2554+ . module_path
2555+ . iter ( )
2556+ . filter ( |seg| seg. ident . name != kw:: PathRoot )
2557+ . map ( |seg| seg. ident . clone ( ) )
2558+ . chain ( std:: iter:: once ( ident) )
2559+ . collect :: < Vec < _ > > ( ) ,
2560+ )
2561+ } ;
2562+ if let Some ( path) = path {
2563+ sugg_paths. push ( ( path, through_reexport) ) ;
2564+ }
24862565 }
24872566 DeclKind :: Def ( _) => { }
24882567 }
0 commit comments