Skip to content

Commit 97aa4c9

Browse files
committed
fix relative paths in private import suggestions
1 parent 65d4539 commit 97aa4c9

3 files changed

Lines changed: 91 additions & 22 deletions

File tree

compiler/rustc_resolve/src/error_helper.rs

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

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)