Compare commits

...

4 Commits

Author SHA1 Message Date
Micha Reiser
3e7cfca47c [ty] Use ThinVec in various places 2025-07-18 09:35:01 +02:00
Micha Reiser
b8d2037373 Reduce inline size of live declarations 2025-07-17 21:22:58 +02:00
Micha Reiser
1714d5c771 [ty] Reduce number of inline stored definitions per place 2025-07-17 21:05:51 +02:00
Brent Westbrook
1fd9103e81 Canonicalize path before filtering (#19407)
## Summary

This came up on
[Discord](https://discord.com/channels/1039017663004942429/1343692072921731082/1395447082520678440)
and also in #19387, but on macOS the tmp directory is a symlink to
`/private/tmp`, which breaks this filter. I'm still not quite sure why
only these tests are affected when we use the `tempdir_filter`
elsewhere, but hopefully this fixes the immediate issue. Just
`tempdir.path().canonicalize()` also worked, but I used `dunce` since
that's what I saw in other tests (I guess it's not _just_ these tests).

Some related links from uv:
-
1b2f212e8b/crates/uv/tests/it/common/mod.rs (L1161-L1178)
-
1b2f212e8b/crates/uv/tests/it/common/mod.rs (L424-L438)
- https://github.com/astral-sh/uv/pull/14290

Thanks to @zanieb for those!

## Test Plan

I tested the `main` branch on my MacBook and reproduced the test
failure, then confirmed that the tests pass after the change. Now to
make sure it passes on Windows, which caused most of the trouble in the
first PR!
2025-07-17 14:02:17 -04:00
11 changed files with 127 additions and 18 deletions

1
Cargo.lock generated
View File

@@ -4287,6 +4287,7 @@ dependencies = [
"strum_macros",
"tempfile",
"test-case",
"thin-vec",
"thiserror 2.0.12",
"tracing",
"ty_python_semantic",

View File

@@ -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" }

View File

@@ -5718,8 +5718,11 @@ match 42: # invalid-syntax
let snapshot = format!("output_format_{output_format}");
let project_dir = dunce::canonicalize(tempdir.path())?;
insta::with_settings!({
filters => vec![
(tempdir_filter(&project_dir).as_str(), "[TMP]/"),
(tempdir_filter(&tempdir).as_str(), "[TMP]/"),
(r#""[^"]+\\?/?input.py"#, r#""[TMP]/input.py"#),
(ruff_linter::VERSION, "[VERSION]"),

View File

@@ -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 }

View File

@@ -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<EagerSnapshotKey, ScopedEagerSnapshotId>,
/// List of all semantic syntax errors in this file.
semantic_syntax_errors: Vec<SemanticSyntaxError>,
semantic_syntax_errors: ThinVecSized<SemanticSyntaxError>,
/// Set of all generator functions in this file.
generator_functions: FxHashSet<FileScopeId>,

View File

@@ -115,7 +115,7 @@ pub(super) struct SemanticIndexBuilder<'db, 'ast> {
generator_functions: FxHashSet<FileScopeId>,
eager_snapshots: FxHashMap<EagerSnapshotKey, ScopedEagerSnapshotId>,
/// Errors collected by the `semantic_checker`.
semantic_syntax_errors: RefCell<Vec<SemanticSyntaxError>>,
semantic_syntax_errors: RefCell<thin_vec::ThinVec<SemanticSyntaxError>>,
}
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,
}
}

View File

@@ -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<PlaceExprSubSegment>,
}
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(),

View File

@@ -71,16 +71,12 @@ impl ScopedDefinitionId {
}
}
/// Can keep inline this many live bindings or declarations per place at a given time; more will
/// go to heap.
const INLINE_DEFINITIONS_PER_PLACE: usize = 4;
/// Live declarations for a single place at some point in control flow, with their
/// corresponding reachability constraints.
#[derive(Clone, Debug, Default, PartialEq, Eq, salsa::Update, get_size2::GetSize)]
pub(super) struct Declarations {
/// A list of live declarations for this place, sorted by their `ScopedDefinitionId`
live_declarations: SmallVec<[LiveDeclaration; INLINE_DEFINITIONS_PER_PLACE]>,
live_declarations: SmallVec<[LiveDeclaration; 2]>,
}
/// One of the live declarations for a single place at some point in control flow.
@@ -199,7 +195,7 @@ pub(super) struct Bindings {
/// "unbound" binding.
unbound_narrowing_constraint: Option<ScopedNarrowingConstraint>,
/// A list of live bindings for this place, sorted by their `ScopedDefinitionId`
live_bindings: SmallVec<[LiveBinding; INLINE_DEFINITIONS_PER_PLACE]>,
live_bindings: SmallVec<[LiveBinding; 2]>,
}
impl Bindings {

View File

@@ -93,7 +93,7 @@ mod definition;
#[cfg(test)]
mod property_tests;
pub fn check_types(db: &dyn Db, file: File) -> Vec<Diagnostic> {
pub fn check_types(db: &dyn Db, file: File) -> thin_vec::ThinVec<Diagnostic> {
let _span = tracing::trace_span!("check_types", ?file).entered();
tracing::debug!("Checking file '{path}'", path = file.path(db));

View File

@@ -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<Diagnostic>,
diagnostics: ThinVecSized<Diagnostic>,
used_suppressions: FxHashSet<FileSuppressionId>,
}
@@ -1649,8 +1650,8 @@ impl TypeCheckDiagnostics {
self.diagnostics.shrink_to_fit();
}
pub(crate) fn into_vec(self) -> Vec<Diagnostic> {
self.diagnostics
pub(crate) fn into_vec(self) -> thin_vec::ThinVec<Diagnostic> {
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<Diagnostic>;
type IntoIter = thin_vec::IntoIter<Diagnostic>;
fn into_iter(self) -> Self::IntoIter {
self.diagnostics.into_iter()

View File

@@ -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<T>(thin_vec::ThinVec<T>);
impl<T> ThinVecSized<T> {
pub(crate) fn into_inner(self) -> thin_vec::ThinVec<T> {
self.0
}
pub(crate) fn new() -> Self {
Self(thin_vec::ThinVec::new())
}
}
impl<T> Default for ThinVecSized<T> {
fn default() -> Self {
Self::new()
}
}
#[allow(unsafe_code)]
unsafe impl<T> salsa::Update for ThinVecSized<T>
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<T> std::fmt::Debug for ThinVecSized<T>
where
T: std::fmt::Debug,
{
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
self.0.fmt(f)
}
}
impl<T> From<thin_vec::ThinVec<T>> for ThinVecSized<T> {
fn from(vec: thin_vec::ThinVec<T>) -> Self {
Self(vec)
}
}
impl<T> Deref for ThinVecSized<T> {
type Target = thin_vec::ThinVec<T>;
fn deref(&self) -> &Self::Target {
&self.0
}
}
impl<T> DerefMut for ThinVecSized<T> {
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.0
}
}
impl<T> GetSize for ThinVecSized<T>
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<T> {
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<T> {
type Item = &'a mut T;
type IntoIter = std::slice::IterMut<'a, T>;
fn into_iter(self) -> Self::IntoIter {
self.0.iter_mut()
}
}
impl<T> IntoIterator for ThinVecSized<T> {
type Item = T;
type IntoIter = thin_vec::IntoIter<T>;
fn into_iter(self) -> Self::IntoIter {
self.0.into_iter()
}
}