mirror of
https://github.com/astral-sh/ruff.git
synced 2025-08-19 01:50:38 +00:00
[ty] Make Module
a Salsa ingredient
We want to write queries that depend on `Module` for caching. While it seems it can be done without making `Module` an ingredient, it seems it is best practice to do so. [best practice to do so]: https://github.com/astral-sh/ruff/pull/19408#discussion_r2215867301
This commit is contained in:
parent
905b9d7f51
commit
4573a0f6a0
24 changed files with 258 additions and 253 deletions
|
@ -20,7 +20,7 @@ impl<'a> Resolver<'a> {
|
||||||
match import {
|
match import {
|
||||||
CollectedImport::Import(import) => {
|
CollectedImport::Import(import) => {
|
||||||
let module = resolve_module(self.db, &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) => {
|
CollectedImport::ImportFrom(import) => {
|
||||||
// Attempt to resolve the member (e.g., given `from foo import bar`, look for `foo.bar`).
|
// 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?)
|
resolve_module(self.db, &parent?)
|
||||||
})?;
|
})?;
|
||||||
|
|
||||||
Some(module.file()?.path(self.db))
|
Some(module.file(self.db)?.path(self.db))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -163,7 +163,7 @@ fn stem(path: &str) -> &str {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Infer the [`Visibility`] of a module from its path.
|
/// 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 {
|
match &module.source {
|
||||||
ModuleSource::Path(path) => {
|
ModuleSource::Path(path) => {
|
||||||
if path.iter().any(|m| is_private_module(m)) {
|
if path.iter().any(|m| is_private_module(m)) {
|
||||||
|
|
|
@ -223,7 +223,7 @@ impl<'a> Definitions<'a> {
|
||||||
// visibility.
|
// visibility.
|
||||||
let visibility = {
|
let visibility = {
|
||||||
match &definition {
|
match &definition {
|
||||||
Definition::Module(module) => module_visibility(module),
|
Definition::Module(module) => module_visibility(*module),
|
||||||
Definition::Member(member) => match member.kind {
|
Definition::Member(member) => match member.kind {
|
||||||
MemberKind::Class(class) => {
|
MemberKind::Class(class) => {
|
||||||
let parent = &definitions[member.parent];
|
let parent = &definitions[member.parent];
|
||||||
|
|
|
@ -230,6 +230,21 @@ impl TestCase {
|
||||||
fn system_file(&self, path: impl AsRef<SystemPath>) -> Result<File, FileError> {
|
fn system_file(&self, path: impl AsRef<SystemPath>) -> Result<File, FileError> {
|
||||||
system_path_to_file(self.db(), path.as_ref())
|
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<String> {
|
||||||
|
let mut names = self
|
||||||
|
.module(parent_module_name)
|
||||||
|
.all_submodules(self.db())
|
||||||
|
.iter()
|
||||||
|
.map(|name| name.as_str().to_string())
|
||||||
|
.collect::<Vec<String>>();
|
||||||
|
names.sort();
|
||||||
|
names
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
trait MatchEvent {
|
trait MatchEvent {
|
||||||
|
@ -1398,7 +1413,7 @@ mod unix {
|
||||||
let baz = resolve_module(case.db(), &ModuleName::new_static("bar.baz").unwrap())
|
let baz = resolve_module(case.db(), &ModuleName::new_static("bar.baz").unwrap())
|
||||||
.expect("Expected bar.baz to exist in site-packages.");
|
.expect("Expected bar.baz to exist in site-packages.");
|
||||||
let baz_project = case.project_path("bar/baz.py");
|
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!(source_text(case.db(), baz_file).as_str(), "def baz(): ...");
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
|
@ -1473,7 +1488,7 @@ mod unix {
|
||||||
|
|
||||||
let baz = resolve_module(case.db(), &ModuleName::new_static("bar.baz").unwrap())
|
let baz = resolve_module(case.db(), &ModuleName::new_static("bar.baz").unwrap())
|
||||||
.expect("Expected bar.baz to exist in site-packages.");
|
.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 bar_baz = case.project_path("bar/baz.py");
|
||||||
|
|
||||||
let patched_bar_baz = case.project_path("patched/bar/baz.py");
|
let patched_bar_baz = case.project_path("patched/bar/baz.py");
|
||||||
|
@ -1594,7 +1609,10 @@ mod unix {
|
||||||
"def baz(): ..."
|
"def baz(): ..."
|
||||||
);
|
);
|
||||||
assert_eq!(
|
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)
|
Some(&*baz_original)
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -1891,19 +1909,9 @@ fn rename_files_casing_only() -> anyhow::Result<()> {
|
||||||
#[test]
|
#[test]
|
||||||
fn submodule_cache_invalidation_created() -> anyhow::Result<()> {
|
fn submodule_cache_invalidation_created() -> anyhow::Result<()> {
|
||||||
let mut case = setup([("lib.py", ""), ("bar/__init__.py", ""), ("bar/foo.py", "")])?;
|
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::<Vec<String>>();
|
|
||||||
names.sort();
|
|
||||||
names.join("\n")
|
|
||||||
};
|
|
||||||
|
|
||||||
insta::assert_snapshot!(
|
insta::assert_snapshot!(
|
||||||
get_submodules(case.db(), &module),
|
case.sorted_submodule_names("bar").join("\n"),
|
||||||
@"foo",
|
@"foo",
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -1912,7 +1920,7 @@ fn submodule_cache_invalidation_created() -> anyhow::Result<()> {
|
||||||
case.apply_changes(changes, None);
|
case.apply_changes(changes, None);
|
||||||
|
|
||||||
insta::assert_snapshot!(
|
insta::assert_snapshot!(
|
||||||
get_submodules(case.db(), &module),
|
case.sorted_submodule_names("bar").join("\n"),
|
||||||
@r"
|
@r"
|
||||||
foo
|
foo
|
||||||
wazoo
|
wazoo
|
||||||
|
@ -1932,19 +1940,9 @@ fn submodule_cache_invalidation_deleted() -> anyhow::Result<()> {
|
||||||
("bar/foo.py", ""),
|
("bar/foo.py", ""),
|
||||||
("bar/wazoo.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::<Vec<String>>();
|
|
||||||
names.sort();
|
|
||||||
names.join("\n")
|
|
||||||
};
|
|
||||||
|
|
||||||
insta::assert_snapshot!(
|
insta::assert_snapshot!(
|
||||||
get_submodules(case.db(), &module),
|
case.sorted_submodule_names("bar").join("\n"),
|
||||||
@r"
|
@r"
|
||||||
foo
|
foo
|
||||||
wazoo
|
wazoo
|
||||||
|
@ -1956,7 +1954,7 @@ fn submodule_cache_invalidation_deleted() -> anyhow::Result<()> {
|
||||||
case.apply_changes(changes, None);
|
case.apply_changes(changes, None);
|
||||||
|
|
||||||
insta::assert_snapshot!(
|
insta::assert_snapshot!(
|
||||||
get_submodules(case.db(), &module),
|
case.sorted_submodule_names("bar").join("\n"),
|
||||||
@"foo",
|
@"foo",
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -1968,19 +1966,9 @@ fn submodule_cache_invalidation_deleted() -> anyhow::Result<()> {
|
||||||
#[test]
|
#[test]
|
||||||
fn submodule_cache_invalidation_created_then_deleted() -> anyhow::Result<()> {
|
fn submodule_cache_invalidation_created_then_deleted() -> anyhow::Result<()> {
|
||||||
let mut case = setup([("lib.py", ""), ("bar/__init__.py", ""), ("bar/foo.py", "")])?;
|
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::<Vec<String>>();
|
|
||||||
names.sort();
|
|
||||||
names.join("\n")
|
|
||||||
};
|
|
||||||
|
|
||||||
insta::assert_snapshot!(
|
insta::assert_snapshot!(
|
||||||
get_submodules(case.db(), &module),
|
case.sorted_submodule_names("bar").join("\n"),
|
||||||
@"foo",
|
@"foo",
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -1993,7 +1981,7 @@ fn submodule_cache_invalidation_created_then_deleted() -> anyhow::Result<()> {
|
||||||
case.apply_changes(changes, None);
|
case.apply_changes(changes, None);
|
||||||
|
|
||||||
insta::assert_snapshot!(
|
insta::assert_snapshot!(
|
||||||
get_submodules(case.db(), &module),
|
case.sorted_submodule_names("bar").join("\n"),
|
||||||
@"foo",
|
@"foo",
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -2006,19 +1994,9 @@ fn submodule_cache_invalidation_created_then_deleted() -> anyhow::Result<()> {
|
||||||
#[test]
|
#[test]
|
||||||
fn submodule_cache_invalidation_after_pyproject_created() -> anyhow::Result<()> {
|
fn submodule_cache_invalidation_after_pyproject_created() -> anyhow::Result<()> {
|
||||||
let mut case = setup([("lib.py", ""), ("bar/__init__.py", ""), ("bar/foo.py", "")])?;
|
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::<Vec<String>>();
|
|
||||||
names.sort();
|
|
||||||
names.join("\n")
|
|
||||||
};
|
|
||||||
|
|
||||||
insta::assert_snapshot!(
|
insta::assert_snapshot!(
|
||||||
get_submodules(case.db(), &module),
|
case.sorted_submodule_names("bar").join("\n"),
|
||||||
@"foo",
|
@"foo",
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -2029,7 +2007,7 @@ fn submodule_cache_invalidation_after_pyproject_created() -> anyhow::Result<()>
|
||||||
case.apply_changes(changes, None);
|
case.apply_changes(changes, None);
|
||||||
|
|
||||||
insta::assert_snapshot!(
|
insta::assert_snapshot!(
|
||||||
get_submodules(case.db(), &module),
|
case.sorted_submodule_names("bar").join("\n"),
|
||||||
@r"
|
@r"
|
||||||
foo
|
foo
|
||||||
wazoo
|
wazoo
|
||||||
|
|
|
@ -525,7 +525,7 @@ fn resolve_module_to_navigation_target(
|
||||||
|
|
||||||
if let Some(module_name) = ModuleName::new(module_name_str) {
|
if let Some(module_name) = ModuleName::new(module_name_str) {
|
||||||
if let Some(resolved_module) = resolve_module(db, &module_name) {
|
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 {
|
return Some(crate::NavigationTargets::single(crate::NavigationTarget {
|
||||||
file: module_file,
|
file: module_file,
|
||||||
focus_range: TextRange::default(),
|
focus_range: TextRange::default(),
|
||||||
|
|
|
@ -103,7 +103,7 @@ impl<'db> DunderAllNamesCollector<'db> {
|
||||||
};
|
};
|
||||||
let Some(module_dunder_all_names) = module_literal
|
let Some(module_dunder_all_names) = module_literal
|
||||||
.module(self.db)
|
.module(self.db)
|
||||||
.file()
|
.file(self.db)
|
||||||
.and_then(|file| dunder_all_names(self.db, file))
|
.and_then(|file| dunder_all_names(self.db, file))
|
||||||
else {
|
else {
|
||||||
// The module either does not have a `__all__` variable or it is invalid.
|
// The module either does not have a `__all__` variable or it is invalid.
|
||||||
|
@ -173,7 +173,7 @@ impl<'db> DunderAllNamesCollector<'db> {
|
||||||
let module_name =
|
let module_name =
|
||||||
ModuleName::from_import_statement(self.db, self.file, import_from).ok()?;
|
ModuleName::from_import_statement(self.db, self.file, import_from).ok()?;
|
||||||
let module = resolve_module(self.db, &module_name)?;
|
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.
|
/// Infer the type of a standalone expression.
|
||||||
|
|
|
@ -345,12 +345,12 @@ fn relative_module_name(
|
||||||
.ok_or(ModuleNameResolutionError::UnknownCurrentModule)?;
|
.ok_or(ModuleNameResolutionError::UnknownCurrentModule)?;
|
||||||
let mut level = level.get();
|
let mut level = level.get();
|
||||||
|
|
||||||
if module.kind().is_package() {
|
if module.kind(db).is_package() {
|
||||||
level = level.saturating_sub(1);
|
level = level.saturating_sub(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut module_name = module
|
let mut module_name = module
|
||||||
.name()
|
.name(db)
|
||||||
.ancestors()
|
.ancestors()
|
||||||
.nth(level as usize)
|
.nth(level as usize)
|
||||||
.ok_or(ModuleNameResolutionError::TooManyDots)?;
|
.ok_or(ModuleNameResolutionError::TooManyDots)?;
|
||||||
|
|
|
@ -1,10 +1,11 @@
|
||||||
use std::fmt::Formatter;
|
use std::fmt::Formatter;
|
||||||
use std::str::FromStr;
|
use std::str::FromStr;
|
||||||
use std::sync::Arc;
|
|
||||||
|
|
||||||
use ruff_db::files::File;
|
use ruff_db::files::File;
|
||||||
use ruff_python_ast::name::Name;
|
use ruff_python_ast::name::Name;
|
||||||
use ruff_python_stdlib::identifiers::is_identifier;
|
use ruff_python_stdlib::identifiers::is_identifier;
|
||||||
|
use salsa::Database;
|
||||||
|
use salsa::plumbing::AsId;
|
||||||
|
|
||||||
use super::path::SearchPath;
|
use super::path::SearchPath;
|
||||||
use crate::Db;
|
use crate::Db;
|
||||||
|
@ -12,14 +13,19 @@ use crate::module_name::ModuleName;
|
||||||
use crate::module_resolver::path::SystemOrVendoredPathRef;
|
use crate::module_resolver::path::SystemOrVendoredPathRef;
|
||||||
|
|
||||||
/// Representation of a Python module.
|
/// Representation of a Python module.
|
||||||
#[derive(Clone, PartialEq, Eq, Hash, get_size2::GetSize)]
|
#[derive(Clone, Copy, Eq, Hash, PartialEq, salsa::Supertype, salsa::Update)]
|
||||||
pub struct Module {
|
pub enum Module<'db> {
|
||||||
inner: Arc<ModuleInner>,
|
File(FileModule<'db>),
|
||||||
|
Namespace(NamespacePackage<'db>),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// The Salsa heap is tracked separately.
|
||||||
|
impl get_size2::GetSize for Module<'_> {}
|
||||||
|
|
||||||
#[salsa::tracked]
|
#[salsa::tracked]
|
||||||
impl Module {
|
impl<'db> Module<'db> {
|
||||||
pub(crate) fn file_module(
|
pub(crate) fn file_module(
|
||||||
|
db: &'db dyn Db,
|
||||||
name: ModuleName,
|
name: ModuleName,
|
||||||
kind: ModuleKind,
|
kind: ModuleKind,
|
||||||
search_path: SearchPath,
|
search_path: SearchPath,
|
||||||
|
@ -27,67 +33,57 @@ impl Module {
|
||||||
) -> Self {
|
) -> Self {
|
||||||
let known = KnownModule::try_from_search_path_and_name(&search_path, &name);
|
let known = KnownModule::try_from_search_path_and_name(&search_path, &name);
|
||||||
|
|
||||||
Self {
|
Self::File(FileModule::new(db, name, kind, search_path, file, known))
|
||||||
inner: Arc::new(ModuleInner::FileModule {
|
|
||||||
name,
|
|
||||||
kind,
|
|
||||||
search_path,
|
|
||||||
file,
|
|
||||||
known,
|
|
||||||
}),
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn namespace_package(name: ModuleName) -> Self {
|
pub(crate) fn namespace_package(db: &'db dyn Db, name: ModuleName) -> Self {
|
||||||
Self {
|
Self::Namespace(NamespacePackage::new(db, name))
|
||||||
inner: Arc::new(ModuleInner::NamespacePackage { name }),
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The absolute name of the module (e.g. `foo.bar`)
|
/// The absolute name of the module (e.g. `foo.bar`)
|
||||||
pub fn name(&self) -> &ModuleName {
|
pub fn name(self, db: &'db dyn Database) -> &'db ModuleName {
|
||||||
match &*self.inner {
|
match self {
|
||||||
ModuleInner::FileModule { name, .. } => name,
|
Module::File(module) => module.name(db),
|
||||||
ModuleInner::NamespacePackage { name, .. } => name,
|
Module::Namespace(ref package) => package.name(db),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The file to the source code that defines this module
|
/// The file to the source code that defines this module
|
||||||
///
|
///
|
||||||
/// This is `None` for namespace packages.
|
/// This is `None` for namespace packages.
|
||||||
pub fn file(&self) -> Option<File> {
|
pub fn file(self, db: &'db dyn Database) -> Option<File> {
|
||||||
match &*self.inner {
|
match self {
|
||||||
ModuleInner::FileModule { file, .. } => Some(*file),
|
Module::File(module) => Some(module.file(db)),
|
||||||
ModuleInner::NamespacePackage { .. } => None,
|
Module::Namespace(_) => None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Is this a module that we special-case somehow? If so, which one?
|
/// Is this a module that we special-case somehow? If so, which one?
|
||||||
pub fn known(&self) -> Option<KnownModule> {
|
pub fn known(self, db: &'db dyn Database) -> Option<KnownModule> {
|
||||||
match &*self.inner {
|
match self {
|
||||||
ModuleInner::FileModule { known, .. } => *known,
|
Module::File(module) => module.known(db),
|
||||||
ModuleInner::NamespacePackage { .. } => None,
|
Module::Namespace(_) => None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Does this module represent the given known module?
|
/// Does this module represent the given known module?
|
||||||
pub fn is_known(&self, known_module: KnownModule) -> bool {
|
pub fn is_known(self, db: &'db dyn Database, known_module: KnownModule) -> bool {
|
||||||
self.known() == Some(known_module)
|
self.known(db) == Some(known_module)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The search path from which the module was resolved.
|
/// The search path from which the module was resolved.
|
||||||
pub(crate) fn search_path(&self) -> Option<&SearchPath> {
|
pub(crate) fn search_path(self, db: &'db dyn Database) -> Option<&'db SearchPath> {
|
||||||
match &*self.inner {
|
match self {
|
||||||
ModuleInner::FileModule { search_path, .. } => Some(search_path),
|
Module::File(module) => Some(module.search_path(db)),
|
||||||
ModuleInner::NamespacePackage { .. } => None,
|
Module::Namespace(_) => None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Determine whether this module is a single-file module or a package
|
/// Determine whether this module is a single-file module or a package
|
||||||
pub fn kind(&self) -> ModuleKind {
|
pub fn kind(self, db: &'db dyn Database) -> ModuleKind {
|
||||||
match &*self.inner {
|
match self {
|
||||||
ModuleInner::FileModule { kind, .. } => *kind,
|
Module::File(module) => module.kind(db),
|
||||||
ModuleInner::NamespacePackage { .. } => ModuleKind::Package,
|
Module::Namespace(_) => ModuleKind::Package,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -98,16 +94,13 @@ impl Module {
|
||||||
///
|
///
|
||||||
/// The names returned correspond to the "base" name of the module.
|
/// The names returned correspond to the "base" name of the module.
|
||||||
/// That is, `{self.name}.{basename}` should give the full module name.
|
/// That is, `{self.name}.{basename}` should give the full module name.
|
||||||
pub fn all_submodules<'db>(&self, db: &'db dyn Db) -> &'db [Name] {
|
pub fn all_submodules(self, db: &'db dyn Db) -> &'db [Name] {
|
||||||
self.clone()
|
self.all_submodules_inner(db).as_deref().unwrap_or_default()
|
||||||
.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))]
|
#[salsa::tracked(returns(ref))]
|
||||||
fn all_submodules_inner(self, db: &dyn Db, _dummy: ()) -> Option<Vec<Name>> {
|
fn all_submodules_inner(self, db: &'db dyn Db) -> Option<Vec<Name>> {
|
||||||
fn is_submodule(
|
fn is_submodule(
|
||||||
is_dir: bool,
|
is_dir: bool,
|
||||||
is_file: bool,
|
is_file: bool,
|
||||||
|
@ -125,16 +118,14 @@ impl Module {
|
||||||
// to a single file; it can span multiple directories across multiple
|
// to a single file; it can span multiple directories across multiple
|
||||||
// search paths. For now, we only compute submodules for traditional
|
// search paths. For now, we only compute submodules for traditional
|
||||||
// packages that exist in a single directory on a single search path.
|
// packages that exist in a single directory on a single search path.
|
||||||
let ModuleInner::FileModule {
|
let Module::File(module) = self else {
|
||||||
kind: ModuleKind::Package,
|
|
||||||
file,
|
|
||||||
..
|
|
||||||
} = &*self.inner
|
|
||||||
else {
|
|
||||||
return None;
|
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!(
|
debug_assert!(
|
||||||
matches!(path.file_name(), Some("__init__.py" | "__init__.pyi")),
|
matches!(path.file_name(), Some("__init__.py" | "__init__.pyi")),
|
||||||
"expected package file `{:?}` to be `__init__.py` or `__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 {
|
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
|
||||||
|
salsa::with_attached_database(|db| {
|
||||||
f.debug_struct("Module")
|
f.debug_struct("Module")
|
||||||
.field("name", &self.name())
|
.field("name", &self.name(db))
|
||||||
.field("kind", &self.kind())
|
.field("kind", &self.kind(db))
|
||||||
.field("file", &self.file())
|
.field("file", &self.file(db))
|
||||||
.field("search_path", &self.search_path())
|
.field("search_path", &self.search_path(db))
|
||||||
.field("known", &self.known())
|
.field("known", &self.known(db))
|
||||||
.finish()
|
.finish()
|
||||||
|
})
|
||||||
|
.unwrap_or_else(|| f.debug_tuple("Module").field(&self.as_id()).finish())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(PartialEq, Eq, Hash, get_size2::GetSize)]
|
/// A module that resolves to a file (`lib.py` or `package/__init__.py`)
|
||||||
enum ModuleInner {
|
#[salsa::tracked(debug)]
|
||||||
/// A module that resolves to a file (`lib.py` or `package/__init__.py`)
|
pub struct FileModule<'db> {
|
||||||
FileModule {
|
#[returns(ref)]
|
||||||
name: ModuleName,
|
name: ModuleName,
|
||||||
kind: ModuleKind,
|
kind: ModuleKind,
|
||||||
|
#[returns(ref)]
|
||||||
search_path: SearchPath,
|
search_path: SearchPath,
|
||||||
file: File,
|
file: File,
|
||||||
known: Option<KnownModule>,
|
known: Option<KnownModule>,
|
||||||
},
|
}
|
||||||
|
|
||||||
/// A namespace package. Namespace packages are special because
|
/// A namespace package.
|
||||||
/// there are multiple possible paths and they have no corresponding
|
///
|
||||||
/// code file.
|
/// Namespace packages are special because there are
|
||||||
NamespacePackage { name: ModuleName },
|
/// 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)]
|
#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash, get_size2::GetSize)]
|
||||||
|
|
|
@ -411,7 +411,7 @@ enum SearchPathInner {
|
||||||
/// and "Standard-library" categories, however, there will always be exactly
|
/// and "Standard-library" categories, however, there will always be exactly
|
||||||
/// one search path from that category in any given list of search paths.
|
/// one search path from that category in any given list of search paths.
|
||||||
#[derive(Debug, Clone, PartialEq, Eq, Hash, get_size2::GetSize)]
|
#[derive(Debug, Clone, PartialEq, Eq, Hash, get_size2::GetSize)]
|
||||||
pub(crate) struct SearchPath(Arc<SearchPathInner>);
|
pub struct SearchPath(Arc<SearchPathInner>);
|
||||||
|
|
||||||
impl SearchPath {
|
impl SearchPath {
|
||||||
fn directory_path(system: &dyn System, root: SystemPathBuf) -> SearchPathResult<SystemPathBuf> {
|
fn directory_path(system: &dyn System, root: SystemPathBuf) -> SearchPathResult<SystemPathBuf> {
|
||||||
|
|
|
@ -20,14 +20,14 @@ use super::module::{Module, ModuleKind};
|
||||||
use super::path::{ModulePath, SearchPath, SearchPathValidationError, SystemOrVendoredPathRef};
|
use super::path::{ModulePath, SearchPath, SearchPathValidationError, SystemOrVendoredPathRef};
|
||||||
|
|
||||||
/// Resolves a module name to a module.
|
/// Resolves a module name to a module.
|
||||||
pub fn resolve_module(db: &dyn Db, module_name: &ModuleName) -> Option<Module> {
|
pub fn resolve_module<'db>(db: &'db dyn Db, module_name: &ModuleName) -> Option<Module<'db>> {
|
||||||
let interned_name = ModuleNameIngredient::new(db, module_name, ModuleResolveMode::StubsAllowed);
|
let interned_name = ModuleNameIngredient::new(db, module_name, ModuleResolveMode::StubsAllowed);
|
||||||
|
|
||||||
resolve_module_query(db, interned_name)
|
resolve_module_query(db, interned_name)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Resolves a module name to a module (stubs not allowed).
|
/// Resolves a module name to a module (stubs not allowed).
|
||||||
pub fn resolve_real_module(db: &dyn Db, module_name: &ModuleName) -> Option<Module> {
|
pub fn resolve_real_module<'db>(db: &'db dyn Db, module_name: &ModuleName) -> Option<Module<'db>> {
|
||||||
let interned_name =
|
let interned_name =
|
||||||
ModuleNameIngredient::new(db, module_name, ModuleResolveMode::StubsNotAllowed);
|
ModuleNameIngredient::new(db, module_name, ModuleResolveMode::StubsNotAllowed);
|
||||||
|
|
||||||
|
@ -55,7 +55,7 @@ impl ModuleResolveMode {
|
||||||
pub(crate) fn resolve_module_query<'db>(
|
pub(crate) fn resolve_module_query<'db>(
|
||||||
db: &'db dyn Db,
|
db: &'db dyn Db,
|
||||||
module_name: ModuleNameIngredient<'db>,
|
module_name: ModuleNameIngredient<'db>,
|
||||||
) -> Option<Module> {
|
) -> Option<Module<'db>> {
|
||||||
let name = module_name.name(db);
|
let name = module_name.name(db);
|
||||||
let mode = module_name.mode(db);
|
let mode = module_name.mode(db);
|
||||||
let _span = tracing::trace_span!("resolve_module", %name).entered();
|
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}`",
|
"Resolved module `{name}` to `{path}`",
|
||||||
path = module.file.path(db)
|
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 => {
|
ResolvedName::NamespacePackage => {
|
||||||
tracing::trace!("Module `{name}` is a namespace package");
|
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.
|
/// Returns `None` if the path is not a module locatable via any of the known search paths.
|
||||||
#[allow(unused)]
|
#[allow(unused)]
|
||||||
pub(crate) fn path_to_module(db: &dyn Db, path: &FilePath) -> Option<Module> {
|
pub(crate) fn path_to_module<'db>(db: &'db dyn Db, path: &FilePath) -> Option<Module<'db>> {
|
||||||
// It's not entirely clear on first sight why this method calls `file_to_module` instead of
|
// 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
|
// it being the other way round, considering that the first thing that `file_to_module` does
|
||||||
// is to retrieve the file's path.
|
// is to retrieve the file's path.
|
||||||
|
@ -103,7 +109,7 @@ pub(crate) fn path_to_module(db: &dyn Db, path: &FilePath) -> Option<Module> {
|
||||||
///
|
///
|
||||||
/// Returns `None` if the file is not a module locatable via any of the known search paths.
|
/// 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)]
|
#[salsa::tracked(heap_size=get_size2::GetSize::get_heap_size)]
|
||||||
pub(crate) fn file_to_module(db: &dyn Db, file: File) -> Option<Module> {
|
pub(crate) fn file_to_module(db: &dyn Db, file: File) -> Option<Module<'_>> {
|
||||||
let _span = tracing::trace_span!("file_to_module", ?file).entered();
|
let _span = tracing::trace_span!("file_to_module", ?file).entered();
|
||||||
|
|
||||||
let path = SystemOrVendoredPathRef::try_from_file(db, file)?;
|
let path = SystemOrVendoredPathRef::try_from_file(db, file)?;
|
||||||
|
@ -121,7 +127,7 @@ pub(crate) fn file_to_module(db: &dyn Db, file: File) -> Option<Module> {
|
||||||
// root paths, but that the module corresponding to `path` is in a lower priority search path,
|
// root paths, but that the module corresponding to `path` is in a lower priority search path,
|
||||||
// in which case we ignore it.
|
// in which case we ignore it.
|
||||||
let module = resolve_module(db, &module_name)?;
|
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) {
|
if file.path(db) == module_file.path(db) {
|
||||||
Some(module)
|
Some(module)
|
||||||
|
@ -939,12 +945,12 @@ mod tests {
|
||||||
resolve_module(&db, &foo_module_name).as_ref()
|
resolve_module(&db, &foo_module_name).as_ref()
|
||||||
);
|
);
|
||||||
|
|
||||||
assert_eq!("foo", foo_module.name());
|
assert_eq!("foo", foo_module.name(&db));
|
||||||
assert_eq!(&src, foo_module.search_path().unwrap());
|
assert_eq!(&src, foo_module.search_path(&db).unwrap());
|
||||||
assert_eq!(ModuleKind::Module, foo_module.kind());
|
assert_eq!(ModuleKind::Module, foo_module.kind(&db));
|
||||||
|
|
||||||
let expected_foo_path = src.join("foo.py");
|
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!(
|
assert_eq!(
|
||||||
Some(foo_module),
|
Some(foo_module),
|
||||||
path_to_module(&db, &FilePath::System(expected_foo_path))
|
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");
|
let builtins = resolve_module(&db, &builtins_module_name).expect("builtins to resolve");
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
builtins.file().unwrap().path(&db),
|
builtins.file(&db).unwrap().path(&db),
|
||||||
&stdlib.join("builtins.pyi")
|
&stdlib.join("builtins.pyi")
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -986,7 +992,7 @@ mod tests {
|
||||||
let builtins = resolve_module(&db, &builtins_module_name).expect("builtins to resolve");
|
let builtins = resolve_module(&db, &builtins_module_name).expect("builtins to resolve");
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
builtins.file().unwrap().path(&db),
|
builtins.file(&db).unwrap().path(&db),
|
||||||
&stdlib.join("builtins.pyi")
|
&stdlib.join("builtins.pyi")
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -1011,13 +1017,13 @@ mod tests {
|
||||||
resolve_module(&db, &functools_module_name).as_ref()
|
resolve_module(&db, &functools_module_name).as_ref()
|
||||||
);
|
);
|
||||||
|
|
||||||
assert_eq!(&stdlib, functools_module.search_path().unwrap());
|
assert_eq!(&stdlib, functools_module.search_path(&db).unwrap());
|
||||||
assert_eq!(ModuleKind::Module, functools_module.kind());
|
assert_eq!(ModuleKind::Module, functools_module.kind(&db));
|
||||||
|
|
||||||
let expected_functools_path = stdlib.join("functools.pyi");
|
let expected_functools_path = stdlib.join("functools.pyi");
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
&expected_functools_path,
|
&expected_functools_path,
|
||||||
functools_module.file().unwrap().path(&db)
|
functools_module.file(&db).unwrap().path(&db)
|
||||||
);
|
);
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
|
@ -1064,7 +1070,7 @@ mod tests {
|
||||||
let resolved_module = resolve_module(&db, &module_name).unwrap_or_else(|| {
|
let resolved_module = resolve_module(&db, &module_name).unwrap_or_else(|| {
|
||||||
panic!("Expected module {module_name} to exist in the mock stdlib")
|
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!(
|
assert_eq!(
|
||||||
&stdlib, search_path,
|
&stdlib, search_path,
|
||||||
"Search path for {module_name} was unexpectedly {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(|| {
|
let resolved_module = resolve_module(&db, &module_name).unwrap_or_else(|| {
|
||||||
panic!("Expected module {module_name} to exist in the mock stdlib")
|
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!(
|
assert_eq!(
|
||||||
&stdlib, search_path,
|
&stdlib, search_path,
|
||||||
"Search path for {module_name} was unexpectedly {search_path:?}"
|
"Search path for {module_name} was unexpectedly {search_path:?}"
|
||||||
|
@ -1221,11 +1227,11 @@ mod tests {
|
||||||
Some(&functools_module),
|
Some(&functools_module),
|
||||||
resolve_module(&db, &functools_module_name).as_ref()
|
resolve_module(&db, &functools_module_name).as_ref()
|
||||||
);
|
);
|
||||||
assert_eq!(&src, functools_module.search_path().unwrap());
|
assert_eq!(&src, functools_module.search_path(&db).unwrap());
|
||||||
assert_eq!(ModuleKind::Module, functools_module.kind());
|
assert_eq!(ModuleKind::Module, functools_module.kind(&db));
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
&src.join("functools.py"),
|
&src.join("functools.py"),
|
||||||
functools_module.file().unwrap().path(&db)
|
functools_module.file(&db).unwrap().path(&db)
|
||||||
);
|
);
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
|
@ -1244,10 +1250,10 @@ mod tests {
|
||||||
let pydoc_data_topics_name = ModuleName::new_static("pydoc_data.topics").unwrap();
|
let pydoc_data_topics_name = ModuleName::new_static("pydoc_data.topics").unwrap();
|
||||||
let pydoc_data_topics = resolve_module(&db, &pydoc_data_topics_name).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", pydoc_data_topics.name(&db));
|
||||||
assert_eq!(pydoc_data_topics.search_path().unwrap(), &stdlib);
|
assert_eq!(pydoc_data_topics.search_path(&db).unwrap(), &stdlib);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
pydoc_data_topics.file().unwrap().path(&db),
|
pydoc_data_topics.file(&db).unwrap().path(&db),
|
||||||
&stdlib.join("pydoc_data/topics.pyi")
|
&stdlib.join("pydoc_data/topics.pyi")
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -1261,9 +1267,9 @@ mod tests {
|
||||||
let foo_path = src.join("foo/__init__.py");
|
let foo_path = src.join("foo/__init__.py");
|
||||||
let foo_module = resolve_module(&db, &ModuleName::new_static("foo").unwrap()).unwrap();
|
let foo_module = resolve_module(&db, &ModuleName::new_static("foo").unwrap()).unwrap();
|
||||||
|
|
||||||
assert_eq!("foo", foo_module.name());
|
assert_eq!("foo", foo_module.name(&db));
|
||||||
assert_eq!(&src, foo_module.search_path().unwrap());
|
assert_eq!(&src, foo_module.search_path(&db).unwrap());
|
||||||
assert_eq!(&foo_path, foo_module.file().unwrap().path(&db));
|
assert_eq!(&foo_path, foo_module.file(&db).unwrap().path(&db));
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
Some(&foo_module),
|
Some(&foo_module),
|
||||||
|
@ -1289,9 +1295,9 @@ mod tests {
|
||||||
let foo_module = resolve_module(&db, &ModuleName::new_static("foo").unwrap()).unwrap();
|
let foo_module = resolve_module(&db, &ModuleName::new_static("foo").unwrap()).unwrap();
|
||||||
let foo_init_path = src.join("foo/__init__.py");
|
let foo_init_path = src.join("foo/__init__.py");
|
||||||
|
|
||||||
assert_eq!(&src, foo_module.search_path().unwrap());
|
assert_eq!(&src, foo_module.search_path(&db).unwrap());
|
||||||
assert_eq!(&foo_init_path, foo_module.file().unwrap().path(&db));
|
assert_eq!(&foo_init_path, foo_module.file(&db).unwrap().path(&db));
|
||||||
assert_eq!(ModuleKind::Package, foo_module.kind());
|
assert_eq!(ModuleKind::Package, foo_module.kind(&db));
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
Some(foo_module),
|
Some(foo_module),
|
||||||
|
@ -1312,8 +1318,8 @@ mod tests {
|
||||||
let foo = resolve_module(&db, &ModuleName::new_static("foo").unwrap()).unwrap();
|
let foo = resolve_module(&db, &ModuleName::new_static("foo").unwrap()).unwrap();
|
||||||
let foo_stub = src.join("foo.pyi");
|
let foo_stub = src.join("foo.pyi");
|
||||||
|
|
||||||
assert_eq!(&src, foo.search_path().unwrap());
|
assert_eq!(&src, foo.search_path(&db).unwrap());
|
||||||
assert_eq!(&foo_stub, foo.file().unwrap().path(&db));
|
assert_eq!(&foo_stub, foo.file(&db).unwrap().path(&db));
|
||||||
|
|
||||||
assert_eq!(Some(foo), path_to_module(&db, &FilePath::System(foo_stub)));
|
assert_eq!(Some(foo), path_to_module(&db, &FilePath::System(foo_stub)));
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
|
@ -1336,8 +1342,8 @@ mod tests {
|
||||||
resolve_module(&db, &ModuleName::new_static("foo.bar.baz").unwrap()).unwrap();
|
resolve_module(&db, &ModuleName::new_static("foo.bar.baz").unwrap()).unwrap();
|
||||||
let baz_path = src.join("foo/bar/baz.py");
|
let baz_path = src.join("foo/bar/baz.py");
|
||||||
|
|
||||||
assert_eq!(&src, baz_module.search_path().unwrap());
|
assert_eq!(&src, baz_module.search_path(&db).unwrap());
|
||||||
assert_eq!(&baz_path, baz_module.file().unwrap().path(&db));
|
assert_eq!(&baz_path, baz_module.file(&db).unwrap().path(&db));
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
Some(baz_module),
|
Some(baz_module),
|
||||||
|
@ -1360,8 +1366,8 @@ mod tests {
|
||||||
let foo_module = resolve_module(&db, &ModuleName::new_static("foo").unwrap()).unwrap();
|
let foo_module = resolve_module(&db, &ModuleName::new_static("foo").unwrap()).unwrap();
|
||||||
let foo_src_path = src.join("foo.py");
|
let foo_src_path = src.join("foo.py");
|
||||||
|
|
||||||
assert_eq!(&src, foo_module.search_path().unwrap());
|
assert_eq!(&src, foo_module.search_path(&db).unwrap());
|
||||||
assert_eq!(&foo_src_path, foo_module.file().unwrap().path(&db));
|
assert_eq!(&foo_src_path, foo_module.file(&db).unwrap().path(&db));
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
Some(foo_module),
|
Some(foo_module),
|
||||||
path_to_module(&db, &FilePath::System(foo_src_path))
|
path_to_module(&db, &FilePath::System(foo_src_path))
|
||||||
|
@ -1433,14 +1439,14 @@ mod tests {
|
||||||
|
|
||||||
assert_ne!(foo_module, bar_module);
|
assert_ne!(foo_module, bar_module);
|
||||||
|
|
||||||
assert_eq!(&src, foo_module.search_path().unwrap());
|
assert_eq!(&src, foo_module.search_path(&db).unwrap());
|
||||||
assert_eq!(&foo, foo_module.file().unwrap().path(&db));
|
assert_eq!(&foo, foo_module.file(&db).unwrap().path(&db));
|
||||||
|
|
||||||
// `foo` and `bar` shouldn't resolve to the same file
|
// `foo` and `bar` shouldn't resolve to the same file
|
||||||
|
|
||||||
assert_eq!(&src, bar_module.search_path().unwrap());
|
assert_eq!(&src, bar_module.search_path(&db).unwrap());
|
||||||
assert_eq!(&bar, bar_module.file().unwrap().path(&db));
|
assert_eq!(&bar, bar_module.file(&db).unwrap().path(&db));
|
||||||
assert_eq!(&foo, foo_module.file().unwrap().path(&db));
|
assert_eq!(&foo, foo_module.file(&db).unwrap().path(&db));
|
||||||
|
|
||||||
assert_ne!(&foo_module, &bar_module);
|
assert_ne!(&foo_module, &bar_module);
|
||||||
|
|
||||||
|
@ -1465,6 +1471,13 @@ mod tests {
|
||||||
|
|
||||||
let foo_module_name = ModuleName::new_static("foo").unwrap();
|
let foo_module_name = ModuleName::new_static("foo").unwrap();
|
||||||
let foo_module = resolve_module(&db, &foo_module_name).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_path = src.join("bar.py");
|
||||||
let bar = system_path_to_file(&db, &bar_path).expect("bar.py to exist");
|
let bar = system_path_to_file(&db, &bar_path).expect("bar.py to exist");
|
||||||
|
@ -1479,6 +1492,15 @@ mod tests {
|
||||||
// for resolving `foo`.
|
// for resolving `foo`.
|
||||||
|
|
||||||
let foo_module2 = resolve_module(&db, &foo_module_name);
|
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!(
|
assert!(
|
||||||
!db.take_salsa_events()
|
!db.take_salsa_events()
|
||||||
|
@ -1486,7 +1508,7 @@ mod tests {
|
||||||
.any(|event| { matches!(event.kind, salsa::EventKind::WillExecute { .. }) })
|
.any(|event| { matches!(event.kind, salsa::EventKind::WillExecute { .. }) })
|
||||||
);
|
);
|
||||||
|
|
||||||
assert_eq!(Some(foo_module), foo_module2);
|
assert_eq!(Some(foo_pieces), foo_pieces2);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
@ -1504,7 +1526,7 @@ mod tests {
|
||||||
let foo_file = system_path_to_file(&db, &foo_path).expect("foo.py to exist");
|
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");
|
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(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
@ -1520,7 +1542,7 @@ mod tests {
|
||||||
let foo_module = resolve_module(&db, &foo_module_name).expect("foo module to exist");
|
let foo_module = resolve_module(&db, &foo_module_name).expect("foo module to exist");
|
||||||
let foo_init_path = src.join("foo/__init__.py");
|
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`
|
// Delete `foo/__init__.py` and the `foo` folder. `foo` should now resolve to `foo.py`
|
||||||
db.memory_file_system().remove_file(&foo_init_path)?;
|
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());
|
File::sync_path(&mut db, foo_init_path.parent().unwrap());
|
||||||
|
|
||||||
let foo_module = resolve_module(&db, &foo_module_name).expect("Foo module to resolve");
|
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(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
@ -1556,9 +1578,9 @@ mod tests {
|
||||||
let stdlib_functools_path = stdlib.join("functools.pyi");
|
let stdlib_functools_path = stdlib.join("functools.pyi");
|
||||||
|
|
||||||
let functools_module = resolve_module(&db, &functools_module_name).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!(
|
assert_eq!(
|
||||||
Ok(functools_module.file().unwrap()),
|
Ok(functools_module.file(&db).unwrap()),
|
||||||
system_path_to_file(&db, &stdlib_functools_path)
|
system_path_to_file(&db, &stdlib_functools_path)
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -1569,6 +1591,8 @@ mod tests {
|
||||||
db.write_file(&site_packages_functools_path, "f: int")
|
db.write_file(&site_packages_functools_path, "f: int")
|
||||||
.unwrap();
|
.unwrap();
|
||||||
let functools_module = resolve_module(&db, &functools_module_name).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();
|
let events = db.take_salsa_events();
|
||||||
assert_function_query_was_not_run(
|
assert_function_query_was_not_run(
|
||||||
&db,
|
&db,
|
||||||
|
@ -1576,9 +1600,9 @@ mod tests {
|
||||||
ModuleNameIngredient::new(&db, functools_module_name, ModuleResolveMode::StubsAllowed),
|
ModuleNameIngredient::new(&db, functools_module_name, ModuleResolveMode::StubsAllowed),
|
||||||
&events,
|
&events,
|
||||||
);
|
);
|
||||||
assert_eq!(functools_module.search_path().unwrap(), &stdlib);
|
assert_eq!(&functools_search_path, &stdlib);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
Ok(functools_module.file().unwrap()),
|
Ok(functools_file),
|
||||||
system_path_to_file(&db, &stdlib_functools_path)
|
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_name = ModuleName::new_static("functools").unwrap();
|
||||||
let functools_module = resolve_module(&db, &functools_module_name).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!(
|
assert_eq!(
|
||||||
Ok(functools_module.file().unwrap()),
|
Ok(functools_module.file(&db).unwrap()),
|
||||||
system_path_to_file(&db, stdlib.join("functools.pyi"))
|
system_path_to_file(&db, stdlib.join("functools.pyi"))
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -1613,9 +1637,9 @@ mod tests {
|
||||||
let src_functools_path = src.join("functools.py");
|
let src_functools_path = src.join("functools.py");
|
||||||
db.write_file(&src_functools_path, "FOO: int").unwrap();
|
db.write_file(&src_functools_path, "FOO: int").unwrap();
|
||||||
let functools_module = resolve_module(&db, &functools_module_name).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!(
|
assert_eq!(
|
||||||
Ok(functools_module.file().unwrap()),
|
Ok(functools_module.file(&db).unwrap()),
|
||||||
system_path_to_file(&db, &src_functools_path)
|
system_path_to_file(&db, &src_functools_path)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -1644,9 +1668,9 @@ mod tests {
|
||||||
let src_functools_path = src.join("functools.py");
|
let src_functools_path = src.join("functools.py");
|
||||||
|
|
||||||
let functools_module = resolve_module(&db, &functools_module_name).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!(
|
assert_eq!(
|
||||||
Ok(functools_module.file().unwrap()),
|
Ok(functools_module.file(&db).unwrap()),
|
||||||
system_path_to_file(&db, &src_functools_path)
|
system_path_to_file(&db, &src_functools_path)
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -1657,9 +1681,9 @@ mod tests {
|
||||||
.unwrap();
|
.unwrap();
|
||||||
File::sync_path(&mut db, &src_functools_path);
|
File::sync_path(&mut db, &src_functools_path);
|
||||||
let functools_module = resolve_module(&db, &functools_module_name).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!(
|
assert_eq!(
|
||||||
Ok(functools_module.file().unwrap()),
|
Ok(functools_module.file(&db).unwrap()),
|
||||||
system_path_to_file(&db, stdlib.join("functools.pyi"))
|
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();
|
let foo_bar_module = resolve_module(&db, &foo_bar_module_name).unwrap();
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
foo_module.file().unwrap().path(&db),
|
foo_module.file(&db).unwrap().path(&db),
|
||||||
&FilePath::system("/x/src/foo/__init__.py")
|
&FilePath::system("/x/src/foo/__init__.py")
|
||||||
);
|
);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
foo_bar_module.file().unwrap().path(&db),
|
foo_bar_module.file(&db).unwrap().path(&db),
|
||||||
&FilePath::system("/x/src/foo/bar.py")
|
&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_name = ModuleName::new_static("bar").unwrap();
|
||||||
let bar_module = resolve_module(&db, &bar_module_name).unwrap();
|
let bar_module = resolve_module(&db, &bar_module_name).unwrap();
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
bar_module.file().unwrap().path(&db),
|
bar_module.file(&db).unwrap().path(&db),
|
||||||
&FilePath::system("/y/src/bar.py")
|
&FilePath::system("/y/src/bar.py")
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -1733,7 +1757,7 @@ mod tests {
|
||||||
let foo_module = resolve_module(&db, &foo_module_name).unwrap();
|
let foo_module = resolve_module(&db, &foo_module_name).unwrap();
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
foo_module.file().unwrap().path(&db),
|
foo_module.file(&db).unwrap().path(&db),
|
||||||
&FilePath::system("/x/y/src/foo.pyi")
|
&FilePath::system("/x/y/src/foo.pyi")
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -1784,19 +1808,19 @@ not_a_directory
|
||||||
let spam_module = resolve_module(&db, &spam_module_name).unwrap();
|
let spam_module = resolve_module(&db, &spam_module_name).unwrap();
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
foo_module.file().unwrap().path(&db),
|
foo_module.file(&db).unwrap().path(&db),
|
||||||
&FilePath::system("/x/y/src/foo.pyi")
|
&FilePath::system("/x/y/src/foo.pyi")
|
||||||
);
|
);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
a_module.file().unwrap().path(&db),
|
a_module.file(&db).unwrap().path(&db),
|
||||||
&FilePath::system("/a.py")
|
&FilePath::system("/a.py")
|
||||||
);
|
);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
b_module.file().unwrap().path(&db),
|
b_module.file(&db).unwrap().path(&db),
|
||||||
&FilePath::system("/baz/b.py")
|
&FilePath::system("/baz/b.py")
|
||||||
);
|
);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
spam_module.file().unwrap().path(&db),
|
spam_module.file(&db).unwrap().path(&db),
|
||||||
&FilePath::System(site_packages.join("spam/spam.py"))
|
&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();
|
let foo_module = resolve_module(&db, &foo_module_name).unwrap();
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
foo_module.file().unwrap().path(&db),
|
foo_module.file(&db).unwrap().path(&db),
|
||||||
&FilePath::system("/x/src/foo.py")
|
&FilePath::system("/x/src/foo.py")
|
||||||
);
|
);
|
||||||
|
|
||||||
db.clear_salsa_events();
|
db.clear_salsa_events();
|
||||||
let bar_module = resolve_module(&db, &bar_module_name).unwrap();
|
let bar_module = resolve_module(&db, &bar_module_name).unwrap();
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
bar_module.file().unwrap().path(&db),
|
bar_module.file(&db).unwrap().path(&db),
|
||||||
&FilePath::system("/y/src/bar.py")
|
&FilePath::system("/y/src/bar.py")
|
||||||
);
|
);
|
||||||
let events = db.take_salsa_events();
|
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_name = ModuleName::new_static("foo").unwrap();
|
||||||
let foo_module = resolve_module(&db, &foo_module_name).unwrap();
|
let foo_module = resolve_module(&db, &foo_module_name).unwrap();
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
foo_module.file().unwrap().path(&db),
|
foo_module.file(&db).unwrap().path(&db),
|
||||||
&FilePath::system("/x/src/foo.py")
|
&FilePath::system("/x/src/foo.py")
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -1877,7 +1901,7 @@ not_a_directory
|
||||||
let foo_module = resolve_module(&db, &foo_module_name).unwrap();
|
let foo_module = resolve_module(&db, &foo_module_name).unwrap();
|
||||||
let src_path = SystemPathBuf::from("/x/src");
|
let src_path = SystemPathBuf::from("/x/src");
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
foo_module.file().unwrap().path(&db),
|
foo_module.file(&db).unwrap().path(&db),
|
||||||
&FilePath::System(src_path.join("foo.py"))
|
&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_name = ModuleName::new_static("a").unwrap();
|
||||||
let a_module = resolve_module(&db, &a_module_name).unwrap();
|
let a_module = resolve_module(&db, &a_module_name).unwrap();
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
a_module.file().unwrap().path(&db),
|
a_module.file(&db).unwrap().path(&db),
|
||||||
&editable_install_location
|
&editable_install_location
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -1962,7 +1986,7 @@ not_a_directory
|
||||||
// second `site-packages` directory
|
// second `site-packages` directory
|
||||||
let a_module = resolve_module(&db, &a_module_name).unwrap();
|
let a_module = resolve_module(&db, &a_module_name).unwrap();
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
a_module.file().unwrap().path(&db),
|
a_module.file(&db).unwrap().path(&db),
|
||||||
&system_site_packages_location
|
&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");
|
let a_module = resolve_module(&db, &a_module_name).expect("a.py to resolve");
|
||||||
assert!(
|
assert!(
|
||||||
a_module
|
a_module
|
||||||
.file()
|
.file(&db)
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.path(&db)
|
.path(&db)
|
||||||
.as_str()
|
.as_str()
|
||||||
|
@ -2059,6 +2083,6 @@ not_a_directory
|
||||||
|
|
||||||
let foo_module_file = File::new(&db, FilePath::System(installed_foo_module));
|
let foo_module_file = File::new(&db, FilePath::System(installed_foo_module));
|
||||||
let module = file_to_module(&db, foo_module_file).unwrap();
|
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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -374,7 +374,7 @@ pub(crate) fn imported_symbol<'db>(
|
||||||
pub(crate) fn builtins_symbol<'db>(db: &'db dyn Db, symbol: &str) -> PlaceAndQualifiers<'db> {
|
pub(crate) fn builtins_symbol<'db>(db: &'db dyn Db, symbol: &str) -> PlaceAndQualifiers<'db> {
|
||||||
resolve_module(db, &KnownModule::Builtins.name())
|
resolve_module(db, &KnownModule::Builtins.name())
|
||||||
.and_then(|module| {
|
.and_then(|module| {
|
||||||
let file = module.file()?;
|
let file = module.file(db)?;
|
||||||
Some(
|
Some(
|
||||||
symbol_impl(
|
symbol_impl(
|
||||||
db,
|
db,
|
||||||
|
@ -404,7 +404,7 @@ pub(crate) fn known_module_symbol<'db>(
|
||||||
) -> PlaceAndQualifiers<'db> {
|
) -> PlaceAndQualifiers<'db> {
|
||||||
resolve_module(db, &known_module.name())
|
resolve_module(db, &known_module.name())
|
||||||
.and_then(|module| {
|
.and_then(|module| {
|
||||||
let file = module.file()?;
|
let file = module.file(db)?;
|
||||||
Some(imported_symbol(db, file, symbol, None))
|
Some(imported_symbol(db, file, symbol, None))
|
||||||
})
|
})
|
||||||
.unwrap_or_default()
|
.unwrap_or_default()
|
||||||
|
@ -442,7 +442,7 @@ pub(crate) fn builtins_module_scope(db: &dyn Db) -> Option<ScopeId<'_>> {
|
||||||
/// Can return `None` if a custom typeshed is used that is missing the core module in question.
|
/// 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<ScopeId<'_>> {
|
fn core_module_scope(db: &dyn Db, core_module: KnownModule) -> Option<ScopeId<'_>> {
|
||||||
let module = resolve_module(db, &core_module.name())?;
|
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
|
/// Infer the combined type from an iterator of bindings, and return it
|
||||||
|
@ -812,7 +812,7 @@ fn symbol_impl<'db>(
|
||||||
|
|
||||||
if name == "platform"
|
if name == "platform"
|
||||||
&& file_to_module(db, scope.file(db))
|
&& 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) {
|
match Program::get(db).python_platform(db) {
|
||||||
crate::PythonPlatform::Identifier(platform) => {
|
crate::PythonPlatform::Identifier(platform) => {
|
||||||
|
|
|
@ -1278,7 +1278,7 @@ impl<'ast> Visitor<'ast> for SemanticIndexBuilder<'_, 'ast> {
|
||||||
continue;
|
continue;
|
||||||
};
|
};
|
||||||
|
|
||||||
let Some(referenced_module) = module.file() else {
|
let Some(referenced_module) = module.file(self.db) else {
|
||||||
continue;
|
continue;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -257,7 +257,7 @@ impl<'db> Visitor<'db> for ExportFinder<'db> {
|
||||||
.iter()
|
.iter()
|
||||||
.flat_map(|module| {
|
.flat_map(|module| {
|
||||||
module
|
module
|
||||||
.file()
|
.file(self.db)
|
||||||
.map(|file| exported_names(self.db, file))
|
.map(|file| exported_names(self.db, file))
|
||||||
.unwrap_or_default()
|
.unwrap_or_default()
|
||||||
})
|
})
|
||||||
|
|
|
@ -67,8 +67,8 @@ impl<'db> SemanticModel<'db> {
|
||||||
tracing::debug!("Could not resolve module from `{module_name:?}`");
|
tracing::debug!("Could not resolve module from `{module_name:?}`");
|
||||||
return vec![];
|
return vec![];
|
||||||
};
|
};
|
||||||
let ty = Type::module_literal(self.db, self.file, &module);
|
let ty = Type::module_literal(self.db, self.file, module);
|
||||||
let builtin = module.is_known(KnownModule::Builtins);
|
let builtin = module.is_known(self.db, KnownModule::Builtins);
|
||||||
|
|
||||||
let mut completions = vec![];
|
let mut completions = vec![];
|
||||||
for crate::types::Member { name, ty } in crate::types::all_members(self.db, ty) {
|
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 {
|
let Some(submodule) = resolve_module(self.db, &submodule_name) else {
|
||||||
continue;
|
continue;
|
||||||
};
|
};
|
||||||
let ty = Type::module_literal(self.db, self.file, &submodule);
|
let ty = Type::module_literal(self.db, self.file, submodule);
|
||||||
completions.push(Completion {
|
completions.push(Completion {
|
||||||
name: submodule_basename.clone(),
|
name: submodule_basename.clone(),
|
||||||
ty,
|
ty,
|
||||||
|
|
|
@ -841,11 +841,11 @@ impl<'db> Type<'db> {
|
||||||
matches!(self, Type::PropertyInstance(..))
|
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(
|
Self::ModuleLiteral(ModuleLiteralType::new(
|
||||||
db,
|
db,
|
||||||
submodule,
|
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;
|
return;
|
||||||
};
|
};
|
||||||
let module = module_type.module(db);
|
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;
|
return;
|
||||||
};
|
};
|
||||||
let Some(module_member_with_same_name) = ty
|
let Some(module_member_with_same_name) = ty
|
||||||
|
@ -7722,7 +7722,7 @@ pub enum WrapperDescriptorKind {
|
||||||
#[derive(PartialOrd, Ord)]
|
#[derive(PartialOrd, Ord)]
|
||||||
pub struct ModuleLiteralType<'db> {
|
pub struct ModuleLiteralType<'db> {
|
||||||
/// The imported module.
|
/// The imported module.
|
||||||
pub module: Module,
|
pub module: Module<'db>,
|
||||||
|
|
||||||
/// The file in which this module was imported.
|
/// 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<File> {
|
fn importing_file(self, db: &'db dyn Db) -> Option<File> {
|
||||||
debug_assert_eq!(
|
debug_assert_eq!(
|
||||||
self._importing_file(db).is_some(),
|
self._importing_file(db).is_some(),
|
||||||
self.module(db).kind().is_package()
|
self.module(db).kind(db).is_package()
|
||||||
);
|
);
|
||||||
self._importing_file(db)
|
self._importing_file(db)
|
||||||
}
|
}
|
||||||
|
@ -7753,17 +7753,17 @@ impl<'db> ModuleLiteralType<'db> {
|
||||||
self.importing_file(db)
|
self.importing_file(db)
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.flat_map(|file| imported_modules(db, file))
|
.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))
|
.filter_map(|relative_submodule| relative_submodule.components().next().map(Name::from))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn resolve_submodule(self, db: &'db dyn Db, name: &str) -> Option<Type<'db>> {
|
fn resolve_submodule(self, db: &'db dyn Db, name: &str) -> Option<Type<'db>> {
|
||||||
let importing_file = self.importing_file(db)?;
|
let importing_file = self.importing_file(db)?;
|
||||||
let relative_submodule_name = ModuleName::new(name)?;
|
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);
|
absolute_submodule_name.extend(&relative_submodule_name);
|
||||||
let submodule = resolve_module(db, &absolute_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> {
|
fn static_member(self, db: &'db dyn Db, name: &str) -> PlaceAndQualifiers<'db> {
|
||||||
|
@ -7792,7 +7792,7 @@ impl<'db> ModuleLiteralType<'db> {
|
||||||
}
|
}
|
||||||
|
|
||||||
self.module(db)
|
self.module(db)
|
||||||
.file()
|
.file(db)
|
||||||
.map(|file| imported_symbol(db, file, name, None))
|
.map(|file| imported_symbol(db, file, name, None))
|
||||||
.unwrap_or_default()
|
.unwrap_or_default()
|
||||||
}
|
}
|
||||||
|
|
|
@ -648,7 +648,7 @@ impl<'db> Bindings<'db> {
|
||||||
Type::ModuleLiteral(module_literal) => {
|
Type::ModuleLiteral(module_literal) => {
|
||||||
let all_names = module_literal
|
let all_names = module_literal
|
||||||
.module(db)
|
.module(db)
|
||||||
.file()
|
.file(db)
|
||||||
.map(|file| dunder_all_names(db, file))
|
.map(|file| dunder_all_names(db, file))
|
||||||
.unwrap_or_default();
|
.unwrap_or_default();
|
||||||
match all_names {
|
match all_names {
|
||||||
|
|
|
@ -3498,7 +3498,7 @@ impl KnownClass {
|
||||||
};
|
};
|
||||||
|
|
||||||
candidate
|
candidate
|
||||||
.check_module(db, file_to_module(db, file)?.known()?)
|
.check_module(db, file_to_module(db, file)?.known(db)?)
|
||||||
.then_some(candidate)
|
.then_some(candidate)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -4067,7 +4067,11 @@ mod tests {
|
||||||
let class_module = resolve_module(&db, &class.canonical_module(&db).name()).unwrap();
|
let class_module = resolve_module(&db, &class.canonical_module(&db).name()).unwrap();
|
||||||
|
|
||||||
assert_eq!(
|
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),
|
Some(class),
|
||||||
"`KnownClass::candidate_from_str` appears to be missing a case for `{class_name}`"
|
"`KnownClass::candidate_from_str` appears to be missing a case for `{class_name}`"
|
||||||
);
|
);
|
||||||
|
|
|
@ -7,7 +7,7 @@ use ruff_text_size::{TextLen, TextRange};
|
||||||
|
|
||||||
#[derive(Debug, PartialEq, Eq, Hash)]
|
#[derive(Debug, PartialEq, Eq, Hash)]
|
||||||
pub enum TypeDefinition<'db> {
|
pub enum TypeDefinition<'db> {
|
||||||
Module(Module),
|
Module(Module<'db>),
|
||||||
Class(Definition<'db>),
|
Class(Definition<'db>),
|
||||||
Function(Definition<'db>),
|
Function(Definition<'db>),
|
||||||
TypeVar(Definition<'db>),
|
TypeVar(Definition<'db>),
|
||||||
|
@ -31,7 +31,7 @@ impl TypeDefinition<'_> {
|
||||||
pub fn full_range(&self, db: &dyn Db) -> Option<FileRange> {
|
pub fn full_range(&self, db: &dyn Db) -> Option<FileRange> {
|
||||||
match self {
|
match self {
|
||||||
Self::Module(module) => {
|
Self::Module(module) => {
|
||||||
let file = module.file()?;
|
let file = module.file(db)?;
|
||||||
let source = source_text(db, file);
|
let source = source_text(db, file);
|
||||||
Some(FileRange::new(file, TextRange::up_to(source.text_len())))
|
Some(FileRange::new(file, TextRange::up_to(source.text_len())))
|
||||||
}
|
}
|
||||||
|
|
|
@ -2522,9 +2522,9 @@ pub(super) fn hint_if_stdlib_submodule_exists_on_other_versions(
|
||||||
db: &dyn Db,
|
db: &dyn Db,
|
||||||
mut diagnostic: LintDiagnosticGuard,
|
mut diagnostic: LintDiagnosticGuard,
|
||||||
full_submodule_name: &ModuleName,
|
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;
|
return;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -2547,7 +2547,7 @@ pub(super) fn hint_if_stdlib_submodule_exists_on_other_versions(
|
||||||
diagnostic.info(format_args!(
|
diagnostic.info(format_args!(
|
||||||
"The stdlib module `{module_name}` only has a `{name}` \
|
"The stdlib module `{module_name}` only has a `{name}` \
|
||||||
submodule on Python {version_range}",
|
submodule on Python {version_range}",
|
||||||
module_name = parent_module.name(),
|
module_name = parent_module.name(db),
|
||||||
name = full_submodule_name
|
name = full_submodule_name
|
||||||
.components()
|
.components()
|
||||||
.next_back()
|
.next_back()
|
||||||
|
|
|
@ -102,7 +102,7 @@ impl Display for DisplayRepresentation<'_> {
|
||||||
},
|
},
|
||||||
Type::PropertyInstance(_) => f.write_str("property"),
|
Type::PropertyInstance(_) => f.write_str("property"),
|
||||||
Type::ModuleLiteral(module) => {
|
Type::ModuleLiteral(module) => {
|
||||||
write!(f, "<module '{}'>", module.module(self.db).name())
|
write!(f, "<module '{}'>", module.module(self.db).name(self.db))
|
||||||
}
|
}
|
||||||
Type::ClassLiteral(class) => {
|
Type::ClassLiteral(class) => {
|
||||||
write!(f, "<class '{}'>", class.name(self.db))
|
write!(f, "<class '{}'>", class.name(self.db))
|
||||||
|
|
|
@ -1097,7 +1097,7 @@ impl KnownFunction {
|
||||||
) -> Option<Self> {
|
) -> Option<Self> {
|
||||||
let candidate = Self::from_str(name).ok()?;
|
let candidate = Self::from_str(name).ok()?;
|
||||||
candidate
|
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)
|
.then_some(candidate)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1368,7 +1368,7 @@ impl KnownFunction {
|
||||||
return;
|
return;
|
||||||
};
|
};
|
||||||
|
|
||||||
overload.set_return_type(Type::module_literal(db, file, &module));
|
overload.set_return_type(Type::module_literal(db, file, module));
|
||||||
}
|
}
|
||||||
|
|
||||||
_ => {}
|
_ => {}
|
||||||
|
|
|
@ -156,7 +156,7 @@ impl<'db> AllMembers<'db> {
|
||||||
self.extend_with_type(db, KnownClass::ModuleType.to_instance(db));
|
self.extend_with_type(db, KnownClass::ModuleType.to_instance(db));
|
||||||
let module = literal.module(db);
|
let module = literal.module(db);
|
||||||
|
|
||||||
let Some(file) = module.file() else {
|
let Some(file) = module.file(db) else {
|
||||||
return;
|
return;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -544,7 +544,7 @@ pub fn definitions_for_attribute<'db>(
|
||||||
for ty in expanded_tys {
|
for ty in expanded_tys {
|
||||||
// Handle modules
|
// Handle modules
|
||||||
if let Type::ModuleLiteral(module_literal) = ty {
|
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);
|
let module_scope = global_scope(db, module_file);
|
||||||
for def in find_symbol_in_scope(db, module_scope, name_str) {
|
for def in find_symbol_in_scope(db, module_scope, name_str) {
|
||||||
resolved.extend(resolve_definition(db, def, Some(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
|
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
|
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 {
|
let Some(resolved_module) = resolve_module(db, &module_name) else {
|
||||||
return Vec::new();
|
return Vec::new();
|
||||||
};
|
};
|
||||||
resolved_module.file()
|
resolved_module.file(db)
|
||||||
};
|
};
|
||||||
|
|
||||||
let Some(module_file) = module_file else {
|
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.
|
// It's definitely a stub, so now rerun module resolution but with stubs disabled.
|
||||||
let stub_module = file_to_module(db, stub_file)?;
|
let stub_module = file_to_module(db, stub_file)?;
|
||||||
trace!("Found stub module: {}", stub_module.name());
|
trace!("Found stub module: {}", stub_module.name(db));
|
||||||
let real_module = resolve_real_module(db, stub_module.name())?;
|
let real_module = resolve_real_module(db, stub_module.name(db))?;
|
||||||
trace!("Found real module: {}", real_module.name());
|
trace!("Found real module: {}", real_module.name(db));
|
||||||
let real_file = real_module.file()?;
|
let real_file = real_module.file(db)?;
|
||||||
trace!("Found real file: {}", real_file.path(db));
|
trace!("Found real file: {}", real_file.path(db));
|
||||||
|
|
||||||
// A definition has a "Definition Path" in a file made of nested definitions (~scopes):
|
// A definition has a "Definition Path" in a file made of nested definitions (~scopes):
|
||||||
|
|
|
@ -4866,7 +4866,7 @@ impl<'db, 'ast> TypeInferenceBuilder<'db, 'ast> {
|
||||||
return;
|
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
|
// The indirection of having `star_import_info` as a separate variable
|
||||||
// is required in order to make the borrow checker happy.
|
// 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).
|
// (e.g. `from parent import submodule` inside the `parent` module).
|
||||||
let import_is_self_referential = module_ty
|
let import_is_self_referential = module_ty
|
||||||
.into_module_literal()
|
.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.
|
// First try loading the requested attribute from the module.
|
||||||
if !import_is_self_referential {
|
if !import_is_self_referential {
|
||||||
|
@ -4990,7 +4990,7 @@ impl<'db, 'ast> TypeInferenceBuilder<'db, 'ast> {
|
||||||
self.db(),
|
self.db(),
|
||||||
diagnostic,
|
diagnostic,
|
||||||
&full_submodule_name,
|
&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<Type<'db>> {
|
fn module_type_from_name(&self, module_name: &ModuleName) -> Option<Type<'db>> {
|
||||||
resolve_module(self.db(), module_name)
|
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> {
|
fn infer_decorator(&mut self, decorator: &ast::Decorator) -> Type<'db> {
|
||||||
|
|
|
@ -187,7 +187,7 @@ impl SpecialFormType {
|
||||||
) -> Option<Self> {
|
) -> Option<Self> {
|
||||||
let candidate = Self::from_str(symbol_name).ok()?;
|
let candidate = Self::from_str(symbol_name).ok()?;
|
||||||
candidate
|
candidate
|
||||||
.check_module(file_to_module(db, file)?.known()?)
|
.check_module(file_to_module(db, file)?.known(db)?)
|
||||||
.then_some(candidate)
|
.then_some(candidate)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue