diff --git a/compiler/rustc_resolve/src/imports.rs b/compiler/rustc_resolve/src/imports.rs index 7696b4b220d6c..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 @@ -1051,6 +1064,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 { 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`.