about summary refs log tree commit diff
path: root/compiler/rustc_resolve/src
diff options
context:
space:
mode:
authorMatthias Krüger <476013+matthiaskrgr@users.noreply.github.com>2025-06-27 22:13:02 +0200
committerGitHub <noreply@github.com>2025-06-27 22:13:02 +0200
commit190a1a7f747408d1936a81065665c687013f6141 (patch)
tree8323759b9e16757fae6d36e92f0d54db355e121c /compiler/rustc_resolve/src
parent9d15167921ead28946d8d603470dbe9a57e74eff (diff)
parent57cb419cc5c57afb2456d9e4af0e722a5b9324b9 (diff)
downloadrust-190a1a7f747408d1936a81065665c687013f6141.tar.gz
rust-190a1a7f747408d1936a81065665c687013f6141.zip
Rollup merge of #142730 - bend-n:suggest_declaring_modules_when_file_found_but_module_not_defined, r=petrochenkov
suggest declaring modules when file found but module not defined

suggests declaring modules when a module is found but not defined, i.e
```
├── main.rs: `use thing::thang;`
└── thing.rs: `struct thang`
```
or
```
├── main.rs: `use thing::thang;`
└── thing
    └── mod.rs: `struct thang`
```
which currently is just
```rust
error[E0432]: unresolved import `yeah`
 --> src/main.rs:1:1
  |
1 | use thing::thang;
  |     ^^^^^ use of unresolved module or unlinked crate `thing`
  |
```
but now would have this nice help:
```text
= help: you may have forgotten to declare the module `thing`. use `mod thing` in this file to declare this module.
```
Diffstat (limited to 'compiler/rustc_resolve/src')
-rw-r--r--compiler/rustc_resolve/src/diagnostics.rs51
1 files changed, 51 insertions, 0 deletions
diff --git a/compiler/rustc_resolve/src/diagnostics.rs b/compiler/rustc_resolve/src/diagnostics.rs
index 8bca350c8ba..18078b760c3 100644
--- a/compiler/rustc_resolve/src/diagnostics.rs
+++ b/compiler/rustc_resolve/src/diagnostics.rs
@@ -2421,6 +2421,8 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
             } else {
                 let suggestion = if suggestion.is_some() {
                     suggestion
+                } else if let Some(m) = self.undeclared_module_exists(ident) {
+                    self.undeclared_module_suggest_declare(ident, m)
                 } else if was_invoked_from_cargo() {
                     Some((
                         vec![],
@@ -2442,6 +2444,55 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
         }
     }
 
+    fn undeclared_module_suggest_declare(
+        &mut self,
+        ident: Ident,
+        path: std::path::PathBuf,
+    ) -> Option<(Vec<(Span, String)>, String, Applicability)> {
+        Some((
+            vec![(self.current_crate_outer_attr_insert_span, format!("mod {ident};\n"))],
+            format!(
+                "to make use of source file {}, use `mod {ident}` \
+                 in this file to declare the module",
+                path.display()
+            ),
+            Applicability::MaybeIncorrect,
+        ))
+    }
+
+    fn undeclared_module_exists(&mut self, ident: Ident) -> Option<std::path::PathBuf> {
+        let map = self.tcx.sess.source_map();
+
+        let src = map.span_to_filename(ident.span).into_local_path()?;
+        let i = ident.as_str();
+        // FIXME: add case where non parent using undeclared module (hard?)
+        let dir = src.parent()?;
+        let src = src.file_stem()?.to_str()?;
+        for file in [
+            // …/x.rs
+            dir.join(i).with_extension("rs"),
+            // …/x/mod.rs
+            dir.join(i).join("mod.rs"),
+        ] {
+            if file.exists() {
+                return Some(file);
+            }
+        }
+        if !matches!(src, "main" | "lib" | "mod") {
+            for file in [
+                // …/x/y.rs
+                dir.join(src).join(i).with_extension("rs"),
+                // …/x/y/mod.rs
+                dir.join(src).join(i).join("mod.rs"),
+            ] {
+                if file.exists() {
+                    return Some(file);
+                }
+            }
+        }
+        None
+    }
+
     /// Adds suggestions for a path that cannot be resolved.
     #[instrument(level = "debug", skip(self, parent_scope))]
     pub(crate) fn make_path_suggestion(