diff --git a/compiler/rustc_resolve/src/diagnostics.rs b/compiler/rustc_resolve/src/diagnostics.rs index c082455380ce7..874b4ca988305 100644 --- a/compiler/rustc_resolve/src/diagnostics.rs +++ b/compiler/rustc_resolve/src/diagnostics.rs @@ -2307,7 +2307,6 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { self.mention_default_field_values(source, ident, &mut err); - let mut not_publicly_reexported = false; if let Some((this_res, outer_ident)) = outermost_res { let mut import_suggestions = self.lookup_import_candidates( outer_ident, @@ -2332,7 +2331,6 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { ); // If we suggest importing a public re-export, don't point at the definition. if point_to_def && ident.span != outer_ident.span { - not_publicly_reexported = true; let label = errors::OuterIdentIsNotPubliclyReexported { span: outer_ident.span, outer_ident_descr: this_res.descr(), @@ -2408,7 +2406,6 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { let first_binding = decl; let mut next_binding = Some(decl); let mut next_ident = ident; - let mut path = vec![]; while let Some(binding) = next_binding { let name = next_ident; next_binding = match binding.kind { @@ -2428,18 +2425,18 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { }; match binding.kind { - DeclKind::Import { import, .. } => { - for segment in import.module_path.iter().skip(1) { - // Don't include `{{root}}` in suggestions - it's an internal symbol - // that should never be shown to users. - if segment.ident.name != kw::PathRoot { - path.push(segment.ident); - } - } - sugg_paths.push(( - path.iter().cloned().chain(std::iter::once(ident)).collect::>(), - true, // re-export - )); + 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)); } DeclKind::Def(_) => {} } @@ -2472,25 +2469,34 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { }; err.subdiagnostic(note); } - // We prioritize shorter paths, non-core imports and direct imports over the alternatives. - sugg_paths.sort_by_key(|(p, reexport)| (p.len(), p[0].name == sym::core, *reexport)); - for (sugg, reexport) in sugg_paths { - if not_publicly_reexported { + // The suggestion replaces `dedup_span` with a path reaching the failing ident. + // That's valid only when + // 1) the failing ident is the imported leaf, otherwise `as` renames and trailing segments + // get dropped, and + // 2) the use isn't nested, otherwise `dedup_span` is one ident in `{...}`. + // + // See issue #156060. + let can_replace_use = + !single_nested && !outermost_res.is_some_and(|(_, outer)| outer.span != ident.span); + if can_replace_use { + // We prioritize shorter paths, non-core imports and direct imports over the + // alternatives. + sugg_paths.sort_by_key(|(p, reexport)| (p.len(), p[0].name == sym::core, *reexport)); + for (sugg, reexport) in sugg_paths { + if sugg.len() <= 1 { + // A single path segment suggestion is wrong. This happens on circular + // imports. `tests/ui/imports/issue-55884-2.rs` + continue; + } + let path = join_path_idents(sugg); + let sugg = if reexport { + errors::ImportIdent::ThroughReExport { span: dedup_span, ident, path } + } else { + errors::ImportIdent::Directly { span: dedup_span, ident, path } + }; + err.subdiagnostic(sugg); break; } - if sugg.len() <= 1 { - // A single path segment suggestion is wrong. This happens on circular imports. - // `tests/ui/imports/issue-55884-2.rs` - continue; - } - let path = join_path_idents(sugg); - let sugg = if reexport { - errors::ImportIdent::ThroughReExport { span: dedup_span, ident, path } - } else { - errors::ImportIdent::Directly { span: dedup_span, ident, path } - }; - err.subdiagnostic(sugg); - break; } err.emit(); diff --git a/tests/ui/imports/ambiguous-import-visibility-globglob-priv.stderr b/tests/ui/imports/ambiguous-import-visibility-globglob-priv.stderr index 4485f5ac96481..a6119dba34d70 100644 --- a/tests/ui/imports/ambiguous-import-visibility-globglob-priv.stderr +++ b/tests/ui/imports/ambiguous-import-visibility-globglob-priv.stderr @@ -14,10 +14,10 @@ note: ...and refers to the struct `S` which is defined here | LL | pub struct S {} | ^^^^^^^^^^^^ you could import this directly -help: import `S` through the re-export +help: import `S` directly | LL - use crate::both::private::S; -LL + use m::S; +LL + use crate::m::S; | error[E0603]: struct import `S` is private @@ -36,10 +36,10 @@ note: ...and refers to the struct `S` which is defined here | LL | pub struct S {} | ^^^^^^^^^^^^ you could import this directly -help: import `S` through the re-export +help: import `S` directly | LL - use crate::both::private::S; -LL + use m::S; +LL + use crate::m::S; | error: aborting due to 2 previous errors diff --git a/tests/ui/imports/issue-55884-2.stderr b/tests/ui/imports/issue-55884-2.stderr index 7425b92a11e0f..55b5158ffca89 100644 --- a/tests/ui/imports/issue-55884-2.stderr +++ b/tests/ui/imports/issue-55884-2.stderr @@ -24,6 +24,11 @@ note: ...and refers to the struct `ParseOptions` which is defined here | LL | pub struct ParseOptions {} | ^^^^^^^^^^^^^^^^^^^^^^^ you could import this directly +help: import `ParseOptions` directly + | +LL - pub use parser::ParseOptions; +LL + pub use options::ParseOptions; + | error: aborting due to 1 previous error diff --git a/tests/ui/imports/private-import-nested-suggestion-156060.rs b/tests/ui/imports/private-import-nested-suggestion-156060.rs new file mode 100644 index 0000000000000..90a7b94aad555 --- /dev/null +++ b/tests/ui/imports/private-import-nested-suggestion-156060.rs @@ -0,0 +1,17 @@ +// Regression test for #156060. + +mod one { + pub struct One(); +} + +mod two { + use crate::one::One; + pub struct Two(); +} + +mod test { + use crate::two::{One, Two}; + //~^ ERROR struct import `One` is private [E0603] +} + +fn main() {} diff --git a/tests/ui/imports/private-import-nested-suggestion-156060.stderr b/tests/ui/imports/private-import-nested-suggestion-156060.stderr new file mode 100644 index 0000000000000..09d5391bd58df --- /dev/null +++ b/tests/ui/imports/private-import-nested-suggestion-156060.stderr @@ -0,0 +1,20 @@ +error[E0603]: struct import `One` is private + --> $DIR/private-import-nested-suggestion-156060.rs:13:22 + | +LL | use crate::two::{One, Two}; + | ^^^ private struct import + | +note: the struct import `One` is defined here... + --> $DIR/private-import-nested-suggestion-156060.rs:8:9 + | +LL | use crate::one::One; + | ^^^^^^^^^^^^^^^ +note: ...and refers to the struct `One` which is defined here + --> $DIR/private-import-nested-suggestion-156060.rs:4:5 + | +LL | pub struct One(); + | ^^^^^^^^^^^^^^^^^ you could import this directly + +error: aborting due to 1 previous error + +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 new file mode 100644 index 0000000000000..95b1760e6a239 --- /dev/null +++ b/tests/ui/imports/private-import-suggestion-path-156244.edition_2015.stderr @@ -0,0 +1,81 @@ +error[E0603]: struct import `One` is private + --> $DIR/private-import-suggestion-path-156244.rs:17:12 + | +LL | use b::One; + | ^^^ private struct import + | +note: the struct import `One` is defined here... + --> $DIR/private-import-suggestion-path-156244.rs:12:20 + | +LL | use crate::a::{One, Two}; + | ^^^ +note: ...and refers to the struct `One` which is defined here + --> $DIR/private-import-suggestion-path-156244.rs:7:5 + | +LL | pub struct One; + | ^^^^^^^^^^^^^^^ you could import this directly +help: import `One` directly + | +LL - use b::One; +LL + use crate::a::One; + | + +error[E0603]: struct import `One` is private + --> $DIR/private-import-suggestion-path-156244.rs:35:20 + | +LL | use crate::b::{One, Two}; + | ^^^ private struct import + | +note: the struct import `One` is defined here... + --> $DIR/private-import-suggestion-path-156244.rs:12:20 + | +LL | use crate::a::{One, Two}; + | ^^^ +note: ...and refers to the struct `One` which is defined here + --> $DIR/private-import-suggestion-path-156244.rs:7:5 + | +LL | pub struct One; + | ^^^^^^^^^^^^^^^ you could import this directly + +error[E0603]: struct import `Two` is private + --> $DIR/private-import-suggestion-path-156244.rs:35:25 + | +LL | use crate::b::{One, Two}; + | ^^^ private struct import + | +note: the struct import `Two` is defined here... + --> $DIR/private-import-suggestion-path-156244.rs:12:25 + | +LL | use crate::a::{One, Two}; + | ^^^ +note: ...and refers to the struct `Two` which is defined here + --> $DIR/private-import-suggestion-path-156244.rs:8:5 + | +LL | pub struct Two; + | ^^^^^^^^^^^^^^^ you could import this directly + +error[E0603]: module import `inner` is private + --> $DIR/private-import-suggestion-path-156244.rs:38:24 + | +LL | use crate::rename::inner::Item as Item1; + | ^^^^^ private module import + | +note: the module import `inner` is defined here... + --> $DIR/private-import-suggestion-path-156244.rs:31:9 + | +LL | use crate::outer::actual as inner; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +note: ...and refers to the module `actual` which is defined here + --> $DIR/private-import-suggestion-path-156244.rs:25:5 + | +LL | pub mod actual { + | ^^^^^^^^^^^^^^ you could import this directly +help: consider importing this struct instead + | +LL - use crate::rename::inner::Item as Item1; +LL + use outer::actual::Item as Item1; + | + +error: aborting due to 4 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 new file mode 100644 index 0000000000000..e153b0cdc95aa --- /dev/null +++ b/tests/ui/imports/private-import-suggestion-path-156244.edition_2018.stderr @@ -0,0 +1,81 @@ +error[E0603]: struct import `One` is private + --> $DIR/private-import-suggestion-path-156244.rs:20:19 + | +LL | use crate::b::One; + | ^^^ private struct import + | +note: the struct import `One` is defined here... + --> $DIR/private-import-suggestion-path-156244.rs:12:20 + | +LL | use crate::a::{One, Two}; + | ^^^ +note: ...and refers to the struct `One` which is defined here + --> $DIR/private-import-suggestion-path-156244.rs:7:5 + | +LL | pub struct One; + | ^^^^^^^^^^^^^^^ you could import this directly +help: import `One` directly + | +LL - use crate::b::One; +LL + use crate::a::One; + | + +error[E0603]: struct import `One` is private + --> $DIR/private-import-suggestion-path-156244.rs:35:20 + | +LL | use crate::b::{One, Two}; + | ^^^ private struct import + | +note: the struct import `One` is defined here... + --> $DIR/private-import-suggestion-path-156244.rs:12:20 + | +LL | use crate::a::{One, Two}; + | ^^^ +note: ...and refers to the struct `One` which is defined here + --> $DIR/private-import-suggestion-path-156244.rs:7:5 + | +LL | pub struct One; + | ^^^^^^^^^^^^^^^ you could import this directly + +error[E0603]: struct import `Two` is private + --> $DIR/private-import-suggestion-path-156244.rs:35:25 + | +LL | use crate::b::{One, Two}; + | ^^^ private struct import + | +note: the struct import `Two` is defined here... + --> $DIR/private-import-suggestion-path-156244.rs:12:25 + | +LL | use crate::a::{One, Two}; + | ^^^ +note: ...and refers to the struct `Two` which is defined here + --> $DIR/private-import-suggestion-path-156244.rs:8:5 + | +LL | pub struct Two; + | ^^^^^^^^^^^^^^^ you could import this directly + +error[E0603]: module import `inner` is private + --> $DIR/private-import-suggestion-path-156244.rs:38:24 + | +LL | use crate::rename::inner::Item as Item1; + | ^^^^^ private module import + | +note: the module import `inner` is defined here... + --> $DIR/private-import-suggestion-path-156244.rs:31:9 + | +LL | use crate::outer::actual as inner; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +note: ...and refers to the module `actual` which is defined here + --> $DIR/private-import-suggestion-path-156244.rs:25:5 + | +LL | pub mod actual { + | ^^^^^^^^^^^^^^ you could import this directly +help: consider importing this struct instead + | +LL - use crate::rename::inner::Item as Item1; +LL + use crate::outer::actual::Item as Item1; + | + +error: aborting due to 4 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 new file mode 100644 index 0000000000000..3f9d247097f7d --- /dev/null +++ b/tests/ui/imports/private-import-suggestion-path-156244.rs @@ -0,0 +1,42 @@ +// PR #156244 comment +//@ revisions: edition_2015 edition_2018 +//@[edition_2015] edition: 2015 +//@[edition_2018] edition: 2018 + +mod a { + pub struct One; + pub struct Two; +} + +mod b { + use crate::a::{One, Two}; +} + +mod test { + #[cfg(edition_2015)] + use b::One; + //[edition_2015]~^ ERROR struct import `One` is private [E0603] + #[cfg(edition_2018)] + use crate::b::One; + //[edition_2018]~^ ERROR struct import `One` is private [E0603] +} + +mod outer { + pub mod actual { + pub struct Item; + } +} + +mod rename { + use crate::outer::actual as inner; +} + +mod bad { + use crate::b::{One, Two}; + //~^ ERROR struct import `One` is private [E0603] + //~| ERROR struct import `Two` is private [E0603] + use crate::rename::inner::Item as Item1; + //~^ ERROR module import `inner` is private [E0603] +} + +fn main() {} diff --git a/tests/ui/imports/private-std-reexport-suggest-public.stderr b/tests/ui/imports/private-std-reexport-suggest-public.stderr index 49718da7fc939..cc4365d73ad9a 100644 --- a/tests/ui/imports/private-std-reexport-suggest-public.stderr +++ b/tests/ui/imports/private-std-reexport-suggest-public.stderr @@ -13,7 +13,7 @@ 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` through the re-export +help: import `mem` directly | LL - use foo::mem; LL + use std::mem; diff --git a/tests/ui/privacy/privacy2.stderr b/tests/ui/privacy/privacy2.stderr index 3d36f26f784ab..cef8fdb6c5154 100644 --- a/tests/ui/privacy/privacy2.stderr +++ b/tests/ui/privacy/privacy2.stderr @@ -20,6 +20,11 @@ note: ...and refers to the function `foo` which is defined here | LL | pub fn foo() {} | ^^^^^^^^^^^^ you could import this directly +help: import `foo` directly + | +LL - use bar::glob::foo; +LL + use crate::foo; + | error: requires `sized` lang_item --> $DIR/privacy2.rs:17:14