diff --git a/Cargo.lock b/Cargo.lock index 2dc5a258c8d12..a39907c7e4c32 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2949,7 +2949,6 @@ dependencies = [ "ruff_python_formatter", "ruff_python_parser", "ruff_python_trivia", - "rustc-hash", "serde", "serde_json", "tikv-jemallocator", @@ -4401,7 +4400,6 @@ dependencies = [ "ruff_python_trivia", "ruff_source_file", "ruff_text_size", - "rustc-hash", "salsa", "smallvec", "tracing", @@ -4435,7 +4433,6 @@ dependencies = [ "ruff_python_ast", "ruff_python_formatter", "ruff_text_size", - "rustc-hash", "salsa", "schemars", "serde", @@ -4527,7 +4524,6 @@ dependencies = [ "ruff_python_ast", "ruff_source_file", "ruff_text_size", - "rustc-hash", "salsa", "serde", "serde_json", @@ -4569,7 +4565,6 @@ dependencies = [ "ruff_python_trivia", "ruff_source_file", "ruff_text_size", - "rustc-hash", "rustc-stable-hash", "salsa", "serde", diff --git a/crates/ruff_benchmark/Cargo.toml b/crates/ruff_benchmark/Cargo.toml index d10c45f4529e9..a7edbdac32a86 100644 --- a/crates/ruff_benchmark/Cargo.toml +++ b/crates/ruff_benchmark/Cargo.toml @@ -88,5 +88,4 @@ mimalloc = { workspace = true } tikv-jemallocator = { workspace = true } [dev-dependencies] -rustc-hash = { workspace = true } rayon = { workspace = true } diff --git a/crates/ruff_benchmark/benches/ty.rs b/crates/ruff_benchmark/benches/ty.rs index 9ae6e9c40bd6a..73945d0243036 100644 --- a/crates/ruff_benchmark/benches/ty.rs +++ b/crates/ruff_benchmark/benches/ty.rs @@ -7,7 +7,6 @@ use std::ops::Range; use criterion::{BatchSize, Criterion, criterion_group, criterion_main}; use rayon::ThreadPoolBuilder; -use rustc_hash::FxHashSet; use ruff_benchmark::TestFile; use ruff_db::diagnostic::{Diagnostic, DiagnosticId, Severity}; @@ -18,7 +17,7 @@ use ruff_python_ast::PythonVersion; use ty_project::metadata::options::{EnvironmentOptions, Options}; use ty_project::metadata::value::{RangedValue, RelativePathBuf}; use ty_project::watch::{ChangeEvent, ChangedKind}; -use ty_project::{CheckMode, Db, ProjectDatabase, ProjectMetadata}; +use ty_project::{CheckMode, Db, FxHashSet, ProjectDatabase, ProjectMetadata}; struct Case { db: ProjectDatabase, diff --git a/crates/ty/tests/file_watching.rs b/crates/ty/tests/file_watching.rs index 5a738b5fd5a79..3abd34f6f33f6 100644 --- a/crates/ty/tests/file_watching.rs +++ b/crates/ty/tests/file_watching.rs @@ -207,7 +207,7 @@ impl TestCase { let mut expected: HashSet<_> = expected.into_iter().collect(); let actual = self.db().project().files(self.db()); - for file in &actual { + for file in actual.unstable_iter() { assert!( expected.remove(&file), "Indexed project files contains '{}' which was not expected.", diff --git a/crates/ty_ide/Cargo.toml b/crates/ty_ide/Cargo.toml index a7665b32ca891..d8ecc42718706 100644 --- a/crates/ty_ide/Cargo.toml +++ b/crates/ty_ide/Cargo.toml @@ -30,7 +30,6 @@ get-size2 = { workspace = true } itertools = { workspace = true } rayon = { workspace = true } regex = { workspace = true } -rustc-hash = { workspace = true } salsa = { workspace = true, features = ["compact_str"] } smallvec = { workspace = true } tracing = { workspace = true } diff --git a/crates/ty_ide/src/importer.rs b/crates/ty_ide/src/importer.rs index 5ff46a1ae14e9..f0333ac632466 100644 --- a/crates/ty_ide/src/importer.rs +++ b/crates/ty_ide/src/importer.rs @@ -16,7 +16,7 @@ The main differences here are: 3. It doesn't have as many facilities as `ruff_linter`'s importer. */ -use rustc_hash::FxHashMap; +use ty_python_semantic::FxHashMap; use ruff_db::files::File; use ruff_db::parsed::ParsedModuleRef; @@ -325,7 +325,7 @@ impl<'ast> MembersInScope<'ast> { let model = SemanticModel::new(db, file); let map = model .members_in_scope_at(node) - .into_iter() + .unstable_into_iter() .map(|(name, memberdef)| { let def = memberdef.first_reachable_definition; let kind = match *def.kind(db) { diff --git a/crates/ty_ide/src/lib.rs b/crates/ty_ide/src/lib.rs index 28989dcf8faab..332b0bd81f8e3 100644 --- a/crates/ty_ide/src/lib.rs +++ b/crates/ty_ide/src/lib.rs @@ -55,9 +55,9 @@ use ruff_db::{ vendored::VendoredPath, }; use ruff_text_size::{Ranged, TextRange}; -use rustc_hash::FxHashSet; use std::ops::{Deref, DerefMut}; use ty_project::Db; +use ty_python_semantic::FxHashSet; use ty_python_semantic::types::{Type, TypeDefinition}; /// Information associated with a text range. @@ -216,7 +216,7 @@ impl NavigationTargets { if unique.is_empty() { Self::empty() } else { - let mut targets = unique.into_iter().collect::>(); + let mut targets = unique.unstable_into_iter().collect::>(); targets.sort_by_key(|target| (target.file, target.focus_range.start())); Self(targets.into()) } diff --git a/crates/ty_ide/src/references.rs b/crates/ty_ide/src/references.rs index d759b1daed20a..18a4369af2b0b 100644 --- a/crates/ty_ide/src/references.rs +++ b/crates/ty_ide/src/references.rs @@ -78,7 +78,7 @@ pub(crate) fn references( // Check if the symbol is potentially visible outside of this module if search_across_files && is_symbol_externally_visible(goto_target) { // Look for references in all other files within the workspace - for other_file in &db.project().files(db) { + for other_file in db.project().files(db).unstable_iter() { // Skip the current file as we already processed it if other_file == file { continue; diff --git a/crates/ty_ide/src/workspace_symbols.rs b/crates/ty_ide/src/workspace_symbols.rs index a9e5e788205ad..89e6cddda031f 100644 --- a/crates/ty_ide/src/workspace_symbols.rs +++ b/crates/ty_ide/src/workspace_symbols.rs @@ -23,16 +23,16 @@ pub fn workspace_symbols(db: &dyn Db, query: &str) -> Vec { rayon::scope(move |s| { // For each file, extract symbols and add them to results - for file in files.iter() { + for file in files.unstable_iter() { let db = db.dyn_clone(); s.spawn(move |_| { - for (_, symbol) in symbols_for_file_global_only(&*db, *file).search(query) { + for (_, symbol) in symbols_for_file_global_only(&*db, file).search(query) { // It seems like we could do better here than // locking `results` for every single symbol, // but this works pretty well as it is. results.lock().unwrap().push(WorkspaceSymbolInfo { symbol: symbol.to_owned(), - file: *file, + file, }); } }); diff --git a/crates/ty_project/Cargo.toml b/crates/ty_project/Cargo.toml index 74356dac24c22..6cd0003e59797 100644 --- a/crates/ty_project/Cargo.toml +++ b/crates/ty_project/Cargo.toml @@ -37,7 +37,6 @@ ordermap = { workspace = true, features = ["serde"] } rayon = { workspace = true } regex = { workspace = true } regex-automata = { workspace = true } -rustc-hash = { workspace = true } salsa = { workspace = true } schemars = { workspace = true, optional = true } serde = { workspace = true } diff --git a/crates/ty_project/src/db/changes.rs b/crates/ty_project/src/db/changes.rs index b4f8a0f19a109..418c641ef4e71 100644 --- a/crates/ty_project/src/db/changes.rs +++ b/crates/ty_project/src/db/changes.rs @@ -9,8 +9,8 @@ use ruff_db::Db as _; use ruff_db::file_revision::FileRevision; use ruff_db::files::{File, FileRootKind, Files}; use ruff_db::system::SystemPath; -use rustc_hash::FxHashSet; use salsa::Setter; +use ty_python_semantic::FxHashSet; use ty_python_semantic::Program; /// Represents the result of applying changes to the project database. @@ -317,7 +317,9 @@ impl ProjectDatabase { } } - let diagnostics = if let Some(walker) = ProjectFilesWalker::incremental(self, added_paths) { + let diagnostics = if let Some(walker) = + ProjectFilesWalker::incremental(self, added_paths.unstable_into_iter()) + { // Use directory walking to discover newly added files. let (files, diagnostics) = walker.collect_vec(self); diff --git a/crates/ty_project/src/files.rs b/crates/ty_project/src/files.rs index 079a42d2a8b50..b361093a1165e 100644 --- a/crates/ty_project/src/files.rs +++ b/crates/ty_project/src/files.rs @@ -2,13 +2,13 @@ use std::marker::PhantomData; use std::ops::Deref; use std::sync::Arc; -use rustc_hash::FxHashSet; use salsa::Setter; use ruff_db::files::File; use crate::db::Db; use crate::{IOErrorDiagnostic, Project}; +use ty_python_semantic::FxHashSet; /// The indexed files of a project. /// @@ -164,6 +164,10 @@ impl Indexed<'_> { pub(super) fn len(&self) -> usize { self.inner.files.len() } + + pub fn unstable_iter(&self) -> IndexedIter<'_> { + self.inner.files.unstable_iter().copied() + } } impl Deref for Indexed<'_> { @@ -176,15 +180,6 @@ impl Deref for Indexed<'_> { pub(super) type IndexedIter<'a> = std::iter::Copied>; -impl<'a> IntoIterator for &'a Indexed<'_> { - type Item = File; - type IntoIter = IndexedIter<'a>; - - fn into_iter(self) -> Self::IntoIter { - self.inner.files.iter().copied() - } -} - /// A Mutable view of a project's indexed files. /// /// Allows in-place mutation of the files without deep cloning the hash set. @@ -251,12 +246,10 @@ impl Drop for IndexedMut<'_> { #[cfg(test)] mod tests { - use rustc_hash::FxHashSet; - - use crate::ProjectMetadata; use crate::db::Db; use crate::db::tests::TestDb; use crate::files::Index; + use crate::{FxHashSet, ProjectMetadata}; use ruff_db::files::system_path_to_file; use ruff_db::system::{DbWithWritableSystem as _, SystemPathBuf}; use ruff_python_ast::name::Name; @@ -288,8 +281,8 @@ mod tests { } Index::Indexed(files_2) => { assert_eq!( - files_2.iter().collect::>(), - files.iter().collect::>() + files_2.unstable_iter().collect::>(), + files.unstable_iter().collect::>() ); } } diff --git a/crates/ty_project/src/lib.rs b/crates/ty_project/src/lib.rs index fe034b0a072fe..68c37c0a0a412 100644 --- a/crates/ty_project/src/lib.rs +++ b/crates/ty_project/src/lib.rs @@ -18,7 +18,6 @@ use ruff_db::files::{File, FileRootKind}; use ruff_db::parsed::parsed_module; use ruff_db::source::{SourceTextError, source_text}; use ruff_db::system::{SystemPath, SystemPathBuf}; -use rustc_hash::FxHashSet; use salsa::Durability; use salsa::Setter; use std::backtrace::BacktraceStatus; @@ -31,6 +30,7 @@ use tracing::error; use ty_python_semantic::add_inferred_python_version_hint_to_diagnostic; use ty_python_semantic::lint::RuleSelection; use ty_python_semantic::types::check_types; +pub use ty_python_semantic::{FxHashMap, FxHashSet}; mod db; mod files; @@ -286,7 +286,7 @@ impl Project { let project_span = &project_span; rayon::scope(move |scope| { - for file in &files { + for file in files.unstable_iter() { let db = db.clone(); let reporter = &*reporter; scope.spawn(move |_| { @@ -612,16 +612,11 @@ impl<'a> ProjectFiles<'a> { ProjectFiles::Indexed(files) => files.len(), } } -} - -impl<'a> IntoIterator for &'a ProjectFiles<'a> { - type Item = File; - type IntoIter = ProjectFilesIter<'a>; - fn into_iter(self) -> Self::IntoIter { + fn unstable_iter(&self) -> ProjectFilesIter<'_> { match self { - ProjectFiles::OpenFiles(files) => ProjectFilesIter::OpenFiles(files.iter()), - ProjectFiles::Indexed(files) => ProjectFilesIter::Indexed(files.into_iter()), + ProjectFiles::OpenFiles(files) => ProjectFilesIter::OpenFiles(files.unstable_iter()), + ProjectFiles::Indexed(files) => ProjectFilesIter::Indexed(files.unstable_iter()), } } } diff --git a/crates/ty_project/src/metadata/options.rs b/crates/ty_project/src/metadata/options.rs index 8fb75ab201a6b..ab83397a31a5a 100644 --- a/crates/ty_project/src/metadata/options.rs +++ b/crates/ty_project/src/metadata/options.rs @@ -19,7 +19,6 @@ use ruff_db::vendored::VendoredFileSystem; use ruff_macros::{Combine, OptionsMetadata, RustDoc}; use ruff_options_metadata::{OptionSet, OptionsMetadata, Visit}; use ruff_python_ast::PythonVersion; -use rustc_hash::FxHasher; use serde::{Deserialize, Serialize}; use std::borrow::Cow; use std::fmt::{self, Debug, Display}; @@ -28,6 +27,7 @@ use std::ops::Deref; use std::sync::Arc; use thiserror::Error; use ty_combine::Combine; +use ty_python_semantic::FxHasher; use ty_python_semantic::lint::{Level, LintSource, RuleSelection}; use ty_python_semantic::{ ProgramSettings, PythonEnvironment, PythonPlatform, PythonVersionFileSource, diff --git a/crates/ty_project/src/walk.rs b/crates/ty_project/src/walk.rs index 8c9958c4166c6..f6e5aa90ec011 100644 --- a/crates/ty_project/src/walk.rs +++ b/crates/ty_project/src/walk.rs @@ -4,9 +4,9 @@ use ruff_db::files::{File, system_path_to_file}; use ruff_db::system::walk_directory::{ErrorKind, WalkDirectoryBuilder, WalkState}; use ruff_db::system::{SystemPath, SystemPathBuf}; use ruff_python_ast::PySourceType; -use rustc_hash::FxHashSet; use std::path::PathBuf; use thiserror::Error; +use ty_python_semantic::FxHashSet; /// Filter that decides which files are included in the project. /// diff --git a/crates/ty_python_semantic/src/dunder_all.rs b/crates/ty_python_semantic/src/dunder_all.rs index 17f1706b7eac0..5d40d926bffbb 100644 --- a/crates/ty_python_semantic/src/dunder_all.rs +++ b/crates/ty_python_semantic/src/dunder_all.rs @@ -1,5 +1,3 @@ -use rustc_hash::FxHashSet; - use ruff_db::files::File; use ruff_db::parsed::parsed_module; use ruff_python_ast::name::Name; @@ -8,7 +6,7 @@ use ruff_python_ast::{self as ast}; use crate::semantic_index::{SemanticIndex, semantic_index}; use crate::types::{Truthiness, Type, TypeContext, infer_expression_types}; -use crate::{Db, ModuleName, resolve_module}; +use crate::{Db, FxHashSet, ModuleName, resolve_module}; fn dunder_all_names_cycle_initial( _db: &dyn Db, @@ -103,7 +101,8 @@ impl<'db> DunderAllNamesCollector<'db> { // The module either does not have a `__all__` variable or it is invalid. return false; }; - self.names.extend(module_dunder_all_names.iter().cloned()); + self.names + .extend(module_dunder_all_names.unstable_iter().cloned()); true } @@ -240,7 +239,7 @@ impl<'db> StatementVisitor<'db> for DunderAllNamesCollector<'db> { if all_names.contains(&Name::new_static("__all__")) { self.update_origin(DunderAllOrigin::StarImport); - self.names.extend(all_names.iter().cloned()); + self.names.extend(all_names.unstable_iter().cloned()); } } else { // `from module import __all__` @@ -270,7 +269,7 @@ impl<'db> StatementVisitor<'db> for DunderAllNamesCollector<'db> { }; self.update_origin(DunderAllOrigin::ExternalModule); - self.names.extend(all_names.iter().cloned()); + self.names.extend(all_names.unstable_iter().cloned()); } } } diff --git a/crates/ty_python_semantic/src/hash.rs b/crates/ty_python_semantic/src/hash.rs new file mode 100644 index 0000000000000..cd9e73dce1465 --- /dev/null +++ b/crates/ty_python_semantic/src/hash.rs @@ -0,0 +1,322 @@ +use rustc_hash::FxBuildHasher; +use std::borrow::Borrow; +use std::hash::Hash; + +pub(crate) type Union<'a, V> = std::collections::hash_set::Union<'a, V, FxBuildHasher>; +pub(crate) type Intersection<'a, V> = + std::collections::hash_set::Intersection<'a, V, FxBuildHasher>; + +/// Always use this instead of [`rustc_hash::FxHashSet`]. +/// This struct intentionally does not implement `(Into)Iterator` because the iterator's output order will be unstable if the set depends on salsa's non-deterministic IDs or execution order. +/// Only use `unstable_iter()`, etc. if you are sure the iterator is safe to use despite that. +#[derive(Debug, Clone, get_size2::GetSize)] +pub struct FxHashSet(rustc_hash::FxHashSet); + +impl PartialEq for FxHashSet { + fn eq(&self, other: &Self) -> bool { + self.0 == other.0 + } +} + +impl Eq for FxHashSet {} + +impl Default for FxHashSet { + fn default() -> Self { + Self(rustc_hash::FxHashSet::default()) + } +} + +#[allow(unsafe_code)] +unsafe impl salsa::Update for FxHashSet { + unsafe fn maybe_update(old_pointer: *mut Self, new_value: Self) -> bool { + unsafe { rustc_hash::FxHashSet::maybe_update(&raw mut (*old_pointer).0, new_value.0) } + } +} + +impl FromIterator for FxHashSet { + fn from_iter>(iter: T) -> Self { + Self(rustc_hash::FxHashSet::from_iter(iter)) + } +} + +impl Extend for FxHashSet { + fn extend>(&mut self, iter: T) { + self.0.extend(iter); + } +} + +impl<'a, V: Eq + Hash + Copy> Extend<&'a V> for FxHashSet { + fn extend>(&mut self, iter: T) { + self.0.extend(iter); + } +} + +impl FxHashSet { + pub fn clear(&mut self) { + self.0.clear(); + } + + pub fn len(&self) -> usize { + self.0.len() + } + + pub fn is_empty(&self) -> bool { + self.0.is_empty() + } + + /// Unstable iterator: ordering may be inconsistent across environments and versions. Use this only if you are sure this instability will not be a problem for your use case. + pub fn unstable_iter(&self) -> std::collections::hash_set::Iter<'_, V> { + self.0.iter() + } + + /// Unstable iterator: ordering may be inconsistent across environments and versions. Use this only if you are sure this instability will not be a problem for your use case. + pub fn unstable_into_iter(self) -> std::collections::hash_set::IntoIter { + self.0.into_iter() + } +} + +impl FxHashSet { + pub fn with_capacity_and_hasher(capacity: usize, hasher: FxBuildHasher) -> Self { + Self(rustc_hash::FxHashSet::with_capacity_and_hasher( + capacity, hasher, + )) + } + + pub fn shrink_to_fit(&mut self) { + self.0.shrink_to_fit(); + } + + pub fn insert(&mut self, value: V) -> bool { + self.0.insert(value) + } + + pub fn remove(&mut self, value: &Q) -> bool + where + V: Borrow, + { + self.0.remove(value) + } + + pub fn contains(&self, value: &Q) -> bool + where + V: Borrow, + { + self.0.contains(value) + } + + pub fn union<'a>(&'a self, other: &'a FxHashSet) -> Union<'a, V> { + self.0.union(&other.0) + } + + pub fn intersection<'a>(&'a self, other: &'a FxHashSet) -> Intersection<'a, V> { + self.0.intersection(&other.0) + } +} + +impl FxHashSet { + /// If you use this often, consider using `BTreeMap` instead of `FxHashMap`. + pub fn sorted_ref_vec(&self) -> Vec<&V> { + let mut vec: Vec<&V> = self.0.iter().collect(); + vec.sort(); + vec + } + + /// If you use this often, consider using `BTreeMap` instead of `FxHashMap`. + pub fn into_sorted_vec(self) -> Vec { + let mut vec: Vec = self.0.into_iter().collect(); + vec.sort(); + vec + } +} + +/// Always use this instead of [`rustc_hash::FxHashMap`]. +/// This struct intentionally does not implement `(Into)Iterator` because the iterator's output order will be unstable if the map depends on salsa's non-deterministic IDs or execution order. +/// Only use `unstable_iter()`, etc. if you are sure the iterator is safe to use despite that. +#[derive(Debug, Clone, get_size2::GetSize)] +pub struct FxHashMap(rustc_hash::FxHashMap); + +impl PartialEq for FxHashMap { + fn eq(&self, other: &Self) -> bool { + self.0 == other.0 + } +} + +impl Eq for FxHashMap {} + +impl Default for FxHashMap { + fn default() -> Self { + Self(rustc_hash::FxHashMap::default()) + } +} + +impl, Q: ?Sized + Eq + Hash, V> std::ops::Index<&Q> for FxHashMap { + type Output = V; + + fn index(&self, key: &Q) -> &V { + &self.0[key] + } +} + +#[allow(unsafe_code)] +unsafe impl salsa::Update for FxHashMap { + unsafe fn maybe_update(old_pointer: *mut Self, new_value: Self) -> bool { + unsafe { rustc_hash::FxHashMap::maybe_update(&raw mut (*old_pointer).0, new_value.0) } + } +} + +impl FromIterator<(K, V)> for FxHashMap { + fn from_iter>(iter: T) -> Self { + Self(rustc_hash::FxHashMap::from_iter(iter)) + } +} + +impl Extend<(K, V)> for FxHashMap { + fn extend>(&mut self, iter: T) { + self.0.extend(iter); + } +} + +impl<'a, K: Eq + Hash + Copy, V: Copy> Extend<(&'a K, &'a V)> for FxHashMap { + fn extend>(&mut self, iter: T) { + self.0.extend(iter); + } +} + +impl FxHashMap { + pub fn with_capacity_and_hasher(capacity: usize, hasher: FxBuildHasher) -> Self { + Self(rustc_hash::FxHashMap::with_capacity_and_hasher( + capacity, hasher, + )) + } + + pub fn clear(&mut self) { + self.0.clear(); + } + + pub fn len(&self) -> usize { + self.0.len() + } + + pub fn is_empty(&self) -> bool { + self.0.is_empty() + } + + /// Unstable iterator: ordering may be inconsistent across environments and versions. Use this only if you are sure this instability will not be a problem for your use case. + pub fn unstable_iter(&self) -> std::collections::hash_map::Iter<'_, K, V> { + self.0.iter() + } + + /// Unstable iterator: ordering may be inconsistent across environments and versions. Use this only if you are sure this instability will not be a problem for your use case. + pub fn unstable_keys(&self) -> std::collections::hash_map::Keys<'_, K, V> { + self.0.keys() + } + + /// Unstable iterator: ordering may be inconsistent across environments and versions. Use this only if you are sure this instability will not be a problem for your use case. + pub fn unstable_values(&self) -> std::collections::hash_map::Values<'_, K, V> { + self.0.values() + } + + /// Unstable iterator: ordering may be inconsistent across environments and versions. Use this only if you are sure this instability will not be a problem for your use case. + pub fn unstable_iter_mut(&mut self) -> std::collections::hash_map::IterMut<'_, K, V> { + self.0.iter_mut() + } + + /// Unstable iterator: ordering may be inconsistent across environments and versions. Use this only if you are sure this instability will not be a problem for your use case. + pub fn unstable_values_mut(&mut self) -> std::collections::hash_map::ValuesMut<'_, K, V> { + self.0.values_mut() + } + + /// Unstable iterator: ordering may be inconsistent across environments and versions. Use this only if you are sure this instability will not be a problem for your use case. + pub fn unstable_into_iter(self) -> std::collections::hash_map::IntoIter { + self.0.into_iter() + } + + /// Unstable iterator: ordering may be inconsistent across environments and versions. Use this only if you are sure this instability will not be a problem for your use case. + pub fn unstable_into_keys(self) -> std::collections::hash_map::IntoKeys { + self.0.into_keys() + } + + /// Unstable iterator: ordering may be inconsistent across environments and versions. Use this only if you are sure this instability will not be a problem for your use case. + pub fn unstable_into_values(self) -> std::collections::hash_map::IntoValues { + self.0.into_values() + } +} + +impl FxHashMap { + pub fn shrink_to_fit(&mut self) { + self.0.shrink_to_fit(); + } + + pub fn get(&self, k: &Q) -> Option<&V> + where + K: Borrow, + { + self.0.get(k) + } + + pub fn get_mut(&mut self, k: &Q) -> Option<&mut V> + where + K: Borrow, + { + self.0.get_mut(k) + } + + pub fn entry(&mut self, k: K) -> std::collections::hash_map::Entry<'_, K, V> { + self.0.entry(k) + } + + pub fn insert(&mut self, k: K, v: V) -> Option { + self.0.insert(k, v) + } + + pub fn remove(&mut self, k: &Q) -> Option + where + K: Borrow, + { + self.0.remove(k) + } + + pub fn contains_key(&self, k: &Q) -> bool + where + K: Borrow, + { + self.0.contains_key(k) + } + + pub fn retain(&mut self, f: F) + where + F: FnMut(&K, &mut V) -> bool, + { + self.0.retain(f); + } +} + +impl FxHashMap { + /// If you use this often, consider using `BTreeMap` instead of `FxHashMap`. + pub fn sorted_key_ref_vec(&self) -> Vec<&K> { + let mut vec: Vec<&K> = self.0.keys().collect(); + vec.sort(); + vec + } + + /// If you use this often, consider using `BTreeMap` instead of `FxHashMap`. + pub fn into_sorted_key_vec(self) -> Vec { + let mut vec: Vec = self.0.into_keys().collect(); + vec.sort(); + vec + } + + /// If you use this often, consider using `BTreeMap` instead of `FxHashMap`. + pub fn sorted_ref_vec(&self) -> Vec<(&K, &V)> { + let mut vec: Vec<(&K, &V)> = self.0.iter().collect(); + vec.sort_by(|(k1, _), (k2, _)| k1.cmp(k2)); + vec + } + + /// If you use this often, consider using `BTreeMap` instead of `FxHashMap`. + pub fn into_sorted_vec(self) -> Vec<(K, V)> { + let mut vec: Vec<(K, V)> = self.0.into_iter().collect(); + vec.sort_by(|(k1, _), (k2, _)| k1.cmp(k2)); + vec + } +} diff --git a/crates/ty_python_semantic/src/lib.rs b/crates/ty_python_semantic/src/lib.rs index 8c1776e1541d7..0040f7a67c4fa 100644 --- a/crates/ty_python_semantic/src/lib.rs +++ b/crates/ty_python_semantic/src/lib.rs @@ -10,6 +10,7 @@ use crate::suppression::{ }; pub use db::Db; pub use diagnostic::add_inferred_python_version_hint_to_diagnostic; +pub use hash::{FxHashMap, FxHashSet}; pub use module_name::{ModuleName, ModuleNameResolutionError}; pub use module_resolver::{ KnownModule, Module, SearchPath, SearchPathValidationError, SearchPaths, all_modules, @@ -21,7 +22,7 @@ pub use program::{ PythonVersionWithSource, SearchPathSettings, }; pub use python_platform::PythonPlatform; -use rustc_hash::FxHasher; +pub use rustc_hash::{FxBuildHasher, FxHasher}; pub use semantic_model::{ Completion, HasDefinition, HasType, MemberDefinition, NameKind, SemanticModel, }; @@ -37,6 +38,7 @@ pub use types::ide_support::{ pub mod ast_node_ref; mod db; mod dunder_all; +mod hash; pub mod lint; pub(crate) mod list; mod module_name; diff --git a/crates/ty_python_semantic/src/lint.rs b/crates/ty_python_semantic/src/lint.rs index f1774cbb40426..f5c82aa69114f 100644 --- a/crates/ty_python_semantic/src/lint.rs +++ b/crates/ty_python_semantic/src/lint.rs @@ -1,8 +1,8 @@ +use crate::FxHashMap; use crate::diagnostic::did_you_mean; use core::fmt; use itertools::Itertools; use ruff_db::diagnostic::{DiagnosticId, LintName, Severity}; -use rustc_hash::FxHashMap; use std::error::Error; use std::fmt::Formatter; use std::hash::Hasher; @@ -389,7 +389,7 @@ impl LintRegistry { } } - let suggestion = did_you_mean(self.by_name.keys(), code); + let suggestion = did_you_mean(self.by_name.unstable_keys(), code); Err(GetLintError::Unknown { code: code.to_string(), @@ -404,11 +404,11 @@ impl LintRegistry { &self.lints } - /// Returns an iterator over all known aliases and to their target lints. + /// Returns an unstable iterator over all known aliases and to their target lints. /// /// This iterator includes aliases that point to removed lints. pub fn aliases(&self) -> impl Iterator + '_ { - self.by_name.iter().filter_map(|(key, value)| { + self.by_name.unstable_iter().filter_map(|(key, value)| { if let LintEntry::Alias(alias) = value { Some((LintName::of(key), *alias)) } else { @@ -417,9 +417,9 @@ impl LintRegistry { }) } - /// Iterates over all removed lints. + /// Iterates over all removed lints (unstable order). pub fn removed(&self) -> impl Iterator + '_ { - self.by_name.iter().filter_map(|(_, value)| { + self.by_name.unstable_iter().filter_map(|(_, value)| { if let LintEntry::Removed(metadata) = value { Some(*metadata) } else { @@ -536,15 +536,15 @@ impl RuleSelection { RuleSelection { lints } } - /// Returns an iterator over all enabled lints. + /// Returns an unstable iterator over all enabled lints. pub fn enabled(&self) -> impl Iterator + '_ { - self.lints.keys().copied() + self.lints.unstable_keys().copied() } - /// Returns an iterator over all enabled lints and their severity. + /// Returns an unstable iterator over all enabled lints and their severity. pub fn iter(&self) -> impl ExactSizeIterator + '_ { self.lints - .iter() + .unstable_iter() .map(|(&lint, &(severity, _))| (lint, severity)) } @@ -579,7 +579,10 @@ impl RuleSelection { // This is way too verbose. impl fmt::Debug for RuleSelection { fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { - let lints = self.lints.iter().sorted_by_key(|(lint, _)| lint.name); + let lints = self + .lints + .unstable_iter() + .sorted_by_key(|(lint, _)| lint.name); if f.alternate() { let mut f = f.debug_map(); diff --git a/crates/ty_python_semantic/src/module_resolver/resolver.rs b/crates/ty_python_semantic/src/module_resolver/resolver.rs index ecf92d2d83ffd..4c241b4e6400f 100644 --- a/crates/ty_python_semantic/src/module_resolver/resolver.rs +++ b/crates/ty_python_semantic/src/module_resolver/resolver.rs @@ -14,7 +14,6 @@ use std::iter::FusedIterator; use std::str::Split; use compact_str::format_compact; -use rustc_hash::{FxBuildHasher, FxHashSet}; use ruff_db::files::{File, FilePath, FileRootKind}; use ruff_db::system::{DirectoryEntry, System, SystemPath, SystemPathBuf}; @@ -27,7 +26,7 @@ use ruff_python_ast::{ use crate::db::Db; use crate::module_name::ModuleName; use crate::module_resolver::typeshed::{TypeshedVersions, vendored_typeshed_versions}; -use crate::{Program, SearchPathSettings}; +use crate::{FxBuildHasher, FxHashSet, Program, SearchPathSettings}; use super::module::{Module, ModuleKind}; use super::path::{ModulePath, SearchPath, SearchPathValidationError, SystemOrVendoredPathRef}; diff --git a/crates/ty_python_semantic/src/module_resolver/typeshed.rs b/crates/ty_python_semantic/src/module_resolver/typeshed.rs index 17b85397b4335..8d2d9310975c4 100644 --- a/crates/ty_python_semantic/src/module_resolver/typeshed.rs +++ b/crates/ty_python_semantic/src/module_resolver/typeshed.rs @@ -6,8 +6,8 @@ use std::str::FromStr; use ruff_db::vendored::VendoredFileSystem; use ruff_python_ast::{PythonVersion, PythonVersionDeserializationError}; -use rustc_hash::FxHashMap; +use crate::FxHashMap; use crate::Program; use crate::db::Db; use crate::module_name::ModuleName; @@ -222,7 +222,7 @@ impl FromStr for TypeshedVersions { impl fmt::Display for TypeshedVersions { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - let sorted_items: BTreeMap<&ModuleName, &PyVersionRange> = self.0.iter().collect(); + let sorted_items: BTreeMap<&ModuleName, &PyVersionRange> = self.0.unstable_iter().collect(); for (module_name, range) in sorted_items { writeln!(f, "{module_name}: {range}")?; } diff --git a/crates/ty_python_semantic/src/semantic_index.rs b/crates/ty_python_semantic/src/semantic_index.rs index f4ab765f08b2b..b7cdd466238a9 100644 --- a/crates/ty_python_semantic/src/semantic_index.rs +++ b/crates/ty_python_semantic/src/semantic_index.rs @@ -7,7 +7,6 @@ use ruff_index::{IndexSlice, IndexVec}; use ruff_python_ast::NodeIndex; use ruff_python_parser::semantic_errors::SemanticSyntaxError; -use rustc_hash::{FxHashMap, FxHashSet}; use salsa::Update; use salsa::plumbing::AsId; @@ -28,6 +27,7 @@ use crate::semantic_index::scope::{ use crate::semantic_index::symbol::ScopedSymbolId; use crate::semantic_index::use_def::{EnclosingSnapshotKey, ScopedEnclosingSnapshotId, UseDefMap}; use crate::semantic_model::HasTrackedScope; +use crate::{FxHashMap, FxHashSet}; pub mod ast_ids; mod builder; diff --git a/crates/ty_python_semantic/src/semantic_index/ast_ids.rs b/crates/ty_python_semantic/src/semantic_index/ast_ids.rs index cc2c65526e4ad..c684bd6ddd427 100644 --- a/crates/ty_python_semantic/src/semantic_index/ast_ids.rs +++ b/crates/ty_python_semantic/src/semantic_index/ast_ids.rs @@ -1,10 +1,9 @@ -use rustc_hash::FxHashMap; - use ruff_index::newtype_index; use ruff_python_ast as ast; use ruff_python_ast::ExprRef; use crate::Db; +use crate::FxHashMap; use crate::semantic_index::ast_ids::node_key::ExpressionNodeKey; use crate::semantic_index::scope::ScopeId; use crate::semantic_index::semantic_index; diff --git a/crates/ty_python_semantic/src/semantic_index/builder.rs b/crates/ty_python_semantic/src/semantic_index/builder.rs index 9ba2069784010..cf2e745873f19 100644 --- a/crates/ty_python_semantic/src/semantic_index/builder.rs +++ b/crates/ty_python_semantic/src/semantic_index/builder.rs @@ -2,7 +2,6 @@ use std::cell::{OnceCell, RefCell}; use std::sync::Arc; use except_handlers::TryNodeContextStackManager; -use rustc_hash::{FxHashMap, FxHashSet}; use ruff_db::files::File; use ruff_db::parsed::ParsedModuleRef; @@ -50,7 +49,7 @@ use crate::semantic_index::use_def::{ use crate::semantic_index::{ExpressionsScopeMap, SemanticIndex, VisibleAncestorsIter}; use crate::semantic_model::HasTrackedScope; use crate::unpack::{EvaluationMode, Unpack, UnpackKind, UnpackPosition, UnpackValue}; -use crate::{Db, Program}; +use crate::{Db, FxHashMap, FxHashSet, Program}; mod except_handlers; @@ -475,7 +474,7 @@ impl<'db, 'ast> SemanticIndexBuilder<'db, 'ast> { if !symbol.is_reassigned() { return; } - for (key, snapshot_id) in &self.enclosing_snapshots { + for (key, snapshot_id) in self.enclosing_snapshots.unstable_iter() { if let Some(enclosing_symbol) = key.enclosing_place.as_symbol() { let name = self.place_tables[key.enclosing_scope] .symbol(enclosing_symbol) diff --git a/crates/ty_python_semantic/src/semantic_index/member.rs b/crates/ty_python_semantic/src/semantic_index/member.rs index 8511c7b295159..c61b8d7ed5bd2 100644 --- a/crates/ty_python_semantic/src/semantic_index/member.rs +++ b/crates/ty_python_semantic/src/semantic_index/member.rs @@ -1,9 +1,9 @@ +use crate::FxHasher; use bitflags::bitflags; use hashbrown::hash_table::Entry; use ruff_index::{IndexVec, newtype_index}; use ruff_python_ast::{self as ast, name::Name}; use ruff_text_size::{TextLen as _, TextRange, TextSize}; -use rustc_hash::FxHasher; use smallvec::SmallVec; use std::hash::{Hash, Hasher as _}; use std::ops::{Deref, DerefMut}; diff --git a/crates/ty_python_semantic/src/semantic_index/re_exports.rs b/crates/ty_python_semantic/src/semantic_index/re_exports.rs index 22389fc549f92..a7c78a14c3137 100644 --- a/crates/ty_python_semantic/src/semantic_index/re_exports.rs +++ b/crates/ty_python_semantic/src/semantic_index/re_exports.rs @@ -26,9 +26,8 @@ use ruff_python_ast::{ name::Name, visitor::{Visitor, walk_expr, walk_pattern, walk_stmt}, }; -use rustc_hash::FxHashMap; -use crate::{Db, module_name::ModuleName, resolve_module}; +use crate::{Db, FxHashMap, module_name::ModuleName, resolve_module}; fn exports_cycle_initial(_db: &dyn Db, _id: salsa::Id, _file: File) -> Box<[Name]> { Box::default() @@ -79,7 +78,7 @@ impl<'db> ExportFinder<'db> { match self.dunder_all { DunderAll::NotPresent => self .exports - .into_iter() + .unstable_into_iter() .filter_map(|(name, kind)| { if kind == PossibleExportKind::StubImportWithoutRedundantAlias { return None; @@ -90,7 +89,7 @@ impl<'db> ExportFinder<'db> { Some(name.clone()) }) .collect(), - DunderAll::Present => self.exports.into_keys().cloned().collect(), + DunderAll::Present => self.exports.unstable_into_keys().cloned().collect(), } } } diff --git a/crates/ty_python_semantic/src/semantic_index/reachability_constraints.rs b/crates/ty_python_semantic/src/semantic_index/reachability_constraints.rs index 9da8bbe87aabb..79b896d5e97dd 100644 --- a/crates/ty_python_semantic/src/semantic_index/reachability_constraints.rs +++ b/crates/ty_python_semantic/src/semantic_index/reachability_constraints.rs @@ -196,9 +196,7 @@ use std::cmp::Ordering; use ruff_index::{Idx, IndexVec}; -use rustc_hash::FxHashMap; -use crate::Db; use crate::dunder_all::dunder_all_names; use crate::place::{RequiresExplicitReExport, imported_symbol}; use crate::rank::RankBitBox; @@ -211,6 +209,7 @@ use crate::types::{ CallableTypes, IntersectionBuilder, Truthiness, Type, TypeContext, UnionBuilder, UnionType, infer_expression_type, static_expression_truthiness, }; +use crate::{Db, FxHashMap}; /// A ternary formula that defines under what conditions a binding is visible. (A ternary formula /// is just like a boolean formula, but with `Ambiguous` as a third potential result. See the diff --git a/crates/ty_python_semantic/src/semantic_index/symbol.rs b/crates/ty_python_semantic/src/semantic_index/symbol.rs index 8aea606f597bf..4f36387a783bb 100644 --- a/crates/ty_python_semantic/src/semantic_index/symbol.rs +++ b/crates/ty_python_semantic/src/semantic_index/symbol.rs @@ -1,8 +1,8 @@ +use crate::FxHasher; use bitflags::bitflags; use hashbrown::hash_table::Entry; use ruff_index::{IndexVec, newtype_index}; use ruff_python_ast::name::Name; -use rustc_hash::FxHasher; use std::hash::{Hash as _, Hasher as _}; use std::ops::{Deref, DerefMut}; diff --git a/crates/ty_python_semantic/src/semantic_index/use_def.rs b/crates/ty_python_semantic/src/semantic_index/use_def.rs index a7c7520806319..7f2057de53b2b 100644 --- a/crates/ty_python_semantic/src/semantic_index/use_def.rs +++ b/crates/ty_python_semantic/src/semantic_index/use_def.rs @@ -241,8 +241,8 @@ //! visits a `StmtIf` node. use ruff_index::{IndexVec, newtype_index}; -use rustc_hash::FxHashMap; +use crate::FxHashMap; use crate::node_key::NodeKey; use crate::place::BoundnessAnalysis; use crate::semantic_index::ast_ids::ScopedUseId; @@ -1077,7 +1077,9 @@ impl<'db> UseDefMapBuilder<'db> { ); // And similarly for all associated members: - for (member_id, pre_definition_member_state) in pre_definition.associated_member_states { + for (member_id, pre_definition_member_state) in + pre_definition.associated_member_states.unstable_into_iter() + { let mut post_definition_state = std::mem::replace( &mut self.member_states[member_id], pre_definition_member_state, @@ -1381,7 +1383,7 @@ impl<'db> UseDefMapBuilder<'db> { for bindings in &mut self.bindings_by_use { bindings.finish(&mut self.reachability_constraints); } - for constraint in self.node_reachability.values() { + for constraint in self.node_reachability.unstable_values() { self.reachability_constraints.mark_used(*constraint); } for symbol_state in &mut self.symbol_states { @@ -1406,10 +1408,10 @@ impl<'db> UseDefMapBuilder<'db> { .declarations .finish(&mut self.reachability_constraints); } - for declarations in self.declarations_by_binding.values_mut() { + for declarations in self.declarations_by_binding.unstable_values_mut() { declarations.finish(&mut self.reachability_constraints); } - for bindings in self.bindings_by_definition.values_mut() { + for bindings in self.bindings_by_definition.unstable_values_mut() { bindings.finish(&mut self.reachability_constraints); } for eager_snapshot in &mut self.enclosing_snapshots { diff --git a/crates/ty_python_semantic/src/semantic_model.rs b/crates/ty_python_semantic/src/semantic_model.rs index 2057db47abf02..7e7fbf54c156f 100644 --- a/crates/ty_python_semantic/src/semantic_model.rs +++ b/crates/ty_python_semantic/src/semantic_model.rs @@ -4,7 +4,6 @@ use ruff_python_ast::{self as ast, ExprStringLiteral, ModExpression}; use ruff_python_ast::{Expr, ExprRef, HasNodeIndex, name::Name}; use ruff_python_parser::Parsed; use ruff_source_file::LineIndex; -use rustc_hash::FxHashMap; use crate::module_name::ModuleName; use crate::module_resolver::{KnownModule, Module, list_modules, resolve_module}; @@ -13,7 +12,7 @@ use crate::semantic_index::scope::FileScopeId; use crate::semantic_index::semantic_index; use crate::types::list_members::{Member, all_members, all_members_of_scope}; use crate::types::{Type, binding_type, infer_scope_types}; -use crate::{Db, resolve_real_shadowable_module}; +use crate::{Db, FxHashMap, resolve_real_shadowable_module}; /// The primary interface the LSP should use for querying semantic information about a [`File`]. /// @@ -164,7 +163,7 @@ impl<'db> SemanticModel<'db> { let builtin = module.is_known(self.db, KnownModule::Builtins); let mut completions = vec![]; - for Member { name, ty } in all_members(self.db, ty) { + for Member { name, ty } in all_members(self.db, ty).unstable_into_iter() { completions.push(Completion { name, ty: Some(ty), @@ -198,7 +197,7 @@ impl<'db> SemanticModel<'db> { pub fn attribute_completions(&self, node: &ast::ExprAttribute) -> Vec> { let ty = node.value.inferred_type(self); all_members(self.db, ty) - .into_iter() + .unstable_into_iter() .map(|member| Completion { name: member.name, ty: Some(member.ty), diff --git a/crates/ty_python_semantic/src/types.rs b/crates/ty_python_semantic/src/types.rs index e3b0aa77172bb..726a7c8b3e3c7 100644 --- a/crates/ty_python_semantic/src/types.rs +++ b/crates/ty_python_semantic/src/types.rs @@ -12621,6 +12621,7 @@ impl<'db> ModuleLiteralType<'db> { } /// Get the submodule attributes we believe to be defined on this module. + /// This is an unstable iterator. /// /// Note that `ModuleLiteralType` is per-importing-file, so this analysis /// includes "imports the importing file has performed". @@ -12674,7 +12675,7 @@ impl<'db> ModuleLiteralType<'db> { fn available_submodule_attributes(&self, db: &'db dyn Db) -> impl Iterator { self.importing_file(db) .into_iter() - .flat_map(|file| imported_modules(db, file)) + .flat_map(|file| imported_modules(db, file).unstable_iter()) .filter_map(|submodule_name| submodule_name.relative_to(self.module(db).name(db))) .filter_map(|relative_submodule| relative_submodule.components().next().map(Name::from)) } diff --git a/crates/ty_python_semantic/src/types/builder.rs b/crates/ty_python_semantic/src/types/builder.rs index 0618682837f1a..12d78c0577ce8 100644 --- a/crates/ty_python_semantic/src/types/builder.rs +++ b/crates/ty_python_semantic/src/types/builder.rs @@ -43,8 +43,7 @@ use crate::types::{ BytesLiteralType, IntersectionType, KnownClass, StringLiteralType, Type, TypeVarBoundOrConstraints, UnionType, }; -use crate::{Db, FxOrderSet}; -use rustc_hash::FxHashSet; +use crate::{Db, FxHashSet, FxOrderSet}; use smallvec::SmallVec; #[derive(Debug, Clone, Copy, PartialEq, Eq)] diff --git a/crates/ty_python_semantic/src/types/call/bind.rs b/crates/ty_python_semantic/src/types/call/bind.rs index 2093f2f377b96..687c286b16f84 100644 --- a/crates/ty_python_semantic/src/types/call/bind.rs +++ b/crates/ty_python_semantic/src/types/call/bind.rs @@ -9,11 +9,9 @@ use std::fmt; use itertools::{Either, Itertools}; use ruff_db::parsed::parsed_module; use ruff_python_ast::name::Name; -use rustc_hash::{FxHashMap, FxHashSet}; use smallvec::{SmallVec, smallvec, smallvec_inline}; use super::{Argument, CallArguments, CallError, CallErrorKind, InferContext, Signature, Type}; -use crate::Program; use crate::db::Db; use crate::dunder_all::dunder_all_names; use crate::place::{Definedness, Place}; @@ -41,6 +39,7 @@ use crate::types::{ TrackedConstraintSet, TypeAliasType, TypeContext, TypeVarVariance, UnionBuilder, UnionType, WrapperDescriptorKind, enums, list_members, todo_type, }; +use crate::{FxHashMap, FxHashSet, Program}; use ruff_db::diagnostic::{Annotation, Diagnostic, SubDiagnostic, SubDiagnosticSeverity}; use ruff_python_ast::{self as ast, ArgOrKeyword, PythonVersion}; @@ -844,8 +843,7 @@ impl<'db> Bindings<'db> { .unwrap_or_default(); match all_names { Some(names) => { - let mut names = names.iter().collect::>(); - names.sort(); + let names = names.sorted_ref_vec(); Type::heterogeneous_tuple( db, names.iter().map(|name| { @@ -889,7 +887,7 @@ impl<'db> Bindings<'db> { overload.set_return_type(Type::heterogeneous_tuple( db, list_members::all_members(db, *ty) - .into_iter() + .unstable_into_iter() .sorted() .map(|member| Type::string_literal(db, &member.name)), )); diff --git a/crates/ty_python_semantic/src/types/class.rs b/crates/ty_python_semantic/src/types/class.rs index 0abb33c54fb33..be40fa835accc 100644 --- a/crates/ty_python_semantic/src/types/class.rs +++ b/crates/ty_python_semantic/src/types/class.rs @@ -8,6 +8,7 @@ use super::{ SpecialFormType, SubclassOfType, Truthiness, Type, TypeQualifiers, class_base::ClassBase, function::FunctionType, }; +use crate::FxHashSet; use crate::module_resolver::KnownModule; use crate::place::TypeOrigin; use crate::semantic_index::definition::{Definition, DefinitionState}; @@ -66,7 +67,6 @@ use ruff_db::parsed::{ParsedModuleRef, parsed_module}; use ruff_python_ast::name::Name; use ruff_python_ast::{self as ast, PythonVersion}; use ruff_text_size::{Ranged, TextRange}; -use rustc_hash::FxHashSet; fn explicit_bases_cycle_initial<'db>( _db: &'db dyn Db, diff --git a/crates/ty_python_semantic/src/types/constraints.rs b/crates/ty_python_semantic/src/types/constraints.rs index 4ec970403bf2a..168123185caf8 100644 --- a/crates/ty_python_semantic/src/types/constraints.rs +++ b/crates/ty_python_semantic/src/types/constraints.rs @@ -72,7 +72,6 @@ use std::fmt::Display; use std::ops::Range; use itertools::Itertools; -use rustc_hash::{FxHashMap, FxHashSet}; use salsa::plumbing::AsId; use crate::types::generics::{GenericContext, InferableTypeVars, Specialization}; @@ -81,7 +80,7 @@ use crate::types::{ BoundTypeVarIdentity, BoundTypeVarInstance, IntersectionType, Type, TypeRelation, TypeVarBoundOrConstraints, UnionType, walk_bound_type_var_type, }; -use crate::{Db, FxOrderSet}; +use crate::{Db, FxHashMap, FxHashSet, FxOrderSet}; /// An extension trait for building constraint sets from [`Option`] values. pub(crate) trait OptionConstraintsExtension { @@ -278,7 +277,7 @@ impl<'db> ConstraintSet<'db> { let outgoing = reachable_typevars .remove(&bound_typevar) .expect("should not visit typevar twice in DFS"); - for outgoing in outgoing { + for outgoing in outgoing.unstable_into_iter() { if discovered.contains(&outgoing) { return true; } @@ -304,12 +303,12 @@ impl<'db> ConstraintSet<'db> { reachable_typevars .entry(constraint.typevar(db).identity(db)) .or_default() - .extend(visitor.reachable_typevars.into_inner()); + .extend(visitor.reachable_typevars.into_inner().unstable_into_iter()); }); // Then perform a depth-first search to see if there are any cycles. let mut discovered: FxHashSet> = FxHashSet::default(); - while let Some(bound_typevar) = reachable_typevars.keys().copied().next() { + while let Some(bound_typevar) = reachable_typevars.unstable_keys().copied().next() { if !discovered.contains(&bound_typevar) { let cycle_found = visit_dfs(&mut reachable_typevars, &mut discovered, bound_typevar); @@ -1082,7 +1081,7 @@ impl<'db> Node<'db> { .is_always_satisfied(db) }; - for typevar in typevars { + for typevar in typevars.unstable_iter() { if typevar.is_inferable(db, inferable) { // If the typevar is in inferable position, we need to verify that some valid // specialization satisfies the constraint set. @@ -1883,7 +1882,7 @@ impl<'db> InteriorNode<'db> { Node::Interior(self).for_each_constraint(db, &mut |constraint| { seen_constraints.insert(constraint); }); - let mut to_visit: Vec<(_, _)> = (seen_constraints.iter().copied()) + let mut to_visit: Vec<(_, _)> = (seen_constraints.unstable_iter().copied()) .tuple_combinations() .collect(); @@ -2042,7 +2041,7 @@ impl<'db> InteriorNode<'db> { // seen set and (if we haven't already seen it) to the to-visit queue. if seen_constraints.insert(intersection_constraint) { to_visit.extend( - (seen_constraints.iter().copied()) + (seen_constraints.unstable_iter().copied()) .filter(|seen| *seen != intersection_constraint) .map(|seen| (seen, intersection_constraint)), ); @@ -2342,7 +2341,7 @@ impl<'db> SequentMap<'db> { // Then check this constraint against all of the other ones we've seen so far, seeing // if they're related to each other. let processed = std::mem::take(&mut self.processed); - for other in &processed { + for other in processed.unstable_iter() { if constraint != *other { tracing::trace!( target: "ty_python_semantic::types::constraints::SequentMap", @@ -2736,7 +2735,7 @@ impl<'db> SequentMap<'db> { } }; - for (ante1, ante2) in &self.map.pair_impossibilities { + for (ante1, ante2) in self.map.pair_impossibilities.unstable_iter() { maybe_write_prefix(f)?; write!( f, @@ -2746,8 +2745,8 @@ impl<'db> SequentMap<'db> { )?; } - for ((ante1, ante2), posts) in &self.map.pair_implications { - for post in posts { + for ((ante1, ante2), posts) in self.map.pair_implications.unstable_iter() { + for post in posts.unstable_iter() { maybe_write_prefix(f)?; write!( f, @@ -2759,8 +2758,8 @@ impl<'db> SequentMap<'db> { } } - for (ante, posts) in &self.map.single_implications { - for post in posts { + for (ante, posts) in self.map.single_implications.unstable_iter() { + for post in posts.unstable_iter() { maybe_write_prefix(f)?; write!(f, "{} → {}", ante.display(self.db), post.display(self.db))?; } @@ -2898,7 +2897,7 @@ impl<'db> PathAssignments<'db> { // don't anticipate the sequent maps to be very large. We might consider avoiding the // brute-force search. - for ante in &map.single_tautologies { + for ante in map.single_tautologies.unstable_iter() { if self.assignment_holds(ante.when_false()) { // The sequent map says (ante1) is always true, and the current path asserts that // it's false. @@ -2915,7 +2914,7 @@ impl<'db> PathAssignments<'db> { } } - for (ante1, ante2) in &map.pair_impossibilities { + for (ante1, ante2) in map.pair_impossibilities.unstable_iter() { if self.assignment_holds(ante1.when_true()) && self.assignment_holds(ante2.when_true()) { // The sequent map says (ante1 ∧ ante2) is an impossible combination, and the @@ -2934,8 +2933,8 @@ impl<'db> PathAssignments<'db> { } } - for ((ante1, ante2), posts) in &map.pair_implications { - for post in posts { + for ((ante1, ante2), posts) in map.pair_implications.unstable_iter() { + for post in posts.unstable_iter() { if self.assignment_holds(ante1.when_true()) && self.assignment_holds(ante2.when_true()) { @@ -2944,8 +2943,8 @@ impl<'db> PathAssignments<'db> { } } - for (ante, posts) in &map.single_implications { - for post in posts { + for (ante, posts) in map.single_implications.unstable_iter() { + for post in posts.unstable_iter() { if self.assignment_holds(ante.when_true()) { self.add_assignment(db, map, post.when_true())?; } diff --git a/crates/ty_python_semantic/src/types/cyclic.rs b/crates/ty_python_semantic/src/types/cyclic.rs index 344881303a552..c52b25ba1127c 100644 --- a/crates/ty_python_semantic/src/types/cyclic.rs +++ b/crates/ty_python_semantic/src/types/cyclic.rs @@ -24,10 +24,8 @@ use std::cmp::Eq; use std::hash::Hash; use std::marker::PhantomData; -use rustc_hash::FxHashMap; - -use crate::FxIndexSet; use crate::types::Type; +use crate::{FxHashMap, FxIndexSet}; pub(crate) type TypeTransformer<'db, Tag> = CycleDetector, Type<'db>>; diff --git a/crates/ty_python_semantic/src/types/diagnostic.rs b/crates/ty_python_semantic/src/types/diagnostic.rs index d72cbf8dbcd84..fafd2c90308a5 100644 --- a/crates/ty_python_semantic/src/types/diagnostic.rs +++ b/crates/ty_python_semantic/src/types/diagnostic.rs @@ -5,6 +5,7 @@ use super::{ CallArguments, CallDunderError, ClassBase, ClassLiteral, KnownClass, add_inferred_python_version_hint_to_diagnostic, }; +use crate::FxHashSet; use crate::diagnostic::did_you_mean; use crate::diagnostic::format_enumeration; use crate::lint::{Level, LintRegistryBuilder, LintStatus}; @@ -43,7 +44,6 @@ use ruff_python_ast::name::Name; use ruff_python_ast::token::parentheses_iterator; use ruff_python_ast::{self as ast, AnyNodeRef, StringFlags}; use ruff_text_size::{Ranged, TextRange}; -use rustc_hash::FxHashSet; use std::fmt::{self, Formatter}; /// Registers all known type check lints. @@ -2235,7 +2235,8 @@ impl TypeCheckDiagnostics { pub(super) fn extend(&mut self, other: &TypeCheckDiagnostics) { self.diagnostics.extend_from_slice(&other.diagnostics); - self.used_suppressions.extend(&other.used_suppressions); + self.used_suppressions + .extend(other.used_suppressions.unstable_iter()); } pub(super) fn extend_diagnostics(&mut self, diagnostics: impl IntoIterator) { diff --git a/crates/ty_python_semantic/src/types/display.rs b/crates/ty_python_semantic/src/types/display.rs index cadd54eef11d4..37fe530edab1d 100644 --- a/crates/ty_python_semantic/src/types/display.rs +++ b/crates/ty_python_semantic/src/types/display.rs @@ -11,9 +11,7 @@ use ruff_db::source::line_index; use ruff_python_ast::str::{Quote, TripleQuotes}; use ruff_python_literal::escape::AsciiEscape; use ruff_text_size::{TextLen, TextRange, TextSize}; -use rustc_hash::{FxHashMap, FxHashSet}; -use crate::Db; use crate::types::class::{ClassLiteral, ClassType, GenericAlias}; use crate::types::function::{FunctionType, OverloadLiteral}; use crate::types::generics::{GenericContext, Specialization}; @@ -25,6 +23,7 @@ use crate::types::{ KnownInstanceType, MaterializationKind, Protocol, ProtocolInstanceType, SpecialFormType, StringLiteralType, SubclassOfInner, Type, UnionType, WrapperDescriptorKind, visitor, }; +use crate::{Db, FxHashMap, FxHashSet}; /// Settings for displaying types and signatures #[derive(Debug, Clone, Default)] @@ -87,7 +86,7 @@ impl<'db> DisplaySettings<'db> { collector .class_names .borrow() - .iter() + .unstable_iter() .filter_map(|(name, ambiguity)| { Some((*name, QualificationLevel::from_ambiguity_state(ambiguity)?)) }) diff --git a/crates/ty_python_semantic/src/types/enums.rs b/crates/ty_python_semantic/src/types/enums.rs index 9a91d1da3d06c..6b24389c478e3 100644 --- a/crates/ty_python_semantic/src/types/enums.rs +++ b/crates/ty_python_semantic/src/types/enums.rs @@ -1,8 +1,7 @@ use ruff_python_ast::name::Name; -use rustc_hash::FxHashMap; use crate::{ - Db, FxIndexMap, + Db, FxHashMap, FxIndexMap, place::{Place, PlaceAndQualifiers, place_from_bindings, place_from_declarations}, semantic_index::{place_table, use_def_map}, types::{ diff --git a/crates/ty_python_semantic/src/types/function.rs b/crates/ty_python_semantic/src/types/function.rs index 4437e09698889..4c75ca6c9d3f6 100644 --- a/crates/ty_python_semantic/src/types/function.rs +++ b/crates/ty_python_semantic/src/types/function.rs @@ -1463,7 +1463,9 @@ impl KnownFunction { }; let ty_members = all_members(db, *ty); overload.set_return_type(Type::BooleanLiteral( - ty_members.iter().any(|m| m.name == member.value(db)), + ty_members + .unstable_iter() + .any(|m| m.name == member.value(db)), )); } diff --git a/crates/ty_python_semantic/src/types/generics.rs b/crates/ty_python_semantic/src/types/generics.rs index de357dfbce2c5..517d5a5bcf39b 100644 --- a/crates/ty_python_semantic/src/types/generics.rs +++ b/crates/ty_python_semantic/src/types/generics.rs @@ -4,7 +4,6 @@ use std::fmt::Display; use itertools::{Either, Itertools}; use ruff_python_ast as ast; -use rustc_hash::{FxHashMap, FxHashSet}; use crate::semantic_index::definition::Definition; use crate::semantic_index::scope::{FileScopeId, NodeWithScopeKind, ScopeId}; @@ -23,7 +22,7 @@ use crate::types::{ TypeMapping, TypeRelation, TypeVarBoundOrConstraints, TypeVarIdentity, TypeVarInstance, TypeVarKind, TypeVarVariance, UnionType, declaration_type, walk_bound_type_var_type, }; -use crate::{Db, FxOrderMap, FxOrderSet}; +use crate::{Db, FxHashMap, FxHashSet, FxOrderMap, FxOrderSet}; /// Returns an iterator of any generic context introduced by the given scope or any enclosing /// scope. @@ -157,7 +156,7 @@ impl<'a, 'db> InferableTypeVars<'a, 'db> { pub(crate) fn iter(self) -> impl Iterator> { match self { InferableTypeVars::None => Either::Left(Either::Left(std::iter::empty())), - InferableTypeVars::One(typevars) => Either::Right(typevars.iter().copied()), + InferableTypeVars::One(typevars) => Either::Right(typevars.unstable_iter().copied()), InferableTypeVars::Two(left, right) => { let chained: Box>> = Box::new(left.iter().chain(right.iter())); @@ -175,7 +174,9 @@ impl<'a, 'db> InferableTypeVars<'a, 'db> { ) { match inferable { InferableTypeVars::None => {} - InferableTypeVars::One(typevars) => result.extend(typevars.iter().copied()), + InferableTypeVars::One(typevars) => { + result.extend(typevars.unstable_iter().copied()); + } InferableTypeVars::Two(left, right) => { find_typevars(result, left); find_typevars(result, right); @@ -188,7 +189,7 @@ impl<'a, 'db> InferableTypeVars<'a, 'db> { format!( "[{}]", typevars - .into_iter() + .unstable_into_iter() .map(|identity| identity.display(db)) .format(", ") ) diff --git a/crates/ty_python_semantic/src/types/ide_support.rs b/crates/ty_python_semantic/src/types/ide_support.rs index 2c53ea275fdf5..1be79c6d40375 100644 --- a/crates/ty_python_semantic/src/types/ide_support.rs +++ b/crates/ty_python_semantic/src/types/ide_support.rs @@ -1,5 +1,6 @@ use std::collections::HashMap; +use crate::FxHashSet; use crate::place::builtins_module_scope; use crate::semantic_index::definition::Definition; use crate::semantic_index::definition::DefinitionKind; @@ -13,7 +14,6 @@ use ruff_db::files::FileRange; use ruff_db::parsed::parsed_module; use ruff_python_ast::{self as ast, AnyNodeRef}; use ruff_text_size::{Ranged, TextRange}; -use rustc_hash::FxHashSet; pub use resolve_definition::{ImportAliasResolution, ResolvedDefinition, map_stub_definition}; use resolve_definition::{find_symbol_in_scope, resolve_definition}; @@ -833,14 +833,13 @@ mod resolve_definition { use ruff_db::system::SystemPath; use ruff_db::vendored::VendoredPathBuf; use ruff_python_ast as ast; - use rustc_hash::FxHashSet; use tracing::trace; use crate::module_resolver::file_to_module; use crate::semantic_index::definition::{Definition, DefinitionKind, module_docstring}; use crate::semantic_index::scope::{NodeWithScopeKind, ScopeId}; use crate::semantic_index::{global_scope, place_table, semantic_index, use_def_map}; - use crate::{Db, ModuleName, resolve_module, resolve_real_module}; + use crate::{Db, FxHashSet, ModuleName, resolve_module, resolve_real_module}; /// Represents the result of resolving an import to either a specific definition or /// a specific range within a file. diff --git a/crates/ty_python_semantic/src/types/infer.rs b/crates/ty_python_semantic/src/types/infer.rs index b9adc93eb28ff..892d71db61e7a 100644 --- a/crates/ty_python_semantic/src/types/infer.rs +++ b/crates/ty_python_semantic/src/types/infer.rs @@ -38,11 +38,9 @@ use ruff_db::parsed::{ParsedModuleRef, parsed_module}; use ruff_text_size::Ranged; -use rustc_hash::{FxHashMap, FxHashSet}; use salsa; use salsa::plumbing::AsId; -use crate::Db; use crate::semantic_index::ast_ids::node_key::ExpressionNodeKey; use crate::semantic_index::definition::Definition; use crate::semantic_index::expression::Expression; @@ -56,6 +54,7 @@ use crate::types::{ ClassLiteral, KnownClass, Truthiness, Type, TypeAndQualifiers, declaration_type, }; use crate::unpack::Unpack; +use crate::{Db, FxHashMap, FxHashSet}; use builder::TypeInferenceBuilder; pub(super) use builder::UnsupportedComparisonError; @@ -565,7 +564,7 @@ impl<'db> ScopeInference<'db> { previous_inference: &ScopeInference<'db>, cycle: &salsa::Cycle, ) -> ScopeInference<'db> { - for (expr, ty) in &mut self.expressions { + for (expr, ty) in self.expressions.unstable_iter_mut() { let previous_ty = previous_inference.expression_type(*expr); *ty = ty.cycle_normalized(db, previous_ty, cycle); } @@ -675,7 +674,7 @@ impl<'db> DefinitionInference<'db> { previous_inference: &DefinitionInference<'db>, cycle: &salsa::Cycle, ) -> DefinitionInference<'db> { - for (expr, ty) in &mut self.expressions { + for (expr, ty) in self.expressions.unstable_iter_mut() { let previous_ty = previous_inference.expression_type(*expr); *ty = ty.cycle_normalized(db, previous_ty, cycle); } @@ -850,7 +849,7 @@ impl<'db> ExpressionInference<'db> { } } - for (expr, ty) in &mut self.expressions { + for (expr, ty) in self.expressions.unstable_iter_mut() { let previous_ty = previous.expression_type(*expr); *ty = ty.cycle_normalized(db, previous_ty, cycle); } diff --git a/crates/ty_python_semantic/src/types/infer/builder.rs b/crates/ty_python_semantic/src/types/infer/builder.rs index 4d05719ebf7a2..a5cade75c17d4 100644 --- a/crates/ty_python_semantic/src/types/infer/builder.rs +++ b/crates/ty_python_semantic/src/types/infer/builder.rs @@ -10,7 +10,6 @@ use ruff_python_ast::{ }; use ruff_python_stdlib::builtins::version_builtin_was_added; use ruff_text_size::{Ranged, TextRange}; -use rustc_hash::{FxHashMap, FxHashSet}; use smallvec::SmallVec; use super::{ @@ -114,7 +113,7 @@ use crate::types::{ }; use crate::types::{ClassBase, add_inferred_python_version_hint_to_diagnostic}; use crate::unpack::{EvaluationMode, UnpackPosition}; -use crate::{Db, FxIndexSet, FxOrderSet, Program}; +use crate::{Db, FxHashMap, FxHashSet, FxIndexSet, FxOrderSet, Program}; mod annotation_expression; mod type_expression; @@ -370,7 +369,8 @@ impl<'db, 'ast> TypeInferenceBuilder<'db, 'ast> { #[cfg(debug_assertions)] assert_eq!(self.scope, inference.scope); - self.expressions.extend(inference.expressions.iter()); + self.expressions + .extend(inference.expressions.unstable_iter()); self.declarations .extend(inference.declarations(), self.multi_inference_state); @@ -385,7 +385,7 @@ impl<'db, 'ast> TypeInferenceBuilder<'db, 'ast> { self.deferred .extend(extra.deferred.iter().copied(), self.multi_inference_state); self.string_annotations - .extend(extra.string_annotations.iter().copied()); + .extend(extra.string_annotations.unstable_iter()); } } @@ -397,13 +397,14 @@ impl<'db, 'ast> TypeInferenceBuilder<'db, 'ast> { } fn extend_expression_unchecked(&mut self, inference: &ExpressionInference<'db>) { - self.expressions.extend(inference.expressions.iter()); + self.expressions + .extend(inference.expressions.unstable_iter()); if let Some(extra) = &inference.extra { self.context.extend(&extra.diagnostics); self.extend_cycle_recovery(extra.cycle_recovery); self.string_annotations - .extend(extra.string_annotations.iter().copied()); + .extend(extra.string_annotations.unstable_iter()); if !matches!(self.region, InferenceRegion::Scope(..)) { self.bindings diff --git a/crates/ty_python_semantic/src/types/list_members.rs b/crates/ty_python_semantic/src/types/list_members.rs index eb47745b740f3..d13381a65aa81 100644 --- a/crates/ty_python_semantic/src/types/list_members.rs +++ b/crates/ty_python_semantic/src/types/list_members.rs @@ -8,10 +8,9 @@ use std::cmp::Ordering; use ruff_python_ast::name::Name; -use rustc_hash::FxHashSet; use crate::{ - Db, NameKind, + Db, FxHashSet, NameKind, place::{ Place, PlaceWithDefinition, imported_symbol, place_from_bindings, place_from_declarations, }, @@ -113,7 +112,8 @@ impl<'db> AllMembers<'db> { .iter() .map(|ty| AllMembers::of(db, *ty).members) .reduce(|acc, members| acc.intersection(&members).cloned().collect()) - .unwrap_or_default(), + .unwrap_or_default() + .unstable_into_iter(), ), Type::Intersection(intersection) => self.members.extend( @@ -122,7 +122,8 @@ impl<'db> AllMembers<'db> { .iter() .map(|ty| AllMembers::of(db, *ty).members) .reduce(|acc, members| acc.union(&members).cloned().collect()) - .unwrap_or_default(), + .unwrap_or_default() + .unstable_into_iter(), ), Type::NominalInstance(instance) => { @@ -203,7 +204,8 @@ impl<'db> AllMembers<'db> { .reduce(|acc, members| { acc.intersection(&members).cloned().collect() }) - .unwrap_or_default(), + .unwrap_or_default() + .unstable_into_iter(), ); } } diff --git a/crates/ty_python_semantic/src/types/mro.rs b/crates/ty_python_semantic/src/types/mro.rs index 21501060dafd6..d2a395e34daf2 100644 --- a/crates/ty_python_semantic/src/types/mro.rs +++ b/crates/ty_python_semantic/src/types/mro.rs @@ -2,12 +2,11 @@ use std::collections::VecDeque; use std::ops::Deref; use indexmap::IndexMap; -use rustc_hash::FxBuildHasher; -use crate::Db; use crate::types::class_base::ClassBase; use crate::types::generics::Specialization; use crate::types::{ClassLiteral, ClassType, KnownClass, KnownInstanceType, SpecialFormType, Type}; +use crate::{Db, FxBuildHasher}; /// The inferred method resolution order of a given class. /// diff --git a/crates/ty_python_semantic/src/types/narrow.rs b/crates/ty_python_semantic/src/types/narrow.rs index 984f214414e24..c652cdfb611c7 100644 --- a/crates/ty_python_semantic/src/types/narrow.rs +++ b/crates/ty_python_semantic/src/types/narrow.rs @@ -1,4 +1,3 @@ -use crate::Db; use crate::semantic_index::expression::Expression; use crate::semantic_index::place::{PlaceExpr, PlaceTable, ScopedPlaceId}; use crate::semantic_index::place_table; @@ -15,6 +14,7 @@ use crate::types::{ SpecialFormType, SubclassOfInner, SubclassOfType, Truthiness, Type, TypeContext, TypeVarBoundOrConstraints, UnionBuilder, infer_expression_types, }; +use crate::{Db, FxHashMap}; use ruff_db::parsed::{ParsedModuleRef, parsed_module}; use ruff_python_stdlib::identifiers::is_identifier; @@ -22,7 +22,6 @@ use ruff_python_stdlib::identifiers::is_identifier; use itertools::Itertools; use ruff_python_ast as ast; use ruff_python_ast::{BoolOp, ExprBoolOp}; -use rustc_hash::FxHashMap; use std::collections::hash_map::Entry; use super::UnionType; @@ -280,7 +279,7 @@ fn merge_constraints_and<'db>( from: &NarrowingConstraints<'db>, db: &'db dyn Db, ) { - for (key, value) in from { + for (key, value) in from.unstable_iter() { match into.entry(*key) { Entry::Occupied(mut entry) => { *entry.get_mut() = IntersectionBuilder::new(db) @@ -300,7 +299,7 @@ fn merge_constraints_or<'db>( from: &NarrowingConstraints<'db>, db: &'db dyn Db, ) { - for (key, value) in from { + for (key, value) in from.unstable_iter() { match into.entry(*key) { Entry::Occupied(mut entry) => { *entry.get_mut() = UnionBuilder::new(db).add(*entry.get()).add(*value).build(); @@ -310,7 +309,7 @@ fn merge_constraints_or<'db>( } } } - for (key, value) in into.iter_mut() { + for (key, value) in into.unstable_iter_mut() { if !from.contains_key(key) { *value = Type::object(); } diff --git a/crates/ty_python_semantic/src/types/overrides.rs b/crates/ty_python_semantic/src/types/overrides.rs index 5d6328a60680f..7a2299145645a 100644 --- a/crates/ty_python_semantic/src/types/overrides.rs +++ b/crates/ty_python_semantic/src/types/overrides.rs @@ -5,10 +5,9 @@ use bitflags::bitflags; use ruff_db::diagnostic::Annotation; -use rustc_hash::FxHashSet; use crate::{ - Db, + Db, FxHashSet, lint::LintId, place::Place, semantic_index::{ @@ -56,8 +55,8 @@ pub(super) fn check_class<'db>(context: &InferContext<'db, '_>, class: ClassLite let scope = class.body_scope(db); let own_class_members: FxHashSet<_> = all_members_of_scope(db, scope).collect(); - for member in own_class_members { - check_class_declaration(context, configuration, class_specialized, scope, &member); + for member in own_class_members.unstable_iter() { + check_class_declaration(context, configuration, class_specialized, scope, member); } } diff --git a/crates/ty_python_semantic/src/types/property_tests/type_generation.rs b/crates/ty_python_semantic/src/types/property_tests/type_generation.rs index ecc274546aecb..81ac854cfc026 100644 --- a/crates/ty_python_semantic/src/types/property_tests/type_generation.rs +++ b/crates/ty_python_semantic/src/types/property_tests/type_generation.rs @@ -6,10 +6,9 @@ use crate::types::{ BoundMethodType, EnumLiteralType, IntersectionBuilder, KnownClass, Parameter, Parameters, Signature, SpecialFormType, SubclassOfType, Type, UnionType, }; -use crate::{Db, module_resolver::KnownModule}; +use crate::{Db, FxHashSet, module_resolver::KnownModule}; use quickcheck::{Arbitrary, Gen}; use ruff_python_ast::name::Name; -use rustc_hash::FxHashSet; /// A test representation of a type that can be transformed unambiguously into a real Type, /// given a db. diff --git a/crates/ty_python_semantic/src/types/protocol_class.rs b/crates/ty_python_semantic/src/types/protocol_class.rs index 80ce2af47c22b..ec5730fadb852 100644 --- a/crates/ty_python_semantic/src/types/protocol_class.rs +++ b/crates/ty_python_semantic/src/types/protocol_class.rs @@ -4,8 +4,8 @@ use std::{collections::BTreeMap, ops::Deref}; use itertools::Itertools; use ruff_python_ast::name::Name; -use rustc_hash::FxHashMap; +use crate::FxHashMap; use crate::types::TypeContext; use crate::{ Db, FxOrderSet, @@ -921,7 +921,7 @@ fn cached_protocol_interface<'db>( } } - for (symbol_id, (ty, qualifiers, bound_on_class)) in direct_members { + for (symbol_id, (ty, qualifiers, bound_on_class)) in direct_members.unstable_into_iter() { let name = place_table.symbol(symbol_id).name(); if excluded_from_proto_members(name) { continue; diff --git a/crates/ty_python_semantic/src/types/unpacker.rs b/crates/ty_python_semantic/src/types/unpacker.rs index eddd3aab0b9aa..28333e0b236d7 100644 --- a/crates/ty_python_semantic/src/types/unpacker.rs +++ b/crates/ty_python_semantic/src/types/unpacker.rs @@ -1,7 +1,7 @@ use std::borrow::Cow; +use crate::FxHashMap; use ruff_db::parsed::ParsedModuleRef; -use rustc_hash::FxHashMap; use ruff_python_ast::{self as ast, AnyNodeRef}; @@ -245,7 +245,7 @@ impl<'db> UnpackResult<'db> { previous_cycle_result: &UnpackResult<'db>, cycle: &salsa::Cycle, ) -> Self { - for (expr, ty) in &mut self.targets { + for (expr, ty) in self.targets.unstable_iter_mut() { let previous_ty = previous_cycle_result.expression_type(*expr); *ty = ty.cycle_normalized(db, previous_ty, cycle); } diff --git a/crates/ty_server/Cargo.toml b/crates/ty_server/Cargo.toml index 67441692416b6..23ced2e1c8582 100644 --- a/crates/ty_server/Cargo.toml +++ b/crates/ty_server/Cargo.toml @@ -30,7 +30,6 @@ crossbeam = { workspace = true } jod-thread = { workspace = true } lsp-server = { workspace = true } lsp-types = { workspace = true } -rustc-hash = { workspace = true } salsa = { workspace = true } serde = { workspace = true } serde_json = { workspace = true } diff --git a/crates/ty_server/src/document/notebook.rs b/crates/ty_server/src/document/notebook.rs index f3f485c942655..7995e340d7536 100644 --- a/crates/ty_server/src/document/notebook.rs +++ b/crates/ty_server/src/document/notebook.rs @@ -1,7 +1,7 @@ use lsp_types::NotebookCellKind; use ruff_notebook::CellMetadata; use ruff_source_file::OneIndexed; -use rustc_hash::FxHashMap; +use ty_python_semantic::FxHashMap; use super::{DocumentKey, DocumentVersion}; use crate::session::index::Index; diff --git a/crates/ty_server/src/server/api/diagnostics.rs b/crates/ty_server/src/server/api/diagnostics.rs index d25e6f524371c..dcb69e01f722f 100644 --- a/crates/ty_server/src/server/api/diagnostics.rs +++ b/crates/ty_server/src/server/api/diagnostics.rs @@ -8,7 +8,7 @@ use lsp_types::{ }; use ruff_diagnostics::Applicability; use ruff_text_size::Ranged; -use rustc_hash::FxHashMap; +use ty_python_semantic::FxHashMap; use ruff_db::diagnostic::{Annotation, Severity, SubDiagnostic}; use ruff_db::files::{File, FileRange}; @@ -186,7 +186,7 @@ pub(super) fn publish_diagnostics(document: &DocumentHandle, session: &Session, publish_diagnostics_notification(document.url().clone(), diagnostics); } LspDiagnostics::NotebookDocument(cell_diagnostics) => { - for (cell_url, diagnostics) in cell_diagnostics { + for (cell_url, diagnostics) in cell_diagnostics.unstable_into_iter() { publish_diagnostics_notification(cell_url, diagnostics); } } @@ -240,7 +240,7 @@ pub(crate) fn publish_settings_diagnostics( // the next time we publish settings diagnostics! let old_untracked = std::mem::replace( &mut state.untracked_files_with_pushed_diagnostics, - diagnostics_by_url.keys().cloned().collect(), + diagnostics_by_url.unstable_keys().cloned().collect(), ); // Add empty diagnostics for any files that had diagnostics before but don't now. @@ -249,7 +249,7 @@ pub(crate) fn publish_settings_diagnostics( diagnostics_by_url.entry(url).or_default(); } // Send the settings diagnostics! - for (url, file_diagnostics) in diagnostics_by_url { + for (url, file_diagnostics) in diagnostics_by_url.unstable_into_iter() { // Convert diagnostics to LSP format let lsp_diagnostics = file_diagnostics .into_iter() diff --git a/crates/ty_server/src/server/api/notifications/did_change_watched_files.rs b/crates/ty_server/src/server/api/notifications/did_change_watched_files.rs index c67bbd8e70e53..01e5f8b6d0b51 100644 --- a/crates/ty_server/src/server/api/notifications/did_change_watched_files.rs +++ b/crates/ty_server/src/server/api/notifications/did_change_watched_files.rs @@ -7,9 +7,9 @@ use crate::session::client::Client; use crate::system::AnySystemPath; use lsp_types as types; use lsp_types::{FileChangeType, notification as notif}; -use rustc_hash::FxHashMap; use ty_project::Db as _; use ty_project::watch::{ChangeEvent, ChangedKind, CreatedKind, DeletedKind}; +use ty_python_semantic::FxHashMap; pub(crate) struct DidChangeWatchedFiles; @@ -75,7 +75,7 @@ impl SyncNotificationHandler for DidChangeWatchedFiles { return Ok(()); } - for (root, changes) in events_by_db { + for (root, changes) in events_by_db.unstable_into_iter() { tracing::debug!("Applying changes to `{root}`"); session.apply_changes(&AnySystemPath::System(root.clone()), changes); diff --git a/crates/ty_server/src/server/api/requests/workspace_diagnostic.rs b/crates/ty_server/src/server/api/requests/workspace_diagnostic.rs index a9f33880e5e01..86b4bb82c6c7e 100644 --- a/crates/ty_server/src/server/api/requests/workspace_diagnostic.rs +++ b/crates/ty_server/src/server/api/requests/workspace_diagnostic.rs @@ -14,9 +14,9 @@ use lsp_types::{ use ruff_db::diagnostic::Diagnostic; use ruff_db::files::File; use ruff_db::source::source_text; -use rustc_hash::FxHashMap; use serde::{Deserialize, Serialize}; use ty_project::{ProgressReporter, ProjectDatabase}; +use ty_python_semantic::FxHashMap; use crate::PositionEncoding; use crate::document::DocumentKey; @@ -453,7 +453,9 @@ impl<'a> ResponseWriter<'a> { // Handle files that had diagnostics in previous request but no longer have any // Any remaining entries in previous_results are files that were fixed - for (key, (previous_url, previous_result_id)) in self.previous_result_ids { + for (key, (previous_url, previous_result_id)) in + self.previous_result_ids.unstable_into_iter() + { // This file had diagnostics before but doesn't now, so we need to report it as having no diagnostics let version = self .index diff --git a/crates/ty_server/src/session/index.rs b/crates/ty_server/src/session/index.rs index 6a34fb4ea24b1..a8b31e7c98724 100644 --- a/crates/ty_server/src/session/index.rs +++ b/crates/ty_server/src/session/index.rs @@ -1,5 +1,5 @@ -use rustc_hash::FxHashMap; use std::sync::Arc; +use ty_python_semantic::FxHashMap; use crate::document::DocumentKey; use crate::session::DocumentHandle; @@ -22,10 +22,11 @@ impl Index { } } + /// Returns an unstable iterator over all text document keys and their associated documents. pub(super) fn text_documents( &self, ) -> impl Iterator + '_ { - self.documents.iter().filter_map(|(key, doc)| { + self.documents.unstable_iter().filter_map(|(key, doc)| { let text_document = doc.as_text()?; Some((key, text_document)) }) @@ -43,10 +44,11 @@ impl Index { Ok(DocumentHandle::from_document(document)) } + /// Returns an unstable iterator over all notebook document keys. #[expect(dead_code)] pub(super) fn notebook_document_keys(&self) -> impl Iterator + '_ { self.documents - .iter() + .unstable_iter() .filter(|(_, doc)| doc.as_notebook().is_some()) .map(|(key, _)| key) } diff --git a/crates/ty_server/src/session/request_queue.rs b/crates/ty_server/src/session/request_queue.rs index 60c601ae92b15..bd35a55166c4f 100644 --- a/crates/ty_server/src/session/request_queue.rs +++ b/crates/ty_server/src/session/request_queue.rs @@ -1,11 +1,11 @@ use crate::session::client::ClientResponseHandler; use lsp_server::RequestId; -use rustc_hash::FxHashMap; use std::cell::{Cell, OnceCell, RefCell}; use std::fmt::Formatter; use std::sync::Arc; use std::sync::atomic::AtomicBool; use std::time::Instant; +use ty_python_semantic::FxHashMap; /// Tracks the pending requests between client and server. pub(crate) struct RequestQueue { diff --git a/crates/ty_server/tests/e2e/main.rs b/crates/ty_server/tests/e2e/main.rs index 8e416d11a3d9d..e06f5265258ef 100644 --- a/crates/ty_server/tests/e2e/main.rs +++ b/crates/ty_server/tests/e2e/main.rs @@ -68,8 +68,8 @@ use lsp_types::{ WorkspaceFolder, }; use ruff_db::system::{OsSystem, SystemPath, SystemPathBuf, TestSystem}; -use rustc_hash::FxHashMap; use tempfile::TempDir; +use ty_python_semantic::FxHashMap; use ty_server::{ClientOptions, LogLevel, Server, init_logging}; diff --git a/crates/ty_test/Cargo.toml b/crates/ty_test/Cargo.toml index f300b614a0d6d..3c80db59fcde0 100644 --- a/crates/ty_test/Cargo.toml +++ b/crates/ty_test/Cargo.toml @@ -30,7 +30,6 @@ insta = { workspace = true, features = ["filters"] } memchr = { workspace = true } path-slash = { workspace = true } regex = { workspace = true } -rustc-hash = { workspace = true } rustc-stable-hash = { workspace = true } salsa = { workspace = true } smallvec = { workspace = true } diff --git a/crates/ty_test/src/parser.rs b/crates/ty_test/src/parser.rs index ceba7285be768..ac07ba43420ec 100644 --- a/crates/ty_test/src/parser.rs +++ b/crates/ty_test/src/parser.rs @@ -7,7 +7,7 @@ use std::{ use anyhow::bail; use ruff_db::system::{SystemPath, SystemPathBuf}; -use rustc_hash::FxHashMap; +use ty_python_semantic::FxHashMap; use crate::config::MarkdownTestConfig; use ruff_index::{IndexVec, newtype_index}; @@ -821,13 +821,13 @@ impl<'s> Parser<'s> { fn current_section_has_explicit_file_paths(&self) -> bool { self.current_section_files - .iter() + .unstable_iter() .any(|(path, _)| path.is_explicit()) } fn current_section_has_merged_snippets(&self) -> bool { self.current_section_files - .values() + .unstable_values() .any(|id| self.files[*id].backtick_offsets.len() > 1) }