1
Fork 0

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:
Esteban Küber 2024-05-21 19:12:05 +00:00
parent 1a73979886
commit 37c54db477
11 changed files with 131 additions and 19 deletions

View file

@ -536,6 +536,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
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 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
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 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
{
// 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 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
}
if !errors.is_empty() {
self.throw_unresolved_import_error(errors);
self.throw_unresolved_import_error(errors, glob_error);
return;
}
@ -599,9 +602,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
}
}
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 @@ 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() {
return;
}
@ -752,7 +757,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:

View file

@ -4039,9 +4039,12 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> {
}
#[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.

View file

@ -37,7 +37,7 @@ use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexMap, FxIndexSet};
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 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
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(),