From 7116a50a2e545186bd7b5d05854f082f9c8b2438 Mon Sep 17 00:00:00 2001 From: yuk1ty Date: Sat, 14 Mar 2026 14:23:55 +0900 Subject: [PATCH 1/2] Consolidate E0433 into E0432 for nested imports with unresolved parent path --- compiler/rustc_resolve/src/imports.rs | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/compiler/rustc_resolve/src/imports.rs b/compiler/rustc_resolve/src/imports.rs index 7696b4b220d6c..100ef8df88e04 100644 --- a/compiler/rustc_resolve/src/imports.rs +++ b/compiler/rustc_resolve/src/imports.rs @@ -1051,6 +1051,22 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { if !self.issue_145575_hack_applied { assert!(import.imported_module.get().is_none()); } + if import.is_nested() { + let module = if let Some(ModuleOrUniformRoot::Module(m)) = module { + m.opt_def_id() + } else { + None + }; + return Some(UnresolvedImportError { + span, + label: Some(label), + note: None, + suggestion, + candidates: None, + segment: Some(segment_name), + module, + }); + } self.report_error( span, ResolutionError::FailedToResolve { From 6671a988dd99e732515f89a91aae5d97097b1cc6 Mon Sep 17 00:00:00 2001 From: yuk1ty Date: Sun, 15 Mar 2026 23:40:07 +0900 Subject: [PATCH 2/2] Suppress redundant E0433 for paths matching failed import prefixes Track first segments of failed imports and skip late resolution errors for paths sharing the same prefix. This avoids redundant E0433 after an E0432 has already been reported for the same missing module, without suppressing unrelated diagnostics. --- compiler/rustc_resolve/src/imports.rs | 13 ++++++++ compiler/rustc_resolve/src/late.rs | 22 +++++++++++-- compiler/rustc_resolve/src/lib.rs | 5 +++ .../absolute-paths-in-nested-use-groups.rs | 6 +--- ...absolute-paths-in-nested-use-groups.stderr | 25 ++++++--------- .../nested-import-root-symbol-150103.rs | 4 +-- .../nested-import-root-symbol-150103.stderr | 6 ++-- .../imports/redundant-import-errors-nested.rs | 8 +++++ .../redundant-import-errors-nested.stderr | 14 +++++++++ tests/ui/traits/const-traits/issue-102156.rs | 1 - .../traits/const-traits/issue-102156.stderr | 19 ++---------- tests/ui/use/use-path-segment-kw.e2015.stderr | 31 +------------------ tests/ui/use/use-path-segment-kw.rs | 8 ++--- tests/ui/use/use-super-global-path.rs | 3 +- tests/ui/use/use-super-global-path.stderr | 21 +++++-------- 15 files changed, 90 insertions(+), 96 deletions(-) create mode 100644 tests/ui/imports/redundant-import-errors-nested.rs create mode 100644 tests/ui/imports/redundant-import-errors-nested.stderr diff --git a/compiler/rustc_resolve/src/imports.rs b/compiler/rustc_resolve/src/imports.rs index 100ef8df88e04..5db238f4e6ff3 100644 --- a/compiler/rustc_resolve/src/imports.rs +++ b/compiler/rustc_resolve/src/imports.rs @@ -217,6 +217,15 @@ impl<'ra> ImportData<'ra> { } } + /// Returns the first meaningful path segment of this import, + /// skipping synthetic segments like `{{root}}` and `$crate`. + pub(crate) fn first_non_root_segment(&self) -> Option { + self.module_path + .iter() + .find(|seg| seg.ident.name != kw::PathRoot && seg.ident.name != kw::DollarCrate) + .map(|seg| seg.ident.name) + } + pub(crate) fn id(&self) -> Option { match self.kind { ImportKind::Single { id, .. } @@ -653,6 +662,10 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { glob_error |= import.is_glob(); + if let Some(name) = import.first_non_root_segment() { + self.failed_import_prefixes.insert(name); + } + if let ImportKind::Single { source, ref decls, .. } = import.kind && source.name == kw::SelfLower // Silence `unresolved import` error if E0429 is already emitted diff --git a/compiler/rustc_resolve/src/late.rs b/compiler/rustc_resolve/src/late.rs index 453fe9d7a8e0e..8f86616cdf3fe 100644 --- a/compiler/rustc_resolve/src/late.rs +++ b/compiler/rustc_resolve/src/late.rs @@ -4424,7 +4424,7 @@ impl<'a, 'ast, 'ra, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> { let Finalize { node_id, path_span, .. } = finalize; let report_errors = |this: &mut Self, res: Option| { - if this.should_report_errs() { + if this.should_report_errs_for_path(path) { let (err, candidates) = this.smart_resolve_report_errors( path, None, @@ -4558,7 +4558,7 @@ impl<'a, 'ast, 'ra, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> { let def_id = this.parent_scope.module.nearest_parent_mod(); - if this.should_report_errs() { + if this.should_report_errs_for_path(path) { if candidates.is_empty() { if path.len() == 2 && let [segment] = prefix_path @@ -4668,7 +4668,9 @@ impl<'a, 'ast, 'ra, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> { Err(err) => { if let Some(err) = report_errors_for_call(self, err) { - self.report_error(err.span, err.node); + if self.should_report_errs_for_path(path) { + self.r.report_error(err.span, err.node); + } } PartialRes::new(Res::Err) @@ -4717,6 +4719,20 @@ impl<'a, 'ast, 'ra, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> { && !self.r.glob_error.is_some() } + /// Like `should_report_errs`, but also suppresses errors for paths whose + /// first segment matches a known-failed import prefix. + fn should_report_errs_for_path(&self, path: &[Segment]) -> bool { + if !self.should_report_errs() { + return false; + } + if let Some(first) = path.first() { + if self.r.failed_import_prefixes.contains(&first.ident.name) { + return false; + } + } + true + } + // Resolve in alternative namespaces if resolution in the primary namespace fails. fn resolve_qpath_anywhere( &mut self, diff --git a/compiler/rustc_resolve/src/lib.rs b/compiler/rustc_resolve/src/lib.rs index ead69473b00d1..7c28a09159b08 100644 --- a/compiler/rustc_resolve/src/lib.rs +++ b/compiler/rustc_resolve/src/lib.rs @@ -1242,6 +1242,10 @@ pub struct Resolver<'ra, 'tcx> { glob_error: Option = None, visibilities_for_hashing: Vec<(LocalDefId, Visibility)> = Vec::new(), used_imports: FxHashSet = default::fx_hash_set(), + /// First segments of import paths that failed to resolve. + /// Used to suppress redundant resolution errors in late resolver + /// for paths sharing the same unresolved prefix. + failed_import_prefixes: FxHashSet, maybe_unused_trait_imports: FxIndexSet, /// Privacy errors are delayed until the end in order to deduplicate them. @@ -1681,6 +1685,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { extern_module_map: Default::default(), glob_map: Default::default(), + failed_import_prefixes: FxHashSet::default(), maybe_unused_trait_imports: Default::default(), arenas, diff --git a/tests/ui/imports/absolute-paths-in-nested-use-groups.rs b/tests/ui/imports/absolute-paths-in-nested-use-groups.rs index 9a8c9aab72828..da72c39126b8f 100644 --- a/tests/ui/imports/absolute-paths-in-nested-use-groups.rs +++ b/tests/ui/imports/absolute-paths-in-nested-use-groups.rs @@ -1,14 +1,10 @@ #![allow(unused_imports)] -mod foo {} - use foo::{ + //~^ ERROR: unresolved import `foo` ::bar, - //~^ ERROR: crate root in paths can only be used in start position super::bar, - //~^ ERROR: `super` in paths can only be used in start position self::bar, - //~^ ERROR: `self` in paths can only be used in start position }; fn main() {} diff --git a/tests/ui/imports/absolute-paths-in-nested-use-groups.stderr b/tests/ui/imports/absolute-paths-in-nested-use-groups.stderr index ff951ad7489c7..3c22d79216bbd 100644 --- a/tests/ui/imports/absolute-paths-in-nested-use-groups.stderr +++ b/tests/ui/imports/absolute-paths-in-nested-use-groups.stderr @@ -1,21 +1,14 @@ -error[E0433]: the crate root in paths can only be used in start position - --> $DIR/absolute-paths-in-nested-use-groups.rs:6:5 +error[E0432]: unresolved import `foo` + --> $DIR/absolute-paths-in-nested-use-groups.rs:3:5 | -LL | ::bar, - | ^ can only be used in path start position - -error[E0433]: `super` in paths can only be used in start position - --> $DIR/absolute-paths-in-nested-use-groups.rs:8:5 +LL | use foo::{ + | ^^^ use of unresolved module or unlinked crate `foo` | -LL | super::bar, - | ^^^^^ can only be used in path start position - -error[E0433]: `self` in paths can only be used in start position - --> $DIR/absolute-paths-in-nested-use-groups.rs:10:5 +help: you might be missing a crate named `foo`, add it to your project and import it in your code + | +LL + extern crate foo; | -LL | self::bar, - | ^^^^ can only be used in path start position -error: aborting due to 3 previous errors +error: aborting due to 1 previous error -For more information about this error, try `rustc --explain E0433`. +For more information about this error, try `rustc --explain E0432`. diff --git a/tests/ui/imports/nested-import-root-symbol-150103.rs b/tests/ui/imports/nested-import-root-symbol-150103.rs index 7e126d8188c76..20bf98523d869 100644 --- a/tests/ui/imports/nested-import-root-symbol-150103.rs +++ b/tests/ui/imports/nested-import-root-symbol-150103.rs @@ -3,11 +3,11 @@ // caused by `{{root}}` appearing in diagnostic suggestions mod A { - use Iuse::{ ::Fish }; //~ ERROR cannot find module or crate `Iuse` in the crate root + use Iuse::{ ::Fish }; //~ ERROR unresolved import `Iuse` } mod B { - use A::{::Fish}; //~ ERROR the crate root in paths can only be used in start position + use A::{::Fish}; //~ ERROR unresolved import `A::Fish` } fn main() {} diff --git a/tests/ui/imports/nested-import-root-symbol-150103.stderr b/tests/ui/imports/nested-import-root-symbol-150103.stderr index e5240ceef2683..ca0be231b089d 100644 --- a/tests/ui/imports/nested-import-root-symbol-150103.stderr +++ b/tests/ui/imports/nested-import-root-symbol-150103.stderr @@ -1,4 +1,4 @@ -error[E0433]: cannot find module or crate `Iuse` in the crate root +error[E0432]: unresolved import `Iuse` --> $DIR/nested-import-root-symbol-150103.rs:6:9 | LL | use Iuse::{ ::Fish }; @@ -9,7 +9,7 @@ help: you might be missing a crate named `Iuse`, add it to your project and impo LL + extern crate Iuse; | -error[E0433]: the crate root in paths can only be used in start position +error[E0432]: unresolved import `A::Fish` --> $DIR/nested-import-root-symbol-150103.rs:10:13 | LL | use A::{::Fish}; @@ -17,4 +17,4 @@ LL | use A::{::Fish}; error: aborting due to 2 previous errors -For more information about this error, try `rustc --explain E0433`. +For more information about this error, try `rustc --explain E0432`. diff --git a/tests/ui/imports/redundant-import-errors-nested.rs b/tests/ui/imports/redundant-import-errors-nested.rs new file mode 100644 index 0000000000000..1602e241e6230 --- /dev/null +++ b/tests/ui/imports/redundant-import-errors-nested.rs @@ -0,0 +1,8 @@ +// Issue #153156: Too many errors for missing crate for nested imports and later uses + +use foo::{bar, baz::bat}; +//~^ ERROR unresolved import `foo` + +pub fn main() { + foo::qux(); +} diff --git a/tests/ui/imports/redundant-import-errors-nested.stderr b/tests/ui/imports/redundant-import-errors-nested.stderr new file mode 100644 index 0000000000000..472f7fd423f37 --- /dev/null +++ b/tests/ui/imports/redundant-import-errors-nested.stderr @@ -0,0 +1,14 @@ +error[E0432]: unresolved import `foo` + --> $DIR/redundant-import-errors-nested.rs:3:5 + | +LL | use foo::{bar, baz::bat}; + | ^^^ use of unresolved module or unlinked crate `foo` + | +help: you might be missing a crate named `foo`, add it to your project and import it in your code + | +LL + extern crate foo; + | + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0432`. diff --git a/tests/ui/traits/const-traits/issue-102156.rs b/tests/ui/traits/const-traits/issue-102156.rs index bd9fdff3e4271..0f7b1414e8562 100644 --- a/tests/ui/traits/const-traits/issue-102156.rs +++ b/tests/ui/traits/const-traits/issue-102156.rs @@ -4,7 +4,6 @@ use core::convert::{From, TryFrom}; //~^ ERROR -//~| ERROR use std::pin::Pin; use std::alloc::Allocator; diff --git a/tests/ui/traits/const-traits/issue-102156.stderr b/tests/ui/traits/const-traits/issue-102156.stderr index 1fce5f1b18fea..2daa9d6631405 100644 --- a/tests/ui/traits/const-traits/issue-102156.stderr +++ b/tests/ui/traits/const-traits/issue-102156.stderr @@ -1,4 +1,4 @@ -error[E0433]: cannot find `core` in the crate root +error[E0432]: unresolved import `core` --> $DIR/issue-102156.rs:5:5 | LL | use core::convert::{From, TryFrom}; @@ -10,19 +10,6 @@ LL - use core::convert::{From, TryFrom}; LL + use std::convert::{From, TryFrom}; | -error[E0433]: cannot find `core` in the crate root - --> $DIR/issue-102156.rs:5:5 - | -LL | use core::convert::{From, TryFrom}; - | ^^^^ you might be missing crate `core` - | - = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` -help: try using `std` instead of `core` - | -LL - use core::convert::{From, TryFrom}; -LL + use std::convert::{From, TryFrom}; - | - -error: aborting due to 2 previous errors +error: aborting due to 1 previous error -For more information about this error, try `rustc --explain E0433`. +For more information about this error, try `rustc --explain E0432`. diff --git a/tests/ui/use/use-path-segment-kw.e2015.stderr b/tests/ui/use/use-path-segment-kw.e2015.stderr index 908e739ec520f..b0d02d80007c8 100644 --- a/tests/ui/use/use-path-segment-kw.e2015.stderr +++ b/tests/ui/use/use-path-segment-kw.e2015.stderr @@ -1027,17 +1027,6 @@ LL | macro_dollar_crate!(); | = note: this error originates in the macro `macro_dollar_crate` (in Nightly builds, run with -Z macro-backtrace for more info) -error[E0433]: `$crate` in paths can only be used in start position - --> $DIR/use-path-segment-kw.rs:20:27 - | -LL | type A3 = foobar::$crate; - | ^^^^^^ can only be used in path start position -... -LL | macro_dollar_crate!(); - | --------------------- in this macro invocation - | - = note: this error originates in the macro `macro_dollar_crate` (in Nightly builds, run with -Z macro-backtrace for more info) - error[E0433]: `$crate` in paths can only be used in start position --> $DIR/use-path-segment-kw.rs:26:26 | @@ -1121,12 +1110,6 @@ error[E0433]: global paths cannot start with `crate` LL | type B2 = ::crate; | ^^^^^ cannot start with this -error[E0433]: `crate` in paths can only be used in start position - --> $DIR/use-path-segment-kw.rs:106:27 - | -LL | type B3 = foobar::crate; - | ^^^^^ can only be used in path start position - error[E0433]: `crate` in paths can only be used in start position --> $DIR/use-path-segment-kw.rs:112:26 | @@ -1151,12 +1134,6 @@ error[E0433]: global paths cannot start with `super` LL | type C2 = ::super; | ^^^^^ cannot start with this -error[E0433]: `super` in paths can only be used in start position - --> $DIR/use-path-segment-kw.rs:144:27 - | -LL | type C3 = foobar::super; - | ^^^^^ can only be used in path start position - error[E0433]: `super` in paths can only be used in start position --> $DIR/use-path-segment-kw.rs:150:26 | @@ -1169,12 +1146,6 @@ error[E0433]: global paths cannot start with `self` LL | type D2 = ::self; | ^^^^ cannot start with this -error[E0433]: `self` in paths can only be used in start position - --> $DIR/use-path-segment-kw.rs:186:27 - | -LL | type D3 = foobar::self; - | ^^^^ can only be used in path start position - error[E0433]: `self` in paths can only be used in start position --> $DIR/use-path-segment-kw.rs:194:26 | @@ -1193,7 +1164,7 @@ error[E0433]: `self` in paths can only be used in start position LL | type D6 = self::self; | ^^^^ can only be used in path start position -error: aborting due to 129 previous errors +error: aborting due to 125 previous errors Some errors have detailed explanations: E0429, E0432, E0433, E0573. For more information about an error, try `rustc --explain E0429`. diff --git a/tests/ui/use/use-path-segment-kw.rs b/tests/ui/use/use-path-segment-kw.rs index be64f239b9fc3..e5a05655f3a70 100644 --- a/tests/ui/use/use-path-segment-kw.rs +++ b/tests/ui/use/use-path-segment-kw.rs @@ -17,7 +17,7 @@ macro_rules! macro_dollar_crate { use ::{$crate}; //~ ERROR `$crate` in paths can only be used in start position use ::{$crate as _nested_dollar_crate2}; //~ ERROR `$crate` in paths can only be used in start position - type A3 = foobar::$crate; //~ ERROR `$crate` in paths can only be used in start position + type A3 = foobar::$crate; //[e2018]~ ERROR `$crate` in paths can only be used in start position use foobar::$crate; //~ ERROR `$crate` in paths can only be used in start position use foobar::$crate as _dollar_crate3; //~ ERROR `$crate` in paths can only be used in start position use foobar::{$crate}; //~ ERROR `$crate` in paths can only be used in start position @@ -103,7 +103,7 @@ mod foo { use ::{crate}; //~ ERROR `crate` in paths can only be used in start position use ::{crate as _nested_crate2}; //~ ERROR `crate` in paths can only be used in start position - type B3 = foobar::crate; //~ ERROR `crate` in paths can only be used in start position + type B3 = foobar::crate; //[e2018]~ ERROR `crate` in paths can only be used in start position use foobar::crate; //~ ERROR `crate` in paths can only be used in start position use foobar::crate as _crate3; //~ ERROR `crate` in paths can only be used in start position use foobar::{crate}; //~ ERROR `crate` in paths can only be used in start position @@ -141,7 +141,7 @@ mod foo { use ::{super}; //~ ERROR `super` in paths can only be used in start position, after `self`, or after another `super` use ::{super as _nested_super2}; //~ ERROR `super` in paths can only be used in start position, after `self`, or after another `super` - type C3 = foobar::super; //~ ERROR `super` in paths can only be used in start position + type C3 = foobar::super; //[e2018]~ ERROR `super` in paths can only be used in start position use foobar::super; //~ ERROR `super` in paths can only be used in start position, after `self`, or after another `super` use foobar::super as _super3; //~ ERROR `super` in paths can only be used in start position, after `self`, or after another `super` use foobar::{super}; //~ ERROR `super` in paths can only be used in start position, after `self`, or after another `super` @@ -183,7 +183,7 @@ mod foo { //[e2015]~^ ERROR imports need to be explicitly named pub use ::{self as _nested_self2}; //[e2018]~ ERROR extern prelude cannot be imported - type D3 = foobar::self; //~ ERROR `self` in paths can only be used in start position + type D3 = foobar::self; //[e2018]~ ERROR `self` in paths can only be used in start position pub use foobar::qux::self; //~ ERROR `self` imports are only allowed within a { } list //[e2015]~^ ERROR unresolved import `foobar` pub use foobar::self as _self3; //~ ERROR `self` imports are only allowed within a { } list diff --git a/tests/ui/use/use-super-global-path.rs b/tests/ui/use/use-super-global-path.rs index d00c6964dea14..93187252f1e2e 100644 --- a/tests/ui/use/use-super-global-path.rs +++ b/tests/ui/use/use-super-global-path.rs @@ -5,8 +5,7 @@ struct Z; mod foo { use ::super::{S, Z}; - //~^ ERROR: global paths cannot start with `super` - //~| ERROR: global paths cannot start with `super` + //~^ ERROR: unresolved import `super` pub fn g() { use ::super::main; //~ ERROR: global paths cannot start with `super` diff --git a/tests/ui/use/use-super-global-path.stderr b/tests/ui/use/use-super-global-path.stderr index dd853aab48305..2fa8543c0bf6c 100644 --- a/tests/ui/use/use-super-global-path.stderr +++ b/tests/ui/use/use-super-global-path.stderr @@ -1,23 +1,16 @@ error[E0433]: global paths cannot start with `super` - --> $DIR/use-super-global-path.rs:7:11 + --> $DIR/use-super-global-path.rs:11:15 | -LL | use ::super::{S, Z}; - | ^^^^^ cannot start with this +LL | use ::super::main; + | ^^^^^ cannot start with this -error[E0433]: global paths cannot start with `super` +error[E0432]: unresolved import `super` --> $DIR/use-super-global-path.rs:7:11 | LL | use ::super::{S, Z}; | ^^^^^ cannot start with this - | - = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` - -error[E0433]: global paths cannot start with `super` - --> $DIR/use-super-global-path.rs:12:15 - | -LL | use ::super::main; - | ^^^^^ cannot start with this -error: aborting due to 3 previous errors +error: aborting due to 2 previous errors -For more information about this error, try `rustc --explain E0433`. +Some errors have detailed explanations: E0432, E0433. +For more information about an error, try `rustc --explain E0432`.