From 3e7cfca47c2a78d8d3e40529e81ebf6751217d5d Mon Sep 17 00:00:00 2001 From: Micha Reiser Date: Fri, 18 Jul 2025 09:19:48 +0200 Subject: [PATCH] [ty] Use `ThinVec` in various places --- Cargo.lock | 1 + Cargo.toml | 1 + crates/ty_python_semantic/Cargo.toml | 1 + .../ty_python_semantic/src/semantic_index.rs | 3 +- .../src/semantic_index/builder.rs | 4 +- .../src/semantic_index/place.rs | 10 +- crates/ty_python_semantic/src/types.rs | 2 +- .../src/types/diagnostic.rs | 9 +- .../ty_python_semantic/src/util/get_size.rs | 103 ++++++++++++++++++ 9 files changed, 122 insertions(+), 12 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index d97f66115e..498b5799e1 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4287,6 +4287,7 @@ dependencies = [ "strum_macros", "tempfile", "test-case", + "thin-vec", "thiserror 2.0.12", "tracing", "ty_python_semantic", diff --git a/Cargo.toml b/Cargo.toml index 8ca8a0d2d2..67354ac07e 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -163,6 +163,7 @@ strum_macros = { version = "0.27.0" } syn = { version = "2.0.55" } tempfile = { version = "3.9.0" } test-case = { version = "3.3.1" } +thin-vec = { version = "0.2.14" } thiserror = { version = "2.0.0" } tikv-jemallocator = { version = "0.6.0" } toml = { version = "0.9.0" } diff --git a/crates/ty_python_semantic/Cargo.toml b/crates/ty_python_semantic/Cargo.toml index 3550ce0e9b..d75ebcb31d 100644 --- a/crates/ty_python_semantic/Cargo.toml +++ b/crates/ty_python_semantic/Cargo.toml @@ -35,6 +35,7 @@ indexmap = { workspace = true } itertools = { workspace = true } ordermap = { workspace = true } salsa = { workspace = true, features = ["compact_str"] } +thin-vec = { workspace = true } thiserror = { workspace = true } tracing = { workspace = true } rustc-hash = { workspace = true } diff --git a/crates/ty_python_semantic/src/semantic_index.rs b/crates/ty_python_semantic/src/semantic_index.rs index 54729b2d52..ef7ba3a083 100644 --- a/crates/ty_python_semantic/src/semantic_index.rs +++ b/crates/ty_python_semantic/src/semantic_index.rs @@ -26,6 +26,7 @@ use crate::semantic_index::place::{ }; use crate::semantic_index::use_def::{EagerSnapshotKey, ScopedEagerSnapshotId, UseDefMap}; use crate::semantic_model::HasTrackedScope; +use crate::util::get_size::ThinVecSized; use crate::util::get_size::untracked_arc_size; pub mod ast_ids; @@ -238,7 +239,7 @@ pub(crate) struct SemanticIndex<'db> { eager_snapshots: FxHashMap, /// List of all semantic syntax errors in this file. - semantic_syntax_errors: Vec, + semantic_syntax_errors: ThinVecSized, /// Set of all generator functions in this file. generator_functions: FxHashSet, diff --git a/crates/ty_python_semantic/src/semantic_index/builder.rs b/crates/ty_python_semantic/src/semantic_index/builder.rs index ef273f2b14..4374e933f2 100644 --- a/crates/ty_python_semantic/src/semantic_index/builder.rs +++ b/crates/ty_python_semantic/src/semantic_index/builder.rs @@ -115,7 +115,7 @@ pub(super) struct SemanticIndexBuilder<'db, 'ast> { generator_functions: FxHashSet, eager_snapshots: FxHashMap, /// Errors collected by the `semantic_checker`. - semantic_syntax_errors: RefCell>, + semantic_syntax_errors: RefCell>, } impl<'db, 'ast> SemanticIndexBuilder<'db, 'ast> { @@ -1063,7 +1063,7 @@ impl<'db, 'ast> SemanticIndexBuilder<'db, 'ast> { imported_modules: Arc::new(self.imported_modules), has_future_annotations: self.has_future_annotations, eager_snapshots: self.eager_snapshots, - semantic_syntax_errors: self.semantic_syntax_errors.into_inner(), + semantic_syntax_errors: self.semantic_syntax_errors.into_inner().into(), generator_functions: self.generator_functions, } } diff --git a/crates/ty_python_semantic/src/semantic_index/place.rs b/crates/ty_python_semantic/src/semantic_index/place.rs index 81b650f19e..d639dd6b22 100644 --- a/crates/ty_python_semantic/src/semantic_index/place.rs +++ b/crates/ty_python_semantic/src/semantic_index/place.rs @@ -10,13 +10,13 @@ use ruff_index::{IndexVec, newtype_index}; use ruff_python_ast as ast; use ruff_python_ast::name::Name; use rustc_hash::FxHasher; -use smallvec::{SmallVec, smallvec}; use crate::Db; use crate::ast_node_ref::AstNodeRef; use crate::node_key::NodeKey; use crate::semantic_index::reachability_constraints::ScopedReachabilityConstraintId; use crate::semantic_index::{PlaceSet, SemanticIndex, semantic_index}; +use crate::util::get_size::ThinVecSized; #[derive(Debug, Clone, PartialEq, Eq, Hash, get_size2::GetSize)] pub(crate) enum PlaceExprSubSegment { @@ -41,7 +41,7 @@ impl PlaceExprSubSegment { #[derive(Eq, PartialEq, Debug, get_size2::GetSize)] pub struct PlaceExpr { root_name: Name, - sub_segments: SmallVec<[PlaceExprSubSegment; 1]>, + sub_segments: ThinVecSized, } impl std::fmt::Display for PlaceExpr { @@ -165,7 +165,7 @@ impl PlaceExpr { pub(crate) fn name(name: Name) -> Self { Self { root_name: name, - sub_segments: smallvec![], + sub_segments: ThinVecSized::new(), } } @@ -230,7 +230,9 @@ impl std::fmt::Display for PlaceExprWithFlags { } impl PlaceExprWithFlags { - pub(crate) fn new(expr: PlaceExpr) -> Self { + pub(crate) fn new(mut expr: PlaceExpr) -> Self { + expr.sub_segments.shrink_to_fit(); + PlaceExprWithFlags { expr, flags: PlaceFlags::empty(), diff --git a/crates/ty_python_semantic/src/types.rs b/crates/ty_python_semantic/src/types.rs index fd3668ccf0..c7d53d7892 100644 --- a/crates/ty_python_semantic/src/types.rs +++ b/crates/ty_python_semantic/src/types.rs @@ -93,7 +93,7 @@ mod definition; #[cfg(test)] mod property_tests; -pub fn check_types(db: &dyn Db, file: File) -> Vec { +pub fn check_types(db: &dyn Db, file: File) -> thin_vec::ThinVec { let _span = tracing::trace_span!("check_types", ?file).entered(); tracing::debug!("Checking file '{path}'", path = file.path(db)); diff --git a/crates/ty_python_semantic/src/types/diagnostic.rs b/crates/ty_python_semantic/src/types/diagnostic.rs index c12cb36f2a..c0bc389b93 100644 --- a/crates/ty_python_semantic/src/types/diagnostic.rs +++ b/crates/ty_python_semantic/src/types/diagnostic.rs @@ -18,6 +18,7 @@ use crate::types::string_annotation::{ use crate::types::tuple::TupleType; use crate::types::{SpecialFormType, Type, protocol_class::ProtocolClassLiteral}; use crate::util::diagnostics::format_enumeration; +use crate::util::get_size::ThinVecSized; use crate::{Db, FxIndexMap, Module, ModuleName, Program, declare_lint}; use itertools::Itertools; use ruff_db::diagnostic::{Annotation, Diagnostic, Severity, SubDiagnostic}; @@ -1614,7 +1615,7 @@ declare_lint! { /// A collection of type check diagnostics. #[derive(Default, Eq, PartialEq, get_size2::GetSize)] pub struct TypeCheckDiagnostics { - diagnostics: Vec, + diagnostics: ThinVecSized, used_suppressions: FxHashSet, } @@ -1649,8 +1650,8 @@ impl TypeCheckDiagnostics { self.diagnostics.shrink_to_fit(); } - pub(crate) fn into_vec(self) -> Vec { - self.diagnostics + pub(crate) fn into_vec(self) -> thin_vec::ThinVec { + self.diagnostics.into_inner() } pub fn iter(&self) -> std::slice::Iter<'_, Diagnostic> { @@ -1666,7 +1667,7 @@ impl std::fmt::Debug for TypeCheckDiagnostics { impl IntoIterator for TypeCheckDiagnostics { type Item = Diagnostic; - type IntoIter = std::vec::IntoIter; + type IntoIter = thin_vec::IntoIter; fn into_iter(self) -> Self::IntoIter { self.diagnostics.into_iter() diff --git a/crates/ty_python_semantic/src/util/get_size.rs b/crates/ty_python_semantic/src/util/get_size.rs index d77cf5c14c..220822a196 100644 --- a/crates/ty_python_semantic/src/util/get_size.rs +++ b/crates/ty_python_semantic/src/util/get_size.rs @@ -1,3 +1,4 @@ +use std::ops::{Deref, DerefMut}; use std::sync::Arc; use get_size2::GetSize; @@ -13,3 +14,105 @@ where { T::get_heap_size(&**arc) } + +#[derive(Clone, Hash, PartialEq, Eq)] +pub(crate) struct ThinVecSized(thin_vec::ThinVec); + +impl ThinVecSized { + pub(crate) fn into_inner(self) -> thin_vec::ThinVec { + self.0 + } + + pub(crate) fn new() -> Self { + Self(thin_vec::ThinVec::new()) + } +} + +impl Default for ThinVecSized { + fn default() -> Self { + Self::new() + } +} + +#[allow(unsafe_code)] +unsafe impl salsa::Update for ThinVecSized +where + T: salsa::Update, +{ + unsafe fn maybe_update(old_pointer: *mut Self, new_value: Self) -> bool { + let old: &mut Self = unsafe { &mut *old_pointer }; + + unsafe { salsa::Update::maybe_update(&raw mut old.0, new_value.0) } + } +} + +impl std::fmt::Debug for ThinVecSized +where + T: std::fmt::Debug, +{ + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + self.0.fmt(f) + } +} + +impl From> for ThinVecSized { + fn from(vec: thin_vec::ThinVec) -> Self { + Self(vec) + } +} + +impl Deref for ThinVecSized { + type Target = thin_vec::ThinVec; + + fn deref(&self) -> &Self::Target { + &self.0 + } +} + +impl DerefMut for ThinVecSized { + fn deref_mut(&mut self) -> &mut Self::Target { + &mut self.0 + } +} + +impl GetSize for ThinVecSized +where + T: GetSize, +{ + fn get_heap_size(&self) -> usize { + let mut total = 0; + for v in self { + total += GetSize::get_size(v); + } + let additional: usize = self.capacity() - self.len(); + total += additional * T::get_stack_size(); + total + } +} + +impl<'a, T> IntoIterator for &'a ThinVecSized { + type Item = &'a T; + type IntoIter = std::slice::Iter<'a, T>; + + fn into_iter(self) -> Self::IntoIter { + self.0.iter() + } +} + +impl<'a, T> IntoIterator for &'a mut ThinVecSized { + type Item = &'a mut T; + type IntoIter = std::slice::IterMut<'a, T>; + + fn into_iter(self) -> Self::IntoIter { + self.0.iter_mut() + } +} + +impl IntoIterator for ThinVecSized { + type Item = T; + type IntoIter = thin_vec::IntoIter; + + fn into_iter(self) -> Self::IntoIter { + self.0.into_iter() + } +}