Skip to content

Commit a1eb5bd

Browse files
committed
add StableKey
1 parent 56a9cf4 commit a1eb5bd

File tree

31 files changed

+119
-46
lines changed

31 files changed

+119
-46
lines changed

Cargo.lock

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

crates/ty_ide/src/importer.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -325,7 +325,7 @@ impl<'ast> MembersInScope<'ast> {
325325
let model = SemanticModel::new(db, file);
326326
let map = model
327327
.members_in_scope_at(node)
328-
.unstable_into_iter()
328+
.stable_into_iter()
329329
.map(|(name, memberdef)| {
330330
let Some(def) = memberdef.definition else {
331331
return (name, MemberInScope::other(memberdef.ty));

crates/ty_project/src/db/changes.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -318,7 +318,7 @@ impl ProjectDatabase {
318318
}
319319

320320
let diagnostics = if let Some(walker) =
321-
ProjectFilesWalker::incremental(self, added_paths.unstable_iter())
321+
ProjectFilesWalker::incremental(self, added_paths.stable_iter())
322322
{
323323
// Use directory walking to discover newly added files.
324324
let (files, diagnostics) = walker.collect_vec(self);

crates/ty_python_semantic/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,7 @@ memchr = { workspace = true }
5252
strum = { workspace = true }
5353
strum_macros = { workspace = true }
5454
strsim = "0.11.1"
55+
url = { workspace = true }
5556

5657
[dev-dependencies]
5758
ruff_db = { workspace = true, features = ["testing", "os"] }

crates/ty_python_semantic/src/dunder_all.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -102,7 +102,7 @@ impl<'db> DunderAllNamesCollector<'db> {
102102
return false;
103103
};
104104
self.names
105-
.extend(module_dunder_all_names.unstable_iter().cloned());
105+
.extend(module_dunder_all_names.stable_iter().cloned());
106106
true
107107
}
108108

@@ -239,7 +239,7 @@ impl<'db> StatementVisitor<'db> for DunderAllNamesCollector<'db> {
239239

240240
if all_names.contains(&Name::new_static("__all__")) {
241241
self.update_origin(DunderAllOrigin::StarImport);
242-
self.names.extend(all_names.unstable_iter().cloned());
242+
self.names.extend(all_names.stable_iter().cloned());
243243
}
244244
} else {
245245
// `from module import __all__`
@@ -269,7 +269,7 @@ impl<'db> StatementVisitor<'db> for DunderAllNamesCollector<'db> {
269269
};
270270

271271
self.update_origin(DunderAllOrigin::ExternalModule);
272-
self.names.extend(all_names.unstable_iter().cloned());
272+
self.names.extend(all_names.stable_iter().cloned());
273273
}
274274
}
275275
}

crates/ty_python_semantic/src/lib.rs

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,16 @@ type FxOrderSet<V> = ordermap::set::OrderSet<V, BuildHasherDefault<FxHasher>>;
6161
type FxIndexMap<K, V> = indexmap::IndexMap<K, V, BuildHasherDefault<FxHasher>>;
6262
type FxIndexSet<V> = indexmap::IndexSet<V, BuildHasherDefault<FxHasher>>;
6363

64+
/// Types that implement this trait are stable as keys of `FxHash{Map, Set}`, and maps and sets can be safely used as iterators.
65+
pub trait StableKey {}
66+
67+
impl StableKey for String {}
68+
impl StableKey for &str {}
69+
impl StableKey for &ruff_python_ast::name::Name {}
70+
impl StableKey for ruff_python_ast::name::Name {}
71+
impl StableKey for ruff_db::system::SystemPathBuf {}
72+
impl StableKey for url::Url {}
73+
6474
/// Always use this instead of [`rustc_hash::FxHashSet`].
6575
/// This struct intentionally does not implement `(Into)Iterator` because the iterator's output order will be unstable if the set's values depend on salsa's non-deterministic IDs.
6676
/// Only use `unstable_iter()`, etc. if you are sure the iterator is safe to use despite that.
@@ -108,6 +118,16 @@ impl<V> std::ops::DerefMut for FxHashSet<V> {
108118
}
109119
}
110120

121+
impl<V: Eq + Hash + StableKey> FxHashSet<V> {
122+
pub fn stable_iter(&self) -> std::collections::hash_set::Iter<'_, V> {
123+
self.0.iter()
124+
}
125+
126+
pub fn stable_into_iter(self) -> std::collections::hash_set::IntoIter<V> {
127+
self.0.into_iter()
128+
}
129+
}
130+
111131
impl<V: Eq + Hash> FxHashSet<V> {
112132
pub fn with_capacity_and_hasher(capacity: usize, hasher: FxBuildHasher) -> Self {
113133
Self(rustc_hash::FxHashSet::with_capacity_and_hasher(
@@ -207,6 +227,40 @@ impl<K, V> std::ops::DerefMut for FxHashMap<K, V> {
207227
}
208228
}
209229

230+
impl<K: Eq + Hash + StableKey, V> FxHashMap<K, V> {
231+
pub fn stable_iter(&self) -> std::collections::hash_map::Iter<'_, K, V> {
232+
self.0.iter()
233+
}
234+
235+
pub fn stable_keys(&self) -> std::collections::hash_map::Keys<'_, K, V> {
236+
self.0.keys()
237+
}
238+
239+
pub fn stable_values(&self) -> std::collections::hash_map::Values<'_, K, V> {
240+
self.0.values()
241+
}
242+
243+
pub fn stable_iter_mut(&mut self) -> std::collections::hash_map::IterMut<'_, K, V> {
244+
self.0.iter_mut()
245+
}
246+
247+
pub fn stable_values_mut(&mut self) -> std::collections::hash_map::ValuesMut<'_, K, V> {
248+
self.0.values_mut()
249+
}
250+
251+
pub fn stable_into_iter(self) -> std::collections::hash_map::IntoIter<K, V> {
252+
self.0.into_iter()
253+
}
254+
255+
pub fn stable_into_keys(self) -> std::collections::hash_map::IntoKeys<K, V> {
256+
self.0.into_keys()
257+
}
258+
259+
pub fn stable_into_values(self) -> std::collections::hash_map::IntoValues<K, V> {
260+
self.0.into_values()
261+
}
262+
}
263+
210264
impl<K: Eq + Hash, V> FxHashMap<K, V> {
211265
pub fn with_capacity_and_hasher(capacity: usize, hasher: FxBuildHasher) -> Self {
212266
Self(rustc_hash::FxHashMap::with_capacity_and_hasher(

crates/ty_python_semantic/src/lint.rs

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -276,6 +276,8 @@ pub struct LintId {
276276
definition: &'static LintMetadata,
277277
}
278278

279+
impl crate::StableKey for LintId {}
280+
279281
impl LintId {
280282
pub const fn of(definition: &'static LintMetadata) -> Self {
281283
LintId { definition }
@@ -389,7 +391,7 @@ impl LintRegistry {
389391
}
390392
}
391393

392-
let suggestion = did_you_mean(self.by_name.unstable_keys(), code);
394+
let suggestion = did_you_mean(self.by_name.stable_keys(), code);
393395

394396
Err(GetLintError::Unknown {
395397
code: code.to_string(),
@@ -408,7 +410,7 @@ impl LintRegistry {
408410
///
409411
/// This iterator includes aliases that point to removed lints.
410412
pub fn aliases(&self) -> impl Iterator<Item = (LintName, LintId)> + '_ {
411-
self.by_name.unstable_iter().filter_map(|(key, value)| {
413+
self.by_name.stable_iter().filter_map(|(key, value)| {
412414
if let LintEntry::Alias(alias) = value {
413415
Some((LintName::of(key), *alias))
414416
} else {
@@ -419,7 +421,7 @@ impl LintRegistry {
419421

420422
/// Iterates over all removed lints.
421423
pub fn removed(&self) -> impl Iterator<Item = LintId> + '_ {
422-
self.by_name.unstable_iter().filter_map(|(_, value)| {
424+
self.by_name.stable_iter().filter_map(|(_, value)| {
423425
if let LintEntry::Removed(metadata) = value {
424426
Some(*metadata)
425427
} else {
@@ -538,13 +540,13 @@ impl RuleSelection {
538540

539541
/// Returns an iterator over all enabled lints.
540542
pub fn enabled(&self) -> impl Iterator<Item = LintId> + '_ {
541-
self.lints.unstable_keys().copied()
543+
self.lints.stable_keys().copied()
542544
}
543545

544546
/// Returns an iterator over all enabled lints and their severity.
545547
pub fn iter(&self) -> impl ExactSizeIterator<Item = (LintId, Severity)> + '_ {
546548
self.lints
547-
.unstable_iter()
549+
.stable_iter()
548550
.map(|(&lint, &(severity, _))| (lint, severity))
549551
}
550552

@@ -581,7 +583,7 @@ impl fmt::Debug for RuleSelection {
581583
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
582584
let lints = self
583585
.lints
584-
.unstable_iter()
586+
.stable_iter()
585587
.sorted_by_key(|(lint, _)| lint.name);
586588

587589
if f.alternate() {

crates/ty_python_semantic/src/module_name.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,8 @@ use crate::{db::Db, module_resolver::file_to_module};
1616
#[derive(Clone, Debug, Eq, PartialEq, Hash, PartialOrd, Ord, get_size2::GetSize)]
1717
pub struct ModuleName(compact_str::CompactString);
1818

19+
impl crate::StableKey for ModuleName {}
20+
1921
impl ModuleName {
2022
/// Creates a new module name for `name`. Returns `Some` if `name` is a valid, absolute
2123
/// module name and `None` otherwise.

crates/ty_python_semantic/src/module_resolver/typeshed.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -222,7 +222,7 @@ impl FromStr for TypeshedVersions {
222222

223223
impl fmt::Display for TypeshedVersions {
224224
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
225-
let sorted_items: BTreeMap<&ModuleName, &PyVersionRange> = self.0.unstable_iter().collect();
225+
let sorted_items: BTreeMap<&ModuleName, &PyVersionRange> = self.0.stable_iter().collect();
226226
for (module_name, range) in sorted_items {
227227
writeln!(f, "{module_name}: {range}")?;
228228
}

crates/ty_python_semantic/src/node_key.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,8 @@ use crate::ast_node_ref::AstNodeRef;
66
#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash, get_size2::GetSize)]
77
pub(super) struct NodeKey(NodeIndex);
88

9+
impl crate::StableKey for NodeKey {}
10+
911
impl NodeKey {
1012
pub(super) fn from_node<N>(node: N) -> Self
1113
where

0 commit comments

Comments
 (0)