diff --git a/crates/ruff_graph/src/resolver.rs b/crates/ruff_graph/src/resolver.rs index baf43c71c9..70b1b083bc 100644 --- a/crates/ruff_graph/src/resolver.rs +++ b/crates/ruff_graph/src/resolver.rs @@ -20,7 +20,7 @@ impl<'a> Resolver<'a> { match import { CollectedImport::Import(import) => { let module = resolve_module(self.db, &import)?; - Some(module.file()?.path(self.db)) + Some(module.file(self.db)?.path(self.db)) } CollectedImport::ImportFrom(import) => { // Attempt to resolve the member (e.g., given `from foo import bar`, look for `foo.bar`). @@ -32,7 +32,7 @@ impl<'a> Resolver<'a> { resolve_module(self.db, &parent?) })?; - Some(module.file()?.path(self.db)) + Some(module.file(self.db)?.path(self.db)) } } } diff --git a/crates/ruff_python_semantic/src/analyze/visibility.rs b/crates/ruff_python_semantic/src/analyze/visibility.rs index a9173f25c7..8c7389a9c0 100644 --- a/crates/ruff_python_semantic/src/analyze/visibility.rs +++ b/crates/ruff_python_semantic/src/analyze/visibility.rs @@ -163,7 +163,7 @@ fn stem(path: &str) -> &str { } /// Infer the [`Visibility`] of a module from its path. -pub(crate) fn module_visibility(module: &Module) -> Visibility { +pub(crate) fn module_visibility(module: Module) -> Visibility { match &module.source { ModuleSource::Path(path) => { if path.iter().any(|m| is_private_module(m)) { diff --git a/crates/ruff_python_semantic/src/definition.rs b/crates/ruff_python_semantic/src/definition.rs index 245bd10179..7f6c724540 100644 --- a/crates/ruff_python_semantic/src/definition.rs +++ b/crates/ruff_python_semantic/src/definition.rs @@ -223,7 +223,7 @@ impl<'a> Definitions<'a> { // visibility. let visibility = { match &definition { - Definition::Module(module) => module_visibility(module), + Definition::Module(module) => module_visibility(*module), Definition::Member(member) => match member.kind { MemberKind::Class(class) => { let parent = &definitions[member.parent]; diff --git a/crates/ty/tests/file_watching.rs b/crates/ty/tests/file_watching.rs index c59dd8135a..e40722d395 100644 --- a/crates/ty/tests/file_watching.rs +++ b/crates/ty/tests/file_watching.rs @@ -230,6 +230,21 @@ impl TestCase { fn system_file(&self, path: impl AsRef) -> Result { system_path_to_file(self.db(), path.as_ref()) } + + fn module<'c>(&'c self, name: &str) -> Module<'c> { + resolve_module(self.db(), &ModuleName::new(name).unwrap()).expect("module to be present") + } + + fn sorted_submodule_names(&self, parent_module_name: &str) -> Vec { + let mut names = self + .module(parent_module_name) + .all_submodules(self.db()) + .iter() + .map(|name| name.as_str().to_string()) + .collect::>(); + names.sort(); + names + } } trait MatchEvent { @@ -1398,7 +1413,7 @@ mod unix { let baz = resolve_module(case.db(), &ModuleName::new_static("bar.baz").unwrap()) .expect("Expected bar.baz to exist in site-packages."); let baz_project = case.project_path("bar/baz.py"); - let baz_file = baz.file().unwrap(); + let baz_file = baz.file(case.db()).unwrap(); assert_eq!(source_text(case.db(), baz_file).as_str(), "def baz(): ..."); assert_eq!( @@ -1473,7 +1488,7 @@ mod unix { let baz = resolve_module(case.db(), &ModuleName::new_static("bar.baz").unwrap()) .expect("Expected bar.baz to exist in site-packages."); - let baz_file = baz.file().unwrap(); + let baz_file = baz.file(case.db()).unwrap(); let bar_baz = case.project_path("bar/baz.py"); let patched_bar_baz = case.project_path("patched/bar/baz.py"); @@ -1594,7 +1609,10 @@ mod unix { "def baz(): ..." ); assert_eq!( - baz.file().unwrap().path(case.db()).as_system_path(), + baz.file(case.db()) + .unwrap() + .path(case.db()) + .as_system_path(), Some(&*baz_original) ); @@ -1891,19 +1909,9 @@ fn rename_files_casing_only() -> anyhow::Result<()> { #[test] fn submodule_cache_invalidation_created() -> anyhow::Result<()> { let mut case = setup([("lib.py", ""), ("bar/__init__.py", ""), ("bar/foo.py", "")])?; - let module = resolve_module(case.db(), &ModuleName::new("bar").unwrap()).expect("`bar` module"); - let get_submodules = |db: &dyn Db, module: &Module| { - let mut names = module - .all_submodules(db) - .iter() - .map(|name| name.as_str().to_string()) - .collect::>(); - names.sort(); - names.join("\n") - }; insta::assert_snapshot!( - get_submodules(case.db(), &module), + case.sorted_submodule_names("bar").join("\n"), @"foo", ); @@ -1912,7 +1920,7 @@ fn submodule_cache_invalidation_created() -> anyhow::Result<()> { case.apply_changes(changes, None); insta::assert_snapshot!( - get_submodules(case.db(), &module), + case.sorted_submodule_names("bar").join("\n"), @r" foo wazoo @@ -1932,19 +1940,9 @@ fn submodule_cache_invalidation_deleted() -> anyhow::Result<()> { ("bar/foo.py", ""), ("bar/wazoo.py", ""), ])?; - let module = resolve_module(case.db(), &ModuleName::new("bar").unwrap()).expect("`bar` module"); - let get_submodules = |db: &dyn Db, module: &Module| { - let mut names = module - .all_submodules(db) - .iter() - .map(|name| name.as_str().to_string()) - .collect::>(); - names.sort(); - names.join("\n") - }; insta::assert_snapshot!( - get_submodules(case.db(), &module), + case.sorted_submodule_names("bar").join("\n"), @r" foo wazoo @@ -1956,7 +1954,7 @@ fn submodule_cache_invalidation_deleted() -> anyhow::Result<()> { case.apply_changes(changes, None); insta::assert_snapshot!( - get_submodules(case.db(), &module), + case.sorted_submodule_names("bar").join("\n"), @"foo", ); @@ -1968,19 +1966,9 @@ fn submodule_cache_invalidation_deleted() -> anyhow::Result<()> { #[test] fn submodule_cache_invalidation_created_then_deleted() -> anyhow::Result<()> { let mut case = setup([("lib.py", ""), ("bar/__init__.py", ""), ("bar/foo.py", "")])?; - let module = resolve_module(case.db(), &ModuleName::new("bar").unwrap()).expect("`bar` module"); - let get_submodules = |db: &dyn Db, module: &Module| { - let mut names = module - .all_submodules(db) - .iter() - .map(|name| name.as_str().to_string()) - .collect::>(); - names.sort(); - names.join("\n") - }; insta::assert_snapshot!( - get_submodules(case.db(), &module), + case.sorted_submodule_names("bar").join("\n"), @"foo", ); @@ -1993,7 +1981,7 @@ fn submodule_cache_invalidation_created_then_deleted() -> anyhow::Result<()> { case.apply_changes(changes, None); insta::assert_snapshot!( - get_submodules(case.db(), &module), + case.sorted_submodule_names("bar").join("\n"), @"foo", ); @@ -2006,19 +1994,9 @@ fn submodule_cache_invalidation_created_then_deleted() -> anyhow::Result<()> { #[test] fn submodule_cache_invalidation_after_pyproject_created() -> anyhow::Result<()> { let mut case = setup([("lib.py", ""), ("bar/__init__.py", ""), ("bar/foo.py", "")])?; - let module = resolve_module(case.db(), &ModuleName::new("bar").unwrap()).expect("`bar` module"); - let get_submodules = |db: &dyn Db, module: &Module| { - let mut names = module - .all_submodules(db) - .iter() - .map(|name| name.as_str().to_string()) - .collect::>(); - names.sort(); - names.join("\n") - }; insta::assert_snapshot!( - get_submodules(case.db(), &module), + case.sorted_submodule_names("bar").join("\n"), @"foo", ); @@ -2029,7 +2007,7 @@ fn submodule_cache_invalidation_after_pyproject_created() -> anyhow::Result<()> case.apply_changes(changes, None); insta::assert_snapshot!( - get_submodules(case.db(), &module), + case.sorted_submodule_names("bar").join("\n"), @r" foo wazoo diff --git a/crates/ty_ide/src/goto.rs b/crates/ty_ide/src/goto.rs index 134e7dd140..9ff23acf6d 100644 --- a/crates/ty_ide/src/goto.rs +++ b/crates/ty_ide/src/goto.rs @@ -525,7 +525,7 @@ fn resolve_module_to_navigation_target( if let Some(module_name) = ModuleName::new(module_name_str) { if let Some(resolved_module) = resolve_module(db, &module_name) { - if let Some(module_file) = resolved_module.file() { + if let Some(module_file) = resolved_module.file(db) { return Some(crate::NavigationTargets::single(crate::NavigationTarget { file: module_file, focus_range: TextRange::default(), diff --git a/crates/ty_python_semantic/src/dunder_all.rs b/crates/ty_python_semantic/src/dunder_all.rs index caf71b0a4d..e99df234e4 100644 --- a/crates/ty_python_semantic/src/dunder_all.rs +++ b/crates/ty_python_semantic/src/dunder_all.rs @@ -103,7 +103,7 @@ impl<'db> DunderAllNamesCollector<'db> { }; let Some(module_dunder_all_names) = module_literal .module(self.db) - .file() + .file(self.db) .and_then(|file| dunder_all_names(self.db, file)) else { // The module either does not have a `__all__` variable or it is invalid. @@ -173,7 +173,7 @@ impl<'db> DunderAllNamesCollector<'db> { let module_name = ModuleName::from_import_statement(self.db, self.file, import_from).ok()?; let module = resolve_module(self.db, &module_name)?; - dunder_all_names(self.db, module.file()?) + dunder_all_names(self.db, module.file(self.db)?) } /// Infer the type of a standalone expression. diff --git a/crates/ty_python_semantic/src/module_name.rs b/crates/ty_python_semantic/src/module_name.rs index eb6ec828de..79a9c0fd63 100644 --- a/crates/ty_python_semantic/src/module_name.rs +++ b/crates/ty_python_semantic/src/module_name.rs @@ -345,12 +345,12 @@ fn relative_module_name( .ok_or(ModuleNameResolutionError::UnknownCurrentModule)?; let mut level = level.get(); - if module.kind().is_package() { + if module.kind(db).is_package() { level = level.saturating_sub(1); } let mut module_name = module - .name() + .name(db) .ancestors() .nth(level as usize) .ok_or(ModuleNameResolutionError::TooManyDots)?; diff --git a/crates/ty_python_semantic/src/module_resolver/module.rs b/crates/ty_python_semantic/src/module_resolver/module.rs index b12a8cf90f..c3046bf2a4 100644 --- a/crates/ty_python_semantic/src/module_resolver/module.rs +++ b/crates/ty_python_semantic/src/module_resolver/module.rs @@ -1,10 +1,11 @@ use std::fmt::Formatter; use std::str::FromStr; -use std::sync::Arc; use ruff_db::files::File; use ruff_python_ast::name::Name; use ruff_python_stdlib::identifiers::is_identifier; +use salsa::Database; +use salsa::plumbing::AsId; use super::path::SearchPath; use crate::Db; @@ -12,14 +13,19 @@ use crate::module_name::ModuleName; use crate::module_resolver::path::SystemOrVendoredPathRef; /// Representation of a Python module. -#[derive(Clone, PartialEq, Eq, Hash, get_size2::GetSize)] -pub struct Module { - inner: Arc, +#[derive(Clone, Copy, Eq, Hash, PartialEq, salsa::Supertype, salsa::Update)] +pub enum Module<'db> { + File(FileModule<'db>), + Namespace(NamespacePackage<'db>), } +// The Salsa heap is tracked separately. +impl get_size2::GetSize for Module<'_> {} + #[salsa::tracked] -impl Module { +impl<'db> Module<'db> { pub(crate) fn file_module( + db: &'db dyn Db, name: ModuleName, kind: ModuleKind, search_path: SearchPath, @@ -27,67 +33,57 @@ impl Module { ) -> Self { let known = KnownModule::try_from_search_path_and_name(&search_path, &name); - Self { - inner: Arc::new(ModuleInner::FileModule { - name, - kind, - search_path, - file, - known, - }), - } + Self::File(FileModule::new(db, name, kind, search_path, file, known)) } - pub(crate) fn namespace_package(name: ModuleName) -> Self { - Self { - inner: Arc::new(ModuleInner::NamespacePackage { name }), - } + pub(crate) fn namespace_package(db: &'db dyn Db, name: ModuleName) -> Self { + Self::Namespace(NamespacePackage::new(db, name)) } /// The absolute name of the module (e.g. `foo.bar`) - pub fn name(&self) -> &ModuleName { - match &*self.inner { - ModuleInner::FileModule { name, .. } => name, - ModuleInner::NamespacePackage { name, .. } => name, + pub fn name(self, db: &'db dyn Database) -> &'db ModuleName { + match self { + Module::File(module) => module.name(db), + Module::Namespace(ref package) => package.name(db), } } /// The file to the source code that defines this module /// /// This is `None` for namespace packages. - pub fn file(&self) -> Option { - match &*self.inner { - ModuleInner::FileModule { file, .. } => Some(*file), - ModuleInner::NamespacePackage { .. } => None, + pub fn file(self, db: &'db dyn Database) -> Option { + match self { + Module::File(module) => Some(module.file(db)), + Module::Namespace(_) => None, } } /// Is this a module that we special-case somehow? If so, which one? - pub fn known(&self) -> Option { - match &*self.inner { - ModuleInner::FileModule { known, .. } => *known, - ModuleInner::NamespacePackage { .. } => None, + pub fn known(self, db: &'db dyn Database) -> Option { + match self { + Module::File(module) => module.known(db), + Module::Namespace(_) => None, } } /// Does this module represent the given known module? - pub fn is_known(&self, known_module: KnownModule) -> bool { - self.known() == Some(known_module) + pub fn is_known(self, db: &'db dyn Database, known_module: KnownModule) -> bool { + self.known(db) == Some(known_module) } /// The search path from which the module was resolved. - pub(crate) fn search_path(&self) -> Option<&SearchPath> { - match &*self.inner { - ModuleInner::FileModule { search_path, .. } => Some(search_path), - ModuleInner::NamespacePackage { .. } => None, + pub(crate) fn search_path(self, db: &'db dyn Database) -> Option<&'db SearchPath> { + match self { + Module::File(module) => Some(module.search_path(db)), + Module::Namespace(_) => None, } } /// Determine whether this module is a single-file module or a package - pub fn kind(&self) -> ModuleKind { - match &*self.inner { - ModuleInner::FileModule { kind, .. } => *kind, - ModuleInner::NamespacePackage { .. } => ModuleKind::Package, + pub fn kind(self, db: &'db dyn Database) -> ModuleKind { + match self { + Module::File(module) => module.kind(db), + Module::Namespace(_) => ModuleKind::Package, } } @@ -98,16 +94,13 @@ impl Module { /// /// The names returned correspond to the "base" name of the module. /// That is, `{self.name}.{basename}` should give the full module name. - pub fn all_submodules<'db>(&self, db: &'db dyn Db) -> &'db [Name] { - self.clone() - .all_submodules_inner(db, ()) - .as_deref() - .unwrap_or_default() + pub fn all_submodules(self, db: &'db dyn Db) -> &'db [Name] { + self.all_submodules_inner(db).as_deref().unwrap_or_default() } - #[allow(clippy::ref_option, clippy::used_underscore_binding)] + #[allow(clippy::ref_option)] #[salsa::tracked(returns(ref))] - fn all_submodules_inner(self, db: &dyn Db, _dummy: ()) -> Option> { + fn all_submodules_inner(self, db: &'db dyn Db) -> Option> { fn is_submodule( is_dir: bool, is_file: bool, @@ -125,16 +118,14 @@ impl Module { // to a single file; it can span multiple directories across multiple // search paths. For now, we only compute submodules for traditional // packages that exist in a single directory on a single search path. - let ModuleInner::FileModule { - kind: ModuleKind::Package, - file, - .. - } = &*self.inner - else { + let Module::File(module) = self else { return None; }; + if !matches!(module.kind(db), ModuleKind::Package) { + return None; + } - let path = SystemOrVendoredPathRef::try_from_file(db, *file)?; + let path = SystemOrVendoredPathRef::try_from_file(db, module.file(db))?; debug_assert!( matches!(path.file_name(), Some("__init__.py" | "__init__.pyi")), "expected package file `{:?}` to be `__init__.py` or `__init__.pyi`", @@ -201,33 +192,41 @@ impl Module { } } -impl std::fmt::Debug for Module { +impl std::fmt::Debug for Module<'_> { fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { - f.debug_struct("Module") - .field("name", &self.name()) - .field("kind", &self.kind()) - .field("file", &self.file()) - .field("search_path", &self.search_path()) - .field("known", &self.known()) - .finish() + salsa::with_attached_database(|db| { + f.debug_struct("Module") + .field("name", &self.name(db)) + .field("kind", &self.kind(db)) + .field("file", &self.file(db)) + .field("search_path", &self.search_path(db)) + .field("known", &self.known(db)) + .finish() + }) + .unwrap_or_else(|| f.debug_tuple("Module").field(&self.as_id()).finish()) } } -#[derive(PartialEq, Eq, Hash, get_size2::GetSize)] -enum ModuleInner { - /// A module that resolves to a file (`lib.py` or `package/__init__.py`) - FileModule { - name: ModuleName, - kind: ModuleKind, - search_path: SearchPath, - file: File, - known: Option, - }, +/// A module that resolves to a file (`lib.py` or `package/__init__.py`) +#[salsa::tracked(debug)] +pub struct FileModule<'db> { + #[returns(ref)] + name: ModuleName, + kind: ModuleKind, + #[returns(ref)] + search_path: SearchPath, + file: File, + known: Option, +} - /// A namespace package. Namespace packages are special because - /// there are multiple possible paths and they have no corresponding - /// code file. - NamespacePackage { name: ModuleName }, +/// A namespace package. +/// +/// Namespace packages are special because there are +/// multiple possible paths and they have no corresponding code file. +#[salsa::tracked(debug)] +pub struct NamespacePackage<'db> { + #[returns(ref)] + name: ModuleName, } #[derive(Copy, Clone, Debug, Eq, PartialEq, Hash, get_size2::GetSize)] diff --git a/crates/ty_python_semantic/src/module_resolver/path.rs b/crates/ty_python_semantic/src/module_resolver/path.rs index 91488d2442..290b20b1fa 100644 --- a/crates/ty_python_semantic/src/module_resolver/path.rs +++ b/crates/ty_python_semantic/src/module_resolver/path.rs @@ -411,7 +411,7 @@ enum SearchPathInner { /// and "Standard-library" categories, however, there will always be exactly /// one search path from that category in any given list of search paths. #[derive(Debug, Clone, PartialEq, Eq, Hash, get_size2::GetSize)] -pub(crate) struct SearchPath(Arc); +pub struct SearchPath(Arc); impl SearchPath { fn directory_path(system: &dyn System, root: SystemPathBuf) -> SearchPathResult { diff --git a/crates/ty_python_semantic/src/module_resolver/resolver.rs b/crates/ty_python_semantic/src/module_resolver/resolver.rs index 2c576fa998..cd9a1fe600 100644 --- a/crates/ty_python_semantic/src/module_resolver/resolver.rs +++ b/crates/ty_python_semantic/src/module_resolver/resolver.rs @@ -20,14 +20,14 @@ use super::module::{Module, ModuleKind}; use super::path::{ModulePath, SearchPath, SearchPathValidationError, SystemOrVendoredPathRef}; /// Resolves a module name to a module. -pub fn resolve_module(db: &dyn Db, module_name: &ModuleName) -> Option { +pub fn resolve_module<'db>(db: &'db dyn Db, module_name: &ModuleName) -> Option> { let interned_name = ModuleNameIngredient::new(db, module_name, ModuleResolveMode::StubsAllowed); resolve_module_query(db, interned_name) } /// Resolves a module name to a module (stubs not allowed). -pub fn resolve_real_module(db: &dyn Db, module_name: &ModuleName) -> Option { +pub fn resolve_real_module<'db>(db: &'db dyn Db, module_name: &ModuleName) -> Option> { let interned_name = ModuleNameIngredient::new(db, module_name, ModuleResolveMode::StubsNotAllowed); @@ -55,7 +55,7 @@ impl ModuleResolveMode { pub(crate) fn resolve_module_query<'db>( db: &'db dyn Db, module_name: ModuleNameIngredient<'db>, -) -> Option { +) -> Option> { let name = module_name.name(db); let mode = module_name.mode(db); let _span = tracing::trace_span!("resolve_module", %name).entered(); @@ -71,11 +71,17 @@ pub(crate) fn resolve_module_query<'db>( "Resolved module `{name}` to `{path}`", path = module.file.path(db) ); - Module::file_module(name.clone(), module.kind, module.search_path, module.file) + Module::file_module( + db, + name.clone(), + module.kind, + module.search_path, + module.file, + ) } ResolvedName::NamespacePackage => { tracing::trace!("Module `{name}` is a namespace package"); - Module::namespace_package(name.clone()) + Module::namespace_package(db, name.clone()) } }; @@ -86,7 +92,7 @@ pub(crate) fn resolve_module_query<'db>( /// /// Returns `None` if the path is not a module locatable via any of the known search paths. #[allow(unused)] -pub(crate) fn path_to_module(db: &dyn Db, path: &FilePath) -> Option { +pub(crate) fn path_to_module<'db>(db: &'db dyn Db, path: &FilePath) -> Option> { // It's not entirely clear on first sight why this method calls `file_to_module` instead of // it being the other way round, considering that the first thing that `file_to_module` does // is to retrieve the file's path. @@ -103,7 +109,7 @@ pub(crate) fn path_to_module(db: &dyn Db, path: &FilePath) -> Option { /// /// Returns `None` if the file is not a module locatable via any of the known search paths. #[salsa::tracked(heap_size=get_size2::GetSize::get_heap_size)] -pub(crate) fn file_to_module(db: &dyn Db, file: File) -> Option { +pub(crate) fn file_to_module(db: &dyn Db, file: File) -> Option> { let _span = tracing::trace_span!("file_to_module", ?file).entered(); let path = SystemOrVendoredPathRef::try_from_file(db, file)?; @@ -121,7 +127,7 @@ pub(crate) fn file_to_module(db: &dyn Db, file: File) -> Option { // root paths, but that the module corresponding to `path` is in a lower priority search path, // in which case we ignore it. let module = resolve_module(db, &module_name)?; - let module_file = module.file()?; + let module_file = module.file(db)?; if file.path(db) == module_file.path(db) { Some(module) @@ -939,12 +945,12 @@ mod tests { resolve_module(&db, &foo_module_name).as_ref() ); - assert_eq!("foo", foo_module.name()); - assert_eq!(&src, foo_module.search_path().unwrap()); - assert_eq!(ModuleKind::Module, foo_module.kind()); + assert_eq!("foo", foo_module.name(&db)); + assert_eq!(&src, foo_module.search_path(&db).unwrap()); + assert_eq!(ModuleKind::Module, foo_module.kind(&db)); let expected_foo_path = src.join("foo.py"); - assert_eq!(&expected_foo_path, foo_module.file().unwrap().path(&db)); + assert_eq!(&expected_foo_path, foo_module.file(&db).unwrap().path(&db)); assert_eq!( Some(foo_module), path_to_module(&db, &FilePath::System(expected_foo_path)) @@ -962,7 +968,7 @@ mod tests { let builtins = resolve_module(&db, &builtins_module_name).expect("builtins to resolve"); assert_eq!( - builtins.file().unwrap().path(&db), + builtins.file(&db).unwrap().path(&db), &stdlib.join("builtins.pyi") ); } @@ -986,7 +992,7 @@ mod tests { let builtins = resolve_module(&db, &builtins_module_name).expect("builtins to resolve"); assert_eq!( - builtins.file().unwrap().path(&db), + builtins.file(&db).unwrap().path(&db), &stdlib.join("builtins.pyi") ); } @@ -1011,13 +1017,13 @@ mod tests { resolve_module(&db, &functools_module_name).as_ref() ); - assert_eq!(&stdlib, functools_module.search_path().unwrap()); - assert_eq!(ModuleKind::Module, functools_module.kind()); + assert_eq!(&stdlib, functools_module.search_path(&db).unwrap()); + assert_eq!(ModuleKind::Module, functools_module.kind(&db)); let expected_functools_path = stdlib.join("functools.pyi"); assert_eq!( &expected_functools_path, - functools_module.file().unwrap().path(&db) + functools_module.file(&db).unwrap().path(&db) ); assert_eq!( @@ -1064,7 +1070,7 @@ mod tests { let resolved_module = resolve_module(&db, &module_name).unwrap_or_else(|| { panic!("Expected module {module_name} to exist in the mock stdlib") }); - let search_path = resolved_module.search_path().unwrap(); + let search_path = resolved_module.search_path(&db).unwrap(); assert_eq!( &stdlib, search_path, "Search path for {module_name} was unexpectedly {search_path:?}" @@ -1160,7 +1166,7 @@ mod tests { let resolved_module = resolve_module(&db, &module_name).unwrap_or_else(|| { panic!("Expected module {module_name} to exist in the mock stdlib") }); - let search_path = resolved_module.search_path().unwrap(); + let search_path = resolved_module.search_path(&db).unwrap(); assert_eq!( &stdlib, search_path, "Search path for {module_name} was unexpectedly {search_path:?}" @@ -1221,11 +1227,11 @@ mod tests { Some(&functools_module), resolve_module(&db, &functools_module_name).as_ref() ); - assert_eq!(&src, functools_module.search_path().unwrap()); - assert_eq!(ModuleKind::Module, functools_module.kind()); + assert_eq!(&src, functools_module.search_path(&db).unwrap()); + assert_eq!(ModuleKind::Module, functools_module.kind(&db)); assert_eq!( &src.join("functools.py"), - functools_module.file().unwrap().path(&db) + functools_module.file(&db).unwrap().path(&db) ); assert_eq!( @@ -1244,10 +1250,10 @@ mod tests { let pydoc_data_topics_name = ModuleName::new_static("pydoc_data.topics").unwrap(); let pydoc_data_topics = resolve_module(&db, &pydoc_data_topics_name).unwrap(); - assert_eq!("pydoc_data.topics", pydoc_data_topics.name()); - assert_eq!(pydoc_data_topics.search_path().unwrap(), &stdlib); + assert_eq!("pydoc_data.topics", pydoc_data_topics.name(&db)); + assert_eq!(pydoc_data_topics.search_path(&db).unwrap(), &stdlib); assert_eq!( - pydoc_data_topics.file().unwrap().path(&db), + pydoc_data_topics.file(&db).unwrap().path(&db), &stdlib.join("pydoc_data/topics.pyi") ); } @@ -1261,9 +1267,9 @@ mod tests { let foo_path = src.join("foo/__init__.py"); let foo_module = resolve_module(&db, &ModuleName::new_static("foo").unwrap()).unwrap(); - assert_eq!("foo", foo_module.name()); - assert_eq!(&src, foo_module.search_path().unwrap()); - assert_eq!(&foo_path, foo_module.file().unwrap().path(&db)); + assert_eq!("foo", foo_module.name(&db)); + assert_eq!(&src, foo_module.search_path(&db).unwrap()); + assert_eq!(&foo_path, foo_module.file(&db).unwrap().path(&db)); assert_eq!( Some(&foo_module), @@ -1289,9 +1295,9 @@ mod tests { let foo_module = resolve_module(&db, &ModuleName::new_static("foo").unwrap()).unwrap(); let foo_init_path = src.join("foo/__init__.py"); - assert_eq!(&src, foo_module.search_path().unwrap()); - assert_eq!(&foo_init_path, foo_module.file().unwrap().path(&db)); - assert_eq!(ModuleKind::Package, foo_module.kind()); + assert_eq!(&src, foo_module.search_path(&db).unwrap()); + assert_eq!(&foo_init_path, foo_module.file(&db).unwrap().path(&db)); + assert_eq!(ModuleKind::Package, foo_module.kind(&db)); assert_eq!( Some(foo_module), @@ -1312,8 +1318,8 @@ mod tests { let foo = resolve_module(&db, &ModuleName::new_static("foo").unwrap()).unwrap(); let foo_stub = src.join("foo.pyi"); - assert_eq!(&src, foo.search_path().unwrap()); - assert_eq!(&foo_stub, foo.file().unwrap().path(&db)); + assert_eq!(&src, foo.search_path(&db).unwrap()); + assert_eq!(&foo_stub, foo.file(&db).unwrap().path(&db)); assert_eq!(Some(foo), path_to_module(&db, &FilePath::System(foo_stub))); assert_eq!( @@ -1336,8 +1342,8 @@ mod tests { resolve_module(&db, &ModuleName::new_static("foo.bar.baz").unwrap()).unwrap(); let baz_path = src.join("foo/bar/baz.py"); - assert_eq!(&src, baz_module.search_path().unwrap()); - assert_eq!(&baz_path, baz_module.file().unwrap().path(&db)); + assert_eq!(&src, baz_module.search_path(&db).unwrap()); + assert_eq!(&baz_path, baz_module.file(&db).unwrap().path(&db)); assert_eq!( Some(baz_module), @@ -1360,8 +1366,8 @@ mod tests { let foo_module = resolve_module(&db, &ModuleName::new_static("foo").unwrap()).unwrap(); let foo_src_path = src.join("foo.py"); - assert_eq!(&src, foo_module.search_path().unwrap()); - assert_eq!(&foo_src_path, foo_module.file().unwrap().path(&db)); + assert_eq!(&src, foo_module.search_path(&db).unwrap()); + assert_eq!(&foo_src_path, foo_module.file(&db).unwrap().path(&db)); assert_eq!( Some(foo_module), path_to_module(&db, &FilePath::System(foo_src_path)) @@ -1433,14 +1439,14 @@ mod tests { assert_ne!(foo_module, bar_module); - assert_eq!(&src, foo_module.search_path().unwrap()); - assert_eq!(&foo, foo_module.file().unwrap().path(&db)); + assert_eq!(&src, foo_module.search_path(&db).unwrap()); + assert_eq!(&foo, foo_module.file(&db).unwrap().path(&db)); // `foo` and `bar` shouldn't resolve to the same file - assert_eq!(&src, bar_module.search_path().unwrap()); - assert_eq!(&bar, bar_module.file().unwrap().path(&db)); - assert_eq!(&foo, foo_module.file().unwrap().path(&db)); + assert_eq!(&src, bar_module.search_path(&db).unwrap()); + assert_eq!(&bar, bar_module.file(&db).unwrap().path(&db)); + assert_eq!(&foo, foo_module.file(&db).unwrap().path(&db)); assert_ne!(&foo_module, &bar_module); @@ -1465,6 +1471,13 @@ mod tests { let foo_module_name = ModuleName::new_static("foo").unwrap(); let foo_module = resolve_module(&db, &foo_module_name).unwrap(); + let foo_pieces = ( + foo_module.name(&db).clone(), + foo_module.file(&db), + foo_module.known(&db), + foo_module.search_path(&db).cloned(), + foo_module.kind(&db), + ); let bar_path = src.join("bar.py"); let bar = system_path_to_file(&db, &bar_path).expect("bar.py to exist"); @@ -1479,6 +1492,15 @@ mod tests { // for resolving `foo`. let foo_module2 = resolve_module(&db, &foo_module_name); + let foo_pieces2 = foo_module2.map(|foo_module2| { + ( + foo_module2.name(&db).clone(), + foo_module2.file(&db), + foo_module2.known(&db), + foo_module2.search_path(&db).cloned(), + foo_module2.kind(&db), + ) + }); assert!( !db.take_salsa_events() @@ -1486,7 +1508,7 @@ mod tests { .any(|event| { matches!(event.kind, salsa::EventKind::WillExecute { .. }) }) ); - assert_eq!(Some(foo_module), foo_module2); + assert_eq!(Some(foo_pieces), foo_pieces2); } #[test] @@ -1504,7 +1526,7 @@ mod tests { let foo_file = system_path_to_file(&db, &foo_path).expect("foo.py to exist"); let foo_module = resolve_module(&db, &foo_module_name).expect("Foo module to resolve"); - assert_eq!(foo_file, foo_module.file().unwrap()); + assert_eq!(foo_file, foo_module.file(&db).unwrap()); Ok(()) } @@ -1520,7 +1542,7 @@ mod tests { let foo_module = resolve_module(&db, &foo_module_name).expect("foo module to exist"); let foo_init_path = src.join("foo/__init__.py"); - assert_eq!(&foo_init_path, foo_module.file().unwrap().path(&db)); + assert_eq!(&foo_init_path, foo_module.file(&db).unwrap().path(&db)); // Delete `foo/__init__.py` and the `foo` folder. `foo` should now resolve to `foo.py` db.memory_file_system().remove_file(&foo_init_path)?; @@ -1530,7 +1552,7 @@ mod tests { File::sync_path(&mut db, foo_init_path.parent().unwrap()); let foo_module = resolve_module(&db, &foo_module_name).expect("Foo module to resolve"); - assert_eq!(&src.join("foo.py"), foo_module.file().unwrap().path(&db)); + assert_eq!(&src.join("foo.py"), foo_module.file(&db).unwrap().path(&db)); Ok(()) } @@ -1556,9 +1578,9 @@ mod tests { let stdlib_functools_path = stdlib.join("functools.pyi"); let functools_module = resolve_module(&db, &functools_module_name).unwrap(); - assert_eq!(functools_module.search_path().unwrap(), &stdlib); + assert_eq!(functools_module.search_path(&db).unwrap(), &stdlib); assert_eq!( - Ok(functools_module.file().unwrap()), + Ok(functools_module.file(&db).unwrap()), system_path_to_file(&db, &stdlib_functools_path) ); @@ -1569,6 +1591,8 @@ mod tests { db.write_file(&site_packages_functools_path, "f: int") .unwrap(); let functools_module = resolve_module(&db, &functools_module_name).unwrap(); + let functools_file = functools_module.file(&db).unwrap(); + let functools_search_path = functools_module.search_path(&db).unwrap().clone(); let events = db.take_salsa_events(); assert_function_query_was_not_run( &db, @@ -1576,9 +1600,9 @@ mod tests { ModuleNameIngredient::new(&db, functools_module_name, ModuleResolveMode::StubsAllowed), &events, ); - assert_eq!(functools_module.search_path().unwrap(), &stdlib); + assert_eq!(&functools_search_path, &stdlib); assert_eq!( - Ok(functools_module.file().unwrap()), + Ok(functools_file), system_path_to_file(&db, &stdlib_functools_path) ); } @@ -1602,9 +1626,9 @@ mod tests { let functools_module_name = ModuleName::new_static("functools").unwrap(); let functools_module = resolve_module(&db, &functools_module_name).unwrap(); - assert_eq!(functools_module.search_path().unwrap(), &stdlib); + assert_eq!(functools_module.search_path(&db).unwrap(), &stdlib); assert_eq!( - Ok(functools_module.file().unwrap()), + Ok(functools_module.file(&db).unwrap()), system_path_to_file(&db, stdlib.join("functools.pyi")) ); @@ -1613,9 +1637,9 @@ mod tests { let src_functools_path = src.join("functools.py"); db.write_file(&src_functools_path, "FOO: int").unwrap(); let functools_module = resolve_module(&db, &functools_module_name).unwrap(); - assert_eq!(functools_module.search_path().unwrap(), &src); + assert_eq!(functools_module.search_path(&db).unwrap(), &src); assert_eq!( - Ok(functools_module.file().unwrap()), + Ok(functools_module.file(&db).unwrap()), system_path_to_file(&db, &src_functools_path) ); } @@ -1644,9 +1668,9 @@ mod tests { let src_functools_path = src.join("functools.py"); let functools_module = resolve_module(&db, &functools_module_name).unwrap(); - assert_eq!(functools_module.search_path().unwrap(), &src); + assert_eq!(functools_module.search_path(&db).unwrap(), &src); assert_eq!( - Ok(functools_module.file().unwrap()), + Ok(functools_module.file(&db).unwrap()), system_path_to_file(&db, &src_functools_path) ); @@ -1657,9 +1681,9 @@ mod tests { .unwrap(); File::sync_path(&mut db, &src_functools_path); let functools_module = resolve_module(&db, &functools_module_name).unwrap(); - assert_eq!(functools_module.search_path().unwrap(), &stdlib); + assert_eq!(functools_module.search_path(&db).unwrap(), &stdlib); assert_eq!( - Ok(functools_module.file().unwrap()), + Ok(functools_module.file(&db).unwrap()), system_path_to_file(&db, stdlib.join("functools.pyi")) ); } @@ -1682,11 +1706,11 @@ mod tests { let foo_bar_module = resolve_module(&db, &foo_bar_module_name).unwrap(); assert_eq!( - foo_module.file().unwrap().path(&db), + foo_module.file(&db).unwrap().path(&db), &FilePath::system("/x/src/foo/__init__.py") ); assert_eq!( - foo_bar_module.file().unwrap().path(&db), + foo_bar_module.file(&db).unwrap().path(&db), &FilePath::system("/x/src/foo/bar.py") ); } @@ -1713,7 +1737,7 @@ mod tests { let bar_module_name = ModuleName::new_static("bar").unwrap(); let bar_module = resolve_module(&db, &bar_module_name).unwrap(); assert_eq!( - bar_module.file().unwrap().path(&db), + bar_module.file(&db).unwrap().path(&db), &FilePath::system("/y/src/bar.py") ); } @@ -1733,7 +1757,7 @@ mod tests { let foo_module = resolve_module(&db, &foo_module_name).unwrap(); assert_eq!( - foo_module.file().unwrap().path(&db), + foo_module.file(&db).unwrap().path(&db), &FilePath::system("/x/y/src/foo.pyi") ); } @@ -1784,19 +1808,19 @@ not_a_directory let spam_module = resolve_module(&db, &spam_module_name).unwrap(); assert_eq!( - foo_module.file().unwrap().path(&db), + foo_module.file(&db).unwrap().path(&db), &FilePath::system("/x/y/src/foo.pyi") ); assert_eq!( - a_module.file().unwrap().path(&db), + a_module.file(&db).unwrap().path(&db), &FilePath::system("/a.py") ); assert_eq!( - b_module.file().unwrap().path(&db), + b_module.file(&db).unwrap().path(&db), &FilePath::system("/baz/b.py") ); assert_eq!( - spam_module.file().unwrap().path(&db), + spam_module.file(&db).unwrap().path(&db), &FilePath::System(site_packages.join("spam/spam.py")) ); } @@ -1817,14 +1841,14 @@ not_a_directory let foo_module = resolve_module(&db, &foo_module_name).unwrap(); assert_eq!( - foo_module.file().unwrap().path(&db), + foo_module.file(&db).unwrap().path(&db), &FilePath::system("/x/src/foo.py") ); db.clear_salsa_events(); let bar_module = resolve_module(&db, &bar_module_name).unwrap(); assert_eq!( - bar_module.file().unwrap().path(&db), + bar_module.file(&db).unwrap().path(&db), &FilePath::system("/y/src/bar.py") ); let events = db.take_salsa_events(); @@ -1849,7 +1873,7 @@ not_a_directory let foo_module_name = ModuleName::new_static("foo").unwrap(); let foo_module = resolve_module(&db, &foo_module_name).unwrap(); assert_eq!( - foo_module.file().unwrap().path(&db), + foo_module.file(&db).unwrap().path(&db), &FilePath::system("/x/src/foo.py") ); @@ -1877,7 +1901,7 @@ not_a_directory let foo_module = resolve_module(&db, &foo_module_name).unwrap(); let src_path = SystemPathBuf::from("/x/src"); assert_eq!( - foo_module.file().unwrap().path(&db), + foo_module.file(&db).unwrap().path(&db), &FilePath::System(src_path.join("foo.py")) ); @@ -1948,7 +1972,7 @@ not_a_directory let a_module_name = ModuleName::new_static("a").unwrap(); let a_module = resolve_module(&db, &a_module_name).unwrap(); assert_eq!( - a_module.file().unwrap().path(&db), + a_module.file(&db).unwrap().path(&db), &editable_install_location ); @@ -1962,7 +1986,7 @@ not_a_directory // second `site-packages` directory let a_module = resolve_module(&db, &a_module_name).unwrap(); assert_eq!( - a_module.file().unwrap().path(&db), + a_module.file(&db).unwrap().path(&db), &system_site_packages_location ); } @@ -2024,7 +2048,7 @@ not_a_directory let a_module = resolve_module(&db, &a_module_name).expect("a.py to resolve"); assert!( a_module - .file() + .file(&db) .unwrap() .path(&db) .as_str() @@ -2059,6 +2083,6 @@ not_a_directory let foo_module_file = File::new(&db, FilePath::System(installed_foo_module)); let module = file_to_module(&db, foo_module_file).unwrap(); - assert_eq!(module.search_path().unwrap(), &site_packages); + assert_eq!(module.search_path(&db).unwrap(), &site_packages); } } diff --git a/crates/ty_python_semantic/src/place.rs b/crates/ty_python_semantic/src/place.rs index 490ec547b2..c2d8edb2e3 100644 --- a/crates/ty_python_semantic/src/place.rs +++ b/crates/ty_python_semantic/src/place.rs @@ -374,7 +374,7 @@ pub(crate) fn imported_symbol<'db>( pub(crate) fn builtins_symbol<'db>(db: &'db dyn Db, symbol: &str) -> PlaceAndQualifiers<'db> { resolve_module(db, &KnownModule::Builtins.name()) .and_then(|module| { - let file = module.file()?; + let file = module.file(db)?; Some( symbol_impl( db, @@ -404,7 +404,7 @@ pub(crate) fn known_module_symbol<'db>( ) -> PlaceAndQualifiers<'db> { resolve_module(db, &known_module.name()) .and_then(|module| { - let file = module.file()?; + let file = module.file(db)?; Some(imported_symbol(db, file, symbol, None)) }) .unwrap_or_default() @@ -442,7 +442,7 @@ pub(crate) fn builtins_module_scope(db: &dyn Db) -> Option> { /// Can return `None` if a custom typeshed is used that is missing the core module in question. fn core_module_scope(db: &dyn Db, core_module: KnownModule) -> Option> { let module = resolve_module(db, &core_module.name())?; - Some(global_scope(db, module.file()?)) + Some(global_scope(db, module.file(db)?)) } /// Infer the combined type from an iterator of bindings, and return it @@ -812,7 +812,7 @@ fn symbol_impl<'db>( if name == "platform" && file_to_module(db, scope.file(db)) - .is_some_and(|module| module.is_known(KnownModule::Sys)) + .is_some_and(|module| module.is_known(db, KnownModule::Sys)) { match Program::get(db).python_platform(db) { crate::PythonPlatform::Identifier(platform) => { diff --git a/crates/ty_python_semantic/src/semantic_index/builder.rs b/crates/ty_python_semantic/src/semantic_index/builder.rs index 7d37371ff6..2d0d57ed5b 100644 --- a/crates/ty_python_semantic/src/semantic_index/builder.rs +++ b/crates/ty_python_semantic/src/semantic_index/builder.rs @@ -1278,7 +1278,7 @@ impl<'ast> Visitor<'ast> for SemanticIndexBuilder<'_, 'ast> { continue; }; - let Some(referenced_module) = module.file() else { + let Some(referenced_module) = module.file(self.db) else { continue; }; diff --git a/crates/ty_python_semantic/src/semantic_index/re_exports.rs b/crates/ty_python_semantic/src/semantic_index/re_exports.rs index 70f76c3707..ba8a912fac 100644 --- a/crates/ty_python_semantic/src/semantic_index/re_exports.rs +++ b/crates/ty_python_semantic/src/semantic_index/re_exports.rs @@ -257,7 +257,7 @@ impl<'db> Visitor<'db> for ExportFinder<'db> { .iter() .flat_map(|module| { module - .file() + .file(self.db) .map(|file| exported_names(self.db, file)) .unwrap_or_default() }) diff --git a/crates/ty_python_semantic/src/semantic_model.rs b/crates/ty_python_semantic/src/semantic_model.rs index 7564ac6ec1..06afb0b795 100644 --- a/crates/ty_python_semantic/src/semantic_model.rs +++ b/crates/ty_python_semantic/src/semantic_model.rs @@ -67,8 +67,8 @@ impl<'db> SemanticModel<'db> { tracing::debug!("Could not resolve module from `{module_name:?}`"); return vec![]; }; - let ty = Type::module_literal(self.db, self.file, &module); - let builtin = module.is_known(KnownModule::Builtins); + let ty = Type::module_literal(self.db, self.file, module); + let builtin = module.is_known(self.db, KnownModule::Builtins); let mut completions = vec![]; for crate::types::Member { name, ty } in crate::types::all_members(self.db, ty) { @@ -84,7 +84,7 @@ impl<'db> SemanticModel<'db> { let Some(submodule) = resolve_module(self.db, &submodule_name) else { continue; }; - let ty = Type::module_literal(self.db, self.file, &submodule); + let ty = Type::module_literal(self.db, self.file, submodule); completions.push(Completion { name: submodule_basename.clone(), ty, diff --git a/crates/ty_python_semantic/src/types.rs b/crates/ty_python_semantic/src/types.rs index 9a0d9c86f8..f23dfcbeb6 100644 --- a/crates/ty_python_semantic/src/types.rs +++ b/crates/ty_python_semantic/src/types.rs @@ -841,11 +841,11 @@ impl<'db> Type<'db> { matches!(self, Type::PropertyInstance(..)) } - pub fn module_literal(db: &'db dyn Db, importing_file: File, submodule: &Module) -> Self { + pub fn module_literal(db: &'db dyn Db, importing_file: File, submodule: Module<'db>) -> Self { Self::ModuleLiteral(ModuleLiteralType::new( db, submodule, - submodule.kind().is_package().then_some(importing_file), + submodule.kind(db).is_package().then_some(importing_file), )) } @@ -6291,7 +6291,7 @@ impl<'db> InvalidTypeExpression<'db> { return; }; let module = module_type.module(db); - let Some(module_name_final_part) = module.name().components().next_back() else { + let Some(module_name_final_part) = module.name(db).components().next_back() else { return; }; let Some(module_member_with_same_name) = ty @@ -7722,7 +7722,7 @@ pub enum WrapperDescriptorKind { #[derive(PartialOrd, Ord)] pub struct ModuleLiteralType<'db> { /// The imported module. - pub module: Module, + pub module: Module<'db>, /// The file in which this module was imported. /// @@ -7744,7 +7744,7 @@ impl<'db> ModuleLiteralType<'db> { fn importing_file(self, db: &'db dyn Db) -> Option { debug_assert_eq!( self._importing_file(db).is_some(), - self.module(db).kind().is_package() + self.module(db).kind(db).is_package() ); self._importing_file(db) } @@ -7753,17 +7753,17 @@ impl<'db> ModuleLiteralType<'db> { 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(|submodule_name| submodule_name.relative_to(self.module(db).name(db))) .filter_map(|relative_submodule| relative_submodule.components().next().map(Name::from)) } fn resolve_submodule(self, db: &'db dyn Db, name: &str) -> Option> { let importing_file = self.importing_file(db)?; let relative_submodule_name = ModuleName::new(name)?; - let mut absolute_submodule_name = self.module(db).name().clone(); + let mut absolute_submodule_name = self.module(db).name(db).clone(); absolute_submodule_name.extend(&relative_submodule_name); let submodule = resolve_module(db, &absolute_submodule_name)?; - Some(Type::module_literal(db, importing_file, &submodule)) + Some(Type::module_literal(db, importing_file, submodule)) } fn static_member(self, db: &'db dyn Db, name: &str) -> PlaceAndQualifiers<'db> { @@ -7792,7 +7792,7 @@ impl<'db> ModuleLiteralType<'db> { } self.module(db) - .file() + .file(db) .map(|file| imported_symbol(db, file, name, None)) .unwrap_or_default() } diff --git a/crates/ty_python_semantic/src/types/call/bind.rs b/crates/ty_python_semantic/src/types/call/bind.rs index 3546013e0c..0b4d0308c8 100644 --- a/crates/ty_python_semantic/src/types/call/bind.rs +++ b/crates/ty_python_semantic/src/types/call/bind.rs @@ -648,7 +648,7 @@ impl<'db> Bindings<'db> { Type::ModuleLiteral(module_literal) => { let all_names = module_literal .module(db) - .file() + .file(db) .map(|file| dunder_all_names(db, file)) .unwrap_or_default(); match all_names { diff --git a/crates/ty_python_semantic/src/types/class.rs b/crates/ty_python_semantic/src/types/class.rs index bc3998c43a..1051b768bb 100644 --- a/crates/ty_python_semantic/src/types/class.rs +++ b/crates/ty_python_semantic/src/types/class.rs @@ -3498,7 +3498,7 @@ impl KnownClass { }; candidate - .check_module(db, file_to_module(db, file)?.known()?) + .check_module(db, file_to_module(db, file)?.known(db)?) .then_some(candidate) } @@ -4067,7 +4067,11 @@ mod tests { let class_module = resolve_module(&db, &class.canonical_module(&db).name()).unwrap(); assert_eq!( - KnownClass::try_from_file_and_name(&db, class_module.file().unwrap(), class_name), + KnownClass::try_from_file_and_name( + &db, + class_module.file(&db).unwrap(), + class_name + ), Some(class), "`KnownClass::candidate_from_str` appears to be missing a case for `{class_name}`" ); diff --git a/crates/ty_python_semantic/src/types/definition.rs b/crates/ty_python_semantic/src/types/definition.rs index a81fb0f925..f98d47ba93 100644 --- a/crates/ty_python_semantic/src/types/definition.rs +++ b/crates/ty_python_semantic/src/types/definition.rs @@ -7,7 +7,7 @@ use ruff_text_size::{TextLen, TextRange}; #[derive(Debug, PartialEq, Eq, Hash)] pub enum TypeDefinition<'db> { - Module(Module), + Module(Module<'db>), Class(Definition<'db>), Function(Definition<'db>), TypeVar(Definition<'db>), @@ -31,7 +31,7 @@ impl TypeDefinition<'_> { pub fn full_range(&self, db: &dyn Db) -> Option { match self { Self::Module(module) => { - let file = module.file()?; + let file = module.file(db)?; let source = source_text(db, file); Some(FileRange::new(file, TextRange::up_to(source.text_len()))) } diff --git a/crates/ty_python_semantic/src/types/diagnostic.rs b/crates/ty_python_semantic/src/types/diagnostic.rs index ecb4bc4aca..391c1df289 100644 --- a/crates/ty_python_semantic/src/types/diagnostic.rs +++ b/crates/ty_python_semantic/src/types/diagnostic.rs @@ -2522,9 +2522,9 @@ pub(super) fn hint_if_stdlib_submodule_exists_on_other_versions( db: &dyn Db, mut diagnostic: LintDiagnosticGuard, full_submodule_name: &ModuleName, - parent_module: &Module, + parent_module: Module, ) { - let Some(search_path) = parent_module.search_path() else { + let Some(search_path) = parent_module.search_path(db) else { return; }; @@ -2547,7 +2547,7 @@ pub(super) fn hint_if_stdlib_submodule_exists_on_other_versions( diagnostic.info(format_args!( "The stdlib module `{module_name}` only has a `{name}` \ submodule on Python {version_range}", - module_name = parent_module.name(), + module_name = parent_module.name(db), name = full_submodule_name .components() .next_back() diff --git a/crates/ty_python_semantic/src/types/display.rs b/crates/ty_python_semantic/src/types/display.rs index 68aec9d293..1495cfc0bd 100644 --- a/crates/ty_python_semantic/src/types/display.rs +++ b/crates/ty_python_semantic/src/types/display.rs @@ -102,7 +102,7 @@ impl Display for DisplayRepresentation<'_> { }, Type::PropertyInstance(_) => f.write_str("property"), Type::ModuleLiteral(module) => { - write!(f, "", module.module(self.db).name()) + write!(f, "", module.module(self.db).name(self.db)) } Type::ClassLiteral(class) => { write!(f, "", class.name(self.db)) diff --git a/crates/ty_python_semantic/src/types/function.rs b/crates/ty_python_semantic/src/types/function.rs index 5934b29634..13e485224b 100644 --- a/crates/ty_python_semantic/src/types/function.rs +++ b/crates/ty_python_semantic/src/types/function.rs @@ -1097,7 +1097,7 @@ impl KnownFunction { ) -> Option { let candidate = Self::from_str(name).ok()?; candidate - .check_module(file_to_module(db, definition.file(db))?.known()?) + .check_module(file_to_module(db, definition.file(db))?.known(db)?) .then_some(candidate) } @@ -1368,7 +1368,7 @@ impl KnownFunction { return; }; - overload.set_return_type(Type::module_literal(db, file, &module)); + overload.set_return_type(Type::module_literal(db, file, module)); } _ => {} diff --git a/crates/ty_python_semantic/src/types/ide_support.rs b/crates/ty_python_semantic/src/types/ide_support.rs index 59fe54412c..1178076aa2 100644 --- a/crates/ty_python_semantic/src/types/ide_support.rs +++ b/crates/ty_python_semantic/src/types/ide_support.rs @@ -156,7 +156,7 @@ impl<'db> AllMembers<'db> { self.extend_with_type(db, KnownClass::ModuleType.to_instance(db)); let module = literal.module(db); - let Some(file) = module.file() else { + let Some(file) = module.file(db) else { return; }; @@ -544,7 +544,7 @@ pub fn definitions_for_attribute<'db>( for ty in expanded_tys { // Handle modules if let Type::ModuleLiteral(module_literal) = ty { - if let Some(module_file) = module_literal.module(db).file() { + if let Some(module_file) = module_literal.module(db).file(db) { let module_scope = global_scope(db, module_file); for def in find_symbol_in_scope(db, module_scope, name_str) { resolved.extend(resolve_definition(db, def, Some(name_str))); @@ -878,7 +878,7 @@ mod resolve_definition { return Vec::new(); // Module not found, return empty list }; - let Some(module_file) = resolved_module.file() else { + let Some(module_file) = resolved_module.file(db) else { return Vec::new(); // No file for module, return empty list }; @@ -939,7 +939,7 @@ mod resolve_definition { let Some(resolved_module) = resolve_module(db, &module_name) else { return Vec::new(); }; - resolved_module.file() + resolved_module.file(db) }; let Some(module_file) = module_file else { @@ -1013,10 +1013,10 @@ mod resolve_definition { // It's definitely a stub, so now rerun module resolution but with stubs disabled. let stub_module = file_to_module(db, stub_file)?; - trace!("Found stub module: {}", stub_module.name()); - let real_module = resolve_real_module(db, stub_module.name())?; - trace!("Found real module: {}", real_module.name()); - let real_file = real_module.file()?; + trace!("Found stub module: {}", stub_module.name(db)); + let real_module = resolve_real_module(db, stub_module.name(db))?; + trace!("Found real module: {}", real_module.name(db)); + let real_file = real_module.file(db)?; trace!("Found real file: {}", real_file.path(db)); // A definition has a "Definition Path" in a file made of nested definitions (~scopes): diff --git a/crates/ty_python_semantic/src/types/infer.rs b/crates/ty_python_semantic/src/types/infer.rs index 25bb5f8f5a..000e6204dd 100644 --- a/crates/ty_python_semantic/src/types/infer.rs +++ b/crates/ty_python_semantic/src/types/infer.rs @@ -4866,7 +4866,7 @@ impl<'db, 'ast> TypeInferenceBuilder<'db, 'ast> { return; }; - let module_ty = Type::module_literal(self.db(), self.file(), &module); + let module_ty = Type::module_literal(self.db(), self.file(), module); // The indirection of having `star_import_info` as a separate variable // is required in order to make the borrow checker happy. @@ -4892,7 +4892,7 @@ impl<'db, 'ast> TypeInferenceBuilder<'db, 'ast> { // (e.g. `from parent import submodule` inside the `parent` module). let import_is_self_referential = module_ty .into_module_literal() - .is_some_and(|module| Some(self.file()) == module.module(self.db()).file()); + .is_some_and(|module| Some(self.file()) == module.module(self.db()).file(self.db())); // First try loading the requested attribute from the module. if !import_is_self_referential { @@ -4990,7 +4990,7 @@ impl<'db, 'ast> TypeInferenceBuilder<'db, 'ast> { self.db(), diagnostic, &full_submodule_name, - &module, + module, ); } } @@ -5144,7 +5144,7 @@ impl<'db, 'ast> TypeInferenceBuilder<'db, 'ast> { fn module_type_from_name(&self, module_name: &ModuleName) -> Option> { resolve_module(self.db(), module_name) - .map(|module| Type::module_literal(self.db(), self.file(), &module)) + .map(|module| Type::module_literal(self.db(), self.file(), module)) } fn infer_decorator(&mut self, decorator: &ast::Decorator) -> Type<'db> { diff --git a/crates/ty_python_semantic/src/types/special_form.rs b/crates/ty_python_semantic/src/types/special_form.rs index f960f3058f..179b9349eb 100644 --- a/crates/ty_python_semantic/src/types/special_form.rs +++ b/crates/ty_python_semantic/src/types/special_form.rs @@ -187,7 +187,7 @@ impl SpecialFormType { ) -> Option { let candidate = Self::from_str(symbol_name).ok()?; candidate - .check_module(file_to_module(db, file)?.known()?) + .check_module(file_to_module(db, file)?.known(db)?) .then_some(candidate) }