Skip to content

Commit 37c54db

Browse files
committed
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.
1 parent 1a73979 commit 37c54db

11 files changed

+131
-19
lines changed

compiler/rustc_resolve/src/imports.rs

+15-7
Original file line numberDiff line numberDiff line change
@@ -536,6 +536,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
536536
let determined_imports = mem::take(&mut self.determined_imports);
537537
let indeterminate_imports = mem::take(&mut self.indeterminate_imports);
538538

539+
let mut glob_error = false;
539540
for (is_indeterminate, import) in determined_imports
540541
.iter()
541542
.map(|i| (false, i))
@@ -547,6 +548,8 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
547548
self.import_dummy_binding(*import, is_indeterminate);
548549

549550
if let Some(err) = unresolved_import_error {
551+
glob_error |= import.is_glob();
552+
550553
if let ImportKind::Single { source, ref source_bindings, .. } = import.kind {
551554
if source.name == kw::SelfLower {
552555
// Silence `unresolved import` error if E0429 is already emitted
@@ -562,7 +565,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
562565
{
563566
// In the case of a new import line, throw a diagnostic message
564567
// for the previous line.
565-
self.throw_unresolved_import_error(errors);
568+
self.throw_unresolved_import_error(errors, glob_error);
566569
errors = vec![];
567570
}
568571
if seen_spans.insert(err.span) {
@@ -573,7 +576,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
573576
}
574577

575578
if !errors.is_empty() {
576-
self.throw_unresolved_import_error(errors);
579+
self.throw_unresolved_import_error(errors, glob_error);
577580
return;
578581
}
579582

@@ -599,9 +602,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
599602
}
600603
}
601604

602-
if !errors.is_empty() {
603-
self.throw_unresolved_import_error(errors);
604-
}
605+
self.throw_unresolved_import_error(errors, glob_error);
605606
}
606607

607608
pub(crate) fn check_hidden_glob_reexports(
@@ -673,7 +674,11 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
673674
}
674675
}
675676

676-
fn throw_unresolved_import_error(&mut self, errors: Vec<(Import<'_>, UnresolvedImportError)>) {
677+
fn throw_unresolved_import_error(
678+
&mut self,
679+
errors: Vec<(Import<'_>, UnresolvedImportError)>,
680+
glob_error: bool,
681+
) {
677682
if errors.is_empty() {
678683
return;
679684
}
@@ -752,7 +757,10 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
752757
}
753758
}
754759

755-
diag.emit();
760+
let guar = diag.emit();
761+
if glob_error {
762+
self.glob_error = Some(guar);
763+
}
756764
}
757765

758766
/// Attempts to resolve the given import, returning:

compiler/rustc_resolve/src/late.rs

+4-1
Original file line numberDiff line numberDiff line change
@@ -4039,9 +4039,12 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> {
40394039
}
40404040

40414041
#[inline]
4042-
/// If we're actually rustdoc then avoid giving a name resolution error for `cfg()` items.
4042+
/// If we're actually rustdoc then avoid giving a name resolution error for `cfg()` items or
4043+
// an invalid `use foo::*;` was found, which can cause unbounded ammounts of "item not found"
4044+
// errors. We silence them all.
40434045
fn should_report_errs(&self) -> bool {
40444046
!(self.r.tcx.sess.opts.actually_rustdoc && self.in_func_body)
4047+
&& !self.r.glob_error.is_some()
40454048
}
40464049

40474050
// Resolve in alternative namespaces if resolution in the primary namespace fails.

compiler/rustc_resolve/src/lib.rs

+3-1
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexMap, FxIndexSet};
3737
use rustc_data_structures::intern::Interned;
3838
use rustc_data_structures::steal::Steal;
3939
use rustc_data_structures::sync::{FreezeReadGuard, Lrc};
40-
use rustc_errors::{Applicability, Diag, ErrCode};
40+
use rustc_errors::{Applicability, Diag, ErrCode, ErrorGuaranteed};
4141
use rustc_expand::base::{DeriveResolution, SyntaxExtension, SyntaxExtensionKind};
4242
use rustc_feature::BUILTIN_ATTRIBUTES;
4343
use rustc_hir::def::Namespace::{self, *};
@@ -1052,6 +1052,7 @@ pub struct Resolver<'a, 'tcx> {
10521052

10531053
/// Maps glob imports to the names of items actually imported.
10541054
glob_map: FxHashMap<LocalDefId, FxHashSet<Symbol>>,
1055+
glob_error: Option<ErrorGuaranteed>,
10551056
visibilities_for_hashing: Vec<(LocalDefId, ty::Visibility)>,
10561057
used_imports: FxHashSet<NodeId>,
10571058
maybe_unused_trait_imports: FxIndexSet<LocalDefId>,
@@ -1421,6 +1422,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
14211422
ast_transform_scopes: FxHashMap::default(),
14221423

14231424
glob_map: Default::default(),
1425+
glob_error: None,
14241426
visibilities_for_hashing: Default::default(),
14251427
used_imports: FxHashSet::default(),
14261428
maybe_unused_trait_imports: Default::default(),
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
mod foo {
2+
use spam::*; //~ ERROR unresolved import `spam` [E0432]
3+
}
4+
5+
fn main() {
6+
// Expect this to pass because the compiler knows there's a failed `*` import in `foo` that
7+
// might have caused it.
8+
foo::bar();
9+
// FIXME: these two should *fail* because they can't be fixed by fixing the glob import in `foo`
10+
ham(); // should error but doesn't
11+
eggs(); // should error but doesn't
12+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
error[E0432]: unresolved import `spam`
2+
--> $DIR/import-from-missing-star-2.rs:2:9
3+
|
4+
LL | use spam::*;
5+
| ^^^^ maybe a missing crate `spam`?
6+
|
7+
= help: consider adding `extern crate spam` to use the `spam` crate
8+
9+
error: aborting due to 1 previous error
10+
11+
For more information about this error, try `rustc --explain E0432`.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
mod foo {
2+
use spam::*; //~ ERROR unresolved import `spam` [E0432]
3+
4+
fn x() {
5+
// Expect these to pass because the compiler knows there's a failed `*` import that might
6+
// fix it.
7+
eggs();
8+
foo::bar();
9+
}
10+
}
11+
12+
mod bar {
13+
fn z() {}
14+
fn x() {
15+
// Expect these to pass because the compiler knows there's a failed `*` import that might
16+
// fix it.
17+
foo::bar();
18+
z();
19+
// FIXME: should error but doesn't because as soon as there's a single glob import error, we
20+
// silence all resolve errors.
21+
eggs();
22+
}
23+
}
24+
25+
mod baz {
26+
fn x() {
27+
use spam::*; //~ ERROR unresolved import `spam` [E0432]
28+
fn qux() {}
29+
qux();
30+
// Expect this to pass because the compiler knows there's a local failed `*` import that
31+
// might have caused it.
32+
eggs();
33+
// Expect this to pass because the compiler knows there's a failed `*` import in `foo` that
34+
// might have caused it.
35+
foo::bar();
36+
}
37+
}
38+
39+
fn main() {
40+
// FIXME: should error but doesn't because as soon as there's a single glob import error, we
41+
// silence all resolve errors.
42+
ham();
43+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
error[E0432]: unresolved import `spam`
2+
--> $DIR/import-from-missing-star-3.rs:2:9
3+
|
4+
LL | use spam::*;
5+
| ^^^^ maybe a missing crate `spam`?
6+
|
7+
= help: consider adding `extern crate spam` to use the `spam` crate
8+
9+
error[E0432]: unresolved import `spam`
10+
--> $DIR/import-from-missing-star-3.rs:27:13
11+
|
12+
LL | use spam::*;
13+
| ^^^^ maybe a missing crate `spam`?
14+
|
15+
= help: consider adding `extern crate spam` to use the `spam` crate
16+
17+
error: aborting due to 2 previous errors
18+
19+
For more information about this error, try `rustc --explain E0432`.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
use spam::*; //~ ERROR unresolved import `spam` [E0432]
2+
3+
fn main() {
4+
// Expect these to pass because the compiler knows there's a failed `*` import that might have
5+
// caused it.
6+
ham();
7+
eggs();
8+
// Even this case, as we might have expected `spam::foo` to exist.
9+
foo::bar();
10+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
error[E0432]: unresolved import `spam`
2+
--> $DIR/import-from-missing-star.rs:1:5
3+
|
4+
LL | use spam::*;
5+
| ^^^^ maybe a missing crate `spam`?
6+
|
7+
= help: consider adding `extern crate spam` to use the `spam` crate
8+
9+
error: aborting due to 1 previous error
10+
11+
For more information about this error, try `rustc --explain E0432`.

tests/ui/imports/issue-31212.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -6,5 +6,5 @@ mod foo {
66
}
77

88
fn main() {
9-
foo::f(); //~ ERROR cannot find function `f` in module `foo`
9+
foo::f(); // cannot find function `f` in module `foo`, but silenced
1010
}

tests/ui/imports/issue-31212.stderr

+2-9
Original file line numberDiff line numberDiff line change
@@ -4,13 +4,6 @@ error[E0432]: unresolved import `self::*`
44
LL | pub use self::*;
55
| ^^^^^^^ cannot glob-import a module into itself
66

7-
error[E0425]: cannot find function `f` in module `foo`
8-
--> $DIR/issue-31212.rs:9:10
9-
|
10-
LL | foo::f();
11-
| ^ not found in `foo`
12-
13-
error: aborting due to 2 previous errors
7+
error: aborting due to 1 previous error
148

15-
Some errors have detailed explanations: E0425, E0432.
16-
For more information about an error, try `rustc --explain E0425`.
9+
For more information about this error, try `rustc --explain E0432`.

0 commit comments

Comments
 (0)