[ty] Consolidate submodule resolving code between types.rs and ide_support.rs (#19256)

This commit is contained in:
Alex Waygood 2025-07-10 14:10:09 +01:00 committed by GitHub
parent 492f5bf2aa
commit 59114d0301
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
2 changed files with 29 additions and 33 deletions

View file

@ -1,5 +1,5 @@
use infer::nearest_enclosing_class; use infer::nearest_enclosing_class;
use itertools::Either; use itertools::{Either, Itertools};
use ruff_db::parsed::parsed_module; use ruff_db::parsed::parsed_module;
use std::slice::Iter; use std::slice::Iter;
@ -7535,6 +7535,23 @@ impl<'db> ModuleLiteralType<'db> {
self._importing_file(db) self._importing_file(db)
} }
fn available_submodule_attributes(&self, db: &'db dyn Db) -> impl Iterator<Item = Name> {
self.importing_file(db)
.into_iter()
.flat_map(|file| imported_modules(db, file))
.filter_map(|submodule_name| submodule_name.relative_to(self.module(db).name()))
.filter_map(|relative_submodule| relative_submodule.components().next().map(Name::from))
}
fn resolve_submodule(self, db: &'db dyn Db, name: &str) -> Option<Type<'db>> {
let importing_file = self.importing_file(db)?;
let relative_submodule_name = ModuleName::new(name)?;
let mut absolute_submodule_name = self.module(db).name().clone();
absolute_submodule_name.extend(&relative_submodule_name);
let submodule = resolve_module(db, &absolute_submodule_name)?;
Some(Type::module_literal(db, importing_file, &submodule))
}
fn static_member(self, db: &'db dyn Db, name: &str) -> PlaceAndQualifiers<'db> { fn static_member(self, db: &'db dyn Db, name: &str) -> PlaceAndQualifiers<'db> {
// `__dict__` is a very special member that is never overridden by module globals; // `__dict__` is a very special member that is never overridden by module globals;
// we should always look it up directly as an attribute on `types.ModuleType`, // we should always look it up directly as an attribute on `types.ModuleType`,
@ -7554,17 +7571,9 @@ impl<'db> ModuleLiteralType<'db> {
// the parent module's `__init__.py` file being evaluated. That said, we have // the parent module's `__init__.py` file being evaluated. That said, we have
// chosen to always have the submodule take priority. (This matches pyright's // chosen to always have the submodule take priority. (This matches pyright's
// current behavior, but is the opposite of mypy's current behavior.) // current behavior, but is the opposite of mypy's current behavior.)
if let Some(importing_file) = self.importing_file(db) { if self.available_submodule_attributes(db).contains(name) {
if let Some(submodule_name) = ModuleName::new(name) { if let Some(submodule) = self.resolve_submodule(db, name) {
let imported_submodules = imported_modules(db, importing_file); return Place::bound(submodule).into();
let mut full_submodule_name = self.module(db).name().clone();
full_submodule_name.extend(&submodule_name);
if imported_submodules.contains(&full_submodule_name) {
if let Some(submodule) = resolve_module(db, &full_submodule_name) {
return Place::bound(Type::module_literal(db, importing_file, &submodule))
.into();
}
}
} }
} }

View file

@ -1,11 +1,10 @@
use std::cmp::Ordering; use std::cmp::Ordering;
use crate::module_resolver::resolve_module;
use crate::place::{Place, imported_symbol, place_from_bindings, place_from_declarations}; use crate::place::{Place, imported_symbol, place_from_bindings, place_from_declarations};
use crate::semantic_index::definition::DefinitionKind; use crate::semantic_index::definition::DefinitionKind;
use crate::semantic_index::place::ScopeId; use crate::semantic_index::place::ScopeId;
use crate::semantic_index::{ use crate::semantic_index::{
attribute_scopes, global_scope, imported_modules, place_table, semantic_index, use_def_map, attribute_scopes, global_scope, place_table, semantic_index, use_def_map,
}; };
use crate::types::{ClassBase, ClassLiteral, KnownClass, KnownInstanceType, Type}; use crate::types::{ClassBase, ClassLiteral, KnownClass, KnownInstanceType, Type};
use crate::{Db, NameKind}; use crate::{Db, NameKind};
@ -197,26 +196,14 @@ impl<'db> AllMembers<'db> {
}); });
} }
let module_name = module.name(); self.members
self.members.extend( .extend(literal.available_submodule_attributes(db).filter_map(
literal |submodule_name| {
.importing_file(db) let ty = literal.resolve_submodule(db, &submodule_name)?;
.into_iter() let name = submodule_name.clone();
.flat_map(|file| imported_modules(db, file))
.filter_map(|submodule_name| {
let module = resolve_module(db, submodule_name)?;
let ty = Type::module_literal(db, file, &module);
Some((submodule_name, ty))
})
.filter_map(|(submodule_name, ty)| {
let relative = submodule_name.relative_to(module_name)?;
Some((relative, ty))
})
.filter_map(|(relative_submodule_name, ty)| {
let name = Name::from(relative_submodule_name.components().next()?);
Some(Member { name, ty }) Some(Member { name, ty })
}), },
); ));
} }
} }
} }