From a7f64be0f4080515aa1ba588932464fe05ce8002 Mon Sep 17 00:00:00 2001 From: Alex Waygood Date: Fri, 9 Aug 2024 20:03:41 +0100 Subject: [PATCH] Remove `red_knot_python_semantic::python_version::TargetVersion` --- crates/red_knot/src/target_version.rs | 32 ++-- crates/red_knot/tests/file_watching.rs | 4 +- crates/red_knot_python_semantic/src/lib.rs | 2 +- .../src/module_resolver/path.rs | 26 ++-- .../src/module_resolver/resolver.rs | 36 ++--- .../src/module_resolver/state.rs | 6 +- .../src/module_resolver/testing.rs | 10 +- .../src/module_resolver/typeshed/versions.rs | 44 +++--- .../red_knot_python_semantic/src/program.rs | 6 +- .../src/python_version.rs | 143 ++++-------------- .../src/semantic_model.rs | 4 +- .../src/types/infer.rs | 6 +- crates/red_knot_server/src/session.rs | 4 +- crates/red_knot_wasm/src/lib.rs | 16 +- crates/red_knot_workspace/src/lint.rs | 4 +- crates/red_knot_workspace/tests/check.rs | 4 +- crates/ruff_benchmark/benches/red_knot.rs | 4 +- 17 files changed, 141 insertions(+), 210 deletions(-) diff --git a/crates/red_knot/src/target_version.rs b/crates/red_knot/src/target_version.rs index 43e249a6c57e0..7db3c514e890b 100644 --- a/crates/red_knot/src/target_version.rs +++ b/crates/red_knot/src/target_version.rs @@ -13,22 +13,36 @@ pub enum TargetVersion { Py313, } +impl TargetVersion { + const fn as_str(self) -> &'static str { + match self { + Self::Py37 => "py37", + Self::Py38 => "py38", + Self::Py39 => "py39", + Self::Py310 => "py310", + Self::Py311 => "py311", + Self::Py312 => "py312", + Self::Py313 => "py313", + } + } +} + impl std::fmt::Display for TargetVersion { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - red_knot_python_semantic::TargetVersion::from(*self).fmt(f) + f.write_str(self.as_str()) } } -impl From for red_knot_python_semantic::TargetVersion { +impl From for red_knot_python_semantic::PythonVersion { fn from(value: TargetVersion) -> Self { match value { - TargetVersion::Py37 => Self::Py37, - TargetVersion::Py38 => Self::Py38, - TargetVersion::Py39 => Self::Py39, - TargetVersion::Py310 => Self::Py310, - TargetVersion::Py311 => Self::Py311, - TargetVersion::Py312 => Self::Py312, - TargetVersion::Py313 => Self::Py313, + TargetVersion::Py37 => Self::PY37, + TargetVersion::Py38 => Self::PY38, + TargetVersion::Py39 => Self::PY39, + TargetVersion::Py310 => Self::PY310, + TargetVersion::Py311 => Self::PY311, + TargetVersion::Py312 => Self::PY312, + TargetVersion::Py313 => Self::PY313, } } } diff --git a/crates/red_knot/tests/file_watching.rs b/crates/red_knot/tests/file_watching.rs index 7e45ec6027dbc..1315c8fd6de9b 100644 --- a/crates/red_knot/tests/file_watching.rs +++ b/crates/red_knot/tests/file_watching.rs @@ -7,7 +7,7 @@ use anyhow::{anyhow, Context}; use salsa::Setter; use red_knot_python_semantic::{ - resolve_module, ModuleName, Program, ProgramSettings, SearchPathSettings, TargetVersion, + resolve_module, ModuleName, Program, ProgramSettings, PythonVersion, SearchPathSettings, }; use red_knot_workspace::db::RootDatabase; use red_knot_workspace::watch; @@ -234,7 +234,7 @@ where } let settings = ProgramSettings { - target_version: TargetVersion::default(), + target_version: PythonVersion::default(), search_paths, }; diff --git a/crates/red_knot_python_semantic/src/lib.rs b/crates/red_knot_python_semantic/src/lib.rs index bd1daf7719ce4..12ea4dd1b9baf 100644 --- a/crates/red_knot_python_semantic/src/lib.rs +++ b/crates/red_knot_python_semantic/src/lib.rs @@ -6,7 +6,7 @@ pub use db::Db; pub use module_name::ModuleName; pub use module_resolver::{resolve_module, system_module_search_paths, vendored_typeshed_stubs}; pub use program::{Program, ProgramSettings, SearchPathSettings}; -pub use python_version::{PythonVersion, TargetVersion, UnsupportedPythonVersion}; +pub use python_version::PythonVersion; pub use semantic_model::{HasTy, SemanticModel}; pub mod ast_node_ref; diff --git a/crates/red_knot_python_semantic/src/module_resolver/path.rs b/crates/red_knot_python_semantic/src/module_resolver/path.rs index b91831de46342..546f4b857c0f5 100644 --- a/crates/red_knot_python_semantic/src/module_resolver/path.rs +++ b/crates/red_knot_python_semantic/src/module_resolver/path.rs @@ -626,7 +626,7 @@ mod tests { use super::*; use crate::module_resolver::testing::{FileSpec, MockedTypeshed, TestCase, TestCaseBuilder}; - use crate::TargetVersion; + use crate::python_version::PythonVersion; impl ModulePath { #[must_use] @@ -866,7 +866,7 @@ mod tests { fn typeshed_test_case( typeshed: MockedTypeshed, - target_version: TargetVersion, + target_version: PythonVersion, ) -> (TestDb, SearchPath) { let TestCase { db, stdlib, .. } = TestCaseBuilder::new() .with_custom_typeshed(typeshed) @@ -878,11 +878,11 @@ mod tests { } fn py38_typeshed_test_case(typeshed: MockedTypeshed) -> (TestDb, SearchPath) { - typeshed_test_case(typeshed, TargetVersion::Py38) + typeshed_test_case(typeshed, PythonVersion::PY38) } fn py39_typeshed_test_case(typeshed: MockedTypeshed) -> (TestDb, SearchPath) { - typeshed_test_case(typeshed, TargetVersion::Py39) + typeshed_test_case(typeshed, PythonVersion::PY39) } #[test] @@ -898,7 +898,7 @@ mod tests { }; let (db, stdlib_path) = py38_typeshed_test_case(TYPESHED); - let resolver = ResolverState::new(&db, TargetVersion::Py38); + let resolver = ResolverState::new(&db, PythonVersion::PY38); let asyncio_regular_package = stdlib_path.join("asyncio"); assert!(asyncio_regular_package.is_directory(&resolver)); @@ -926,7 +926,7 @@ mod tests { }; let (db, stdlib_path) = py38_typeshed_test_case(TYPESHED); - let resolver = ResolverState::new(&db, TargetVersion::Py38); + let resolver = ResolverState::new(&db, PythonVersion::PY38); let xml_namespace_package = stdlib_path.join("xml"); assert!(xml_namespace_package.is_directory(&resolver)); @@ -948,7 +948,7 @@ mod tests { }; let (db, stdlib_path) = py38_typeshed_test_case(TYPESHED); - let resolver = ResolverState::new(&db, TargetVersion::Py38); + let resolver = ResolverState::new(&db, PythonVersion::PY38); let functools_module = stdlib_path.join("functools.pyi"); assert!(functools_module.to_file(&resolver).is_some()); @@ -964,7 +964,7 @@ mod tests { }; let (db, stdlib_path) = py38_typeshed_test_case(TYPESHED); - let resolver = ResolverState::new(&db, TargetVersion::Py38); + let resolver = ResolverState::new(&db, PythonVersion::PY38); let collections_regular_package = stdlib_path.join("collections"); assert_eq!(collections_regular_package.to_file(&resolver), None); @@ -980,7 +980,7 @@ mod tests { }; let (db, stdlib_path) = py38_typeshed_test_case(TYPESHED); - let resolver = ResolverState::new(&db, TargetVersion::Py38); + let resolver = ResolverState::new(&db, PythonVersion::PY38); let importlib_namespace_package = stdlib_path.join("importlib"); assert_eq!(importlib_namespace_package.to_file(&resolver), None); @@ -1001,7 +1001,7 @@ mod tests { }; let (db, stdlib_path) = py38_typeshed_test_case(TYPESHED); - let resolver = ResolverState::new(&db, TargetVersion::Py38); + let resolver = ResolverState::new(&db, PythonVersion::PY38); let non_existent = stdlib_path.join("doesnt_even_exist"); assert_eq!(non_existent.to_file(&resolver), None); @@ -1029,7 +1029,7 @@ mod tests { }; let (db, stdlib_path) = py39_typeshed_test_case(TYPESHED); - let resolver = ResolverState::new(&db, TargetVersion::Py39); + let resolver = ResolverState::new(&db, PythonVersion::PY39); // Since we've set the target version to Py39, // `collections` should now exist as a directory, according to VERSIONS... @@ -1058,7 +1058,7 @@ mod tests { }; let (db, stdlib_path) = py39_typeshed_test_case(TYPESHED); - let resolver = ResolverState::new(&db, TargetVersion::Py39); + let resolver = ResolverState::new(&db, PythonVersion::PY39); // The `importlib` directory now also exists let importlib_namespace_package = stdlib_path.join("importlib"); @@ -1082,7 +1082,7 @@ mod tests { }; let (db, stdlib_path) = py39_typeshed_test_case(TYPESHED); - let resolver = ResolverState::new(&db, TargetVersion::Py39); + let resolver = ResolverState::new(&db, PythonVersion::PY39); // The `xml` package no longer exists on py39: let xml_namespace_package = stdlib_path.join("xml"); diff --git a/crates/red_knot_python_semantic/src/module_resolver/resolver.rs b/crates/red_knot_python_semantic/src/module_resolver/resolver.rs index c6173a3180027..913abd6b1ed4a 100644 --- a/crates/red_knot_python_semantic/src/module_resolver/resolver.rs +++ b/crates/red_knot_python_semantic/src/module_resolver/resolver.rs @@ -12,7 +12,7 @@ use super::path::{ModulePath, SearchPath, SearchPathValidationError}; use super::state::ResolverState; use crate::db::Db; use crate::module_name::ModuleName; -use crate::{Program, SearchPathSettings, TargetVersion}; +use crate::{Program, PythonVersion, SearchPathSettings}; /// Resolves a module name to a module. pub fn resolve_module(db: &dyn Db, module_name: ModuleName) -> Option { @@ -451,7 +451,7 @@ impl<'db> Iterator for PthFileIterator<'db> { /// Validated and normalized module-resolution settings. #[derive(Clone, Debug, PartialEq, Eq)] pub(crate) struct ModuleResolutionSettings { - target_version: TargetVersion, + target_version: PythonVersion, /// Search paths that have been statically determined purely from reading Ruff's configuration settings. /// These shouldn't ever change unless the config settings themselves change. @@ -467,7 +467,7 @@ pub(crate) struct ModuleResolutionSettings { } impl ModuleResolutionSettings { - fn target_version(&self) -> TargetVersion { + fn target_version(&self) -> PythonVersion { self.target_version } @@ -496,7 +496,7 @@ fn resolve_name(db: &dyn Db, name: &ModuleName) -> Option<(SearchPath, File, Mod let target_version = resolver_settings.target_version(); let resolver_state = ResolverState::new(db, target_version); let is_builtin_module = - ruff_python_stdlib::sys::is_builtin_module(target_version.minor_version(), name.as_str()); + ruff_python_stdlib::sys::is_builtin_module(target_version.minor, name.as_str()); for search_path in resolver_settings.search_paths(db) { // When a builtin module is imported, standard module resolution is bypassed: @@ -706,7 +706,7 @@ mod tests { let TestCase { db, stdlib, .. } = TestCaseBuilder::new() .with_src_files(SRC) .with_custom_typeshed(TYPESHED) - .with_target_version(TargetVersion::Py38) + .with_target_version(PythonVersion::PY38) .build(); let builtins_module_name = ModuleName::new_static("builtins").unwrap(); @@ -724,7 +724,7 @@ mod tests { let TestCase { db, stdlib, .. } = TestCaseBuilder::new() .with_custom_typeshed(TYPESHED) - .with_target_version(TargetVersion::Py38) + .with_target_version(PythonVersion::PY38) .build(); let functools_module_name = ModuleName::new_static("functools").unwrap(); @@ -777,7 +777,7 @@ mod tests { let TestCase { db, stdlib, .. } = TestCaseBuilder::new() .with_custom_typeshed(TYPESHED) - .with_target_version(TargetVersion::Py38) + .with_target_version(PythonVersion::PY38) .build(); let existing_modules = create_module_names(&["asyncio", "functools", "xml.etree"]); @@ -822,7 +822,7 @@ mod tests { let TestCase { db, .. } = TestCaseBuilder::new() .with_custom_typeshed(TYPESHED) - .with_target_version(TargetVersion::Py38) + .with_target_version(PythonVersion::PY38) .build(); let nonexisting_modules = create_module_names(&[ @@ -866,7 +866,7 @@ mod tests { let TestCase { db, stdlib, .. } = TestCaseBuilder::new() .with_custom_typeshed(TYPESHED) - .with_target_version(TargetVersion::Py39) + .with_target_version(PythonVersion::PY39) .build(); let existing_modules = create_module_names(&[ @@ -908,7 +908,7 @@ mod tests { let TestCase { db, .. } = TestCaseBuilder::new() .with_custom_typeshed(TYPESHED) - .with_target_version(TargetVersion::Py39) + .with_target_version(PythonVersion::PY39) .build(); let nonexisting_modules = create_module_names(&["importlib", "xml", "xml.etree"]); @@ -932,7 +932,7 @@ mod tests { let TestCase { db, src, .. } = TestCaseBuilder::new() .with_src_files(SRC) .with_custom_typeshed(TYPESHED) - .with_target_version(TargetVersion::Py38) + .with_target_version(PythonVersion::PY38) .build(); let functools_module_name = ModuleName::new_static("functools").unwrap(); @@ -956,7 +956,7 @@ mod tests { fn stdlib_uses_vendored_typeshed_when_no_custom_typeshed_supplied() { let TestCase { db, stdlib, .. } = TestCaseBuilder::new() .with_vendored_typeshed() - .with_target_version(TargetVersion::default()) + .with_target_version(PythonVersion::default()) .build(); let pydoc_data_topics_name = ModuleName::new_static("pydoc_data.topics").unwrap(); @@ -1209,7 +1209,7 @@ mod tests { site_packages: vec![site_packages], }; - Program::new(&db, TargetVersion::Py38, search_paths); + Program::new(&db, PythonVersion::PY38, search_paths); let foo_module = resolve_module(&db, ModuleName::new_static("foo").unwrap()).unwrap(); let bar_module = resolve_module(&db, ModuleName::new_static("bar").unwrap()).unwrap(); @@ -1243,7 +1243,7 @@ mod tests { fn deleting_an_unrelated_file_doesnt_change_module_resolution() { let TestCase { mut db, src, .. } = TestCaseBuilder::new() .with_src_files(&[("foo.py", "x = 1"), ("bar.py", "x = 2")]) - .with_target_version(TargetVersion::Py38) + .with_target_version(PythonVersion::PY38) .build(); let foo_module_name = ModuleName::new_static("foo").unwrap(); @@ -1331,7 +1331,7 @@ mod tests { .. } = TestCaseBuilder::new() .with_custom_typeshed(TYPESHED) - .with_target_version(TargetVersion::Py38) + .with_target_version(PythonVersion::PY38) .build(); let functools_module_name = ModuleName::new_static("functools").unwrap(); @@ -1379,7 +1379,7 @@ mod tests { .. } = TestCaseBuilder::new() .with_custom_typeshed(TYPESHED) - .with_target_version(TargetVersion::Py38) + .with_target_version(PythonVersion::PY38) .build(); let functools_module_name = ModuleName::new_static("functools").unwrap(); @@ -1419,7 +1419,7 @@ mod tests { } = TestCaseBuilder::new() .with_src_files(SRC) .with_custom_typeshed(TYPESHED) - .with_target_version(TargetVersion::Py38) + .with_target_version(PythonVersion::PY38) .build(); let functools_module_name = ModuleName::new_static("functools").unwrap(); @@ -1705,7 +1705,7 @@ not_a_directory Program::new( &db, - TargetVersion::default(), + PythonVersion::default(), SearchPathSettings { extra_paths: vec![], src_root: SystemPathBuf::from("/src"), diff --git a/crates/red_knot_python_semantic/src/module_resolver/state.rs b/crates/red_knot_python_semantic/src/module_resolver/state.rs index 1b16e13e40091..cb56e5c8463fd 100644 --- a/crates/red_knot_python_semantic/src/module_resolver/state.rs +++ b/crates/red_knot_python_semantic/src/module_resolver/state.rs @@ -2,16 +2,16 @@ use ruff_db::vendored::VendoredFileSystem; use super::typeshed::LazyTypeshedVersions; use crate::db::Db; -use crate::TargetVersion; +use crate::python_version::PythonVersion; pub(crate) struct ResolverState<'db> { pub(crate) db: &'db dyn Db, pub(crate) typeshed_versions: LazyTypeshedVersions<'db>, - pub(crate) target_version: TargetVersion, + pub(crate) target_version: PythonVersion, } impl<'db> ResolverState<'db> { - pub(crate) fn new(db: &'db dyn Db, target_version: TargetVersion) -> Self { + pub(crate) fn new(db: &'db dyn Db, target_version: PythonVersion) -> Self { Self { db, typeshed_versions: LazyTypeshedVersions::new(), diff --git a/crates/red_knot_python_semantic/src/module_resolver/testing.rs b/crates/red_knot_python_semantic/src/module_resolver/testing.rs index 628a702e13a2e..a754348403f8a 100644 --- a/crates/red_knot_python_semantic/src/module_resolver/testing.rs +++ b/crates/red_knot_python_semantic/src/module_resolver/testing.rs @@ -3,7 +3,7 @@ use ruff_db::vendored::VendoredPathBuf; use crate::db::tests::TestDb; use crate::program::{Program, SearchPathSettings}; -use crate::python_version::TargetVersion; +use crate::python_version::PythonVersion; /// A test case for the module resolver. /// @@ -17,7 +17,7 @@ pub(crate) struct TestCase { // so this is a single directory instead of a `Vec` of directories, // like it is in `ruff_db::Program`. pub(crate) site_packages: SystemPathBuf, - pub(crate) target_version: TargetVersion, + pub(crate) target_version: PythonVersion, } /// A `(file_name, file_contents)` tuple @@ -99,7 +99,7 @@ pub(crate) struct UnspecifiedTypeshed; /// to `()`. pub(crate) struct TestCaseBuilder { typeshed_option: T, - target_version: TargetVersion, + target_version: PythonVersion, first_party_files: Vec, site_packages_files: Vec, } @@ -118,7 +118,7 @@ impl TestCaseBuilder { } /// Specify the target Python version the module resolver should assume - pub(crate) fn with_target_version(mut self, target_version: TargetVersion) -> Self { + pub(crate) fn with_target_version(mut self, target_version: PythonVersion) -> Self { self.target_version = target_version; self } @@ -145,7 +145,7 @@ impl TestCaseBuilder { pub(crate) fn new() -> TestCaseBuilder { Self { typeshed_option: UnspecifiedTypeshed, - target_version: TargetVersion::default(), + target_version: PythonVersion::default(), first_party_files: vec![], site_packages_files: vec![], } diff --git a/crates/red_knot_python_semantic/src/module_resolver/typeshed/versions.rs b/crates/red_knot_python_semantic/src/module_resolver/typeshed/versions.rs index 6962953f12035..de53f0054809f 100644 --- a/crates/red_knot_python_semantic/src/module_resolver/typeshed/versions.rs +++ b/crates/red_knot_python_semantic/src/module_resolver/typeshed/versions.rs @@ -14,7 +14,7 @@ use ruff_db::files::{system_path_to_file, File}; use super::vendored::vendored_typeshed_stubs; use crate::db::Db; use crate::module_name::ModuleName; -use crate::python_version::{PythonVersion, TargetVersion}; +use crate::python_version::PythonVersion; #[derive(Debug)] pub(crate) struct LazyTypeshedVersions<'db>(OnceCell<&'db TypeshedVersions>); @@ -43,7 +43,7 @@ impl<'db> LazyTypeshedVersions<'db> { db: &'db dyn Db, module: &ModuleName, stdlib_root: Option<&SystemPath>, - target_version: TargetVersion, + target_version: PythonVersion, ) -> TypeshedVersionsQueryResult { let versions = self.0.get_or_init(|| { let versions_path = if let Some(system_path) = stdlib_root { @@ -63,7 +63,7 @@ impl<'db> LazyTypeshedVersions<'db> { // Unwrapping here is not correct... parse_typeshed_versions(db, versions_file).as_ref().unwrap() }); - versions.query_module(module, PythonVersion::from(target_version)) + versions.query_module(module, target_version) } } @@ -427,27 +427,27 @@ mod tests { assert!(versions.contains_exact(&asyncio)); assert_eq!( - versions.query_module(&asyncio, TargetVersion::Py310.into()), + versions.query_module(&asyncio, PythonVersion::PY310), TypeshedVersionsQueryResult::Exists ); assert!(versions.contains_exact(&asyncio_staggered)); assert_eq!( - versions.query_module(&asyncio_staggered, TargetVersion::Py38.into()), + versions.query_module(&asyncio_staggered, PythonVersion::PY38), TypeshedVersionsQueryResult::Exists ); assert_eq!( - versions.query_module(&asyncio_staggered, TargetVersion::Py37.into()), + versions.query_module(&asyncio_staggered, PythonVersion::PY37), TypeshedVersionsQueryResult::DoesNotExist ); assert!(versions.contains_exact(&audioop)); assert_eq!( - versions.query_module(&audioop, TargetVersion::Py312.into()), + versions.query_module(&audioop, PythonVersion::PY312), TypeshedVersionsQueryResult::Exists ); assert_eq!( - versions.query_module(&audioop, TargetVersion::Py313.into()), + versions.query_module(&audioop, PythonVersion::PY313), TypeshedVersionsQueryResult::DoesNotExist ); } @@ -539,15 +539,15 @@ foo: 3.8- # trailing comment assert!(parsed_versions.contains_exact(&bar)); assert_eq!( - parsed_versions.query_module(&bar, TargetVersion::Py37.into()), + parsed_versions.query_module(&bar, PythonVersion::PY37), TypeshedVersionsQueryResult::Exists ); assert_eq!( - parsed_versions.query_module(&bar, TargetVersion::Py310.into()), + parsed_versions.query_module(&bar, PythonVersion::PY310), TypeshedVersionsQueryResult::Exists ); assert_eq!( - parsed_versions.query_module(&bar, TargetVersion::Py311.into()), + parsed_versions.query_module(&bar, PythonVersion::PY311), TypeshedVersionsQueryResult::DoesNotExist ); } @@ -559,15 +559,15 @@ foo: 3.8- # trailing comment assert!(parsed_versions.contains_exact(&foo)); assert_eq!( - parsed_versions.query_module(&foo, TargetVersion::Py37.into()), + parsed_versions.query_module(&foo, PythonVersion::PY37), TypeshedVersionsQueryResult::DoesNotExist ); assert_eq!( - parsed_versions.query_module(&foo, TargetVersion::Py38.into()), + parsed_versions.query_module(&foo, PythonVersion::PY38), TypeshedVersionsQueryResult::Exists ); assert_eq!( - parsed_versions.query_module(&foo, TargetVersion::Py311.into()), + parsed_versions.query_module(&foo, PythonVersion::PY311), TypeshedVersionsQueryResult::Exists ); } @@ -579,15 +579,15 @@ foo: 3.8- # trailing comment assert!(parsed_versions.contains_exact(&bar_baz)); assert_eq!( - parsed_versions.query_module(&bar_baz, TargetVersion::Py37.into()), + parsed_versions.query_module(&bar_baz, PythonVersion::PY37), TypeshedVersionsQueryResult::Exists ); assert_eq!( - parsed_versions.query_module(&bar_baz, TargetVersion::Py39.into()), + parsed_versions.query_module(&bar_baz, PythonVersion::PY39), TypeshedVersionsQueryResult::Exists ); assert_eq!( - parsed_versions.query_module(&bar_baz, TargetVersion::Py310.into()), + parsed_versions.query_module(&bar_baz, PythonVersion::PY310), TypeshedVersionsQueryResult::DoesNotExist ); } @@ -599,15 +599,15 @@ foo: 3.8- # trailing comment assert!(!parsed_versions.contains_exact(&bar_eggs)); assert_eq!( - parsed_versions.query_module(&bar_eggs, TargetVersion::Py37.into()), + parsed_versions.query_module(&bar_eggs, PythonVersion::PY37), TypeshedVersionsQueryResult::MaybeExists ); assert_eq!( - parsed_versions.query_module(&bar_eggs, TargetVersion::Py310.into()), + parsed_versions.query_module(&bar_eggs, PythonVersion::PY310), TypeshedVersionsQueryResult::MaybeExists ); assert_eq!( - parsed_versions.query_module(&bar_eggs, TargetVersion::Py311.into()), + parsed_versions.query_module(&bar_eggs, PythonVersion::PY311), TypeshedVersionsQueryResult::DoesNotExist ); } @@ -619,11 +619,11 @@ foo: 3.8- # trailing comment assert!(!parsed_versions.contains_exact(&spam)); assert_eq!( - parsed_versions.query_module(&spam, TargetVersion::Py37.into()), + parsed_versions.query_module(&spam, PythonVersion::PY37), TypeshedVersionsQueryResult::DoesNotExist ); assert_eq!( - parsed_versions.query_module(&spam, TargetVersion::Py313.into()), + parsed_versions.query_module(&spam, PythonVersion::PY313), TypeshedVersionsQueryResult::DoesNotExist ); } diff --git a/crates/red_knot_python_semantic/src/program.rs b/crates/red_knot_python_semantic/src/program.rs index 00b225cedb6b9..7b79caed38a1f 100644 --- a/crates/red_knot_python_semantic/src/program.rs +++ b/crates/red_knot_python_semantic/src/program.rs @@ -1,11 +1,11 @@ -use crate::python_version::TargetVersion; +use crate::python_version::PythonVersion; use crate::Db; use ruff_db::system::SystemPathBuf; use salsa::Durability; #[salsa::input(singleton)] pub struct Program { - pub target_version: TargetVersion, + pub target_version: PythonVersion, #[return_ref] pub search_paths: SearchPathSettings, @@ -21,7 +21,7 @@ impl Program { #[derive(Debug, Eq, PartialEq)] pub struct ProgramSettings { - pub target_version: TargetVersion, + pub target_version: PythonVersion, pub search_paths: SearchPathSettings, } diff --git a/crates/red_knot_python_semantic/src/python_version.rs b/crates/red_knot_python_semantic/src/python_version.rs index 8e631ec2e7fa4..37aff2ce65ce3 100644 --- a/crates/red_knot_python_semantic/src/python_version.rs +++ b/crates/red_knot_python_semantic/src/python_version.rs @@ -1,58 +1,9 @@ use std::fmt; -/// Enumeration of all supported Python versions +/// Representation of a Python version. /// -/// TODO: unify with the `PythonVersion` enum in the linter/formatter crates? -#[derive(Copy, Clone, Hash, PartialEq, Eq, PartialOrd, Ord, Default)] -pub enum TargetVersion { - Py37, - #[default] - Py38, - Py39, - Py310, - Py311, - Py312, - Py313, -} - -impl TargetVersion { - pub fn major_version(self) -> u8 { - PythonVersion::from(self).major - } - - pub fn minor_version(self) -> u8 { - PythonVersion::from(self).minor - } - - const fn as_display_str(self) -> &'static str { - match self { - Self::Py37 => "py37", - Self::Py38 => "py38", - Self::Py39 => "py39", - Self::Py310 => "py310", - Self::Py311 => "py311", - Self::Py312 => "py312", - Self::Py313 => "py313", - } - } -} - -impl fmt::Display for TargetVersion { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.write_str(self.as_display_str()) - } -} - -impl fmt::Debug for TargetVersion { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - fmt::Display::fmt(self, f) - } -} - -/// Generic representation for a Python version. -/// -/// Unlike [`TargetVersion`], this does not necessarily represent -/// a Python version that we actually support. +/// Unlike the `TargetVersion` enums in the CLI crates, +/// this does not necessarily represent a Python version that we actually support. #[derive(Debug, Clone, Copy, Eq, PartialEq, Ord, PartialOrd, Hash)] pub struct PythonVersion { pub major: u8, @@ -60,11 +11,34 @@ pub struct PythonVersion { } impl PythonVersion { + pub const PY37: PythonVersion = PythonVersion { major: 3, minor: 7 }; + pub const PY38: PythonVersion = PythonVersion { major: 3, minor: 8 }; + pub const PY39: PythonVersion = PythonVersion { major: 3, minor: 9 }; + pub const PY310: PythonVersion = PythonVersion { + major: 3, + minor: 10, + }; + pub const PY311: PythonVersion = PythonVersion { + major: 3, + minor: 11, + }; + pub const PY312: PythonVersion = PythonVersion { + major: 3, + minor: 12, + }; + pub const PY313: PythonVersion = PythonVersion { + major: 3, + minor: 13, + }; + pub fn free_threaded_build_available(self) -> bool { - self >= PythonVersion { - major: 3, - minor: 13, - } + self >= PythonVersion::PY313 + } +} + +impl Default for PythonVersion { + fn default() -> Self { + Self::PY38 } } @@ -86,60 +60,3 @@ impl fmt::Display for PythonVersion { write!(f, "{major}.{minor}") } } - -impl From for PythonVersion { - fn from(value: TargetVersion) -> Self { - match value { - TargetVersion::Py37 => PythonVersion { major: 3, minor: 7 }, - TargetVersion::Py38 => PythonVersion { major: 3, minor: 8 }, - TargetVersion::Py39 => PythonVersion { major: 3, minor: 9 }, - TargetVersion::Py310 => PythonVersion { - major: 3, - minor: 10, - }, - TargetVersion::Py311 => PythonVersion { - major: 3, - minor: 11, - }, - TargetVersion::Py312 => PythonVersion { - major: 3, - minor: 12, - }, - TargetVersion::Py313 => PythonVersion { - major: 3, - minor: 13, - }, - } - } -} - -#[derive(Debug, PartialEq, Eq, Clone, Copy)] -pub struct UnsupportedPythonVersion(PythonVersion); - -impl fmt::Display for UnsupportedPythonVersion { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "Python version {} is unsupported", self.0) - } -} - -impl std::error::Error for UnsupportedPythonVersion {} - -impl TryFrom for TargetVersion { - type Error = UnsupportedPythonVersion; - - fn try_from(value: PythonVersion) -> Result { - let PythonVersion { major: 3, minor } = value else { - return Err(UnsupportedPythonVersion(value)); - }; - match minor { - 7 => Ok(TargetVersion::Py37), - 8 => Ok(TargetVersion::Py38), - 9 => Ok(TargetVersion::Py39), - 10 => Ok(TargetVersion::Py310), - 11 => Ok(TargetVersion::Py311), - 12 => Ok(TargetVersion::Py312), - 13 => Ok(TargetVersion::Py313), - _ => Err(UnsupportedPythonVersion(value)), - } - } -} diff --git a/crates/red_knot_python_semantic/src/semantic_model.rs b/crates/red_knot_python_semantic/src/semantic_model.rs index ef9916ae3a97e..4b8b24be0b043 100644 --- a/crates/red_knot_python_semantic/src/semantic_model.rs +++ b/crates/red_knot_python_semantic/src/semantic_model.rs @@ -169,7 +169,7 @@ mod tests { use crate::db::tests::TestDb; use crate::program::{Program, SearchPathSettings}; - use crate::python_version::TargetVersion; + use crate::python_version::PythonVersion; use crate::types::Type; use crate::{HasTy, SemanticModel}; @@ -177,7 +177,7 @@ mod tests { let db = TestDb::new(); Program::new( &db, - TargetVersion::Py38, + PythonVersion::default(), SearchPathSettings { extra_paths: vec![], src_root: SystemPathBuf::from("/src"), diff --git a/crates/red_knot_python_semantic/src/types/infer.rs b/crates/red_knot_python_semantic/src/types/infer.rs index 2f2443046552d..40cf6eb873f4f 100644 --- a/crates/red_knot_python_semantic/src/types/infer.rs +++ b/crates/red_knot_python_semantic/src/types/infer.rs @@ -1503,7 +1503,7 @@ mod tests { use crate::builtins::builtins_scope; use crate::db::tests::TestDb; use crate::program::{Program, SearchPathSettings}; - use crate::python_version::TargetVersion; + use crate::python_version::PythonVersion; use crate::semantic_index::definition::Definition; use crate::semantic_index::symbol::FileScopeId; use crate::semantic_index::{global_scope, semantic_index, symbol_table, use_def_map}; @@ -1515,7 +1515,7 @@ mod tests { Program::new( &db, - TargetVersion::Py38, + PythonVersion::default(), SearchPathSettings { extra_paths: Vec::new(), src_root: SystemPathBuf::from("/src"), @@ -1532,7 +1532,7 @@ mod tests { Program::new( &db, - TargetVersion::Py38, + PythonVersion::default(), SearchPathSettings { extra_paths: Vec::new(), src_root: SystemPathBuf::from("/src"), diff --git a/crates/red_knot_server/src/session.rs b/crates/red_knot_server/src/session.rs index 1236f51b71a8f..594a370085375 100644 --- a/crates/red_knot_server/src/session.rs +++ b/crates/red_knot_server/src/session.rs @@ -8,7 +8,7 @@ use std::sync::Arc; use anyhow::anyhow; use lsp_types::{ClientCapabilities, Url}; -use red_knot_python_semantic::{ProgramSettings, SearchPathSettings, TargetVersion}; +use red_knot_python_semantic::{ProgramSettings, PythonVersion, SearchPathSettings}; use red_knot_workspace::db::RootDatabase; use red_knot_workspace::workspace::WorkspaceMetadata; use ruff_db::files::{system_path_to_file, File}; @@ -70,7 +70,7 @@ impl Session { let metadata = WorkspaceMetadata::from_path(system_path, &system)?; // TODO(dhruvmanila): Get the values from the client settings let program_settings = ProgramSettings { - target_version: TargetVersion::default(), + target_version: PythonVersion::default(), search_paths: SearchPathSettings { extra_paths: vec![], src_root: system_path.to_path_buf(), diff --git a/crates/red_knot_wasm/src/lib.rs b/crates/red_knot_wasm/src/lib.rs index 70d2020798d64..87d06b6a21262 100644 --- a/crates/red_knot_wasm/src/lib.rs +++ b/crates/red_knot_wasm/src/lib.rs @@ -184,16 +184,16 @@ pub enum TargetVersion { Py313, } -impl From for red_knot_python_semantic::TargetVersion { +impl From for red_knot_python_semantic::PythonVersion { fn from(value: TargetVersion) -> Self { match value { - TargetVersion::Py37 => Self::Py37, - TargetVersion::Py38 => Self::Py38, - TargetVersion::Py39 => Self::Py39, - TargetVersion::Py310 => Self::Py310, - TargetVersion::Py311 => Self::Py311, - TargetVersion::Py312 => Self::Py312, - TargetVersion::Py313 => Self::Py313, + TargetVersion::Py37 => Self::PY37, + TargetVersion::Py38 => Self::PY38, + TargetVersion::Py39 => Self::PY39, + TargetVersion::Py310 => Self::PY310, + TargetVersion::Py311 => Self::PY311, + TargetVersion::Py312 => Self::PY312, + TargetVersion::Py313 => Self::PY313, } } } diff --git a/crates/red_knot_workspace/src/lint.rs b/crates/red_knot_workspace/src/lint.rs index 0165c4bea6839..d1dfedcf094d5 100644 --- a/crates/red_knot_workspace/src/lint.rs +++ b/crates/red_knot_workspace/src/lint.rs @@ -305,7 +305,7 @@ enum AnyImportRef<'a> { #[cfg(test)] mod tests { - use red_knot_python_semantic::{Program, SearchPathSettings, TargetVersion}; + use red_knot_python_semantic::{Program, PythonVersion, SearchPathSettings}; use ruff_db::files::system_path_to_file; use ruff_db::system::{DbWithTestSystem, SystemPathBuf}; @@ -322,7 +322,7 @@ mod tests { Program::new( &db, - TargetVersion::Py38, + PythonVersion::default(), SearchPathSettings { extra_paths: Vec::new(), src_root, diff --git a/crates/red_knot_workspace/tests/check.rs b/crates/red_knot_workspace/tests/check.rs index dfb4a6e540dd5..dfbc14101b7ce 100644 --- a/crates/red_knot_workspace/tests/check.rs +++ b/crates/red_knot_workspace/tests/check.rs @@ -1,4 +1,4 @@ -use red_knot_python_semantic::{ProgramSettings, SearchPathSettings, TargetVersion}; +use red_knot_python_semantic::{ProgramSettings, PythonVersion, SearchPathSettings}; use red_knot_workspace::db::RootDatabase; use red_knot_workspace::lint::lint_semantic; use red_knot_workspace::workspace::WorkspaceMetadata; @@ -17,7 +17,7 @@ fn setup_db(workspace_root: SystemPathBuf) -> anyhow::Result { site_packages: vec![], }; let settings = ProgramSettings { - target_version: TargetVersion::default(), + target_version: PythonVersion::default(), search_paths, }; let db = RootDatabase::new(workspace, settings, system); diff --git a/crates/ruff_benchmark/benches/red_knot.rs b/crates/ruff_benchmark/benches/red_knot.rs index 95bf0b7d1e057..eb0f3638f85c9 100644 --- a/crates/ruff_benchmark/benches/red_knot.rs +++ b/crates/ruff_benchmark/benches/red_knot.rs @@ -1,6 +1,6 @@ #![allow(clippy::disallowed_names)] -use red_knot_python_semantic::{ProgramSettings, SearchPathSettings, TargetVersion}; +use red_knot_python_semantic::{ProgramSettings, PythonVersion, SearchPathSettings}; use red_knot_workspace::db::RootDatabase; use red_knot_workspace::workspace::WorkspaceMetadata; use ruff_benchmark::criterion::{criterion_group, criterion_main, BatchSize, Criterion}; @@ -43,7 +43,7 @@ fn setup_case() -> Case { let src_root = SystemPath::new("/src"); let metadata = WorkspaceMetadata::from_path(src_root, &system).unwrap(); let settings = ProgramSettings { - target_version: TargetVersion::Py312, + target_version: PythonVersion::PY312, search_paths: SearchPathSettings { extra_paths: vec![], src_root: src_root.to_path_buf(),