Skip to content

Commit c128242

Browse files
committed
fix relative paths in private import suggestions
1 parent f9f1f24 commit c128242

3 files changed

Lines changed: 91 additions & 22 deletions

File tree

compiler/rustc_resolve/src/diagnostics.rs

Lines changed: 89 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -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
}

tests/ui/imports/private-import-suggestion-path-156244.edition_2015.stderr

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -95,7 +95,7 @@ LL | pub struct Hi;
9595
help: import `Hi` directly
9696
|
9797
LL - use testing::Hi;
98-
LL + use super::public::Hi;
98+
LL + use public::Hi;
9999
|
100100

101101
error[E0603]: struct import `Hi` is private
@@ -114,11 +114,6 @@ note: ...and refers to the struct `Hi` which is defined here
114114
|
115115
LL | pub struct Hi;
116116
| ^^^^^^^^^^^^^^ you could import this directly
117-
help: import `Hi` directly
118-
|
119-
LL - use inaccessible_ancestor::testing::Hi;
120-
LL + use super::private::public::Hi;
121-
|
122117

123118
error[E0603]: module import `mem` is private
124119
--> $DIR/private-import-suggestion-path-156244.rs:77:21

tests/ui/imports/private-import-suggestion-path-156244.edition_2018.stderr

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -95,7 +95,7 @@ LL | pub struct Hi;
9595
help: import `Hi` directly
9696
|
9797
LL - use testing::Hi;
98-
LL + use super::public::Hi;
98+
LL + use public::Hi;
9999
|
100100

101101
error[E0603]: struct import `Hi` is private
@@ -114,11 +114,6 @@ note: ...and refers to the struct `Hi` which is defined here
114114
|
115115
LL | pub struct Hi;
116116
| ^^^^^^^^^^^^^^ you could import this directly
117-
help: import `Hi` directly
118-
|
119-
LL - use inaccessible_ancestor::testing::Hi;
120-
LL + use super::private::public::Hi;
121-
|
122117

123118
error[E0603]: module import `mem` is private
124119
--> $DIR/private-import-suggestion-path-156244.rs:77:21

0 commit comments

Comments
 (0)