From d1986726ada2e80245f1f0742a55367adc6772c8 Mon Sep 17 00:00:00 2001 From: Alex Waygood Date: Fri, 21 Nov 2025 12:31:35 +0000 Subject: [PATCH 1/2] [ty] Improve debug messages when imports fail --- crates/ty_python_semantic/src/types/infer/builder.rs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/crates/ty_python_semantic/src/types/infer/builder.rs b/crates/ty_python_semantic/src/types/infer/builder.rs index cd93f59526df4..d9358ac5be3db 100644 --- a/crates/ty_python_semantic/src/types/infer/builder.rs +++ b/crates/ty_python_semantic/src/types/infer/builder.rs @@ -6026,7 +6026,8 @@ impl<'db, 'ast> TypeInferenceBuilder<'db, 'ast> { } Err(ModuleNameResolutionError::TooManyDots) => { tracing::debug!( - "Relative module resolution `{}` failed: too many leading dots", + "Relative module resolution `{}` failed: too many leading dots \ + (try adjusting configured search paths?)", format_import_from_module(*level, module), ); self.report_unresolved_import( @@ -6039,7 +6040,8 @@ impl<'db, 'ast> TypeInferenceBuilder<'db, 'ast> { } Err(ModuleNameResolutionError::UnknownCurrentModule) => { tracing::debug!( - "Relative module resolution `{}` failed; could not resolve file `{}` to a module", + "Relative module resolution `{}` failed: could not resolve file `{}` to a module \ + (try adjusting configured search paths?)", format_import_from_module(*level, module), self.file().path(self.db()) ); From d97b99bd0dbbad2e2cff60b4a876bddc88f6fa35 Mon Sep 17 00:00:00 2001 From: Alex Waygood Date: Fri, 21 Nov 2025 13:32:36 +0000 Subject: [PATCH 2/2] iteratively try reducing the number of leading dots for relative imports --- ...th_to\342\200\246_(4b8ba6ee48180cdd).snap" | 2 ++ .../src/types/infer/builder.rs | 32 ++++++++++++++++--- 2 files changed, 29 insertions(+), 5 deletions(-) diff --git "a/crates/ty_python_semantic/resources/mdtest/snapshots/unresolved_import.md_-_Unresolved_import_di\342\200\246_-_Using_`from`_with_to\342\200\246_(4b8ba6ee48180cdd).snap" "b/crates/ty_python_semantic/resources/mdtest/snapshots/unresolved_import.md_-_Unresolved_import_di\342\200\246_-_Using_`from`_with_to\342\200\246_(4b8ba6ee48180cdd).snap" index 54a26313aeb6a..2df94a06f57a8 100644 --- "a/crates/ty_python_semantic/resources/mdtest/snapshots/unresolved_import.md_-_Unresolved_import_di\342\200\246_-_Using_`from`_with_to\342\200\246_(4b8ba6ee48180cdd).snap" +++ "b/crates/ty_python_semantic/resources/mdtest/snapshots/unresolved_import.md_-_Unresolved_import_di\342\200\246_-_Using_`from`_with_to\342\200\246_(4b8ba6ee48180cdd).snap" @@ -40,6 +40,8 @@ error[unresolved-import]: Cannot resolve imported module `....foo` 2 | 3 | stat = add(10, 15) | +help: The module can be resolved if the number of leading dots is reduced +help: Did you mean `...foo`? info: Searched in the following paths during module resolution: info: 1. /src (first-party code) info: 2. vendored://stdlib (stdlib typeshed stubs vendored by ty) diff --git a/crates/ty_python_semantic/src/types/infer/builder.rs b/crates/ty_python_semantic/src/types/infer/builder.rs index d9358ac5be3db..0e8a218f2ad14 100644 --- a/crates/ty_python_semantic/src/types/infer/builder.rs +++ b/crates/ty_python_semantic/src/types/infer/builder.rs @@ -5799,9 +5799,8 @@ impl<'db, 'ast> TypeInferenceBuilder<'db, 'ast> { return; }; let mut diagnostic = builder.into_diagnostic(format_args!( - "Cannot resolve imported module `{}{}`", - ".".repeat(level as usize), - module.unwrap_or_default() + "Cannot resolve imported module `{}`", + format_import_from_module(level, module) )); if level == 0 { @@ -5832,6 +5831,30 @@ impl<'db, 'ast> TypeInferenceBuilder<'db, 'ast> { } } } + } else { + if let Some(better_level) = (0..level).rev().find(|reduced_level| { + let Ok(module_name) = ModuleName::from_identifier_parts( + self.db(), + self.file(), + module, + *reduced_level, + ) else { + return false; + }; + resolve_module(self.db(), &module_name).is_some() + }) { + diagnostic + .help("The module can be resolved if the number of leading dots is reduced"); + diagnostic.help(format_args!( + "Did you mean `{}`?", + format_import_from_module(better_level, module) + )); + diagnostic.set_concise_message(format_args!( + "Cannot resolve imported module `{}` - did you mean `{}`?", + format_import_from_module(level, module), + format_import_from_module(better_level, module) + )); + } } // Add search paths information to the diagnostic @@ -6026,8 +6049,7 @@ impl<'db, 'ast> TypeInferenceBuilder<'db, 'ast> { } Err(ModuleNameResolutionError::TooManyDots) => { tracing::debug!( - "Relative module resolution `{}` failed: too many leading dots \ - (try adjusting configured search paths?)", + "Relative module resolution `{}` failed: too many leading dots", format_import_from_module(*level, module), ); self.report_unresolved_import(