Silence some resolve errors when there have been glob import errors
When encountering `use foo::*;` where `foo` fails to be found, and we later encounter resolution errors, we silence those later errors. A single case of the above, for an *existing* import on a big codebase would otherwise have a huge number of knock-down spurious errors. Ideally, instead of a global flag to silence all subsequent resolve errors, we'd want to introduce an unameable binding in the appropriate rib as a sentinel when there's a failed glob import, so when we encounter a resolve error we can search for that sentinel and if found, and only then, silence that error. The current approach is just a quick proof of concept to iterate over. Partially address #96799.
This commit is contained in:
parent
1a73979886
commit
37c54db477
@ -536,6 +536,7 @@ pub(crate) fn finalize_imports(&mut self) {
|
||||
let determined_imports = mem::take(&mut self.determined_imports);
|
||||
let indeterminate_imports = mem::take(&mut self.indeterminate_imports);
|
||||
|
||||
let mut glob_error = false;
|
||||
for (is_indeterminate, import) in determined_imports
|
||||
.iter()
|
||||
.map(|i| (false, i))
|
||||
@ -547,6 +548,8 @@ pub(crate) fn finalize_imports(&mut self) {
|
||||
self.import_dummy_binding(*import, is_indeterminate);
|
||||
|
||||
if let Some(err) = unresolved_import_error {
|
||||
glob_error |= import.is_glob();
|
||||
|
||||
if let ImportKind::Single { source, ref source_bindings, .. } = import.kind {
|
||||
if source.name == kw::SelfLower {
|
||||
// Silence `unresolved import` error if E0429 is already emitted
|
||||
@ -562,7 +565,7 @@ pub(crate) fn finalize_imports(&mut self) {
|
||||
{
|
||||
// In the case of a new import line, throw a diagnostic message
|
||||
// for the previous line.
|
||||
self.throw_unresolved_import_error(errors);
|
||||
self.throw_unresolved_import_error(errors, glob_error);
|
||||
errors = vec![];
|
||||
}
|
||||
if seen_spans.insert(err.span) {
|
||||
@ -573,7 +576,7 @@ pub(crate) fn finalize_imports(&mut self) {
|
||||
}
|
||||
|
||||
if !errors.is_empty() {
|
||||
self.throw_unresolved_import_error(errors);
|
||||
self.throw_unresolved_import_error(errors, glob_error);
|
||||
return;
|
||||
}
|
||||
|
||||
@ -599,9 +602,7 @@ pub(crate) fn finalize_imports(&mut self) {
|
||||
}
|
||||
}
|
||||
|
||||
if !errors.is_empty() {
|
||||
self.throw_unresolved_import_error(errors);
|
||||
}
|
||||
self.throw_unresolved_import_error(errors, glob_error);
|
||||
}
|
||||
|
||||
pub(crate) fn check_hidden_glob_reexports(
|
||||
@ -673,7 +674,11 @@ pub(crate) fn check_hidden_glob_reexports(
|
||||
}
|
||||
}
|
||||
|
||||
fn throw_unresolved_import_error(&mut self, errors: Vec<(Import<'_>, UnresolvedImportError)>) {
|
||||
fn throw_unresolved_import_error(
|
||||
&mut self,
|
||||
errors: Vec<(Import<'_>, UnresolvedImportError)>,
|
||||
glob_error: bool,
|
||||
) {
|
||||
if errors.is_empty() {
|
||||
return;
|
||||
}
|
||||
@ -752,7 +757,10 @@ fn throw_unresolved_import_error(&mut self, errors: Vec<(Import<'_>, UnresolvedI
|
||||
}
|
||||
}
|
||||
|
||||
diag.emit();
|
||||
let guar = diag.emit();
|
||||
if glob_error {
|
||||
self.glob_error = Some(guar);
|
||||
}
|
||||
}
|
||||
|
||||
/// Attempts to resolve the given import, returning:
|
||||
|
@ -4039,9 +4039,12 @@ fn report_error(&mut self, span: Span, resolution_error: ResolutionError<'a>) {
|
||||
}
|
||||
|
||||
#[inline]
|
||||
/// If we're actually rustdoc then avoid giving a name resolution error for `cfg()` items.
|
||||
/// If we're actually rustdoc then avoid giving a name resolution error for `cfg()` items or
|
||||
// an invalid `use foo::*;` was found, which can cause unbounded ammounts of "item not found"
|
||||
// errors. We silence them all.
|
||||
fn should_report_errs(&self) -> bool {
|
||||
!(self.r.tcx.sess.opts.actually_rustdoc && self.in_func_body)
|
||||
&& !self.r.glob_error.is_some()
|
||||
}
|
||||
|
||||
// Resolve in alternative namespaces if resolution in the primary namespace fails.
|
||||
|
@ -37,7 +37,7 @@
|
||||
use rustc_data_structures::intern::Interned;
|
||||
use rustc_data_structures::steal::Steal;
|
||||
use rustc_data_structures::sync::{FreezeReadGuard, Lrc};
|
||||
use rustc_errors::{Applicability, Diag, ErrCode};
|
||||
use rustc_errors::{Applicability, Diag, ErrCode, ErrorGuaranteed};
|
||||
use rustc_expand::base::{DeriveResolution, SyntaxExtension, SyntaxExtensionKind};
|
||||
use rustc_feature::BUILTIN_ATTRIBUTES;
|
||||
use rustc_hir::def::Namespace::{self, *};
|
||||
@ -1052,6 +1052,7 @@ pub struct Resolver<'a, 'tcx> {
|
||||
|
||||
/// Maps glob imports to the names of items actually imported.
|
||||
glob_map: FxHashMap<LocalDefId, FxHashSet<Symbol>>,
|
||||
glob_error: Option<ErrorGuaranteed>,
|
||||
visibilities_for_hashing: Vec<(LocalDefId, ty::Visibility)>,
|
||||
used_imports: FxHashSet<NodeId>,
|
||||
maybe_unused_trait_imports: FxIndexSet<LocalDefId>,
|
||||
@ -1421,6 +1422,7 @@ pub fn new(
|
||||
ast_transform_scopes: FxHashMap::default(),
|
||||
|
||||
glob_map: Default::default(),
|
||||
glob_error: None,
|
||||
visibilities_for_hashing: Default::default(),
|
||||
used_imports: FxHashSet::default(),
|
||||
maybe_unused_trait_imports: Default::default(),
|
||||
|
12
tests/ui/imports/import-from-missing-star-2.rs
Normal file
12
tests/ui/imports/import-from-missing-star-2.rs
Normal file
@ -0,0 +1,12 @@
|
||||
mod foo {
|
||||
use spam::*; //~ ERROR unresolved import `spam` [E0432]
|
||||
}
|
||||
|
||||
fn main() {
|
||||
// Expect this to pass because the compiler knows there's a failed `*` import in `foo` that
|
||||
// might have caused it.
|
||||
foo::bar();
|
||||
// FIXME: these two should *fail* because they can't be fixed by fixing the glob import in `foo`
|
||||
ham(); // should error but doesn't
|
||||
eggs(); // should error but doesn't
|
||||
}
|
11
tests/ui/imports/import-from-missing-star-2.stderr
Normal file
11
tests/ui/imports/import-from-missing-star-2.stderr
Normal file
@ -0,0 +1,11 @@
|
||||
error[E0432]: unresolved import `spam`
|
||||
--> $DIR/import-from-missing-star-2.rs:2:9
|
||||
|
|
||||
LL | use spam::*;
|
||||
| ^^^^ maybe a missing crate `spam`?
|
||||
|
|
||||
= help: consider adding `extern crate spam` to use the `spam` crate
|
||||
|
||||
error: aborting due to 1 previous error
|
||||
|
||||
For more information about this error, try `rustc --explain E0432`.
|
43
tests/ui/imports/import-from-missing-star-3.rs
Normal file
43
tests/ui/imports/import-from-missing-star-3.rs
Normal file
@ -0,0 +1,43 @@
|
||||
mod foo {
|
||||
use spam::*; //~ ERROR unresolved import `spam` [E0432]
|
||||
|
||||
fn x() {
|
||||
// Expect these to pass because the compiler knows there's a failed `*` import that might
|
||||
// fix it.
|
||||
eggs();
|
||||
foo::bar();
|
||||
}
|
||||
}
|
||||
|
||||
mod bar {
|
||||
fn z() {}
|
||||
fn x() {
|
||||
// Expect these to pass because the compiler knows there's a failed `*` import that might
|
||||
// fix it.
|
||||
foo::bar();
|
||||
z();
|
||||
// FIXME: should error but doesn't because as soon as there's a single glob import error, we
|
||||
// silence all resolve errors.
|
||||
eggs();
|
||||
}
|
||||
}
|
||||
|
||||
mod baz {
|
||||
fn x() {
|
||||
use spam::*; //~ ERROR unresolved import `spam` [E0432]
|
||||
fn qux() {}
|
||||
qux();
|
||||
// Expect this to pass because the compiler knows there's a local failed `*` import that
|
||||
// might have caused it.
|
||||
eggs();
|
||||
// Expect this to pass because the compiler knows there's a failed `*` import in `foo` that
|
||||
// might have caused it.
|
||||
foo::bar();
|
||||
}
|
||||
}
|
||||
|
||||
fn main() {
|
||||
// FIXME: should error but doesn't because as soon as there's a single glob import error, we
|
||||
// silence all resolve errors.
|
||||
ham();
|
||||
}
|
19
tests/ui/imports/import-from-missing-star-3.stderr
Normal file
19
tests/ui/imports/import-from-missing-star-3.stderr
Normal file
@ -0,0 +1,19 @@
|
||||
error[E0432]: unresolved import `spam`
|
||||
--> $DIR/import-from-missing-star-3.rs:2:9
|
||||
|
|
||||
LL | use spam::*;
|
||||
| ^^^^ maybe a missing crate `spam`?
|
||||
|
|
||||
= help: consider adding `extern crate spam` to use the `spam` crate
|
||||
|
||||
error[E0432]: unresolved import `spam`
|
||||
--> $DIR/import-from-missing-star-3.rs:27:13
|
||||
|
|
||||
LL | use spam::*;
|
||||
| ^^^^ maybe a missing crate `spam`?
|
||||
|
|
||||
= help: consider adding `extern crate spam` to use the `spam` crate
|
||||
|
||||
error: aborting due to 2 previous errors
|
||||
|
||||
For more information about this error, try `rustc --explain E0432`.
|
10
tests/ui/imports/import-from-missing-star.rs
Normal file
10
tests/ui/imports/import-from-missing-star.rs
Normal file
@ -0,0 +1,10 @@
|
||||
use spam::*; //~ ERROR unresolved import `spam` [E0432]
|
||||
|
||||
fn main() {
|
||||
// Expect these to pass because the compiler knows there's a failed `*` import that might have
|
||||
// caused it.
|
||||
ham();
|
||||
eggs();
|
||||
// Even this case, as we might have expected `spam::foo` to exist.
|
||||
foo::bar();
|
||||
}
|
11
tests/ui/imports/import-from-missing-star.stderr
Normal file
11
tests/ui/imports/import-from-missing-star.stderr
Normal file
@ -0,0 +1,11 @@
|
||||
error[E0432]: unresolved import `spam`
|
||||
--> $DIR/import-from-missing-star.rs:1:5
|
||||
|
|
||||
LL | use spam::*;
|
||||
| ^^^^ maybe a missing crate `spam`?
|
||||
|
|
||||
= help: consider adding `extern crate spam` to use the `spam` crate
|
||||
|
||||
error: aborting due to 1 previous error
|
||||
|
||||
For more information about this error, try `rustc --explain E0432`.
|
@ -6,5 +6,5 @@ mod foo {
|
||||
}
|
||||
|
||||
fn main() {
|
||||
foo::f(); //~ ERROR cannot find function `f` in module `foo`
|
||||
foo::f(); // cannot find function `f` in module `foo`, but silenced
|
||||
}
|
||||
|
@ -4,13 +4,6 @@ error[E0432]: unresolved import `self::*`
|
||||
LL | pub use self::*;
|
||||
| ^^^^^^^ cannot glob-import a module into itself
|
||||
|
||||
error[E0425]: cannot find function `f` in module `foo`
|
||||
--> $DIR/issue-31212.rs:9:10
|
||||
|
|
||||
LL | foo::f();
|
||||
| ^ not found in `foo`
|
||||
error: aborting due to 1 previous error
|
||||
|
||||
error: aborting due to 2 previous errors
|
||||
|
||||
Some errors have detailed explanations: E0425, E0432.
|
||||
For more information about an error, try `rustc --explain E0425`.
|
||||
For more information about this error, try `rustc --explain E0432`.
|
||||
|
Loading…
Reference in New Issue
Block a user