diff --git a/compiler/rustc_resolve/src/diagnostics/impls.rs b/compiler/rustc_resolve/src/diagnostics/impls.rs index 6ddfff9f88d83..1880a1eb60b62 100644 --- a/compiler/rustc_resolve/src/diagnostics/impls.rs +++ b/compiler/rustc_resolve/src/diagnostics/impls.rs @@ -2496,6 +2496,39 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { Some(path) } + /// Returns the original import's source path if it resolves to `source_res` from the use site. + fn import_source_suggestion_path( + &self, + import: Import<'ra>, + source: Ident, + source_res: Res, + parent_scope: &ParentScope<'ra>, + ) -> Option> { + let path = Path { + span: source.span, + segments: import + .module_path + .iter() + .filter(|segment| segment.ident.name != kw::PathRoot) + .map(|segment| segment.ident.clone()) + .chain(std::iter::once(source)) + .map(ast::PathSegment::from_ident) + .collect(), + }; + let segments = Segment::from_path(&path); + let resolves_to_source = + match self.cm().maybe_resolve_path(&segments, source_res.ns(), parent_scope, None) { + PathResult::NonModule(partial_res) => partial_res.full_res() == Some(source_res), + PathResult::Module(ModuleOrUniformRoot::Module(module)) => { + module.res() == Some(source_res) + } + PathResult::Module(_) | PathResult::Indeterminate | PathResult::Failed { .. } => { + false + } + }; + resolves_to_source.then(|| path.segments.iter().map(|segment| segment.ident).collect()) + } + fn shorten_candidate_path( &self, suggestion: &mut ImportSuggestion, @@ -2712,111 +2745,101 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { } } + let has_direct_suggestion = !sugg_paths.is_empty(); // Print the whole import chain to make it easier to see what happens. let first_binding = decl; - let mut next_binding = Some(decl); + let mut next_binding = Some((decl, false)); let mut next_ident = ident; - while let Some(binding) = next_binding { + while let Some((binding, path_to_binding_accessible)) = next_binding { let name = next_ident; next_binding = match binding.kind { _ if res == Res::Err => None, - DeclKind::Import { source_decl, import, .. } => match import.kind { - _ if source_decl.span.is_dummy() => None, - ImportKind::Single { source, .. } => { - next_ident = source; - Some(source_decl) - } - ImportKind::Glob { .. } - | ImportKind::MacroUse { .. } - | ImportKind::MacroExport => Some(source_decl), - ImportKind::ExternCrate { .. } => None, - }, - _ => None, - }; - - match binding.kind { + DeclKind::Import { source_decl, .. } if source_decl.span.is_dummy() => None, DeclKind::Import { source_decl, import, .. } => { - let through_reexport = !matches!(source_decl.kind, DeclKind::Def(..)); - 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; + let source = match import.kind { + ImportKind::Single { source, .. } => Some(source), + ImportKind::Glob { .. } + | ImportKind::MacroUse { .. } + | ImportKind::MacroExport => Some(next_ident), + ImportKind::ExternCrate { .. } => None, + }; + if let Some(source) = source { + next_ident = source; + let source_res = source_decl.res(); + let through_reexport = source_decl.is_import(); + let mut path_is_accessible = has_direct_suggestion && !through_reexport; + if let Some(path) = self.import_source_suggestion_path( + import, + source, + source_res, + &parent_scope, + ) { + path_is_accessible = true; + sugg_paths.push((path, through_reexport)); + } else if !has_direct_suggestion && let Some(ns) = source_res.ns() { + let candidate = self + .lookup_import_candidates(source, ns, &parent_scope, |res| { + res == source_res + }) + .into_iter() + .filter(|candidate| candidate.accessible) + .map(|mut candidate| { + self.shorten_candidate_path( + &mut candidate, + parent_scope.module, + ); + candidate + }) + .min_by_key(|candidate| { + ( + candidate.path.segments.len(), + candidate.path.segments[0].ident.name == sym::core, + ) + }); + if let Some(candidate) = candidate { + // The same item may have several re-exports. Only label this one + // if the suggested path resolves to its binding. + let segments = Segment::from_path(&candidate.path); + path_is_accessible = if let Some((last, prefix)) = + segments.split_last() + && let PathResult::Module(module) = self + .cm() + .maybe_resolve_path(prefix, None, &parent_scope, None) + { + self.cm() + .maybe_resolve_ident_in_module( + module, + last.ident, + ns, + &parent_scope, + None, + ) + .is_ok_and(|decl| decl == source_decl) + } else { + false + }; + let path = + candidate.path.segments.iter().map(|seg| seg.ident).collect(); + sugg_paths.push((path, candidate.via_import)); } - if visible_from_use_site { Some(module_path) } else { None } - } else { - None - }; - - module_path.map(|module_path| { - // `import.module_path` is relative to the import's module, not to the - // failing use site. - let mut 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(), - }; - self.shorten_import_path(res_def_id, &mut path, parent_scope.module); - path.segments.iter().map(|seg| seg.ident).collect() - }) + } + Some((source_decl, path_is_accessible)) } 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)); + None } } - DeclKind::Def(..) => {} - } + _ => None, + }; let first = binding == first_binding; let def_span = self.tcx.sess.source_map().guess_head_span(binding.span); let mut note_span = MultiSpan::from_span(def_span); - if !first && binding.vis().is_public() { + if !first + // The same `Res` may be reachable through a different import binding. + && self.is_accessible_from(binding.vis(), parent_scope.module) + && path_to_binding_accessible + // A circular import chain can lead back to the failing import itself. + && !binding.span.contains(ident.span) + { let desc = match binding.kind { DeclKind::Import { .. } => "re-export", _ => "directly", @@ -2862,6 +2885,8 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { // imports. `tests/ui/imports/issue-55884-2.rs` continue; } + // The suggested path may use a different name than the private alias. + let ident = *sugg.last().expect("at least one segment"); let path = join_path_idents(sugg); let sugg = if reexport { diagnostics::ImportIdent::ThroughReExport { span: dedup_span, ident, path } diff --git a/tests/ui/imports/issue-55884-2.fixed b/tests/ui/imports/issue-55884-2.fixed new file mode 100644 index 0000000000000..e77bfa658197a --- /dev/null +++ b/tests/ui/imports/issue-55884-2.fixed @@ -0,0 +1,22 @@ +//@ edition:2015 +//@ run-rustfix + +// Suggest a usable import path instead of a shadowed or circular re-export. + +#![allow(unused_imports)] + +mod options { + pub struct ParseOptions {} +} + +mod parser { + pub use options::*; + // Private single import shadows public glob import, but arrives too late for initial + // resolution of `use parser::ParseOptions` because it depends on that resolution itself. + #[allow(hidden_glob_reexports)] + use ParseOptions; +} + +pub use options::ParseOptions; //~ ERROR struct import `ParseOptions` is private + +fn main() {} diff --git a/tests/ui/imports/issue-55884-2.rs b/tests/ui/imports/issue-55884-2.rs index 1355a6c52b89a..699abe68d4dc7 100644 --- a/tests/ui/imports/issue-55884-2.rs +++ b/tests/ui/imports/issue-55884-2.rs @@ -1,4 +1,10 @@ //@ edition:2015 +//@ run-rustfix + +// Suggest a usable import path instead of a shadowed or circular re-export. + +#![allow(unused_imports)] + mod options { pub struct ParseOptions {} } diff --git a/tests/ui/imports/issue-55884-2.stderr b/tests/ui/imports/issue-55884-2.stderr index 55b5158ffca89..02ef97c7402bb 100644 --- a/tests/ui/imports/issue-55884-2.stderr +++ b/tests/ui/imports/issue-55884-2.stderr @@ -1,26 +1,26 @@ error[E0603]: struct import `ParseOptions` is private - --> $DIR/issue-55884-2.rs:14:17 + --> $DIR/issue-55884-2.rs:20:17 | LL | pub use parser::ParseOptions; | ^^^^^^^^^^^^ private struct import | note: the struct import `ParseOptions` is defined here... - --> $DIR/issue-55884-2.rs:11:9 + --> $DIR/issue-55884-2.rs:17:9 | LL | use ParseOptions; | ^^^^^^^^^^^^ note: ...and refers to the struct import `ParseOptions` which is defined here... - --> $DIR/issue-55884-2.rs:14:9 + --> $DIR/issue-55884-2.rs:20:9 | LL | pub use parser::ParseOptions; - | ^^^^^^^^^^^^^^^^^^^^ you could import this re-export + | ^^^^^^^^^^^^^^^^^^^^ note: ...and refers to the struct import `ParseOptions` which is defined here... - --> $DIR/issue-55884-2.rs:7:13 + --> $DIR/issue-55884-2.rs:13:13 | LL | pub use options::*; - | ^^^^^^^^^^ you could import this re-export + | ^^^^^^^^^^ note: ...and refers to the struct `ParseOptions` which is defined here - --> $DIR/issue-55884-2.rs:3:5 + --> $DIR/issue-55884-2.rs:9:5 | LL | pub struct ParseOptions {} | ^^^^^^^^^^^^^^^^^^^^^^^ you could import this directly diff --git a/tests/ui/imports/private-import-alias-private-parent-issue-149418.rs b/tests/ui/imports/private-import-alias-private-parent-issue-149418.rs new file mode 100644 index 0000000000000..017b09def95f1 --- /dev/null +++ b/tests/ui/imports/private-import-alias-private-parent-issue-149418.rs @@ -0,0 +1,28 @@ +//@ check-fail +//@ edition: 2024 + +// Private import aliases should not suggest paths through private parent modules. + +mod delicious_snacks { + use self::fruits::PEAR as fruit; + + mod fruits { + pub const PEAR: &str = "Pear"; + pub const APPLE: &str = "Apple"; + } +} + +mod delicious_snacks_without_self { + use fruits::PEAR as fruit; + + mod fruits { + pub const PEAR: &str = "Pear"; + } +} + +fn main() { + let _ = delicious_snacks::fruit; + //~^ ERROR constant import `fruit` is private + let _ = delicious_snacks_without_self::fruit; + //~^ ERROR constant import `fruit` is private +} diff --git a/tests/ui/imports/private-import-alias-private-parent-issue-149418.stderr b/tests/ui/imports/private-import-alias-private-parent-issue-149418.stderr new file mode 100644 index 0000000000000..bd19951b72631 --- /dev/null +++ b/tests/ui/imports/private-import-alias-private-parent-issue-149418.stderr @@ -0,0 +1,37 @@ +error[E0603]: constant import `fruit` is private + --> $DIR/private-import-alias-private-parent-issue-149418.rs:24:31 + | +LL | let _ = delicious_snacks::fruit; + | ^^^^^ private constant import + | +note: the constant import `fruit` is defined here... + --> $DIR/private-import-alias-private-parent-issue-149418.rs:7:9 + | +LL | use self::fruits::PEAR as fruit; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ +note: ...and refers to the constant `PEAR` which is defined here + --> $DIR/private-import-alias-private-parent-issue-149418.rs:10:9 + | +LL | pub const PEAR: &str = "Pear"; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error[E0603]: constant import `fruit` is private + --> $DIR/private-import-alias-private-parent-issue-149418.rs:26:44 + | +LL | let _ = delicious_snacks_without_self::fruit; + | ^^^^^ private constant import + | +note: the constant import `fruit` is defined here... + --> $DIR/private-import-alias-private-parent-issue-149418.rs:16:9 + | +LL | use fruits::PEAR as fruit; + | ^^^^^^^^^^^^^^^^^^^^^ +note: ...and refers to the constant `PEAR` which is defined here + --> $DIR/private-import-alias-private-parent-issue-149418.rs:19:9 + | +LL | pub const PEAR: &str = "Pear"; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0603`. diff --git a/tests/ui/imports/private-import-alias-public-parent-issue-149418.fixed b/tests/ui/imports/private-import-alias-public-parent-issue-149418.fixed new file mode 100644 index 0000000000000..ca30e9f03a574 --- /dev/null +++ b/tests/ui/imports/private-import-alias-public-parent-issue-149418.fixed @@ -0,0 +1,113 @@ +//@ run-rustfix +//@ edition: 2024 + +// Private import aliases should suggest their source through an accessible parent module or +// re-export. + +#![allow(unused_imports, dead_code)] + +mod accessible_parent { + use self::fruits::PEAR as fruit; + + pub mod fruits { + pub const PEAR: &str = "Pear"; + } +} + +mod accessible_parent_without_self { + use fruits::PEAR as fruit; + + pub mod fruits { + pub const PEAR: &str = "Pear"; + } +} + +mod public_reexport { + mod private { + pub struct Item; + } + + pub use self::private::Item; +} + +mod nested_alias { + pub mod inner { + use super::super::public_reexport::Item as Alias; + } +} + +mod absolute_alias { + use crate::public_reexport::Item as Alias; +} + +mod hidden_reexport { + mod private { + pub use crate::public_reexport::Item; + } + + pub mod inner { + use super::private::Item as Alias; + } +} + +mod use_site { + fn check() { + let _: crate::public_reexport::Item; + //~^ ERROR struct import `Alias` is private + // Keep pointing at a re-export when the original import path is accessible here. + let _: crate::public_reexport::Item; + //~^ ERROR struct import `Alias` is private + // Finding another public re-export does not make `hidden_reexport::private` accessible. + let _: crate::public_reexport::Item; + //~^ ERROR struct import `Alias` is private + } +} + +fn main() { + let _ = accessible_parent::fruits::PEAR; + //~^ ERROR constant import `fruit` is private + let _ = accessible_parent_without_self::fruits::PEAR; + //~^ ERROR constant import `fruit` is private +} + +mod crate_visible { + pub(crate) struct Item; + + pub mod nested { + use crate::crate_visible::Item as Alias; + } +} + +fn check_crate_visible() { + // A crate-visible definition can be recommended from within the same crate. + let _: crate::crate_visible::Item; + //~^ ERROR struct import `Alias` is private +} + +mod inaccessible_import { + use crate::public_reexport::Item; + + pub mod nested { + use super::Item as Alias; + } +} + +mod accessible_import { + use crate::public_reexport::Item; + + mod nested { + use super::Item as Alias; + } + + mod use_site { + fn check() { + // The private import in our parent module is accessible here. + let _: super::Item; + //~^ ERROR struct import `Alias` is private + // `super::Item` resolves here, but not through `inaccessible_import::Item`. + // Do not recommend that inaccessible binding merely because its `Res` matches. + let _: super::Item; + //~^ ERROR struct import `Alias` is private + } + } +} diff --git a/tests/ui/imports/private-import-alias-public-parent-issue-149418.rs b/tests/ui/imports/private-import-alias-public-parent-issue-149418.rs new file mode 100644 index 0000000000000..fba9c7508b48d --- /dev/null +++ b/tests/ui/imports/private-import-alias-public-parent-issue-149418.rs @@ -0,0 +1,113 @@ +//@ run-rustfix +//@ edition: 2024 + +// Private import aliases should suggest their source through an accessible parent module or +// re-export. + +#![allow(unused_imports, dead_code)] + +mod accessible_parent { + use self::fruits::PEAR as fruit; + + pub mod fruits { + pub const PEAR: &str = "Pear"; + } +} + +mod accessible_parent_without_self { + use fruits::PEAR as fruit; + + pub mod fruits { + pub const PEAR: &str = "Pear"; + } +} + +mod public_reexport { + mod private { + pub struct Item; + } + + pub use self::private::Item; +} + +mod nested_alias { + pub mod inner { + use super::super::public_reexport::Item as Alias; + } +} + +mod absolute_alias { + use crate::public_reexport::Item as Alias; +} + +mod hidden_reexport { + mod private { + pub use crate::public_reexport::Item; + } + + pub mod inner { + use super::private::Item as Alias; + } +} + +mod use_site { + fn check() { + let _: super::nested_alias::inner::Alias; + //~^ ERROR struct import `Alias` is private + // Keep pointing at a re-export when the original import path is accessible here. + let _: super::absolute_alias::Alias; + //~^ ERROR struct import `Alias` is private + // Finding another public re-export does not make `hidden_reexport::private` accessible. + let _: super::hidden_reexport::inner::Alias; + //~^ ERROR struct import `Alias` is private + } +} + +fn main() { + let _ = accessible_parent::fruit; + //~^ ERROR constant import `fruit` is private + let _ = accessible_parent_without_self::fruit; + //~^ ERROR constant import `fruit` is private +} + +mod crate_visible { + pub(crate) struct Item; + + pub mod nested { + use crate::crate_visible::Item as Alias; + } +} + +fn check_crate_visible() { + // A crate-visible definition can be recommended from within the same crate. + let _: crate_visible::nested::Alias; + //~^ ERROR struct import `Alias` is private +} + +mod inaccessible_import { + use crate::public_reexport::Item; + + pub mod nested { + use super::Item as Alias; + } +} + +mod accessible_import { + use crate::public_reexport::Item; + + mod nested { + use super::Item as Alias; + } + + mod use_site { + fn check() { + // The private import in our parent module is accessible here. + let _: super::nested::Alias; + //~^ ERROR struct import `Alias` is private + // `super::Item` resolves here, but not through `inaccessible_import::Item`. + // Do not recommend that inaccessible binding merely because its `Res` matches. + let _: crate::inaccessible_import::nested::Alias; + //~^ ERROR struct import `Alias` is private + } + } +} diff --git a/tests/ui/imports/private-import-alias-public-parent-issue-149418.stderr b/tests/ui/imports/private-import-alias-public-parent-issue-149418.stderr new file mode 100644 index 0000000000000..01d4067b1403e --- /dev/null +++ b/tests/ui/imports/private-import-alias-public-parent-issue-149418.stderr @@ -0,0 +1,217 @@ +error[E0603]: struct import `Alias` is private + --> $DIR/private-import-alias-public-parent-issue-149418.rs:55:44 + | +LL | let _: super::nested_alias::inner::Alias; + | ^^^^^ private struct import + | +note: the struct import `Alias` is defined here... + --> $DIR/private-import-alias-public-parent-issue-149418.rs:35:13 + | +LL | use super::super::public_reexport::Item as Alias; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +note: ...and refers to the struct import `Item` which is defined here... + --> $DIR/private-import-alias-public-parent-issue-149418.rs:30:13 + | +LL | pub use self::private::Item; + | ^^^^^^^^^^^^^^^^^^^ you could import this re-export +note: ...and refers to the struct `Item` which is defined here + --> $DIR/private-import-alias-public-parent-issue-149418.rs:27:9 + | +LL | pub struct Item; + | ^^^^^^^^^^^^^^^^ +help: import `Item` through the re-export + | +LL - let _: super::nested_alias::inner::Alias; +LL + let _: crate::public_reexport::Item; + | + +error[E0603]: struct import `Alias` is private + --> $DIR/private-import-alias-public-parent-issue-149418.rs:58:39 + | +LL | let _: super::absolute_alias::Alias; + | ^^^^^ private struct import + | +note: the struct import `Alias` is defined here... + --> $DIR/private-import-alias-public-parent-issue-149418.rs:40:9 + | +LL | use crate::public_reexport::Item as Alias; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +note: ...and refers to the struct import `Item` which is defined here... + --> $DIR/private-import-alias-public-parent-issue-149418.rs:30:13 + | +LL | pub use self::private::Item; + | ^^^^^^^^^^^^^^^^^^^ you could import this re-export +note: ...and refers to the struct `Item` which is defined here + --> $DIR/private-import-alias-public-parent-issue-149418.rs:27:9 + | +LL | pub struct Item; + | ^^^^^^^^^^^^^^^^ +help: import `Item` through the re-export + | +LL - let _: super::absolute_alias::Alias; +LL + let _: crate::public_reexport::Item; + | + +error[E0603]: struct import `Alias` is private + --> $DIR/private-import-alias-public-parent-issue-149418.rs:61:47 + | +LL | let _: super::hidden_reexport::inner::Alias; + | ^^^^^ private struct import + | +note: the struct import `Alias` is defined here... + --> $DIR/private-import-alias-public-parent-issue-149418.rs:49:13 + | +LL | use super::private::Item as Alias; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +note: ...and refers to the struct import `Item` which is defined here... + --> $DIR/private-import-alias-public-parent-issue-149418.rs:45:17 + | +LL | pub use crate::public_reexport::Item; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +note: ...and refers to the struct import `Item` which is defined here... + --> $DIR/private-import-alias-public-parent-issue-149418.rs:30:13 + | +LL | pub use self::private::Item; + | ^^^^^^^^^^^^^^^^^^^ you could import this re-export +note: ...and refers to the struct `Item` which is defined here + --> $DIR/private-import-alias-public-parent-issue-149418.rs:27:9 + | +LL | pub struct Item; + | ^^^^^^^^^^^^^^^^ +help: import `Item` through the re-export + | +LL - let _: super::hidden_reexport::inner::Alias; +LL + let _: crate::public_reexport::Item; + | + +error[E0603]: constant import `fruit` is private + --> $DIR/private-import-alias-public-parent-issue-149418.rs:67:32 + | +LL | let _ = accessible_parent::fruit; + | ^^^^^ private constant import + | +note: the constant import `fruit` is defined here... + --> $DIR/private-import-alias-public-parent-issue-149418.rs:10:9 + | +LL | use self::fruits::PEAR as fruit; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ +note: ...and refers to the constant `PEAR` which is defined here + --> $DIR/private-import-alias-public-parent-issue-149418.rs:13:9 + | +LL | pub const PEAR: &str = "Pear"; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ you could import this directly +help: import `PEAR` directly + | +LL | let _ = accessible_parent::fruits::PEAR; + | +++++++ + +error[E0603]: constant import `fruit` is private + --> $DIR/private-import-alias-public-parent-issue-149418.rs:69:45 + | +LL | let _ = accessible_parent_without_self::fruit; + | ^^^^^ private constant import + | +note: the constant import `fruit` is defined here... + --> $DIR/private-import-alias-public-parent-issue-149418.rs:18:9 + | +LL | use fruits::PEAR as fruit; + | ^^^^^^^^^^^^^^^^^^^^^ +note: ...and refers to the constant `PEAR` which is defined here + --> $DIR/private-import-alias-public-parent-issue-149418.rs:21:9 + | +LL | pub const PEAR: &str = "Pear"; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ you could import this directly +help: import `PEAR` directly + | +LL | let _ = accessible_parent_without_self::fruits::PEAR; + | +++++++ + +error[E0603]: struct import `Alias` is private + --> $DIR/private-import-alias-public-parent-issue-149418.rs:83:35 + | +LL | let _: crate_visible::nested::Alias; + | ^^^^^ private struct import + | +note: the struct import `Alias` is defined here... + --> $DIR/private-import-alias-public-parent-issue-149418.rs:77:13 + | +LL | use crate::crate_visible::Item as Alias; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +note: ...and refers to the struct `Item` which is defined here + --> $DIR/private-import-alias-public-parent-issue-149418.rs:74:5 + | +LL | pub(crate) struct Item; + | ^^^^^^^^^^^^^^^^^^^^^^^ you could import this directly +help: import `Item` directly + | +LL - let _: crate_visible::nested::Alias; +LL + let _: crate::crate_visible::Item; + | + +error[E0603]: struct import `Alias` is private + --> $DIR/private-import-alias-public-parent-issue-149418.rs:105:35 + | +LL | let _: super::nested::Alias; + | ^^^^^ private struct import + | +note: the struct import `Alias` is defined here... + --> $DIR/private-import-alias-public-parent-issue-149418.rs:99:13 + | +LL | use super::Item as Alias; + | ^^^^^^^^^^^^^^^^^^^^ +note: ...and refers to the struct import `Item` which is defined here... + --> $DIR/private-import-alias-public-parent-issue-149418.rs:96:9 + | +LL | use crate::public_reexport::Item; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ you could import this re-export +note: ...and refers to the struct import `Item` which is defined here... + --> $DIR/private-import-alias-public-parent-issue-149418.rs:30:13 + | +LL | pub use self::private::Item; + | ^^^^^^^^^^^^^^^^^^^ you could import this re-export +note: ...and refers to the struct `Item` which is defined here + --> $DIR/private-import-alias-public-parent-issue-149418.rs:27:9 + | +LL | pub struct Item; + | ^^^^^^^^^^^^^^^^ +help: import `Item` through the re-export + | +LL - let _: super::nested::Alias; +LL + let _: super::Item; + | + +error[E0603]: struct import `Alias` is private + --> $DIR/private-import-alias-public-parent-issue-149418.rs:109:56 + | +LL | let _: crate::inaccessible_import::nested::Alias; + | ^^^^^ private struct import + | +note: the struct import `Alias` is defined here... + --> $DIR/private-import-alias-public-parent-issue-149418.rs:91:13 + | +LL | use super::Item as Alias; + | ^^^^^^^^^^^^^^^^^^^^ +note: ...and refers to the struct import `Item` which is defined here... + --> $DIR/private-import-alias-public-parent-issue-149418.rs:88:9 + | +LL | use crate::public_reexport::Item; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +note: ...and refers to the struct import `Item` which is defined here... + --> $DIR/private-import-alias-public-parent-issue-149418.rs:30:13 + | +LL | pub use self::private::Item; + | ^^^^^^^^^^^^^^^^^^^ you could import this re-export +note: ...and refers to the struct `Item` which is defined here + --> $DIR/private-import-alias-public-parent-issue-149418.rs:27:9 + | +LL | pub struct Item; + | ^^^^^^^^^^^^^^^^ +help: import `Item` through the re-export + | +LL - let _: crate::inaccessible_import::nested::Alias; +LL + let _: super::Item; + | + +error: aborting due to 8 previous errors + +For more information about this error, try `rustc --explain E0603`. 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 2a8795b6ab93c..cf865e86f39b2 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 @@ -91,7 +91,7 @@ note: ...and refers to the struct `Hi` which is defined here --> $DIR/private-import-suggestion-path-156244.rs:46:13 | LL | pub struct Hi; - | ^^^^^^^^^^^^^^ you could import this directly + | ^^^^^^^^^^^^^^ error[E0603]: module import `mem` is private --> $DIR/private-import-suggestion-path-156244.rs:65:21 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 9f112fe4e7551..65bca594bf5ae 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 @@ -91,7 +91,7 @@ note: ...and refers to the struct `Hi` which is defined here --> $DIR/private-import-suggestion-path-156244.rs:46:13 | LL | pub struct Hi; - | ^^^^^^^^^^^^^^ you could import this directly + | ^^^^^^^^^^^^^^ error[E0603]: module import `mem` is private --> $DIR/private-import-suggestion-path-156244.rs:65:21 diff --git a/tests/ui/shadowed/shadowed-use-visibility.fixed b/tests/ui/shadowed/shadowed-use-visibility.fixed new file mode 100644 index 0000000000000..83624183a968c --- /dev/null +++ b/tests/ui/shadowed/shadowed-use-visibility.fixed @@ -0,0 +1,22 @@ +//@ run-rustfix + +// Import suggestions should bypass private module aliases in favor of accessible functions. + +#![allow(unused_imports, dead_code)] + +mod foo { + pub fn f() {} + + use crate::foo as bar; + pub use self::f as bar; +} + +mod bar { + use foo::f as g; //~ ERROR module import `bar` is private + + use crate::foo as f; + pub use crate::foo::*; +} + +use bar::f; //~ ERROR module import `f` is private +fn main() {} diff --git a/tests/ui/shadowed/shadowed-use-visibility.rs b/tests/ui/shadowed/shadowed-use-visibility.rs index 070aeaf146700..4e83fe07e91fc 100644 --- a/tests/ui/shadowed/shadowed-use-visibility.rs +++ b/tests/ui/shadowed/shadowed-use-visibility.rs @@ -1,3 +1,9 @@ +//@ run-rustfix + +// Import suggestions should bypass private module aliases in favor of accessible functions. + +#![allow(unused_imports, dead_code)] + mod foo { pub fn f() {} diff --git a/tests/ui/shadowed/shadowed-use-visibility.stderr b/tests/ui/shadowed/shadowed-use-visibility.stderr index bbec8380fd032..c3f0e02029f0b 100644 --- a/tests/ui/shadowed/shadowed-use-visibility.stderr +++ b/tests/ui/shadowed/shadowed-use-visibility.stderr @@ -1,19 +1,19 @@ error[E0603]: module import `bar` is private - --> $DIR/shadowed-use-visibility.rs:9:21 + --> $DIR/shadowed-use-visibility.rs:15:21 | LL | use crate::foo::bar::f as g; | ^^^ private module import | note: the module import `bar` is defined here... - --> $DIR/shadowed-use-visibility.rs:4:9 + --> $DIR/shadowed-use-visibility.rs:10:9 | LL | use crate::foo as bar; | ^^^^^^^^^^^^^^^^^ note: ...and refers to the module `foo` which is defined here - --> $DIR/shadowed-use-visibility.rs:1:1 + --> $DIR/shadowed-use-visibility.rs:7:1 | LL | mod foo { - | ^^^^^^^ + | ^^^^^^^ you could import this directly help: consider importing this function instead | LL - use crate::foo::bar::f as g; @@ -21,21 +21,21 @@ LL + use foo::f as g; | error[E0603]: module import `f` is private - --> $DIR/shadowed-use-visibility.rs:15:10 + --> $DIR/shadowed-use-visibility.rs:21:10 | LL | use bar::f::f; | ^ private module import | note: the module import `f` is defined here... - --> $DIR/shadowed-use-visibility.rs:11:9 + --> $DIR/shadowed-use-visibility.rs:17:9 | LL | use crate::foo as f; | ^^^^^^^^^^^^^^^ note: ...and refers to the module `foo` which is defined here - --> $DIR/shadowed-use-visibility.rs:1:1 + --> $DIR/shadowed-use-visibility.rs:7:1 | LL | mod foo { - | ^^^^^^^ + | ^^^^^^^ you could import this directly help: consider importing this function through its public re-export instead | LL - use bar::f::f;