about summary refs log tree commit diff
diff options
context:
space:
mode:
author许杰友 Jieyou Xu (Joe) <39484203+jieyouxu@users.noreply.github.com>2024-05-29 03:25:08 +0100
committerGitHub <noreply@github.com>2024-05-29 03:25:08 +0100
commitbc1a069ec54a71d57604dbcf4b5bf204cc068033 (patch)
treea6074930f444990f8e921a93873cd5cc8d6a6a2f
parent3cc59aeaaeddb6fa6c2723e4664f46a395d25e30 (diff)
parent37c54db477b06ade1cb69b4fd1af46184b650a43 (diff)
downloadrust-bc1a069ec54a71d57604dbcf4b5bf204cc068033.tar.gz
rust-bc1a069ec54a71d57604dbcf4b5bf204cc068033.zip
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.
-rw-r--r--compiler/rustc_resolve/src/imports.rs22
-rw-r--r--compiler/rustc_resolve/src/late.rs5
-rw-r--r--compiler/rustc_resolve/src/lib.rs4
-rw-r--r--tests/ui/imports/import-from-missing-star-2.rs12
-rw-r--r--tests/ui/imports/import-from-missing-star-2.stderr11
-rw-r--r--tests/ui/imports/import-from-missing-star-3.rs43
-rw-r--r--tests/ui/imports/import-from-missing-star-3.stderr19
-rw-r--r--tests/ui/imports/import-from-missing-star.rs10
-rw-r--r--tests/ui/imports/import-from-missing-star.stderr11
-rw-r--r--tests/ui/imports/issue-31212.rs2
-rw-r--r--tests/ui/imports/issue-31212.stderr11
11 files changed, 131 insertions, 19 deletions
diff --git a/compiler/rustc_resolve/src/imports.rs b/compiler/rustc_resolve/src/imports.rs
index 51b87c5a9b0..6bbde26db34 100644
--- a/compiler/rustc_resolve/src/imports.rs
+++ b/compiler/rustc_resolve/src/imports.rs
@@ -537,6 +537,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))
@@ -548,6 +549,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
@@ -563,7 +566,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) {
@@ -574,7 +577,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;
         }
 
@@ -600,9 +603,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(
@@ -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() {
             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:
diff --git a/compiler/rustc_resolve/src/late.rs b/compiler/rustc_resolve/src/late.rs
index 08326d1ef57..0655484ad85 100644
--- a/compiler/rustc_resolve/src/late.rs
+++ b/compiler/rustc_resolve/src/late.rs
@@ -4033,9 +4033,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.
diff --git a/compiler/rustc_resolve/src/lib.rs b/compiler/rustc_resolve/src/lib.rs
index f4c5ad8f672..9557b0f5ebc 100644
--- a/compiler/rustc_resolve/src/lib.rs
+++ b/compiler/rustc_resolve/src/lib.rs
@@ -32,7 +32,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, *};
@@ -1048,6 +1048,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>,
@@ -1417,6 +1418,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(),
diff --git a/tests/ui/imports/import-from-missing-star-2.rs b/tests/ui/imports/import-from-missing-star-2.rs
new file mode 100644
index 00000000000..cb341b0b0ca
--- /dev/null
+++ b/tests/ui/imports/import-from-missing-star-2.rs
@@ -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
+}
diff --git a/tests/ui/imports/import-from-missing-star-2.stderr b/tests/ui/imports/import-from-missing-star-2.stderr
new file mode 100644
index 00000000000..ea3876248c9
--- /dev/null
+++ b/tests/ui/imports/import-from-missing-star-2.stderr
@@ -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`.
diff --git a/tests/ui/imports/import-from-missing-star-3.rs b/tests/ui/imports/import-from-missing-star-3.rs
new file mode 100644
index 00000000000..bec51fd47b3
--- /dev/null
+++ b/tests/ui/imports/import-from-missing-star-3.rs
@@ -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();
+}
diff --git a/tests/ui/imports/import-from-missing-star-3.stderr b/tests/ui/imports/import-from-missing-star-3.stderr
new file mode 100644
index 00000000000..1fe5d4f19a9
--- /dev/null
+++ b/tests/ui/imports/import-from-missing-star-3.stderr
@@ -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`.
diff --git a/tests/ui/imports/import-from-missing-star.rs b/tests/ui/imports/import-from-missing-star.rs
new file mode 100644
index 00000000000..cb21e16ba67
--- /dev/null
+++ b/tests/ui/imports/import-from-missing-star.rs
@@ -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();
+}
diff --git a/tests/ui/imports/import-from-missing-star.stderr b/tests/ui/imports/import-from-missing-star.stderr
new file mode 100644
index 00000000000..f8e29507804
--- /dev/null
+++ b/tests/ui/imports/import-from-missing-star.stderr
@@ -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`.
diff --git a/tests/ui/imports/issue-31212.rs b/tests/ui/imports/issue-31212.rs
index 556f0d18f9f..fe69c5af270 100644
--- a/tests/ui/imports/issue-31212.rs
+++ b/tests/ui/imports/issue-31212.rs
@@ -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
 }
diff --git a/tests/ui/imports/issue-31212.stderr b/tests/ui/imports/issue-31212.stderr
index 0bb56b361cb..5bba791fd02 100644
--- a/tests/ui/imports/issue-31212.stderr
+++ b/tests/ui/imports/issue-31212.stderr
@@ -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 2 previous errors
+error: aborting due to 1 previous error
 
-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`.