From 3583423536a3140680613927db10293dc4cd2f02 Mon Sep 17 00:00:00 2001 From: bendn Date: Fri, 20 Jun 2025 00:01:06 +0700 Subject: [PATCH] suggest declaring modules when file found but module not defined --- compiler/rustc_resolve/src/diagnostics.rs | 51 +++++++++++++++++++ .../mod_file_disambig.stderr | 5 +- 2 files changed, 55 insertions(+), 1 deletion(-) diff --git a/compiler/rustc_resolve/src/diagnostics.rs b/compiler/rustc_resolve/src/diagnostics.rs index 9149974a6177..101d6b0be26d 100644 --- a/compiler/rustc_resolve/src/diagnostics.rs +++ b/compiler/rustc_resolve/src/diagnostics.rs @@ -2423,6 +2423,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![], @@ -2444,6 +2446,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 { + 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( diff --git a/tests/ui/modules_and_files_visibility/mod_file_disambig.stderr b/tests/ui/modules_and_files_visibility/mod_file_disambig.stderr index f82d613015f5..e71a6de2fb9b 100644 --- a/tests/ui/modules_and_files_visibility/mod_file_disambig.stderr +++ b/tests/ui/modules_and_files_visibility/mod_file_disambig.stderr @@ -12,7 +12,10 @@ error[E0433]: failed to resolve: use of unresolved module or unlinked crate `mod LL | assert_eq!(mod_file_aux::bar(), 10); | ^^^^^^^^^^^^ use of unresolved module or unlinked crate `mod_file_aux` | - = help: you might be missing a crate named `mod_file_aux` +help: to make use of source file $DIR/mod_file_aux.rs, use `mod mod_file_aux` in this file to declare the module + | +LL + mod mod_file_aux; + | error: aborting due to 2 previous errors