diff --git a/compiler/rustc_resolve/src/error_helper.rs b/compiler/rustc_resolve/src/error_helper.rs index 3f62f3b2df3bd..a0d99e9486c74 100644 --- a/compiler/rustc_resolve/src/error_helper.rs +++ b/compiler/rustc_resolve/src/error_helper.rs @@ -2472,17 +2472,96 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { match binding.kind { DeclKind::Import { source_decl, import, .. } => { - // Don't include `{{root}}` in suggestions - it's an internal symbol - // that should never be shown to users. - let path = import - .module_path - .iter() - .filter(|seg| seg.ident.name != kw::PathRoot) - .map(|seg| seg.ident.clone()) - .chain(std::iter::once(ident)) - .collect::>(); let through_reexport = !matches!(source_decl.kind, DeclKind::Def(_)); - sugg_paths.push((path, through_reexport)); + let uses_relative_path = import + .module_path + .first() + .is_some_and(|seg| matches!(seg.ident.name, kw::SelfLower | kw::Super)); + let res_def_id = res.opt_def_id(); + let path = if uses_relative_path { + // A path recovered from `self`/`super` is only useful if both the + // target and every module segment can be named from the failing use site. + let module_path = if let Some(ModuleOrUniformRoot::Module(module)) = + import.imported_module.get() + && module.is_local() + && let Some(module_path) = self.module_path_names(module) + && let Some(mut def_id) = module.opt_def_id() + && res_def_id.is_none_or(|def_id| { + self.is_accessible_from( + self.tcx.visibility(def_id), + parent_scope.module, + ) + }) { + // `module_path_names` tells us the resolved module's canonical path. + // Before suggesting that path from the failing use site, make sure + // every segment in it can actually be named from there. + let mut visible_from_use_site = true; + while let Some(parent) = self.tcx.opt_parent(def_id) { + if !self.is_accessible_from( + self.tcx.visibility(def_id), + parent_scope.module, + ) { + visible_from_use_site = false; + break; + } + if parent.is_top_level_module() { + break; + } + def_id = parent; + } + if visible_from_use_site { Some(module_path) } else { None } + } else { + None + }; + + if let Some(module_path) = module_path { + // `import.module_path` is relative to the import's module, not to the + // failing use site. + let mut suggestion = ImportSuggestion { + did: res_def_id, + descr: "", + path: Path { + span: ident.span, + segments: module_path + .into_iter() + .chain(std::iter::once(ident.name)) + .map(|name| { + ast::PathSegment::from_ident(Ident::with_dummy_span( + name, + )) + }) + .collect(), + tokens: None, + }, + accessible: true, + doc_visible: true, + via_import: false, + note: None, + is_stable: true, + }; + // Reuse the existing relative shortening policy. The fields above + // other than `did` and `path` are not used by this helper. + self.shorten_candidate_path(&mut suggestion, parent_scope.module); + Some(suggestion.path.segments.iter().map(|seg| seg.ident).collect()) + } else { + None + } + } else { + // Don't include `{{root}}` in suggestions - it's an internal symbol + // that should never be shown to users. + Some( + import + .module_path + .iter() + .filter(|seg| seg.ident.name != kw::PathRoot) + .map(|seg| seg.ident.clone()) + .chain(std::iter::once(ident)) + .collect::>(), + ) + }; + if let Some(path) = path { + sugg_paths.push((path, through_reexport)); + } } DeclKind::Def(_) => {} } diff --git a/tests/ui/imports/private-import-suggestion-path-156244.edition_2015.stderr b/tests/ui/imports/private-import-suggestion-path-156244.edition_2015.stderr index 95b1760e6a239..9e51641447f89 100644 --- a/tests/ui/imports/private-import-suggestion-path-156244.edition_2015.stderr +++ b/tests/ui/imports/private-import-suggestion-path-156244.edition_2015.stderr @@ -76,6 +76,66 @@ LL - use crate::rename::inner::Item as Item1; LL + use outer::actual::Item as Item1; | -error: aborting due to 4 previous errors +error[E0603]: struct import `Hi` is private + --> $DIR/private-import-suggestion-path-156244.rs:51:14 + | +LL | use testing::Hi; + | ^^ private struct import + | +note: the struct import `Hi` is defined here... + --> $DIR/private-import-suggestion-path-156244.rs:48:9 + | +LL | use super::public::Hi; + | ^^^^^^^^^^^^^^^^^ +note: ...and refers to the struct `Hi` which is defined here + --> $DIR/private-import-suggestion-path-156244.rs:44:5 + | +LL | pub struct Hi; + | ^^^^^^^^^^^^^^ you could import this directly +help: import `Hi` directly + | +LL - use testing::Hi; +LL + use public::Hi; + | + +error[E0603]: struct import `Hi` is private + --> $DIR/private-import-suggestion-path-156244.rs:67:37 + | +LL | use inaccessible_ancestor::testing::Hi; + | ^^ private struct import + | +note: the struct import `Hi` is defined here... + --> $DIR/private-import-suggestion-path-156244.rs:63:13 + | +LL | use super::private::public::Hi; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ +note: ...and refers to the struct `Hi` which is defined here + --> $DIR/private-import-suggestion-path-156244.rs:58:13 + | +LL | pub struct Hi; + | ^^^^^^^^^^^^^^ you could import this directly + +error[E0603]: module import `mem` is private + --> $DIR/private-import-suggestion-path-156244.rs:77:21 + | +LL | use external_alias::mem; + | ^^^ private module import + | +note: the module import `mem` is defined here... + --> $DIR/private-import-suggestion-path-156244.rs:74:9 + | +LL | use super::s::mem; + | ^^^^^^^^^^^^^ +note: ...and refers to the module `mem` which is defined here + --> $SRC_DIR/std/src/lib.rs:LL:COL + | + = note: you could import this directly +help: import `mem` directly + | +LL - use external_alias::mem; +LL + use core::mem; + | + +error: aborting due to 7 previous errors For more information about this error, try `rustc --explain E0603`. diff --git a/tests/ui/imports/private-import-suggestion-path-156244.edition_2018.stderr b/tests/ui/imports/private-import-suggestion-path-156244.edition_2018.stderr index e153b0cdc95aa..c1f059a09d4d9 100644 --- a/tests/ui/imports/private-import-suggestion-path-156244.edition_2018.stderr +++ b/tests/ui/imports/private-import-suggestion-path-156244.edition_2018.stderr @@ -76,6 +76,66 @@ LL - use crate::rename::inner::Item as Item1; LL + use crate::outer::actual::Item as Item1; | -error: aborting due to 4 previous errors +error[E0603]: struct import `Hi` is private + --> $DIR/private-import-suggestion-path-156244.rs:51:14 + | +LL | use testing::Hi; + | ^^ private struct import + | +note: the struct import `Hi` is defined here... + --> $DIR/private-import-suggestion-path-156244.rs:48:9 + | +LL | use super::public::Hi; + | ^^^^^^^^^^^^^^^^^ +note: ...and refers to the struct `Hi` which is defined here + --> $DIR/private-import-suggestion-path-156244.rs:44:5 + | +LL | pub struct Hi; + | ^^^^^^^^^^^^^^ you could import this directly +help: import `Hi` directly + | +LL - use testing::Hi; +LL + use public::Hi; + | + +error[E0603]: struct import `Hi` is private + --> $DIR/private-import-suggestion-path-156244.rs:67:37 + | +LL | use inaccessible_ancestor::testing::Hi; + | ^^ private struct import + | +note: the struct import `Hi` is defined here... + --> $DIR/private-import-suggestion-path-156244.rs:63:13 + | +LL | use super::private::public::Hi; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ +note: ...and refers to the struct `Hi` which is defined here + --> $DIR/private-import-suggestion-path-156244.rs:58:13 + | +LL | pub struct Hi; + | ^^^^^^^^^^^^^^ you could import this directly + +error[E0603]: module import `mem` is private + --> $DIR/private-import-suggestion-path-156244.rs:77:21 + | +LL | use external_alias::mem; + | ^^^ private module import + | +note: the module import `mem` is defined here... + --> $DIR/private-import-suggestion-path-156244.rs:74:9 + | +LL | use super::s::mem; + | ^^^^^^^^^^^^^ +note: ...and refers to the module `mem` which is defined here + --> $SRC_DIR/std/src/lib.rs:LL:COL + | + = note: you could import this directly +help: import `mem` directly + | +LL - use external_alias::mem; +LL + use core::mem; + | + +error: aborting due to 7 previous errors For more information about this error, try `rustc --explain E0603`. diff --git a/tests/ui/imports/private-import-suggestion-path-156244.rs b/tests/ui/imports/private-import-suggestion-path-156244.rs index 3f9d247097f7d..8732564920720 100644 --- a/tests/ui/imports/private-import-suggestion-path-156244.rs +++ b/tests/ui/imports/private-import-suggestion-path-156244.rs @@ -39,4 +39,42 @@ mod bad { //~^ ERROR module import `inner` is private [E0603] } +// Regression test for https://github.com/rust-lang/rust/issues/157455: no root `super`. +mod public { + pub struct Hi; +} + +mod testing { + use super::public::Hi; +} + +use testing::Hi; +//~^ ERROR struct import `Hi` is private [E0603] + +// Regression test for https://github.com/rust-lang/rust/issues/157455: no private ancestors. +mod inaccessible_ancestor { + mod private { + pub mod public { + pub struct Hi; + } + } + + pub mod testing { + use super::private::public::Hi; + } +} + +use inaccessible_ancestor::testing::Hi; +//~^ ERROR struct import `Hi` is private [E0603] + +// Regression test for https://github.com/rust-lang/rust/issues/157455: no external alias rewrite. +use std as s; + +mod external_alias { + use super::s::mem; +} + +use external_alias::mem; +//~^ ERROR module import `mem` is private [E0603] + fn main() {}