From 6d4949bae16b1d69f082e272aecdd9be267559e8 Mon Sep 17 00:00:00 2001 From: Alex Waygood Date: Sat, 22 Nov 2025 15:32:06 +0000 Subject: [PATCH] [ty] Add `from` imports to `imported_modules` *if* the module being imported is not relative to the current module --- crates/ty_python_semantic/src/module_name.rs | 2 +- .../src/semantic_index/builder.rs | 61 +++++++++++-------- 2 files changed, 38 insertions(+), 25 deletions(-) diff --git a/crates/ty_python_semantic/src/module_name.rs b/crates/ty_python_semantic/src/module_name.rs index ff25d1fdbd..2089f82843 100644 --- a/crates/ty_python_semantic/src/module_name.rs +++ b/crates/ty_python_semantic/src/module_name.rs @@ -318,7 +318,7 @@ impl ModuleName { db: &dyn Db, importing_file: File, ) -> Result { - Self::from_identifier_parts(db, importing_file, None, 1) + relative_module_name(db, importing_file, None, NonZeroU32::new(1).unwrap()) } } diff --git a/crates/ty_python_semantic/src/semantic_index/builder.rs b/crates/ty_python_semantic/src/semantic_index/builder.rs index 3591bd66d2..6f7a739f78 100644 --- a/crates/ty_python_semantic/src/semantic_index/builder.rs +++ b/crates/ty_python_semantic/src/semantic_index/builder.rs @@ -1521,33 +1521,46 @@ impl<'ast> Visitor<'ast> for SemanticIndexBuilder<'_, 'ast> { // that `x` can be freely overwritten, and that we don't assume that an import // in one function is visible in another function. let mut is_self_import = false; - if self.file.is_package(self.db) - && let Ok(module_name) = ModuleName::from_identifier_parts( - self.db, - self.file, - node.module.as_deref(), - node.level, - ) - && let Ok(thispackage) = ModuleName::package_for_file(self.db, self.file) - { + let is_package = self.file.is_package(self.db); + let this_package = ModuleName::package_for_file(self.db, self.file); + + if let Ok(module_name) = ModuleName::from_identifier_parts( + self.db, + self.file, + node.module.as_deref(), + node.level, + ) { // Record whether this is equivalent to `from . import ...` - is_self_import = module_name == thispackage; + if is_package && let Ok(thispackage) = this_package.as_ref() { + is_self_import = &module_name == thispackage; + } - if node.module.is_some() - && let Some(relative_submodule) = module_name.relative_to(&thispackage) - && let Some(direct_submodule) = relative_submodule.components().next() - && !self.seen_submodule_imports.contains(direct_submodule) - && self.current_scope().is_global() - { - self.seen_submodule_imports - .insert(direct_submodule.to_owned()); + if self.current_scope().is_global() && node.module.is_some() { + if let Ok(thispackage) = this_package + && let Some(relative_submodule) = module_name.relative_to(&thispackage) + { + if is_package + && let Some(direct_submodule) = + relative_submodule.components().next() + && !self.seen_submodule_imports.contains(direct_submodule) + { + self.seen_submodule_imports + .insert(direct_submodule.to_owned()); - let direct_submodule_name = Name::new(direct_submodule); - let symbol = self.add_symbol(direct_submodule_name); - self.add_definition( - symbol.into(), - ImportFromSubmoduleDefinitionNodeRef { node }, - ); + let direct_submodule_name = Name::new(direct_submodule); + let symbol = self.add_symbol(direct_submodule_name); + self.add_definition( + symbol.into(), + ImportFromSubmoduleDefinitionNodeRef { node }, + ); + } + } else { + self.imported_modules.extend( + module_name + .ancestors() + .zip(std::iter::repeat(ImportKind::ImportFrom)), + ); + } } }