From 2a8f95c437d64fdd9b2d512ac065288d775aabfb Mon Sep 17 00:00:00 2001 From: Alex Waygood Date: Mon, 22 Jul 2024 20:44:27 +0100 Subject: [PATCH] [red-knot] Use a distinct type for module search paths in the module resolver (#12379) --- crates/red_knot_module_resolver/src/module.rs | 10 +- crates/red_knot_module_resolver/src/path.rs | 507 ++++++++++-------- .../red_knot_module_resolver/src/resolver.rs | 119 ++-- crates/ruff_db/src/program.rs | 4 +- 4 files changed, 329 insertions(+), 311 deletions(-) diff --git a/crates/red_knot_module_resolver/src/module.rs b/crates/red_knot_module_resolver/src/module.rs index 9592cbe65df84..8115f9da967ba 100644 --- a/crates/red_knot_module_resolver/src/module.rs +++ b/crates/red_knot_module_resolver/src/module.rs @@ -5,7 +5,7 @@ use ruff_db::files::File; use crate::db::Db; use crate::module_name::ModuleName; -use crate::path::{ModuleResolutionPathBuf, ModuleResolutionPathRef}; +use crate::path::ModuleSearchPath; /// Representation of a Python module. #[derive(Clone, PartialEq, Eq)] @@ -17,7 +17,7 @@ impl Module { pub(crate) fn new( name: ModuleName, kind: ModuleKind, - search_path: Arc, + search_path: ModuleSearchPath, file: File, ) -> Self { Self { @@ -41,8 +41,8 @@ impl Module { } /// The search path from which the module was resolved. - pub(crate) fn search_path(&self) -> ModuleResolutionPathRef { - ModuleResolutionPathRef::from(&*self.inner.search_path) + pub(crate) fn search_path(&self) -> &ModuleSearchPath { + &self.inner.search_path } /// Determine whether this module is a single-file module or a package @@ -77,7 +77,7 @@ impl salsa::DebugWithDb for Module { struct ModuleInner { name: ModuleName, kind: ModuleKind, - search_path: Arc, + search_path: ModuleSearchPath, file: File, } diff --git a/crates/red_knot_module_resolver/src/path.rs b/crates/red_knot_module_resolver/src/path.rs index d0577a5055266..83692231d86e2 100644 --- a/crates/red_knot_module_resolver/src/path.rs +++ b/crates/red_knot_module_resolver/src/path.rs @@ -4,6 +4,8 @@ //! use std::fmt; +use std::ops::Deref; +use std::sync::Arc; use ruff_db::files::{system_path_to_file, vendored_path_to_file, File, FilePath}; use ruff_db::system::{System, SystemPath, SystemPathBuf}; @@ -68,7 +70,7 @@ impl<'a> From<&'a FilePath> for FilePathRef<'a> { /// /// [the order given in the typing spec]: https://typing.readthedocs.io/en/latest/spec/distributing.html#import-resolution-ordering #[derive(Debug, Clone, PartialEq, Eq, Hash)] -enum ModuleResolutionPathBufInner { +enum ModulePathBufInner { Extra(SystemPathBuf), FirstParty(SystemPathBuf), StandardLibrary(FilePath), @@ -76,7 +78,7 @@ enum ModuleResolutionPathBufInner { EditableInstall(SystemPathBuf), } -impl ModuleResolutionPathBufInner { +impl ModulePathBufInner { fn push(&mut self, component: &str) { let extension = camino::Utf8Path::new(component).extension(); match self { @@ -153,9 +155,9 @@ impl ModuleResolutionPathBufInner { } #[derive(Clone, PartialEq, Eq, Hash)] -pub(crate) struct ModuleResolutionPathBuf(ModuleResolutionPathBufInner); +pub(crate) struct ModulePathBuf(ModulePathBufInner); -impl ModuleResolutionPathBuf { +impl ModulePathBuf { /// Push a new part to the path, /// while maintaining the invariant that the path can only have `.py` or `.pyi` extensions. /// For the stdlib variant specifically, it may only have a `.pyi` extension. @@ -171,7 +173,7 @@ impl ModuleResolutionPathBuf { let path = path.into(); path.extension() .map_or(true, |ext| matches!(ext, "py" | "pyi")) - .then_some(Self(ModuleResolutionPathBufInner::Extra(path))) + .then_some(Self(ModulePathBufInner::Extra(path))) } #[must_use] @@ -179,28 +181,14 @@ impl ModuleResolutionPathBuf { let path = path.into(); path.extension() .map_or(true, |ext| matches!(ext, "pyi" | "py")) - .then_some(Self(ModuleResolutionPathBufInner::FirstParty(path))) + .then_some(Self(ModulePathBufInner::FirstParty(path))) } #[must_use] pub(crate) fn standard_library(path: FilePath) -> Option { path.extension() .map_or(true, |ext| ext == "pyi") - .then_some(Self(ModuleResolutionPathBufInner::StandardLibrary(path))) - } - - #[must_use] - pub(crate) fn stdlib_from_custom_typeshed_root(typeshed_root: &SystemPath) -> Option { - Self::standard_library(FilePath::System( - typeshed_root.join(SystemPath::new("stdlib")), - )) - } - - #[must_use] - pub(crate) fn vendored_stdlib() -> Self { - Self(ModuleResolutionPathBufInner::StandardLibrary( - FilePath::Vendored(VendoredPathBuf::from("stdlib")), - )) + .then_some(Self(ModulePathBufInner::StandardLibrary(path))) } #[must_use] @@ -208,7 +196,7 @@ impl ModuleResolutionPathBuf { let path = path.into(); path.extension() .map_or(true, |ext| matches!(ext, "pyi" | "py")) - .then_some(Self(ModuleResolutionPathBufInner::SitePackages(path))) + .then_some(Self(ModulePathBufInner::SitePackages(path))) } #[must_use] @@ -220,104 +208,115 @@ impl ModuleResolutionPathBuf { // TODO: Add Salsa invalidation to this system call: system .is_directory(&path) - .then_some(Self(ModuleResolutionPathBufInner::EditableInstall(path))) + .then_some(Self(ModulePathBufInner::EditableInstall(path))) } #[must_use] pub(crate) fn is_regular_package(&self, search_path: &Self, resolver: &ResolverState) -> bool { - ModuleResolutionPathRef::from(self).is_regular_package(search_path, resolver) + ModulePathRef::from(self).is_regular_package(search_path, resolver) } #[must_use] pub(crate) fn is_directory(&self, search_path: &Self, resolver: &ResolverState) -> bool { - ModuleResolutionPathRef::from(self).is_directory(search_path, resolver) + ModulePathRef::from(self).is_directory(search_path, resolver) } #[must_use] pub(crate) const fn is_site_packages(&self) -> bool { - matches!(self.0, ModuleResolutionPathBufInner::SitePackages(_)) + matches!(self.0, ModulePathBufInner::SitePackages(_)) } #[must_use] pub(crate) const fn is_standard_library(&self) -> bool { - matches!(self.0, ModuleResolutionPathBufInner::StandardLibrary(_)) + matches!(self.0, ModulePathBufInner::StandardLibrary(_)) } #[must_use] pub(crate) fn with_pyi_extension(&self) -> Self { - ModuleResolutionPathRef::from(self).with_pyi_extension() + ModulePathRef::from(self).with_pyi_extension() } #[must_use] pub(crate) fn with_py_extension(&self) -> Option { - ModuleResolutionPathRef::from(self).with_py_extension() + ModulePathRef::from(self).with_py_extension() } #[must_use] pub(crate) fn relativize_path<'a>( &'a self, absolute_path: &'a FilePath, - ) -> Option> { - ModuleResolutionPathRef::from(self).relativize_path(&FilePathRef::from(absolute_path)) + ) -> Option> { + ModulePathRef::from(self).relativize_path(&FilePathRef::from(absolute_path)) } /// Returns `None` if the path doesn't exist, isn't accessible, or if the path points to a directory. pub(crate) fn to_file(&self, search_path: &Self, resolver: &ResolverState) -> Option { - ModuleResolutionPathRef::from(self).to_file(search_path, resolver) + ModulePathRef::from(self).to_file(search_path, resolver) } pub(crate) fn as_system_path(&self) -> Option<&SystemPathBuf> { match &self.0 { - ModuleResolutionPathBufInner::Extra(path) => Some(path), - ModuleResolutionPathBufInner::FirstParty(path) => Some(path), - ModuleResolutionPathBufInner::StandardLibrary(_) => None, - ModuleResolutionPathBufInner::SitePackages(path) => Some(path), - ModuleResolutionPathBufInner::EditableInstall(path) => Some(path), + ModulePathBufInner::Extra(path) => Some(path), + ModulePathBufInner::FirstParty(path) => Some(path), + ModulePathBufInner::StandardLibrary(_) => None, + ModulePathBufInner::SitePackages(path) => Some(path), + ModulePathBufInner::EditableInstall(path) => Some(path), } } } -impl fmt::Debug for ModuleResolutionPathBuf { +impl fmt::Debug for ModulePathBuf { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match &self.0 { - ModuleResolutionPathBufInner::Extra(path) => f - .debug_tuple("ModuleResolutionPathBuf::Extra") - .field(path) - .finish(), - ModuleResolutionPathBufInner::FirstParty(path) => f - .debug_tuple("ModuleResolutionPathBuf::FirstParty") + ModulePathBufInner::Extra(path) => { + f.debug_tuple("ModulePathBuf::Extra").field(path).finish() + } + ModulePathBufInner::FirstParty(path) => f + .debug_tuple("ModulePathBuf::FirstParty") .field(path) .finish(), - ModuleResolutionPathBufInner::SitePackages(path) => f - .debug_tuple("ModuleResolutionPathBuf::SitePackages") + ModulePathBufInner::SitePackages(path) => f + .debug_tuple("ModulePathBuf::SitePackages") .field(path) .finish(), - ModuleResolutionPathBufInner::StandardLibrary(path) => f - .debug_tuple("ModuleResolutionPathBuf::StandardLibrary") + ModulePathBufInner::StandardLibrary(path) => f + .debug_tuple("ModulePathBuf::StandardLibrary") .field(path) .finish(), - ModuleResolutionPathBufInner::EditableInstall(path) => f - .debug_tuple("ModuleResolutionPathBuf::EditableInstall") + ModulePathBufInner::EditableInstall(path) => f + .debug_tuple("ModulePathBuf::EditableInstall") .field(path) .finish(), } } } -impl PartialEq for ModuleResolutionPathBuf { +impl PartialEq for ModulePathBuf { fn eq(&self, other: &SystemPathBuf) -> bool { - ModuleResolutionPathRef::from(self) == **other + ModulePathRef::from(self) == **other + } +} + +impl PartialEq for SystemPathBuf { + fn eq(&self, other: &ModulePathBuf) -> bool { + other.eq(self) + } +} + +impl PartialEq for ModulePathBuf { + fn eq(&self, other: &VendoredPathBuf) -> bool { + ModulePathRef::from(self) == **other } } -impl PartialEq for SystemPathBuf { - fn eq(&self, other: &ModuleResolutionPathBuf) -> bool { +impl PartialEq for VendoredPathBuf { + fn eq(&self, other: &ModulePathBuf) -> bool { other.eq(self) } } #[derive(Debug, PartialEq, Eq, Hash, Clone, Copy)] -enum ModuleResolutionPathRefInner<'a> { +enum ModulePathRefInner<'a> { Extra(&'a SystemPath), FirstParty(&'a SystemPath), StandardLibrary(FilePathRef<'a>), @@ -325,7 +324,7 @@ enum ModuleResolutionPathRefInner<'a> { EditableInstall(&'a SystemPath), } -impl<'a> ModuleResolutionPathRefInner<'a> { +impl<'a> ModulePathRefInner<'a> { #[must_use] fn query_stdlib_version<'db>( module_path: &FilePathRef<'a>, @@ -463,45 +462,37 @@ impl<'a> ModuleResolutionPathRefInner<'a> { } #[must_use] - fn with_pyi_extension(&self) -> ModuleResolutionPathBufInner { + fn with_pyi_extension(&self) -> ModulePathBufInner { match self { - Self::Extra(path) => ModuleResolutionPathBufInner::Extra(path.with_extension("pyi")), - Self::FirstParty(path) => { - ModuleResolutionPathBufInner::FirstParty(path.with_extension("pyi")) - } + Self::Extra(path) => ModulePathBufInner::Extra(path.with_extension("pyi")), + Self::FirstParty(path) => ModulePathBufInner::FirstParty(path.with_extension("pyi")), Self::StandardLibrary(FilePathRef::System(path)) => { - ModuleResolutionPathBufInner::StandardLibrary(FilePath::System( - path.with_extension("pyi"), - )) + ModulePathBufInner::StandardLibrary(FilePath::System(path.with_extension("pyi"))) } Self::StandardLibrary(FilePathRef::Vendored(path)) => { - ModuleResolutionPathBufInner::StandardLibrary(FilePath::Vendored( - path.with_pyi_extension(), - )) + ModulePathBufInner::StandardLibrary(FilePath::Vendored(path.with_pyi_extension())) } Self::SitePackages(path) => { - ModuleResolutionPathBufInner::SitePackages(path.with_extension("pyi")) + ModulePathBufInner::SitePackages(path.with_extension("pyi")) } Self::EditableInstall(path) => { - ModuleResolutionPathBufInner::EditableInstall(path.with_extension("pyi")) + ModulePathBufInner::EditableInstall(path.with_extension("pyi")) } } } #[must_use] - fn with_py_extension(&self) -> Option { + fn with_py_extension(&self) -> Option { match self { - Self::Extra(path) => Some(ModuleResolutionPathBufInner::Extra( - path.with_extension("py"), - )), - Self::FirstParty(path) => Some(ModuleResolutionPathBufInner::FirstParty( - path.with_extension("py"), - )), + Self::Extra(path) => Some(ModulePathBufInner::Extra(path.with_extension("py"))), + Self::FirstParty(path) => { + Some(ModulePathBufInner::FirstParty(path.with_extension("py"))) + } Self::StandardLibrary(_) => None, - Self::SitePackages(path) => Some(ModuleResolutionPathBufInner::SitePackages( - path.with_extension("py"), - )), - Self::EditableInstall(path) => Some(ModuleResolutionPathBufInner::EditableInstall( + Self::SitePackages(path) => { + Some(ModulePathBufInner::SitePackages(path.with_extension("py"))) + } + Self::EditableInstall(path) => Some(ModulePathBufInner::EditableInstall( path.with_extension("py"), )), } @@ -567,9 +558,9 @@ impl<'a> ModuleResolutionPathRefInner<'a> { } #[derive(Clone, Copy, PartialEq, Eq)] -pub(crate) struct ModuleResolutionPathRef<'a>(ModuleResolutionPathRefInner<'a>); +pub(crate) struct ModulePathRef<'a>(ModulePathRefInner<'a>); -impl<'a> ModuleResolutionPathRef<'a> { +impl<'a> ModulePathRef<'a> { #[must_use] pub(crate) fn is_directory( &self, @@ -603,13 +594,13 @@ impl<'a> ModuleResolutionPathRef<'a> { } #[must_use] - pub(crate) fn with_pyi_extension(&self) -> ModuleResolutionPathBuf { - ModuleResolutionPathBuf(self.0.with_pyi_extension()) + pub(crate) fn with_pyi_extension(&self) -> ModulePathBuf { + ModulePathBuf(self.0.with_pyi_extension()) } #[must_use] - pub(crate) fn with_py_extension(self) -> Option { - self.0.with_py_extension().map(ModuleResolutionPathBuf) + pub(crate) fn with_py_extension(self) -> Option { + self.0.with_py_extension().map(ModulePathBuf) } #[must_use] @@ -618,123 +609,188 @@ impl<'a> ModuleResolutionPathRef<'a> { } } -impl fmt::Debug for ModuleResolutionPathRef<'_> { +impl fmt::Debug for ModulePathRef<'_> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match &self.0 { - ModuleResolutionPathRefInner::Extra(path) => f - .debug_tuple("ModuleResolutionPathRef::Extra") - .field(path) - .finish(), - ModuleResolutionPathRefInner::FirstParty(path) => f - .debug_tuple("ModuleResolutionPathRef::FirstParty") + ModulePathRefInner::Extra(path) => { + f.debug_tuple("ModulePathRef::Extra").field(path).finish() + } + ModulePathRefInner::FirstParty(path) => f + .debug_tuple("ModulePathRef::FirstParty") .field(path) .finish(), - ModuleResolutionPathRefInner::SitePackages(path) => f - .debug_tuple("ModuleResolutionPathRef::SitePackages") + ModulePathRefInner::SitePackages(path) => f + .debug_tuple("ModulePathRef::SitePackages") .field(path) .finish(), - ModuleResolutionPathRefInner::StandardLibrary(path) => f - .debug_tuple("ModuleResolutionPathRef::StandardLibrary") + ModulePathRefInner::StandardLibrary(path) => f + .debug_tuple("ModulePathRef::StandardLibrary") .field(path) .finish(), - ModuleResolutionPathRefInner::EditableInstall(path) => f - .debug_tuple("ModuleResolutionPathRef::EditableInstall") + ModulePathRefInner::EditableInstall(path) => f + .debug_tuple("ModulePathRef::EditableInstall") .field(path) .finish(), } } } -impl<'a> From<&'a ModuleResolutionPathBuf> for ModuleResolutionPathRef<'a> { - fn from(value: &'a ModuleResolutionPathBuf) -> Self { +impl<'a> From<&'a ModulePathBuf> for ModulePathRef<'a> { + fn from(value: &'a ModulePathBuf) -> Self { let inner = match &value.0 { - ModuleResolutionPathBufInner::Extra(path) => ModuleResolutionPathRefInner::Extra(path), - ModuleResolutionPathBufInner::FirstParty(path) => { - ModuleResolutionPathRefInner::FirstParty(path) - } - ModuleResolutionPathBufInner::StandardLibrary(FilePath::System(path)) => { - ModuleResolutionPathRefInner::StandardLibrary(FilePathRef::System(path)) - } - ModuleResolutionPathBufInner::StandardLibrary(FilePath::Vendored(path)) => { - ModuleResolutionPathRefInner::StandardLibrary(FilePathRef::Vendored(path)) - } - ModuleResolutionPathBufInner::SitePackages(path) => { - ModuleResolutionPathRefInner::SitePackages(path) + ModulePathBufInner::Extra(path) => ModulePathRefInner::Extra(path), + ModulePathBufInner::FirstParty(path) => ModulePathRefInner::FirstParty(path), + ModulePathBufInner::StandardLibrary(FilePath::System(path)) => { + ModulePathRefInner::StandardLibrary(FilePathRef::System(path)) } - ModuleResolutionPathBufInner::EditableInstall(path) => { - ModuleResolutionPathRefInner::EditableInstall(path) + ModulePathBufInner::StandardLibrary(FilePath::Vendored(path)) => { + ModulePathRefInner::StandardLibrary(FilePathRef::Vendored(path)) } + ModulePathBufInner::SitePackages(path) => ModulePathRefInner::SitePackages(path), + ModulePathBufInner::EditableInstall(path) => ModulePathRefInner::EditableInstall(path), }; - ModuleResolutionPathRef(inner) + ModulePathRef(inner) } } -impl PartialEq for ModuleResolutionPathRef<'_> { +impl PartialEq for ModulePathRef<'_> { fn eq(&self, other: &SystemPath) -> bool { match self.0 { - ModuleResolutionPathRefInner::Extra(path) => path == other, - ModuleResolutionPathRefInner::FirstParty(path) => path == other, - ModuleResolutionPathRefInner::SitePackages(path) => path == other, - ModuleResolutionPathRefInner::EditableInstall(path) => path == other, - ModuleResolutionPathRefInner::StandardLibrary(FilePathRef::System(path)) => { - path == other - } - ModuleResolutionPathRefInner::StandardLibrary(FilePathRef::Vendored(_)) => false, + ModulePathRefInner::Extra(path) => path == other, + ModulePathRefInner::FirstParty(path) => path == other, + ModulePathRefInner::SitePackages(path) => path == other, + ModulePathRefInner::EditableInstall(path) => path == other, + ModulePathRefInner::StandardLibrary(FilePathRef::System(path)) => path == other, + ModulePathRefInner::StandardLibrary(FilePathRef::Vendored(_)) => false, } } } -impl PartialEq> for SystemPath { - fn eq(&self, other: &ModuleResolutionPathRef) -> bool { +impl PartialEq> for SystemPath { + fn eq(&self, other: &ModulePathRef) -> bool { other == self } } -impl PartialEq for ModuleResolutionPathRef<'_> { +impl PartialEq for ModulePathRef<'_> { fn eq(&self, other: &SystemPathBuf) -> bool { self == &**other } } -impl PartialEq> for SystemPathBuf { - fn eq(&self, other: &ModuleResolutionPathRef<'_>) -> bool { +impl PartialEq> for SystemPathBuf { + fn eq(&self, other: &ModulePathRef<'_>) -> bool { &**self == other } } -impl PartialEq for ModuleResolutionPathRef<'_> { +impl PartialEq for ModulePathRef<'_> { fn eq(&self, other: &VendoredPath) -> bool { match self.0 { - ModuleResolutionPathRefInner::Extra(_) => false, - ModuleResolutionPathRefInner::FirstParty(_) => false, - ModuleResolutionPathRefInner::SitePackages(_) => false, - ModuleResolutionPathRefInner::EditableInstall(_) => false, - ModuleResolutionPathRefInner::StandardLibrary(FilePathRef::System(_)) => false, - ModuleResolutionPathRefInner::StandardLibrary(FilePathRef::Vendored(path)) => { - path == other - } + ModulePathRefInner::Extra(_) => false, + ModulePathRefInner::FirstParty(_) => false, + ModulePathRefInner::SitePackages(_) => false, + ModulePathRefInner::EditableInstall(_) => false, + ModulePathRefInner::StandardLibrary(FilePathRef::System(_)) => false, + ModulePathRefInner::StandardLibrary(FilePathRef::Vendored(path)) => path == other, } } } -impl PartialEq> for VendoredPath { - fn eq(&self, other: &ModuleResolutionPathRef) -> bool { +impl PartialEq> for VendoredPath { + fn eq(&self, other: &ModulePathRef) -> bool { other == self } } -impl PartialEq for ModuleResolutionPathRef<'_> { +impl PartialEq for ModulePathRef<'_> { fn eq(&self, other: &VendoredPathBuf) -> bool { self == &**other } } -impl PartialEq> for VendoredPathBuf { - fn eq(&self, other: &ModuleResolutionPathRef<'_>) -> bool { +impl PartialEq> for VendoredPathBuf { + fn eq(&self, other: &ModulePathRef<'_>) -> bool { &**self == other } } +#[derive(Clone, Debug, PartialEq, Eq, Hash)] +pub(crate) struct ModuleSearchPath(Arc); + +impl ModuleSearchPath { + pub(crate) fn extra(path: SystemPathBuf) -> Option { + Some(Self(Arc::new(ModulePathBuf::extra(path)?))) + } + + pub(crate) fn first_party(path: SystemPathBuf) -> Option { + Some(Self(Arc::new(ModulePathBuf::first_party(path)?))) + } + + pub(crate) fn custom_stdlib(path: &SystemPath) -> Option { + Some(Self(Arc::new(ModulePathBuf::standard_library( + FilePath::System(path.join("stdlib")), + )?))) + } + + pub(crate) fn vendored_stdlib() -> Self { + Self(Arc::new(ModulePathBuf( + ModulePathBufInner::StandardLibrary(FilePath::Vendored(VendoredPathBuf::from( + "stdlib", + ))), + ))) + } + + pub(crate) fn site_packages(path: SystemPathBuf) -> Option { + Some(Self(Arc::new(ModulePathBuf::site_packages(path)?))) + } + + pub(crate) fn editable(system: &dyn System, path: SystemPathBuf) -> Option { + Some(Self(Arc::new(ModulePathBuf::editable_installation_root( + system, path, + )?))) + } + + pub(crate) fn as_module_path(&self) -> &ModulePathBuf { + &self.0 + } +} + +impl PartialEq for ModuleSearchPath { + fn eq(&self, other: &SystemPathBuf) -> bool { + &*self.0 == other + } +} + +impl PartialEq for SystemPathBuf { + fn eq(&self, other: &ModuleSearchPath) -> bool { + other.eq(self) + } +} + +impl PartialEq for ModuleSearchPath { + fn eq(&self, other: &VendoredPathBuf) -> bool { + &*self.0 == other + } +} + +impl PartialEq for VendoredPathBuf { + fn eq(&self, other: &ModuleSearchPath) -> bool { + other.eq(self) + } +} + +// TODO: this is unprincipled. +// We should instead just implement the methods we need on ModuleSearchPath, +// and adjust the signatures/implementations of methods that receive ModuleSearchPaths. +impl Deref for ModuleSearchPath { + type Target = ModulePathBuf; + + fn deref(&self) -> &Self::Target { + &self.0 + } +} + #[cfg(test)] mod tests { use insta::assert_debug_snapshot; @@ -751,67 +807,60 @@ mod tests { } } - impl ModuleResolutionPathBuf { + impl ModulePathBuf { #[must_use] pub(crate) fn join(&self, component: &str) -> Self { - ModuleResolutionPathRef::from(self).join(component) + ModulePathRef::from(self).join(component) } } - impl<'a> ModuleResolutionPathRef<'a> { + impl<'a> ModulePathRef<'a> { #[must_use] - fn join( - &self, - component: &'a (impl AsRef + ?Sized), - ) -> ModuleResolutionPathBuf { + fn join(&self, component: &'a (impl AsRef + ?Sized)) -> ModulePathBuf { let mut result = self.to_path_buf(); result.push(component.as_ref().as_str()); result } #[must_use] - pub(crate) fn to_path_buf(self) -> ModuleResolutionPathBuf { + pub(crate) fn to_path_buf(self) -> ModulePathBuf { let inner = match self.0 { - ModuleResolutionPathRefInner::Extra(path) => { - ModuleResolutionPathBufInner::Extra(path.to_path_buf()) + ModulePathRefInner::Extra(path) => ModulePathBufInner::Extra(path.to_path_buf()), + ModulePathRefInner::FirstParty(path) => { + ModulePathBufInner::FirstParty(path.to_path_buf()) } - ModuleResolutionPathRefInner::FirstParty(path) => { - ModuleResolutionPathBufInner::FirstParty(path.to_path_buf()) + ModulePathRefInner::StandardLibrary(FilePathRef::System(path)) => { + ModulePathBufInner::StandardLibrary(FilePath::System(path.to_path_buf())) } - ModuleResolutionPathRefInner::StandardLibrary(FilePathRef::System(path)) => { - ModuleResolutionPathBufInner::StandardLibrary(FilePath::System( - path.to_path_buf(), - )) + ModulePathRefInner::StandardLibrary(FilePathRef::Vendored(path)) => { + ModulePathBufInner::StandardLibrary(FilePath::Vendored(path.to_path_buf())) } - ModuleResolutionPathRefInner::StandardLibrary(FilePathRef::Vendored(path)) => { - ModuleResolutionPathBufInner::StandardLibrary(FilePath::Vendored( - path.to_path_buf(), - )) + ModulePathRefInner::SitePackages(path) => { + ModulePathBufInner::SitePackages(path.to_path_buf()) } - ModuleResolutionPathRefInner::SitePackages(path) => { - ModuleResolutionPathBufInner::SitePackages(path.to_path_buf()) - } - ModuleResolutionPathRefInner::EditableInstall(path) => { - ModuleResolutionPathBufInner::EditableInstall(path.to_path_buf()) + ModulePathRefInner::EditableInstall(path) => { + ModulePathBufInner::EditableInstall(path.to_path_buf()) } }; - ModuleResolutionPathBuf(inner) + ModulePathBuf(inner) } + } + impl ModuleSearchPath { #[must_use] - pub(crate) const fn is_stdlib_search_path(&self) -> bool { - matches!(&self.0, ModuleResolutionPathRefInner::StandardLibrary(_)) + pub(crate) fn is_stdlib_search_path(&self) -> bool { + matches!(&self.0 .0, ModulePathBufInner::StandardLibrary(_)) } } #[test] fn constructor_rejects_non_pyi_stdlib_paths() { assert_eq!( - ModuleResolutionPathBuf::standard_library(FilePath::system("foo.py")), + ModulePathBuf::standard_library(FilePath::system("foo.py")), None ); assert_eq!( - ModuleResolutionPathBuf::standard_library(FilePath::system("foo/__init__.py")), + ModulePathBuf::standard_library(FilePath::system("foo/__init__.py")), None ); } @@ -819,9 +868,9 @@ mod tests { #[test] fn path_buf_debug_impl() { assert_debug_snapshot!( - ModuleResolutionPathBuf::standard_library(FilePath::system("foo/bar.pyi")).unwrap(), + ModulePathBuf::standard_library(FilePath::system("foo/bar.pyi")).unwrap(), @r###" - ModuleResolutionPathBuf::StandardLibrary( + ModulePathBuf::StandardLibrary( System( "foo/bar.pyi", ), @@ -833,9 +882,9 @@ mod tests { #[test] fn path_ref_debug_impl() { assert_debug_snapshot!( - ModuleResolutionPathRef(ModuleResolutionPathRefInner::Extra(SystemPath::new("foo/bar.py"))), + ModulePathRef(ModulePathRefInner::Extra(SystemPath::new("foo/bar.py"))), @r###" - ModuleResolutionPathRef::Extra( + ModulePathRef::Extra( "foo/bar.py", ) "### @@ -845,50 +894,49 @@ mod tests { #[test] fn with_extension_methods() { assert_eq!( - ModuleResolutionPathBuf::standard_library(FilePath::system("foo")) + ModulePathBuf::standard_library(FilePath::system("foo")) .unwrap() .with_py_extension(), None ); assert_eq!( - ModuleResolutionPathBuf::standard_library(FilePath::system("foo")) + ModulePathBuf::standard_library(FilePath::system("foo")) .unwrap() .with_pyi_extension(), - ModuleResolutionPathBuf(ModuleResolutionPathBufInner::StandardLibrary( - FilePath::System(SystemPathBuf::from("foo.pyi")) - )) + ModulePathBuf(ModulePathBufInner::StandardLibrary(FilePath::System( + SystemPathBuf::from("foo.pyi") + ))) ); assert_eq!( - ModuleResolutionPathBuf::first_party("foo/bar") + ModulePathBuf::first_party("foo/bar") .unwrap() .with_py_extension() .unwrap(), - ModuleResolutionPathBuf(ModuleResolutionPathBufInner::FirstParty( - SystemPathBuf::from("foo/bar.py") - )) + ModulePathBuf(ModulePathBufInner::FirstParty(SystemPathBuf::from( + "foo/bar.py" + ))) ); } #[test] fn module_name_1_part() { assert_eq!( - ModuleResolutionPathRef(ModuleResolutionPathRefInner::Extra(SystemPath::new("foo"))) - .to_module_name(), + ModulePathRef(ModulePathRefInner::Extra(SystemPath::new("foo"))).to_module_name(), ModuleName::new_static("foo") ); assert_eq!( - ModuleResolutionPathRef(ModuleResolutionPathRefInner::StandardLibrary( - FilePathRef::system("foo.pyi") - )) + ModulePathRef(ModulePathRefInner::StandardLibrary(FilePathRef::system( + "foo.pyi" + ))) .to_module_name(), ModuleName::new_static("foo") ); assert_eq!( - ModuleResolutionPathRef(ModuleResolutionPathRefInner::FirstParty(SystemPath::new( + ModulePathRef(ModulePathRefInner::FirstParty(SystemPath::new( "foo/__init__.py" ))) .to_module_name(), @@ -899,23 +947,21 @@ mod tests { #[test] fn module_name_2_parts() { assert_eq!( - ModuleResolutionPathRef(ModuleResolutionPathRefInner::StandardLibrary( - FilePathRef::system("foo/bar") - )) + ModulePathRef(ModulePathRefInner::StandardLibrary(FilePathRef::system( + "foo/bar" + ))) .to_module_name(), ModuleName::new_static("foo.bar") ); assert_eq!( - ModuleResolutionPathRef(ModuleResolutionPathRefInner::Extra(SystemPath::new( - "foo/bar.pyi" - ))) - .to_module_name(), + ModulePathRef(ModulePathRefInner::Extra(SystemPath::new("foo/bar.pyi"))) + .to_module_name(), ModuleName::new_static("foo.bar") ); assert_eq!( - ModuleResolutionPathRef(ModuleResolutionPathRefInner::SitePackages(SystemPath::new( + ModulePathRef(ModulePathRefInner::SitePackages(SystemPath::new( "foo/bar/__init__.pyi" ))) .to_module_name(), @@ -926,7 +972,7 @@ mod tests { #[test] fn module_name_3_parts() { assert_eq!( - ModuleResolutionPathRef(ModuleResolutionPathRefInner::SitePackages(SystemPath::new( + ModulePathRef(ModulePathRefInner::SitePackages(SystemPath::new( "foo/bar/__init__.pyi" ))) .to_module_name(), @@ -934,7 +980,7 @@ mod tests { ); assert_eq!( - ModuleResolutionPathRef(ModuleResolutionPathRefInner::SitePackages(SystemPath::new( + ModulePathRef(ModulePathRefInner::SitePackages(SystemPath::new( "foo/bar/baz" ))) .to_module_name(), @@ -945,35 +991,31 @@ mod tests { #[test] fn join() { assert_eq!( - ModuleResolutionPathBuf::standard_library(FilePath::system("foo")) + ModulePathBuf::standard_library(FilePath::system("foo")) .unwrap() .join("bar"), - ModuleResolutionPathBuf(ModuleResolutionPathBufInner::StandardLibrary( - FilePath::system("foo/bar") - )) + ModulePathBuf(ModulePathBufInner::StandardLibrary(FilePath::system( + "foo/bar" + ))) ); assert_eq!( - ModuleResolutionPathBuf::standard_library(FilePath::system("foo")) + ModulePathBuf::standard_library(FilePath::system("foo")) .unwrap() .join("bar.pyi"), - ModuleResolutionPathBuf(ModuleResolutionPathBufInner::StandardLibrary( - FilePath::system("foo/bar.pyi") - )) + ModulePathBuf(ModulePathBufInner::StandardLibrary(FilePath::system( + "foo/bar.pyi" + ))) ); assert_eq!( - ModuleResolutionPathBuf::extra("foo") - .unwrap() - .join("bar.py"), - ModuleResolutionPathBuf(ModuleResolutionPathBufInner::Extra(SystemPathBuf::from( - "foo/bar.py" - ))) + ModulePathBuf::extra("foo").unwrap().join("bar.py"), + ModulePathBuf(ModulePathBufInner::Extra(SystemPathBuf::from("foo/bar.py"))) ); } #[test] #[should_panic(expected = "Extension must be `pyi`; got `py`")] fn stdlib_path_invalid_join_py() { - ModuleResolutionPathBuf::standard_library(FilePath::system("foo")) + ModulePathBuf::standard_library(FilePath::system("foo")) .unwrap() .push("bar.py"); } @@ -981,7 +1023,7 @@ mod tests { #[test] #[should_panic(expected = "Extension must be `pyi`; got `rs`")] fn stdlib_path_invalid_join_rs() { - ModuleResolutionPathBuf::standard_library(FilePath::system("foo")) + ModulePathBuf::standard_library(FilePath::system("foo")) .unwrap() .push("bar.rs"); } @@ -989,23 +1031,20 @@ mod tests { #[test] #[should_panic(expected = "Extension must be `py` or `pyi`; got `rs`")] fn non_stdlib_path_invalid_join_rs() { - ModuleResolutionPathBuf::site_packages("foo") - .unwrap() - .push("bar.rs"); + ModulePathBuf::site_packages("foo").unwrap().push("bar.rs"); } #[test] #[should_panic(expected = "already has an extension")] fn invalid_stdlib_join_too_many_extensions() { - ModuleResolutionPathBuf::standard_library(FilePath::system("foo.pyi")) + ModulePathBuf::standard_library(FilePath::system("foo.pyi")) .unwrap() .push("bar.pyi"); } #[test] fn relativize_stdlib_path_errors() { - let root = - ModuleResolutionPathBuf::standard_library(FilePath::system("foo/stdlib")).unwrap(); + let root = ModulePathBuf::standard_library(FilePath::system("foo/stdlib")).unwrap(); // Must have a `.pyi` extension or no extension: let bad_absolute_path = FilePath::system("foo/stdlib/x.py"); @@ -1020,7 +1059,7 @@ mod tests { #[test] fn relativize_non_stdlib_path_errors() { - let root = ModuleResolutionPathBuf::extra("foo/stdlib").unwrap(); + let root = ModulePathBuf::extra("foo/stdlib").unwrap(); // Must have a `.py` extension, a `.pyi` extension, or no extension: let bad_absolute_path = FilePath::system("foo/stdlib/x.rs"); assert_eq!(root.relativize_path(&bad_absolute_path), None); @@ -1032,33 +1071,33 @@ mod tests { #[test] fn relativize_path() { assert_eq!( - ModuleResolutionPathBuf::standard_library(FilePath::system("foo/baz")) + ModulePathBuf::standard_library(FilePath::system("foo/baz")) .unwrap() .relativize_path(&FilePath::system("foo/baz/eggs/__init__.pyi")) .unwrap(), - ModuleResolutionPathRef(ModuleResolutionPathRefInner::StandardLibrary( - FilePathRef::system("eggs/__init__.pyi") - )) + ModulePathRef(ModulePathRefInner::StandardLibrary(FilePathRef::system( + "eggs/__init__.pyi" + ))) ); } fn typeshed_test_case( typeshed: MockedTypeshed, target_version: TargetVersion, - ) -> (TestDb, ModuleResolutionPathBuf) { + ) -> (TestDb, ModulePathBuf) { let TestCase { db, stdlib, .. } = TestCaseBuilder::new() .with_custom_typeshed(typeshed) .with_target_version(target_version) .build(); - let stdlib = ModuleResolutionPathBuf::standard_library(FilePath::System(stdlib)).unwrap(); + let stdlib = ModulePathBuf::standard_library(FilePath::System(stdlib)).unwrap(); (db, stdlib) } - fn py38_typeshed_test_case(typeshed: MockedTypeshed) -> (TestDb, ModuleResolutionPathBuf) { + fn py38_typeshed_test_case(typeshed: MockedTypeshed) -> (TestDb, ModulePathBuf) { typeshed_test_case(typeshed, TargetVersion::Py38) } - fn py39_typeshed_test_case(typeshed: MockedTypeshed) -> (TestDb, ModuleResolutionPathBuf) { + fn py39_typeshed_test_case(typeshed: MockedTypeshed) -> (TestDb, ModulePathBuf) { typeshed_test_case(typeshed, TargetVersion::Py39) } diff --git a/crates/red_knot_module_resolver/src/resolver.rs b/crates/red_knot_module_resolver/src/resolver.rs index 8a281763522a3..86319b9502f35 100644 --- a/crates/red_knot_module_resolver/src/resolver.rs +++ b/crates/red_knot_module_resolver/src/resolver.rs @@ -1,6 +1,5 @@ use std::borrow::Cow; use std::iter::FusedIterator; -use std::sync::Arc; use once_cell::sync::Lazy; use rustc_hash::{FxBuildHasher, FxHashSet}; @@ -12,11 +11,9 @@ use ruff_db::system::{DirectoryEntry, System, SystemPath, SystemPathBuf}; use crate::db::Db; use crate::module::{Module, ModuleKind}; use crate::module_name::ModuleName; -use crate::path::ModuleResolutionPathBuf; +use crate::path::{ModulePathBuf, ModuleSearchPath}; use crate::state::ResolverState; -type SearchPathRoot = Arc; - /// Resolves a module name to a module. pub fn resolve_module(db: &dyn Db, module_name: ModuleName) -> Option { let interned_name = internal::ModuleNameIngredient::new(db, module_name); @@ -137,38 +134,25 @@ pub(crate) fn module_resolution_settings(db: &dyn Db) -> ModuleResolutionSetting let mut static_search_paths: Vec<_> = extra_paths .iter() - .map(|fs_path| { - Arc::new( - ModuleResolutionPathBuf::extra(SystemPath::absolute(fs_path, current_directory)) - .unwrap(), - ) - }) + .map(|path| ModuleSearchPath::extra(SystemPath::absolute(path, current_directory)).unwrap()) .collect(); - static_search_paths.push(Arc::new( - ModuleResolutionPathBuf::first_party(SystemPath::absolute( - workspace_root, - current_directory, - )) - .unwrap(), - )); + static_search_paths.push( + ModuleSearchPath::first_party(SystemPath::absolute(workspace_root, current_directory)) + .unwrap(), + ); - static_search_paths.push(Arc::new(custom_typeshed.as_ref().map_or_else( - ModuleResolutionPathBuf::vendored_stdlib, + static_search_paths.push(custom_typeshed.as_ref().map_or_else( + ModuleSearchPath::vendored_stdlib, |custom| { - ModuleResolutionPathBuf::stdlib_from_custom_typeshed_root(&SystemPath::absolute( - custom, - current_directory, - )) - .unwrap() + ModuleSearchPath::custom_stdlib(&SystemPath::absolute(custom, current_directory)) + .unwrap() }, - ))); + )); if let Some(path) = site_packages { - let site_packages_root = Arc::new( - ModuleResolutionPathBuf::site_packages(SystemPath::absolute(path, current_directory)) - .unwrap(), - ); + let site_packages_root = + ModuleSearchPath::site_packages(SystemPath::absolute(path, current_directory)).unwrap(); static_search_paths.push(site_packages_root); } @@ -204,7 +188,7 @@ pub(crate) fn module_resolution_settings(db: &dyn Db) -> ModuleResolutionSetting /// search paths listed in `.pth` files in the `site-packages` directory /// due to editable installations of third-party packages. #[salsa::tracked(return_ref)] -pub(crate) fn editable_install_resolution_paths(db: &dyn Db) -> Vec> { +pub(crate) fn editable_install_resolution_paths(db: &dyn Db) -> Vec { // This query needs to be re-executed each time a `.pth` file // is added, modified or removed from the `site-packages` directory. // However, we don't use Salsa queries to read the source text of `.pth` files; @@ -259,7 +243,7 @@ pub(crate) fn editable_install_resolution_paths(db: &dyn Db) -> Vec Vec { db: &'db dyn Db, - static_paths: std::slice::Iter<'db, SearchPathRoot>, - dynamic_paths: Option>, + static_paths: std::slice::Iter<'db, ModuleSearchPath>, + dynamic_paths: Option>, } impl<'db> Iterator for SearchPathIterator<'db> { - type Item = &'db SearchPathRoot; + type Item = &'db ModuleSearchPath; fn next(&mut self) -> Option { let SearchPathIterator { @@ -314,7 +298,7 @@ struct PthFile<'db> { impl<'db> PthFile<'db> { /// Yield paths in this `.pth` file that appear to represent editable installations, /// and should therefore be added as module-resolution search paths. - fn editable_installations(&'db self) -> impl Iterator + 'db { + fn editable_installations(&'db self) -> impl Iterator + 'db { let PthFile { system, path: _, @@ -336,7 +320,7 @@ impl<'db> PthFile<'db> { return None; } let possible_editable_install = SystemPath::absolute(line, site_packages); - ModuleResolutionPathBuf::editable_installation_root(*system, possible_editable_install) + ModuleSearchPath::editable(*system, possible_editable_install) }) } } @@ -408,7 +392,7 @@ pub(crate) struct ModuleResolutionSettings { /// /// Note that `site-packages` *is included* as a search path in this sequence, /// but it is also stored separately so that we're able to find editable installs later. - static_search_paths: Vec, + static_search_paths: Vec, } impl ModuleResolutionSettings { @@ -491,10 +475,7 @@ static BUILTIN_MODULES: Lazy> = Lazy::new(|| { /// Given a module name and a list of search paths in which to lookup modules, /// attempt to resolve the module name -fn resolve_name( - db: &dyn Db, - name: &ModuleName, -) -> Option<(Arc, File, ModuleKind)> { +fn resolve_name(db: &dyn Db, name: &ModuleName) -> Option<(ModuleSearchPath, File, ModuleKind)> { let resolver_settings = module_resolution_settings(db); let resolver_state = ResolverState::new(db, resolver_settings.target_version()); let is_builtin_module = BUILTIN_MODULES.contains(&name.as_str()); @@ -554,14 +535,14 @@ fn resolve_name( } fn resolve_package<'a, 'db, I>( - module_search_path: &ModuleResolutionPathBuf, + module_search_path: &ModuleSearchPath, components: I, resolver_state: &ResolverState<'db>, ) -> Result where I: Iterator, { - let mut package_path = module_search_path.clone(); + let mut package_path = module_search_path.as_module_path().clone(); // `true` if inside a folder that is a namespace package (has no `__init__.py`). // Namespace packages are special because they can be spread across multiple search paths. @@ -613,7 +594,7 @@ where #[derive(Debug)] struct ResolvedPackage { - path: ModuleResolutionPathBuf, + path: ModulePathBuf, kind: PackageKind, } @@ -669,7 +650,7 @@ mod tests { ); assert_eq!("foo", foo_module.name()); - assert_eq!(&src, &foo_module.search_path()); + assert_eq!(&src, foo_module.search_path()); assert_eq!(ModuleKind::Module, foo_module.kind()); let expected_foo_path = src.join("foo.py"); @@ -734,7 +715,7 @@ mod tests { resolve_module(&db, functools_module_name).as_ref() ); - assert_eq!(&stdlib, &functools_module.search_path().to_path_buf()); + assert_eq!(&stdlib, functools_module.search_path()); assert_eq!(ModuleKind::Module, functools_module.kind()); let expected_functools_path = stdlib.join("functools.pyi"); @@ -786,7 +767,7 @@ mod tests { }); let search_path = resolved_module.search_path(); assert_eq!( - &stdlib, &search_path, + &stdlib, search_path, "Search path for {module_name} was unexpectedly {search_path:?}" ); assert!( @@ -882,7 +863,7 @@ mod tests { }); let search_path = resolved_module.search_path(); assert_eq!( - &stdlib, &search_path, + &stdlib, search_path, "Search path for {module_name} was unexpectedly {search_path:?}" ); assert!( @@ -941,7 +922,7 @@ mod tests { Some(&functools_module), resolve_module(&db, functools_module_name).as_ref() ); - assert_eq!(&src, &functools_module.search_path()); + assert_eq!(&src, functools_module.search_path()); assert_eq!(ModuleKind::Module, functools_module.kind()); assert_eq!(&src.join("functools.py"), functools_module.file().path(&db)); @@ -962,7 +943,7 @@ mod tests { 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(), stdlib); + assert_eq!(pydoc_data_topics.search_path(), &stdlib); assert_eq!( pydoc_data_topics.file().path(&db), &stdlib.join("pydoc_data/topics.pyi") @@ -979,7 +960,7 @@ mod tests { 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()); + assert_eq!(&src, foo_module.search_path()); assert_eq!(&foo_path, foo_module.file().path(&db)); assert_eq!( @@ -1006,7 +987,7 @@ 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()); + assert_eq!(&src, foo_module.search_path()); assert_eq!(&foo_init_path, foo_module.file().path(&db)); assert_eq!(ModuleKind::Package, foo_module.kind()); @@ -1029,7 +1010,6 @@ 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()); assert_eq!(&foo_stub, foo.file().path(&db)); assert_eq!(Some(foo), path_to_module(&db, &FilePath::System(foo_stub))); @@ -1053,7 +1033,7 @@ 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()); + assert_eq!(&src, baz_module.search_path()); assert_eq!(&baz_path, baz_module.file().path(&db)); assert_eq!( @@ -1153,7 +1133,7 @@ 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()); + assert_eq!(&src, foo_module.search_path()); assert_eq!(&foo_src_path, foo_module.file().path(&db)); assert_eq!( Some(foo_module), @@ -1205,12 +1185,12 @@ mod tests { assert_ne!(foo_module, bar_module); - assert_eq!(&src, &foo_module.search_path()); + assert_eq!(&src, foo_module.search_path()); assert_eq!(&foo, foo_module.file().path(&db)); // `foo` and `bar` shouldn't resolve to the same file - assert_eq!(&src, &bar_module.search_path()); + assert_eq!(&src, bar_module.search_path()); assert_eq!(&bar, bar_module.file().path(&db)); assert_eq!(&foo, foo_module.file().path(&db)); @@ -1326,7 +1306,7 @@ mod tests { let stdlib_functools_path = stdlib.join("functools.pyi"); let functools_module = resolve_module(&db, functools_module_name.clone()).unwrap(); - assert_eq!(functools_module.search_path(), stdlib); + assert_eq!(functools_module.search_path(), &stdlib); assert_eq!( Some(functools_module.file()), system_path_to_file(&db, &stdlib_functools_path) @@ -1346,7 +1326,7 @@ mod tests { &ModuleNameIngredient::new(&db, functools_module_name.clone()), &events, ); - assert_eq!(functools_module.search_path(), stdlib); + assert_eq!(functools_module.search_path(), &stdlib); assert_eq!( Some(functools_module.file()), system_path_to_file(&db, &stdlib_functools_path) @@ -1372,7 +1352,7 @@ mod tests { let functools_module_name = ModuleName::new_static("functools").unwrap(); let functools_module = resolve_module(&db, functools_module_name.clone()).unwrap(); - assert_eq!(functools_module.search_path(), stdlib); + assert_eq!(functools_module.search_path(), &stdlib); assert_eq!( Some(functools_module.file()), system_path_to_file(&db, stdlib.join("functools.pyi")) @@ -1383,7 +1363,7 @@ 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.clone()).unwrap(); - assert_eq!(functools_module.search_path(), src); + assert_eq!(functools_module.search_path(), &src); assert_eq!( Some(functools_module.file()), system_path_to_file(&db, &src_functools_path) @@ -1414,7 +1394,7 @@ mod tests { let src_functools_path = src.join("functools.py"); let functools_module = resolve_module(&db, functools_module_name.clone()).unwrap(); - assert_eq!(functools_module.search_path(), src); + assert_eq!(functools_module.search_path(), &src); assert_eq!( Some(functools_module.file()), system_path_to_file(&db, &src_functools_path) @@ -1427,7 +1407,7 @@ mod tests { .unwrap(); File::touch_path(&mut db, &src_functools_path); let functools_module = resolve_module(&db, functools_module_name.clone()).unwrap(); - assert_eq!(functools_module.search_path(), stdlib); + assert_eq!(functools_module.search_path(), &stdlib); assert_eq!( Some(functools_module.file()), system_path_to_file(&db, stdlib.join("functools.pyi")) @@ -1677,15 +1657,14 @@ not_a_directory .with_site_packages_files(&[("_foo.pth", "/src")]) .build(); - let search_paths: Vec<&SearchPathRoot> = + let search_paths: Vec<&ModuleSearchPath> = module_resolution_settings(&db).search_paths(&db).collect(); - assert!(search_paths.contains(&&Arc::new( - ModuleResolutionPathBuf::first_party("/src").unwrap() - ))); + assert!(search_paths + .contains(&&ModuleSearchPath::first_party(SystemPathBuf::from("/src")).unwrap())); - assert!(!search_paths.contains(&&Arc::new( - ModuleResolutionPathBuf::editable_installation_root(db.system(), "/src").unwrap() - ))); + assert!(!search_paths.contains( + &&ModuleSearchPath::editable(db.system(), SystemPathBuf::from("/src")).unwrap() + )); } } diff --git a/crates/ruff_db/src/program.rs b/crates/ruff_db/src/program.rs index 3eb9a2bde3468..98298d1bdf583 100644 --- a/crates/ruff_db/src/program.rs +++ b/crates/ruff_db/src/program.rs @@ -75,8 +75,8 @@ pub struct SearchPathSettings { /// The root of the workspace, used for finding first-party modules. pub workspace_root: SystemPathBuf, - /// Optional (already validated) path to standard-library typeshed stubs. - /// If this is not provided, we will fallback to our vendored typeshed stubs + /// Optional path to a "custom typeshed" directory on disk for us to use for standard-library types. + /// If this is not provided, we will fallback to our vendored typeshed stubs for the stdlib, /// bundled as a zip file in the binary pub custom_typeshed: Option,