1
Fork 0

Rollup merge of #125381 - estebank:issue-96799, r=petrochenkov

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 unnameable 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:
许杰友 Jieyou Xu (Joe) 2024-05-29 03:25:08 +01:00 committed by GitHub
commit bc1a069ec5
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
11 changed files with 131 additions and 19 deletions

View file

@ -537,6 +537,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
let determined_imports = mem::take(&mut self.determined_imports); let determined_imports = mem::take(&mut self.determined_imports);
let indeterminate_imports = mem::take(&mut self.indeterminate_imports); let indeterminate_imports = mem::take(&mut self.indeterminate_imports);
let mut glob_error = false;
for (is_indeterminate, import) in determined_imports for (is_indeterminate, import) in determined_imports
.iter() .iter()
.map(|i| (false, i)) .map(|i| (false, i))
@ -548,6 +549,8 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
self.import_dummy_binding(*import, is_indeterminate); self.import_dummy_binding(*import, is_indeterminate);
if let Some(err) = unresolved_import_error { if let Some(err) = unresolved_import_error {
glob_error |= import.is_glob();
if let ImportKind::Single { source, ref source_bindings, .. } = import.kind { if let ImportKind::Single { source, ref source_bindings, .. } = import.kind {
if source.name == kw::SelfLower { if source.name == kw::SelfLower {
// Silence `unresolved import` error if E0429 is already emitted // Silence `unresolved import` error if E0429 is already emitted
@ -563,7 +566,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
{ {
// In the case of a new import line, throw a diagnostic message // In the case of a new import line, throw a diagnostic message
// for the previous line. // for the previous line.
self.throw_unresolved_import_error(errors); self.throw_unresolved_import_error(errors, glob_error);
errors = vec![]; errors = vec![];
} }
if seen_spans.insert(err.span) { if seen_spans.insert(err.span) {
@ -574,7 +577,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
} }
if !errors.is_empty() { if !errors.is_empty() {
self.throw_unresolved_import_error(errors); self.throw_unresolved_import_error(errors, glob_error);
return; return;
} }
@ -600,9 +603,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
} }
} }
if !errors.is_empty() { self.throw_unresolved_import_error(errors, glob_error);
self.throw_unresolved_import_error(errors);
}
} }
pub(crate) fn check_hidden_glob_reexports( pub(crate) fn check_hidden_glob_reexports(
@ -672,7 +673,11 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
} }
} }
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() { if errors.is_empty() {
return; return;
} }
@ -751,7 +756,10 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
} }
} }
diag.emit(); let guar = diag.emit();
if glob_error {
self.glob_error = Some(guar);
}
} }
/// Attempts to resolve the given import, returning: /// Attempts to resolve the given import, returning:

View file

@ -4033,9 +4033,12 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> {
} }
#[inline] #[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 { fn should_report_errs(&self) -> bool {
!(self.r.tcx.sess.opts.actually_rustdoc && self.in_func_body) !(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. // Resolve in alternative namespaces if resolution in the primary namespace fails.

View file

@ -32,7 +32,7 @@ use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexMap, FxIndexSet};
use rustc_data_structures::intern::Interned; use rustc_data_structures::intern::Interned;
use rustc_data_structures::steal::Steal; use rustc_data_structures::steal::Steal;
use rustc_data_structures::sync::{FreezeReadGuard, Lrc}; 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_expand::base::{DeriveResolution, SyntaxExtension, SyntaxExtensionKind};
use rustc_feature::BUILTIN_ATTRIBUTES; use rustc_feature::BUILTIN_ATTRIBUTES;
use rustc_hir::def::Namespace::{self, *}; use rustc_hir::def::Namespace::{self, *};
@ -1048,6 +1048,7 @@ pub struct Resolver<'a, 'tcx> {
/// Maps glob imports to the names of items actually imported. /// Maps glob imports to the names of items actually imported.
glob_map: FxHashMap<LocalDefId, FxHashSet<Symbol>>, glob_map: FxHashMap<LocalDefId, FxHashSet<Symbol>>,
glob_error: Option<ErrorGuaranteed>,
visibilities_for_hashing: Vec<(LocalDefId, ty::Visibility)>, visibilities_for_hashing: Vec<(LocalDefId, ty::Visibility)>,
used_imports: FxHashSet<NodeId>, used_imports: FxHashSet<NodeId>,
maybe_unused_trait_imports: FxIndexSet<LocalDefId>, maybe_unused_trait_imports: FxIndexSet<LocalDefId>,
@ -1417,6 +1418,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
ast_transform_scopes: FxHashMap::default(), ast_transform_scopes: FxHashMap::default(),
glob_map: Default::default(), glob_map: Default::default(),
glob_error: None,
visibilities_for_hashing: Default::default(), visibilities_for_hashing: Default::default(),
used_imports: FxHashSet::default(), used_imports: FxHashSet::default(),
maybe_unused_trait_imports: Default::default(), maybe_unused_trait_imports: Default::default(),

View 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
}

View 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`.

View 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();
}

View 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`.

View 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();
}

View 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`.

View file

@ -6,5 +6,5 @@ mod foo {
} }
fn main() { fn main() {
foo::f(); //~ ERROR cannot find function `f` in module `foo` foo::f(); // cannot find function `f` in module `foo`, but silenced
} }

View file

@ -4,13 +4,6 @@ error[E0432]: unresolved import `self::*`
LL | pub use self::*; LL | pub use self::*;
| ^^^^^^^ cannot glob-import a module into itself | ^^^^^^^ cannot glob-import a module into itself
error[E0425]: cannot find function `f` in module `foo` error: aborting due to 1 previous error
--> $DIR/issue-31212.rs:9:10
|
LL | foo::f();
| ^ not found in `foo`
error: aborting due to 2 previous errors For more information about this error, try `rustc --explain E0432`.
Some errors have detailed explanations: E0425, E0432.
For more information about an error, try `rustc --explain E0425`.