[ty] Add environment variable to dump Salsa memory usage stats (#18928)

## Summary

Setting `TY_MEMORY_REPORT=full` will generate and print a memory usage
report to the CLI after a `ty check` run:

```
=======SALSA STRUCTS=======
`Definition`                                       metadata=7.24MB   fields=17.38MB  count=181062
`Expression`                                       metadata=4.45MB   fields=5.94MB   count=92804
`member_lookup_with_policy_::interned_arguments`   metadata=1.97MB   fields=2.25MB   count=35176
...
=======SALSA QUERIES=======
`File -> ty_python_semantic::semantic_index::SemanticIndex`
    metadata=11.46MB  fields=88.86MB  count=1638
`Definition -> ty_python_semantic::types::infer::TypeInference`
    metadata=24.52MB  fields=86.68MB  count=146018
`File -> ruff_db::parsed::ParsedModule`
    metadata=0.12MB   fields=69.06MB  count=1642
...
=======SALSA SUMMARY=======
TOTAL MEMORY USAGE: 577.61MB
    struct metadata = 29.00MB
    struct fields = 35.68MB
    memo metadata = 103.87MB
    memo fields = 409.06MB
```

Eventually, we should integrate these numbers into CI in some form. The
one limitation currently is that heap allocations in salsa structs (e.g.
interned values) are not tracked, but memoized values should have full
coverage. We may also want a peak memory usage counter (that accounts
for non-salsa memory), but that is relatively simple to profile manually
(e.g. `time -v ty check`) and would require a compile-time option to
avoid runtime overhead.
This commit is contained in:
Ibraheem Ahmed 2025-06-26 17:27:51 -04:00 committed by GitHub
parent a1579d82d0
commit 6f7b1c9bb3
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
79 changed files with 905 additions and 207 deletions

View file

@ -89,6 +89,8 @@ where
}
}
impl<T> get_size2::GetSize for AstNodeRef<T> {}
#[allow(clippy::missing_fields_in_debug)]
impl<T> Debug for AstNodeRef<T>
where

View file

@ -28,7 +28,7 @@ fn dunder_all_names_cycle_initial(_db: &dyn Db, _file: File) -> Option<FxHashSet
/// Returns a set of names in the `__all__` variable for `file`, [`None`] if it is not defined or
/// if it contains invalid elements.
#[salsa::tracked(returns(as_ref), cycle_fn=dunder_all_names_cycle_recover, cycle_initial=dunder_all_names_cycle_initial)]
#[salsa::tracked(returns(as_ref), cycle_fn=dunder_all_names_cycle_recover, cycle_initial=dunder_all_names_cycle_initial, heap_size=get_size2::GetSize::get_heap_size)]
pub(crate) fn dunder_all_names(db: &dyn Db, file: File) -> Option<FxHashSet<Name>> {
let _span = tracing::trace_span!("dunder_all_names", file=?file.path(db)).entered();

View file

@ -262,7 +262,7 @@ macro_rules! declare_lint {
///
/// Implements `PartialEq`, `Eq`, and `Hash` based on the `LintMetadata` pointer
/// for fast comparison and lookup.
#[derive(Debug, Clone, Copy)]
#[derive(Debug, Clone, Copy, get_size2::GetSize)]
pub struct LintId {
definition: &'static LintMetadata,
}
@ -415,7 +415,7 @@ impl LintRegistry {
}
}
#[derive(Error, Debug, Clone, PartialEq, Eq)]
#[derive(Error, Debug, Clone, PartialEq, Eq, get_size2::GetSize)]
pub enum GetLintError {
/// The name maps to this removed lint.
#[error("lint `{0}` has been removed")]
@ -463,7 +463,7 @@ impl From<&'static LintMetadata> for LintEntry {
}
}
#[derive(Debug, Clone, Default, PartialEq, Eq)]
#[derive(Debug, Clone, Default, PartialEq, Eq, get_size2::GetSize)]
pub struct RuleSelection {
/// Map with the severity for each enabled lint rule.
///
@ -541,7 +541,7 @@ impl RuleSelection {
}
}
#[derive(Default, Copy, Clone, Debug, PartialEq, Eq)]
#[derive(Default, Copy, Clone, Debug, PartialEq, Eq, get_size2::GetSize)]
pub enum LintSource {
/// The user didn't enable the rule explicitly, instead it's enabled by default.
#[default]

View file

@ -69,7 +69,7 @@ use ruff_index::{IndexVec, newtype_index};
/// A handle to an association list. Use [`ListStorage`] to access its elements, and
/// [`ListBuilder`] to construct other lists based on this one.
#[derive(Clone, Copy, Debug, Eq, Ord, PartialEq, PartialOrd)]
#[derive(Clone, Copy, Debug, Eq, Ord, PartialEq, PartialOrd, get_size2::GetSize)]
pub(crate) struct List<K, V = ()> {
last: Option<ListCellId>,
_phantom: PhantomData<(K, V)>,
@ -95,12 +95,12 @@ impl<K, V> Default for List<K, V> {
}
#[newtype_index]
#[derive(PartialOrd, Ord)]
#[derive(PartialOrd, Ord, get_size2::GetSize)]
struct ListCellId;
/// Stores one or more association lists. This type provides read-only access to the lists. Use a
/// [`ListBuilder`] to create lists.
#[derive(Debug, Eq, PartialEq)]
#[derive(Debug, Eq, PartialEq, get_size2::GetSize)]
pub(crate) struct ListStorage<K, V = ()> {
cells: IndexVec<ListCellId, ListCell<K, V>>,
}
@ -111,7 +111,7 @@ pub(crate) struct ListStorage<K, V = ()> {
/// **Terminology**: The elements of a cons cell are usually called `head` and `tail` (assuming
/// you're not in Lisp-land, where they're called `car` and `cdr`). The elements of a snoc cell
/// are usually called `rest` and `last`.
#[derive(Debug, Eq, PartialEq)]
#[derive(Debug, Eq, PartialEq, get_size2::GetSize)]
struct ListCell<K, V> {
rest: Option<ListCellId>,
key: K,

View file

@ -13,7 +13,7 @@ use crate::{db::Db, module_resolver::file_to_module};
/// A module name, e.g. `foo.bar`.
///
/// Always normalized to the absolute form (never a relative module name, i.e., never `.foo`).
#[derive(Clone, Debug, Eq, PartialEq, Hash, PartialOrd, Ord)]
#[derive(Clone, Debug, Eq, PartialEq, Hash, PartialOrd, Ord, get_size2::GetSize)]
pub struct ModuleName(compact_str::CompactString);
impl ModuleName {

View file

@ -8,7 +8,7 @@ use super::path::SearchPath;
use crate::module_name::ModuleName;
/// Representation of a Python module.
#[derive(Clone, PartialEq, Eq, Hash)]
#[derive(Clone, PartialEq, Eq, Hash, get_size2::GetSize)]
pub struct Module {
inner: Arc<ModuleInner>,
}
@ -99,7 +99,7 @@ impl std::fmt::Debug for Module {
}
}
#[derive(PartialEq, Eq, Hash)]
#[derive(PartialEq, Eq, Hash, get_size2::GetSize)]
enum ModuleInner {
/// A module that resolves to a file (`lib.py` or `package/__init__.py`)
FileModule {
@ -116,7 +116,7 @@ enum ModuleInner {
NamespacePackage { name: ModuleName },
}
#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash)]
#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash, get_size2::GetSize)]
pub enum ModuleKind {
/// A single-file module (e.g. `foo.py` or `foo.pyi`)
Module,
@ -135,7 +135,7 @@ impl ModuleKind {
}
/// Enumeration of various core stdlib modules in which important types are located
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, strum_macros::EnumString)]
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, strum_macros::EnumString, get_size2::GetSize)]
#[cfg_attr(test, derive(strum_macros::EnumIter))]
#[strum(serialize_all = "snake_case")]
pub enum KnownModule {

View file

@ -371,7 +371,7 @@ impl From<SitePackagesDiscoveryError> for SearchPathValidationError {
type SearchPathResult<T> = Result<T, SearchPathValidationError>;
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
#[derive(Debug, Clone, PartialEq, Eq, Hash, get_size2::GetSize)]
enum SearchPathInner {
Extra(SystemPathBuf),
FirstParty(SystemPathBuf),
@ -406,7 +406,7 @@ enum SearchPathInner {
/// or the "Editable" category. For the "First-party", "Site-packages"
/// and "Standard-library" categories, however, there will always be exactly
/// one search path from that category in any given list of search paths.
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
#[derive(Debug, Clone, PartialEq, Eq, Hash, get_size2::GetSize)]
pub(crate) struct SearchPath(Arc<SearchPathInner>);
impl SearchPath {

View file

@ -30,7 +30,7 @@ pub fn resolve_module(db: &dyn Db, module_name: &ModuleName) -> Option<Module> {
///
/// This query should not be called directly. Instead, use [`resolve_module`]. It only exists
/// because Salsa requires the module name to be an ingredient.
#[salsa::tracked]
#[salsa::tracked(heap_size=get_size2::GetSize::get_heap_size)]
pub(crate) fn resolve_module_query<'db>(
db: &'db dyn Db,
module_name: ModuleNameIngredient<'db>,
@ -95,7 +95,7 @@ impl std::fmt::Display for SystemOrVendoredPathRef<'_> {
/// Resolves the module for the file with the given id.
///
/// Returns `None` if the file is not a module locatable via any of the known search paths.
#[salsa::tracked]
#[salsa::tracked(heap_size=get_size2::GetSize::get_heap_size)]
pub(crate) fn file_to_module(db: &dyn Db, file: File) -> Option<Module> {
let _span = tracing::trace_span!("file_to_module", ?file).entered();
@ -297,7 +297,7 @@ impl SearchPaths {
/// The editable-install search paths for the first `site-packages` directory
/// should come between the two `site-packages` directories when it comes to
/// module-resolution priority.
#[salsa::tracked(returns(deref))]
#[salsa::tracked(returns(deref), heap_size=get_size2::GetSize::get_heap_size)]
pub(crate) fn dynamic_resolution_paths(db: &dyn Db) -> Vec<SearchPath> {
tracing::debug!("Resolving dynamic module resolution paths");

View file

@ -1,7 +1,7 @@
use ruff_python_ast::{HasNodeIndex, NodeIndex};
/// Compact key for a node for use in a hash map.
#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash)]
#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash, get_size2::GetSize)]
pub(super) struct NodeKey(NodeIndex);
impl NodeKey {

View file

@ -18,7 +18,7 @@ pub(crate) use implicit_globals::{
module_type_implicit_global_declaration, module_type_implicit_global_symbol,
};
#[derive(Debug, Clone, Copy, Hash, PartialEq, Eq)]
#[derive(Debug, Clone, Copy, Hash, PartialEq, Eq, get_size2::GetSize)]
pub(crate) enum Boundness {
Bound,
PossiblyUnbound,
@ -50,7 +50,7 @@ impl Boundness {
/// possibly_unbound: Place::Type(Type::IntLiteral(2), Boundness::PossiblyUnbound),
/// non_existent: Place::Unbound,
/// ```
#[derive(Debug, Clone, PartialEq, Eq, salsa::Update)]
#[derive(Debug, Clone, PartialEq, Eq, salsa::Update, get_size2::GetSize)]
pub(crate) enum Place<'db> {
Type(Type<'db>, Boundness),
Unbound,
@ -497,7 +497,7 @@ pub(crate) type PlaceFromDeclarationsResult<'db> =
/// that this comes with a [`CLASS_VAR`] type qualifier.
///
/// [`CLASS_VAR`]: crate::types::TypeQualifiers::CLASS_VAR
#[derive(Debug, Clone, PartialEq, Eq, salsa::Update)]
#[derive(Debug, Clone, PartialEq, Eq, salsa::Update, get_size2::GetSize)]
pub(crate) struct PlaceAndQualifiers<'db> {
pub(crate) place: Place<'db>,
pub(crate) qualifiers: TypeQualifiers,
@ -625,7 +625,7 @@ fn place_cycle_initial<'db>(
Place::bound(Type::Never).into()
}
#[salsa::tracked(cycle_fn=place_cycle_recover, cycle_initial=place_cycle_initial)]
#[salsa::tracked(cycle_fn=place_cycle_recover, cycle_initial=place_cycle_initial, heap_size=get_size2::GetSize::get_heap_size)]
fn place_by_id<'db>(
db: &'db dyn Db,
scope: ScopeId<'db>,
@ -1312,7 +1312,7 @@ mod implicit_globals {
/// Conceptually this function could be a `Set` rather than a list,
/// but the number of symbols declared in this scope is likely to be very small,
/// so the cost of hashing the names is likely to be more expensive than it's worth.
#[salsa::tracked(returns(deref))]
#[salsa::tracked(returns(deref), heap_size=get_size2::GetSize::get_heap_size)]
fn module_type_symbols<'db>(db: &'db dyn Db) -> smallvec::SmallVec<[ast::name::Name; 8]> {
let Some(module_type) = KnownClass::ModuleType
.to_class_literal(db)

View file

@ -24,6 +24,7 @@ use crate::semantic_index::place::{
ScopeKind, ScopedPlaceId,
};
use crate::semantic_index::use_def::{EagerSnapshotKey, ScopedEagerSnapshotId, UseDefMap};
use crate::util::get_size::untracked_arc_size;
pub mod ast_ids;
mod builder;
@ -46,7 +47,7 @@ type PlaceSet = hashbrown::HashTable<ScopedPlaceId>;
/// Returns the semantic index for `file`.
///
/// Prefer using [`symbol_table`] when working with symbols from a single scope.
#[salsa::tracked(returns(ref), no_eq)]
#[salsa::tracked(returns(ref), no_eq, heap_size=get_size2::GetSize::get_heap_size)]
pub(crate) fn semantic_index(db: &dyn Db, file: File) -> SemanticIndex<'_> {
let _span = tracing::trace_span!("semantic_index", ?file).entered();
@ -60,7 +61,7 @@ pub(crate) fn semantic_index(db: &dyn Db, file: File) -> SemanticIndex<'_> {
/// Using [`place_table`] over [`semantic_index`] has the advantage that
/// Salsa can avoid invalidating dependent queries if this scope's place table
/// is unchanged.
#[salsa::tracked(returns(deref))]
#[salsa::tracked(returns(deref), heap_size=get_size2::GetSize::get_heap_size)]
pub(crate) fn place_table<'db>(db: &'db dyn Db, scope: ScopeId<'db>) -> Arc<PlaceTable> {
let file = scope.file(db);
let _span = tracing::trace_span!("place_table", scope=?scope.as_id(), ?file).entered();
@ -80,7 +81,7 @@ pub(crate) fn place_table<'db>(db: &'db dyn Db, scope: ScopeId<'db>) -> Arc<Plac
///
/// - We cannot resolve relative imports (which aren't allowed in `import` statements) without
/// knowing the name of the current module, and whether it's a package.
#[salsa::tracked(returns(deref))]
#[salsa::tracked(returns(deref), heap_size=get_size2::GetSize::get_heap_size)]
pub(crate) fn imported_modules<'db>(db: &'db dyn Db, file: File) -> Arc<FxHashSet<ModuleName>> {
semantic_index(db, file).imported_modules.clone()
}
@ -90,8 +91,8 @@ pub(crate) fn imported_modules<'db>(db: &'db dyn Db, file: File) -> Arc<FxHashSe
/// Using [`use_def_map`] over [`semantic_index`] has the advantage that
/// Salsa can avoid invalidating dependent queries if this scope's use-def map
/// is unchanged.
#[salsa::tracked(returns(deref))]
pub(crate) fn use_def_map<'db>(db: &'db dyn Db, scope: ScopeId<'db>) -> Arc<UseDefMap<'db>> {
#[salsa::tracked(returns(deref), heap_size=get_size2::GetSize::get_heap_size)]
pub(crate) fn use_def_map<'db>(db: &'db dyn Db, scope: ScopeId<'db>) -> ArcUseDefMap<'db> {
let file = scope.file(db);
let _span = tracing::trace_span!("use_def_map", scope=?scope.as_id(), ?file).entered();
let index = semantic_index(db, file);
@ -116,7 +117,10 @@ pub(crate) fn attribute_assignments<'db, 's>(
let place_table = index.place_table(function_scope_id);
let place = place_table.place_id_by_instance_attribute_name(name)?;
let use_def = &index.use_def_maps[function_scope_id];
Some((use_def.end_of_scope_bindings(place), function_scope_id))
Some((
use_def.inner.end_of_scope_bindings(place),
function_scope_id,
))
})
}
@ -151,7 +155,7 @@ pub(crate) fn attribute_scopes<'db, 's>(
}
/// Returns the module global scope of `file`.
#[salsa::tracked]
#[salsa::tracked(heap_size=get_size2::GetSize::get_heap_size)]
pub(crate) fn global_scope(db: &dyn Db, file: File) -> ScopeId<'_> {
let _span = tracing::trace_span!("global_scope", ?file).entered();
@ -166,7 +170,7 @@ pub(crate) enum EagerSnapshotResult<'map, 'db> {
}
/// The place tables and use-def maps for all scopes in a file.
#[derive(Debug, Update)]
#[derive(Debug, Update, get_size2::GetSize)]
pub(crate) struct SemanticIndex<'db> {
/// List of all place tables in this file, indexed by scope.
place_tables: IndexVec<FileScopeId, Arc<PlaceTable>>,
@ -193,7 +197,7 @@ pub(crate) struct SemanticIndex<'db> {
globals_by_scope: FxHashMap<FileScopeId, FxHashSet<ScopedPlaceId>>,
/// Use-def map for each scope in this file.
use_def_maps: IndexVec<FileScopeId, Arc<UseDefMap<'db>>>,
use_def_maps: IndexVec<FileScopeId, ArcUseDefMap<'db>>,
/// Lookup table to map between node ids and ast nodes.
///
@ -232,7 +236,7 @@ impl<'db> SemanticIndex<'db> {
/// Use the Salsa cached [`use_def_map()`] query if you only need the
/// use-def map for a single scope.
#[track_caller]
pub(super) fn use_def_map(&self, scope_id: FileScopeId) -> Arc<UseDefMap> {
pub(super) fn use_def_map(&self, scope_id: FileScopeId) -> ArcUseDefMap<'_> {
self.use_def_maps[scope_id].clone()
}
@ -457,7 +461,7 @@ impl<'db> SemanticIndex<'db> {
let Some(id) = self.eager_snapshots.get(&key) else {
return EagerSnapshotResult::NotFound;
};
self.use_def_maps[enclosing_scope].eager_snapshot(*id)
self.use_def_maps[enclosing_scope].inner.eager_snapshot(*id)
}
pub(crate) fn semantic_syntax_errors(&self) -> &[SemanticSyntaxError] {
@ -465,6 +469,28 @@ impl<'db> SemanticIndex<'db> {
}
}
#[derive(Debug, PartialEq, Eq, Clone, salsa::Update, get_size2::GetSize)]
pub(crate) struct ArcUseDefMap<'db> {
#[get_size(size_fn = untracked_arc_size)]
inner: Arc<UseDefMap<'db>>,
}
impl<'db> std::ops::Deref for ArcUseDefMap<'db> {
type Target = UseDefMap<'db>;
fn deref(&self) -> &Self::Target {
&self.inner
}
}
impl<'db> ArcUseDefMap<'db> {
pub(crate) fn new(inner: UseDefMap<'db>) -> Self {
Self {
inner: Arc::new(inner),
}
}
}
pub struct AncestorsIter<'a> {
scopes: &'a IndexSlice<FileScopeId, Scope>,
next_id: Option<FileScopeId>,

View file

@ -24,7 +24,7 @@ use crate::semantic_index::semantic_index;
///
/// x = foo()
/// ```
#[derive(Debug, salsa::Update)]
#[derive(Debug, salsa::Update, get_size2::GetSize)]
pub(crate) struct AstIds {
/// Maps expressions to their expression id.
expressions_map: FxHashMap<ExpressionNodeKey, ScopedExpressionId>,
@ -51,6 +51,7 @@ fn ast_ids<'db>(db: &'db dyn Db, scope: ScopeId) -> &'db AstIds {
/// Uniquely identifies a use of a name in a [`crate::semantic_index::place::FileScopeId`].
#[newtype_index]
#[derive(get_size2::GetSize)]
pub struct ScopedUseId;
pub trait HasScopedUseId {
@ -95,7 +96,7 @@ impl HasScopedUseId for ast::ExprRef<'_> {
/// Uniquely identifies an [`ast::Expr`] in a [`crate::semantic_index::place::FileScopeId`].
#[newtype_index]
#[derive(salsa::Update)]
#[derive(salsa::Update, get_size2::GetSize)]
pub struct ScopedExpressionId;
pub trait HasScopedExpressionId {
@ -203,7 +204,7 @@ pub(crate) mod node_key {
use crate::node_key::NodeKey;
#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug, salsa::Update)]
#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug, salsa::Update, get_size2::GetSize)]
pub(crate) struct ExpressionNodeKey(NodeKey);
impl From<ast::ExprRef<'_>> for ExpressionNodeKey {

View file

@ -20,7 +20,6 @@ use crate::ast_node_ref::AstNodeRef;
use crate::module_name::ModuleName;
use crate::module_resolver::resolve_module;
use crate::node_key::NodeKey;
use crate::semantic_index::SemanticIndex;
use crate::semantic_index::ast_ids::AstIdsBuilder;
use crate::semantic_index::ast_ids::node_key::ExpressionNodeKey;
use crate::semantic_index::definition::{
@ -46,6 +45,7 @@ use crate::semantic_index::reachability_constraints::{
use crate::semantic_index::use_def::{
EagerSnapshotKey, FlowSnapshot, ScopedEagerSnapshotId, UseDefMapBuilder,
};
use crate::semantic_index::{ArcUseDefMap, SemanticIndex};
use crate::unpack::{Unpack, UnpackKind, UnpackPosition, UnpackValue};
use crate::{Db, Program};
@ -998,7 +998,7 @@ impl<'db, 'ast> SemanticIndexBuilder<'db, 'ast> {
let mut use_def_maps: IndexVec<_, _> = self
.use_def_maps
.into_iter()
.map(|builder| Arc::new(builder.finish()))
.map(|builder| ArcUseDefMap::new(builder.finish()))
.collect();
let mut ast_ids: IndexVec<_, _> = self

View file

@ -44,6 +44,9 @@ pub struct Definition<'db> {
count: countme::Count<Definition<'static>>,
}
// The Salsa heap is tracked separately.
impl get_size2::GetSize for Definition<'_> {}
impl<'db> Definition<'db> {
pub(crate) fn scope(self, db: &'db dyn Db) -> ScopeId<'db> {
self.file_scope(db).to_scope_id(db, self.file(db))
@ -59,16 +62,20 @@ impl<'db> Definition<'db> {
}
/// One or more [`Definition`]s.
#[derive(Debug, Default, PartialEq, Eq, salsa::Update)]
pub struct Definitions<'db>(smallvec::SmallVec<[Definition<'db>; 1]>);
#[derive(Debug, Default, PartialEq, Eq, salsa::Update, get_size2::GetSize)]
pub struct Definitions<'db> {
definitions: smallvec::SmallVec<[Definition<'db>; 1]>,
}
impl<'db> Definitions<'db> {
pub(crate) fn single(definition: Definition<'db>) -> Self {
Self(smallvec::smallvec![definition])
Self {
definitions: smallvec::smallvec![definition],
}
}
pub(crate) fn push(&mut self, definition: Definition<'db>) {
self.0.push(definition);
self.definitions.push(definition);
}
}
@ -76,7 +83,7 @@ impl<'db> Deref for Definitions<'db> {
type Target = [Definition<'db>];
fn deref(&self) -> &Self::Target {
&self.0
&self.definitions
}
}
@ -85,11 +92,11 @@ impl<'a, 'db> IntoIterator for &'a Definitions<'db> {
type IntoIter = std::slice::Iter<'a, Definition<'db>>;
fn into_iter(self) -> Self::IntoIter {
self.0.iter()
self.definitions.iter()
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, salsa::Update)]
#[derive(Debug, Clone, Copy, PartialEq, Eq, salsa::Update, get_size2::GetSize)]
pub(crate) enum DefinitionState<'db> {
Defined(Definition<'db>),
/// Represents the implicit "unbound"/"undeclared" definition of every place.
@ -999,7 +1006,7 @@ impl ExceptHandlerDefinitionKind {
}
}
#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug, salsa::Update)]
#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug, salsa::Update, get_size2::GetSize)]
pub(crate) struct DefinitionNodeKey(NodeKey);
impl From<&ast::Alias> for DefinitionNodeKey {

View file

@ -62,6 +62,9 @@ pub(crate) struct Expression<'db> {
count: countme::Count<Expression<'static>>,
}
// The Salsa heap is tracked separately.
impl get_size2::GetSize for Expression<'_> {}
impl<'db> Expression<'db> {
pub(crate) fn node_ref<'ast>(
self,

View file

@ -55,7 +55,7 @@ pub(crate) enum ConstraintKey {
/// [`ScopedPredicateId`] to refer to the underlying predicate.
///
/// [`Predicate`]: crate::semantic_index::predicate::Predicate
#[derive(Clone, Copy, Debug, Eq, Ord, PartialEq, PartialOrd)]
#[derive(Clone, Copy, Debug, Eq, Ord, PartialEq, PartialOrd, get_size2::GetSize)]
pub(crate) struct ScopedNarrowingConstraintPredicate(ScopedPredicateId);
impl ScopedNarrowingConstraintPredicate {
@ -72,7 +72,7 @@ impl From<ScopedPredicateId> for ScopedNarrowingConstraintPredicate {
}
/// A collection of narrowing constraints for a given scope.
#[derive(Debug, Eq, PartialEq)]
#[derive(Debug, Eq, PartialEq, get_size2::GetSize)]
pub(crate) struct NarrowingConstraints {
lists: ListStorage<ScopedNarrowingConstraintPredicate>,
}

View file

@ -18,7 +18,7 @@ use crate::node_key::NodeKey;
use crate::semantic_index::reachability_constraints::ScopedReachabilityConstraintId;
use crate::semantic_index::{PlaceSet, SemanticIndex, semantic_index};
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
#[derive(Debug, Clone, PartialEq, Eq, Hash, get_size2::GetSize)]
pub(crate) enum PlaceExprSubSegment {
/// A member access, e.g. `.y` in `x.y`
Member(ast::name::Name),
@ -38,7 +38,7 @@ impl PlaceExprSubSegment {
}
/// An expression that can be the target of a `Definition`.
#[derive(Eq, PartialEq, Debug)]
#[derive(Eq, PartialEq, Debug, get_size2::GetSize)]
pub struct PlaceExpr {
root_name: Name,
sub_segments: SmallVec<[PlaceExprSubSegment; 1]>,
@ -217,7 +217,7 @@ impl PlaceExpr {
}
/// A [`PlaceExpr`] with flags, e.g. whether it is used, bound, an instance attribute, etc.
#[derive(Eq, PartialEq, Debug)]
#[derive(Eq, PartialEq, Debug, get_size2::GetSize)]
pub struct PlaceExprWithFlags {
pub(crate) expr: PlaceExpr,
flags: PlaceFlags,
@ -405,6 +405,8 @@ bitflags! {
}
}
impl get_size2::GetSize for PlaceFlags {}
/// ID that uniquely identifies a place in a file.
#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash)]
pub struct FilePlaceId {
@ -430,7 +432,7 @@ impl From<FilePlaceId> for ScopedPlaceId {
/// ID that uniquely identifies a place inside a [`Scope`].
#[newtype_index]
#[derive(salsa::Update)]
#[derive(salsa::Update, get_size2::GetSize)]
pub struct ScopedPlaceId;
/// A cross-module identifier of a scope that can be used as a salsa query parameter.
@ -443,6 +445,9 @@ pub struct ScopeId<'db> {
count: countme::Count<ScopeId<'static>>,
}
// The Salsa heap is tracked separately.
impl get_size2::GetSize for ScopeId<'_> {}
impl<'db> ScopeId<'db> {
pub(crate) fn is_function_like(self, db: &'db dyn Db) -> bool {
self.node(db).scope_kind().is_function_like()
@ -489,7 +494,7 @@ impl<'db> ScopeId<'db> {
/// ID that uniquely identifies a scope inside of a module.
#[newtype_index]
#[derive(salsa::Update)]
#[derive(salsa::Update, get_size2::GetSize)]
pub struct FileScopeId;
impl FileScopeId {
@ -512,7 +517,7 @@ impl FileScopeId {
}
}
#[derive(Debug, salsa::Update)]
#[derive(Debug, salsa::Update, get_size2::GetSize)]
pub struct Scope {
parent: Option<FileScopeId>,
node: NodeWithScopeKind,
@ -609,7 +614,7 @@ impl ScopeKind {
}
/// [`PlaceExpr`] table for a specific [`Scope`].
#[derive(Default)]
#[derive(Default, get_size2::GetSize)]
pub struct PlaceTable {
/// The place expressions in this scope.
places: IndexVec<ScopedPlaceId, PlaceExprWithFlags>,
@ -932,7 +937,7 @@ impl NodeWithScopeRef<'_> {
}
/// Node that introduces a new scope.
#[derive(Clone, Debug, salsa::Update)]
#[derive(Clone, Debug, salsa::Update, get_size2::GetSize)]
pub enum NodeWithScopeKind {
Module,
Class(AstNodeRef<ast::StmtClassDef>),
@ -1011,7 +1016,7 @@ impl NodeWithScopeKind {
}
}
#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash)]
#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash, get_size2::GetSize)]
pub(crate) enum NodeWithScopeKey {
Module,
Class(NodeKey),

View file

@ -18,7 +18,7 @@ use crate::semantic_index::place::{FileScopeId, ScopeId, ScopedPlaceId};
// A scoped identifier for each `Predicate` in a scope.
#[newtype_index]
#[derive(Ord, PartialOrd)]
#[derive(Ord, PartialOrd, get_size2::GetSize)]
pub(crate) struct ScopedPredicateId;
// A collection of predicates for a given scope.
@ -43,7 +43,7 @@ impl<'db> PredicatesBuilder<'db> {
}
}
#[derive(Clone, Copy, Debug, Hash, PartialEq, Eq, salsa::Update)]
#[derive(Clone, Copy, Debug, Hash, PartialEq, Eq, salsa::Update, get_size2::GetSize)]
pub(crate) struct Predicate<'db> {
pub(crate) node: PredicateNode<'db>,
pub(crate) is_positive: bool,
@ -58,7 +58,7 @@ impl Predicate<'_> {
}
}
#[derive(Clone, Copy, Debug, Hash, PartialEq, Eq, salsa::Update)]
#[derive(Clone, Copy, Debug, Hash, PartialEq, Eq, salsa::Update, get_size2::GetSize)]
pub(crate) enum PredicateNode<'db> {
Expression(Expression<'db>),
Pattern(PatternPredicate<'db>),
@ -91,6 +91,9 @@ pub(crate) struct PatternPredicate<'db> {
count: countme::Count<PatternPredicate<'static>>,
}
// The Salsa heap is tracked separately.
impl get_size2::GetSize for PatternPredicate<'_> {}
impl<'db> PatternPredicate<'db> {
pub(crate) fn scope(self, db: &'db dyn Db) -> ScopeId<'db> {
self.file_scope(db).to_scope_id(db, self.file(db))
@ -155,6 +158,9 @@ pub(crate) struct StarImportPlaceholderPredicate<'db> {
pub(crate) referenced_file: File,
}
// The Salsa heap is tracked separately.
impl get_size2::GetSize for StarImportPlaceholderPredicate<'_> {}
impl<'db> StarImportPlaceholderPredicate<'db> {
pub(crate) fn scope(self, db: &'db dyn Db) -> ScopeId<'db> {
// See doc-comment above [`StarImportPlaceholderPredicate::symbol_id`]:

View file

@ -43,7 +43,7 @@ fn exports_cycle_initial(_db: &dyn Db, _file: File) -> Box<[Name]> {
Box::default()
}
#[salsa::tracked(returns(deref), cycle_fn=exports_cycle_recover, cycle_initial=exports_cycle_initial)]
#[salsa::tracked(returns(deref), cycle_fn=exports_cycle_recover, cycle_initial=exports_cycle_initial, heap_size=get_size2::GetSize::get_heap_size)]
pub(super) fn exported_names(db: &dyn Db, file: File) -> Box<[Name]> {
let module = parsed_module(db.upcast(), file).load(db.upcast());
let mut finder = ExportFinder::new(db, file);

View file

@ -226,7 +226,7 @@ use crate::types::{Truthiness, Type, infer_expression_type};
///
/// reachability constraints are normalized, so equivalent constraints are guaranteed to have equal
/// IDs.
#[derive(Clone, Copy, Eq, Hash, PartialEq)]
#[derive(Clone, Copy, Eq, Hash, PartialEq, get_size2::GetSize)]
pub(crate) struct ScopedReachabilityConstraintId(u32);
impl std::fmt::Debug for ScopedReachabilityConstraintId {
@ -255,7 +255,7 @@ impl std::fmt::Debug for ScopedReachabilityConstraintId {
// _Interior nodes_ provide the TDD structure for the formula. Interior nodes are stored in an
// arena Vec, with the constraint ID providing an index into the arena.
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq, get_size2::GetSize)]
struct InteriorNode {
/// A "variable" that is evaluated as part of a TDD ternary function. For reachability
/// constraints, this is a `Predicate` that represents some runtime property of the Python
@ -306,7 +306,7 @@ const ALWAYS_FALSE: ScopedReachabilityConstraintId = ScopedReachabilityConstrain
const SMALLEST_TERMINAL: ScopedReachabilityConstraintId = ALWAYS_FALSE;
/// A collection of reachability constraints for a given scope.
#[derive(Debug, PartialEq, Eq, salsa::Update)]
#[derive(Debug, PartialEq, Eq, salsa::Update, get_size2::GetSize)]
pub(crate) struct ReachabilityConstraints {
interiors: IndexVec<ScopedReachabilityConstraintId, InteriorNode>,
}

View file

@ -259,7 +259,7 @@ use crate::types::{IntersectionBuilder, Truthiness, Type, infer_narrowing_constr
mod place_state;
/// Applicable definitions and constraints for every use of a name.
#[derive(Debug, PartialEq, Eq, salsa::Update)]
#[derive(Debug, PartialEq, Eq, salsa::Update, get_size2::GetSize)]
pub(crate) struct UseDefMap<'db> {
/// Array of [`Definition`] in this scope. Only the first entry should be [`DefinitionState::Undefined`];
/// this represents the implicit "unbound"/"undeclared" definition of every place.
@ -549,9 +549,10 @@ impl<'db> UseDefMap<'db> {
///
/// There is a unique ID for each distinct [`EagerSnapshotKey`] in the file.
#[newtype_index]
#[derive(get_size2::GetSize)]
pub(crate) struct ScopedEagerSnapshotId;
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq, get_size2::GetSize)]
pub(crate) struct EagerSnapshotKey {
/// The enclosing scope containing the bindings
pub(crate) enclosing_scope: FileScopeId,
@ -680,7 +681,7 @@ impl<'db> Iterator for DeclarationsIterator<'_, 'db> {
impl std::iter::FusedIterator for DeclarationsIterator<'_, '_> {}
#[derive(Debug, PartialEq, Eq, salsa::Update)]
#[derive(Debug, PartialEq, Eq, salsa::Update, get_size2::GetSize)]
struct ReachableDefinitions {
bindings: Bindings,
declarations: Declarations,

View file

@ -55,7 +55,7 @@ use crate::semantic_index::reachability_constraints::{
/// A newtype-index for a definition in a particular scope.
#[newtype_index]
#[derive(Ord, PartialOrd)]
#[derive(Ord, PartialOrd, get_size2::GetSize)]
pub(super) struct ScopedDefinitionId;
impl ScopedDefinitionId {
@ -77,14 +77,14 @@ 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)]
#[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]>,
}
/// One of the live declarations for a single place at some point in control flow.
#[derive(Clone, Debug, PartialEq, Eq)]
#[derive(Clone, Debug, PartialEq, Eq, get_size2::GetSize)]
pub(super) struct LiveDeclaration {
pub(super) declaration: ScopedDefinitionId,
pub(super) reachability_constraint: ScopedReachabilityConstraintId,
@ -183,7 +183,7 @@ impl Declarations {
/// Even if it's a class scope (class variables are not visible to nested scopes) or there are no
/// bindings, the current narrowing constraint is necessary for narrowing, so it's stored in
/// `Constraint`.
#[derive(Clone, Debug, PartialEq, Eq, salsa::Update)]
#[derive(Clone, Debug, PartialEq, Eq, salsa::Update, get_size2::GetSize)]
pub(super) enum EagerSnapshot {
Constraint(ScopedNarrowingConstraint),
Bindings(Bindings),
@ -191,7 +191,7 @@ pub(super) enum EagerSnapshot {
/// Live bindings for a single place at some point in control flow. Each live binding comes
/// with a set of narrowing constraints and a reachability constraint.
#[derive(Clone, Debug, Default, PartialEq, Eq, salsa::Update)]
#[derive(Clone, Debug, Default, PartialEq, Eq, salsa::Update, get_size2::GetSize)]
pub(super) struct Bindings {
/// The narrowing constraint applicable to the "unbound" binding, if we need access to it even
/// when it's not visible. This happens in class scopes, where local name bindings are not visible
@ -210,7 +210,7 @@ impl Bindings {
}
/// One of the live bindings for a single place at some point in control flow.
#[derive(Clone, Debug, PartialEq, Eq)]
#[derive(Clone, Debug, PartialEq, Eq, get_size2::GetSize)]
pub(super) struct LiveBinding {
pub(super) binding: ScopedDefinitionId,
pub(super) narrowing_constraint: ScopedNarrowingConstraint,
@ -338,7 +338,7 @@ impl Bindings {
}
}
#[derive(Clone, Debug, PartialEq, Eq)]
#[derive(Clone, Debug, PartialEq, Eq, get_size2::GetSize)]
pub(in crate::semantic_index) struct PlaceState {
declarations: Declarations,
bindings: Bindings,

View file

@ -86,7 +86,7 @@ declare_lint! {
}
}
#[salsa::tracked(returns(ref))]
#[salsa::tracked(returns(ref), heap_size=get_size2::GetSize::get_heap_size)]
pub(crate) fn suppressions(db: &dyn Db, file: File) -> Suppressions {
let parsed = parsed_module(db.upcast(), file).load(db.upcast());
let source = source_text(db.upcast(), file);
@ -331,7 +331,7 @@ impl<'a> CheckSuppressionsContext<'a> {
}
/// The suppressions of a single file.
#[derive(Debug, Eq, PartialEq)]
#[derive(Debug, Eq, PartialEq, get_size2::GetSize)]
pub(crate) struct Suppressions {
/// Suppressions that apply to the entire file.
///
@ -424,7 +424,7 @@ impl<'a> IntoIterator for &'a Suppressions {
/// Suppression comments that suppress multiple codes
/// create multiple suppressions: one for every code.
/// They all share the same `comment_range`.
#[derive(Clone, Debug, Eq, PartialEq)]
#[derive(Clone, Debug, Eq, PartialEq, get_size2::GetSize)]
pub(crate) struct Suppression {
target: SuppressionTarget,
kind: SuppressionKind,
@ -466,10 +466,10 @@ impl Suppression {
/// The wrapped `TextRange` is the suppression's range.
/// This is unique enough because it is its exact
/// location in the source.
#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash)]
#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash, get_size2::GetSize)]
pub(crate) struct FileSuppressionId(TextRange);
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
#[derive(Copy, Clone, Debug, Eq, PartialEq, get_size2::GetSize)]
enum SuppressionTarget {
/// Suppress all lints
All,
@ -628,7 +628,7 @@ impl<'a> SuppressionsBuilder<'a> {
}
/// Suppression for an unknown lint rule.
#[derive(Debug, PartialEq, Eq)]
#[derive(Debug, PartialEq, Eq, get_size2::GetSize)]
struct UnknownSuppression {
/// The range of the code.
range: TextRange,
@ -639,7 +639,7 @@ struct UnknownSuppression {
reason: GetLintError,
}
#[derive(Debug, PartialEq, Eq)]
#[derive(Debug, PartialEq, Eq, get_size2::GetSize)]
struct InvalidSuppression {
kind: SuppressionKind,
error: ParseError,
@ -843,7 +843,7 @@ struct SuppressionComment {
codes: Option<SmallVec<[TextRange; 2]>>,
}
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
#[derive(Copy, Clone, Debug, Eq, PartialEq, get_size2::GetSize)]
enum SuppressionKind {
TypeIgnore,
Ty,
@ -871,7 +871,7 @@ impl fmt::Display for SuppressionKind {
}
}
#[derive(Debug, Eq, PartialEq, Clone)]
#[derive(Debug, Eq, PartialEq, Clone, get_size2::GetSize)]
struct ParseError {
kind: ParseErrorKind,
@ -893,7 +893,7 @@ impl fmt::Display for ParseError {
impl Error for ParseError {}
#[derive(Debug, Eq, PartialEq, Clone, Error)]
#[derive(Debug, Eq, PartialEq, Clone, Error, get_size2::GetSize)]
enum ParseErrorKind {
/// The comment isn't a suppression comment.
#[error("not a suppression comment")]

View file

@ -85,7 +85,7 @@ mod definition;
#[cfg(test)]
mod property_tests;
#[salsa::tracked(returns(ref))]
#[salsa::tracked(returns(ref), heap_size=get_size2::GetSize::get_heap_size)]
pub fn check_types(db: &dyn Db, file: File) -> TypeCheckDiagnostics {
let _span = tracing::trace_span!("check_types", ?file).entered();
@ -160,7 +160,7 @@ fn definition_expression_type<'db>(
/// define a `__get__` method, while data descriptors additionally define a `__set__`
/// method or a `__delete__` method. This enum is used to categorize attributes into two
/// groups: (1) data descriptors and (2) normal attributes or non-data descriptors.
#[derive(Clone, Debug, Copy, PartialEq, Eq, Hash, salsa::Update)]
#[derive(Clone, Debug, Copy, PartialEq, Eq, Hash, salsa::Update, get_size2::GetSize)]
pub(crate) enum AttributeKind {
DataDescriptor,
NormalOrNonDataDescriptor,
@ -284,7 +284,7 @@ fn class_lookup_cycle_initial<'db>(
/// Meta data for `Type::Todo`, which represents a known limitation in ty.
#[cfg(debug_assertions)]
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, get_size2::GetSize)]
pub struct TodoType(pub &'static str);
#[cfg(debug_assertions)]
@ -295,7 +295,7 @@ impl std::fmt::Display for TodoType {
}
#[cfg(not(debug_assertions))]
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, get_size2::GetSize)]
pub struct TodoType;
#[cfg(not(debug_assertions))]
@ -370,6 +370,9 @@ pub struct PropertyInstanceType<'db> {
setter: Option<Type<'db>>,
}
// The Salsa heap is tracked separately.
impl get_size2::GetSize for PropertyInstanceType<'_> {}
impl<'db> PropertyInstanceType<'db> {
fn apply_type_mapping<'a>(self, db: &'db dyn Db, type_mapping: &TypeMapping<'a, 'db>) -> Self {
let getter = self
@ -423,6 +426,8 @@ bitflags! {
}
}
impl get_size2::GetSize for DataclassParams {}
impl Default for DataclassParams {
fn default() -> Self {
Self::INIT | Self::REPR | Self::EQ | Self::MATCH_ARGS
@ -456,7 +461,7 @@ impl From<DataclassTransformerParams> for DataclassParams {
/// Representation of a type: a set of possible values at runtime.
///
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, salsa::Update)]
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, salsa::Update, get_size2::GetSize)]
pub enum Type<'db> {
/// The dynamic type: a statically unknown set of values
Dynamic(DynamicType),
@ -2483,7 +2488,7 @@ impl<'db> Type<'db> {
}
}
#[salsa::tracked]
#[salsa::tracked(heap_size=get_size2::GetSize::get_heap_size)]
#[allow(unused_variables)]
// If we choose name `_unit`, the macro will generate code that uses `_unit`, causing clippy to fail.
fn lookup_dunder_new(self, db: &'db dyn Db, unit: ()) -> Option<PlaceAndQualifiers<'db>> {
@ -2504,7 +2509,7 @@ impl<'db> Type<'db> {
self.class_member_with_policy(db, name, MemberLookupPolicy::default())
}
#[salsa::tracked(cycle_fn=class_lookup_cycle_recover, cycle_initial=class_lookup_cycle_initial)]
#[salsa::tracked(cycle_fn=class_lookup_cycle_recover, cycle_initial=class_lookup_cycle_initial, heap_size=get_size2::GetSize::get_heap_size)]
fn class_member_with_policy(
self,
db: &'db dyn Db,
@ -2657,7 +2662,7 @@ impl<'db> Type<'db> {
/// that `self` represents: (1) a data descriptor or (2) a non-data descriptor / normal attribute.
///
/// If `__get__` is not defined on the meta-type, this method returns `None`.
#[salsa::tracked]
#[salsa::tracked(heap_size=get_size2::GetSize::get_heap_size)]
pub(crate) fn try_call_dunder_get(
self,
db: &'db dyn Db,
@ -2950,7 +2955,7 @@ impl<'db> Type<'db> {
/// Similar to [`Type::member`], but allows the caller to specify what policy should be used
/// when looking up attributes. See [`MemberLookupPolicy`] for more information.
#[salsa::tracked(cycle_fn=member_lookup_cycle_recover, cycle_initial=member_lookup_cycle_initial)]
#[salsa::tracked(cycle_fn=member_lookup_cycle_recover, cycle_initial=member_lookup_cycle_initial, heap_size=get_size2::GetSize::get_heap_size)]
fn member_lookup_with_policy(
self,
db: &'db dyn Db,
@ -5209,7 +5214,7 @@ impl<'db> Type<'db> {
/// Note that this does not specialize generic classes, functions, or type aliases! That is a
/// different operation that is performed explicitly (via a subscript operation), or implicitly
/// via a call to the generic object.
#[salsa::tracked]
#[salsa::tracked(heap_size=get_size2::GetSize::get_heap_size)]
pub fn apply_specialization(
self,
db: &'db dyn Db,
@ -5701,7 +5706,9 @@ impl<'db> TypeMapping<'_, 'db> {
/// Ordering between variants is stable and should be the same between runs.
/// Ordering within variants is based on the wrapped data's salsa-assigned id and not on its values.
/// The id may change between runs, or when e.g. a `TypeVarInstance` was garbage-collected and recreated.
#[derive(Copy, Clone, Debug, Eq, Hash, PartialEq, salsa::Update, Ord, PartialOrd)]
#[derive(
Copy, Clone, Debug, Eq, Hash, PartialEq, salsa::Update, Ord, PartialOrd, get_size2::GetSize,
)]
pub enum KnownInstanceType<'db> {
/// The type of `Protocol[T]`, `Protocol[U, S]`, etc -- usually only found in a class's bases list.
///
@ -5790,7 +5797,7 @@ impl<'db> KnownInstanceType<'db> {
}
}
#[derive(Copy, Clone, Debug, Eq, Hash, PartialEq)]
#[derive(Copy, Clone, Debug, Eq, Hash, PartialEq, get_size2::GetSize)]
pub enum DynamicType {
/// An explicitly annotated `typing.Any`
Any,
@ -5848,6 +5855,8 @@ bitflags! {
}
}
impl get_size2::GetSize for TypeQualifiers {}
/// When inferring the type of an annotation expression, we can also encounter type qualifiers
/// such as `ClassVar` or `Final`. These do not affect the inferred type itself, but rather
/// control how a particular place can be accessed or modified. This struct holds a type and
@ -5855,7 +5864,7 @@ bitflags! {
///
/// Example: `Annotated[ClassVar[tuple[int]], "metadata"]` would have type `tuple[int]` and the
/// qualifier `ClassVar`.
#[derive(Clone, Debug, Copy, Eq, PartialEq, salsa::Update)]
#[derive(Clone, Debug, Copy, Eq, PartialEq, salsa::Update, get_size2::GetSize)]
pub(crate) struct TypeAndQualifiers<'db> {
inner: Type<'db>,
qualifiers: TypeQualifiers,
@ -6081,6 +6090,9 @@ pub struct TypeVarInstance<'db> {
pub kind: TypeVarKind,
}
// The Salsa heap is tracked separately.
impl get_size2::GetSize for TypeVarInstance<'_> {}
impl<'db> TypeVarInstance<'db> {
pub(crate) fn is_legacy(self, db: &'db dyn Db) -> bool {
matches!(self.kind(db), TypeVarKind::Legacy)
@ -7057,6 +7069,9 @@ pub struct BoundMethodType<'db> {
self_instance: Type<'db>,
}
// The Salsa heap is tracked separately.
impl get_size2::GetSize for BoundMethodType<'_> {}
impl<'db> BoundMethodType<'db> {
pub(crate) fn into_callable_type(self, db: &'db dyn Db) -> Type<'db> {
Type::Callable(CallableType::new(
@ -7122,6 +7137,9 @@ pub struct CallableType<'db> {
is_function_like: bool,
}
// The Salsa heap is tracked separately.
impl get_size2::GetSize for CallableType<'_> {}
impl<'db> CallableType<'db> {
/// Create a callable type with a single non-overloaded signature.
pub(crate) fn single(db: &'db dyn Db, signature: Signature<'db>) -> Type<'db> {
@ -7232,7 +7250,9 @@ impl<'db> CallableType<'db> {
}
/// Represents a specific instance of `types.MethodWrapperType`
#[derive(Debug, Copy, Clone, Hash, PartialEq, Eq, PartialOrd, Ord, salsa::Update)]
#[derive(
Debug, Copy, Clone, Hash, PartialEq, Eq, PartialOrd, Ord, salsa::Update, get_size2::GetSize,
)]
pub enum MethodWrapperKind<'db> {
/// Method wrapper for `some_function.__get__`
FunctionTypeDunderGet(FunctionType<'db>),
@ -7337,7 +7357,9 @@ impl<'db> MethodWrapperKind<'db> {
}
/// Represents a specific instance of `types.WrapperDescriptorType`
#[derive(Debug, Copy, Clone, Hash, PartialEq, Eq, PartialOrd, Ord, salsa::Update)]
#[derive(
Debug, Copy, Clone, Hash, PartialEq, Eq, PartialOrd, Ord, salsa::Update, get_size2::GetSize,
)]
pub enum WrapperDescriptorKind {
/// `FunctionType.__get__`
FunctionTypeDunderGet,
@ -7363,6 +7385,9 @@ pub struct ModuleLiteralType<'db> {
pub module: Module,
}
// The Salsa heap is tracked separately.
impl get_size2::GetSize for ModuleLiteralType<'_> {}
impl<'db> ModuleLiteralType<'db> {
fn static_member(self, db: &'db dyn Db, name: &str) -> Place<'db> {
// `__dict__` is a very special member that is never overridden by module globals;
@ -7416,6 +7441,9 @@ pub struct PEP695TypeAliasType<'db> {
rhs_scope: ScopeId<'db>,
}
// The Salsa heap is tracked separately.
impl get_size2::GetSize for PEP695TypeAliasType<'_> {}
#[salsa::tracked]
impl<'db> PEP695TypeAliasType<'db> {
pub(crate) fn definition(self, db: &'db dyn Db) -> Definition<'db> {
@ -7426,7 +7454,7 @@ impl<'db> PEP695TypeAliasType<'db> {
semantic_index(db, scope.file(db)).expect_single_definition(type_alias_stmt_node)
}
#[salsa::tracked]
#[salsa::tracked(heap_size=get_size2::GetSize::get_heap_size)]
pub(crate) fn value_type(self, db: &'db dyn Db) -> Type<'db> {
let scope = self.rhs_scope(db);
let module = parsed_module(db.upcast(), scope.file(db)).load(db.upcast());
@ -7452,6 +7480,9 @@ pub struct BareTypeAliasType<'db> {
pub value: Type<'db>,
}
// The Salsa heap is tracked separately.
impl get_size2::GetSize for BareTypeAliasType<'_> {}
impl<'db> BareTypeAliasType<'db> {
fn normalized(self, db: &'db dyn Db) -> Self {
Self::new(
@ -7463,7 +7494,9 @@ impl<'db> BareTypeAliasType<'db> {
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, salsa::Update)]
#[derive(
Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, salsa::Update, get_size2::GetSize,
)]
pub enum TypeAliasType<'db> {
PEP695(PEP695TypeAliasType<'db>),
Bare(BareTypeAliasType<'db>),
@ -7500,7 +7533,7 @@ impl<'db> TypeAliasType<'db> {
}
/// Either the explicit `metaclass=` keyword of the class, or the inferred metaclass of one of its base classes.
#[derive(Debug, Clone, PartialEq, Eq, salsa::Update)]
#[derive(Debug, Clone, PartialEq, Eq, salsa::Update, get_size2::GetSize)]
pub(super) struct MetaclassCandidate<'db> {
metaclass: ClassType<'db>,
explicit_metaclass_of: ClassLiteral<'db>,
@ -7513,6 +7546,9 @@ pub struct UnionType<'db> {
pub elements: Box<[Type<'db>]>,
}
// The Salsa heap is tracked separately.
impl get_size2::GetSize for UnionType<'_> {}
impl<'db> UnionType<'db> {
/// Create a union from a list of elements
/// (which may be eagerly simplified into a different variant of [`Type`] altogether).
@ -7726,6 +7762,9 @@ pub struct IntersectionType<'db> {
negative: FxOrderSet<Type<'db>>,
}
// The Salsa heap is tracked separately.
impl get_size2::GetSize for IntersectionType<'_> {}
impl<'db> IntersectionType<'db> {
/// Return a new `IntersectionType` instance with the positive and negative types sorted
/// according to a canonical ordering, and other normalizations applied to each element as applicable.
@ -7895,6 +7934,9 @@ pub struct StringLiteralType<'db> {
value: Box<str>,
}
// The Salsa heap is tracked separately.
impl get_size2::GetSize for StringLiteralType<'_> {}
impl<'db> StringLiteralType<'db> {
/// The length of the string, as would be returned by Python's `len()`.
pub(crate) fn python_len(self, db: &'db dyn Db) -> usize {
@ -7920,6 +7962,9 @@ pub struct BytesLiteralType<'db> {
value: Box<[u8]>,
}
// The Salsa heap is tracked separately.
impl get_size2::GetSize for BytesLiteralType<'_> {}
impl<'db> BytesLiteralType<'db> {
pub(crate) fn python_len(self, db: &'db dyn Db) -> usize {
self.value(db).len()
@ -8061,6 +8106,9 @@ pub struct BoundSuperType<'db> {
pub owner: SuperOwnerKind<'db>,
}
// The Salsa heap is tracked separately.
impl get_size2::GetSize for BoundSuperType<'_> {}
impl<'db> BoundSuperType<'db> {
/// Attempts to build a `Type::BoundSuper` based on the given `pivot_class` and `owner`.
///
@ -8239,6 +8287,9 @@ pub struct TypeIsType<'db> {
place_info: Option<(ScopeId<'db>, ScopedPlaceId)>,
}
// The Salsa heap is tracked separately.
impl get_size2::GetSize for TypeIsType<'_> {}
impl<'db> TypeIsType<'db> {
pub fn place_name(self, db: &'db dyn Db) -> Option<String> {
let (scope, place) = self.place_info(db)?;

View file

@ -178,6 +178,9 @@ pub struct GenericAlias<'db> {
pub(crate) specialization: Specialization<'db>,
}
// The Salsa heap is tracked separately.
impl get_size2::GetSize for GenericAlias<'_> {}
impl<'db> GenericAlias<'db> {
pub(super) fn normalized(self, db: &'db dyn Db) -> Self {
Self::new(db, self.origin(db), self.specialization(db).normalized(db))
@ -227,7 +230,17 @@ impl<'db> From<GenericAlias<'db>> for Type<'db> {
/// Represents a class type, which might be a non-generic class, or a specialization of a generic
/// class.
#[derive(
Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd, salsa::Supertype, salsa::Update,
Clone,
Copy,
Debug,
Eq,
Hash,
Ord,
PartialEq,
PartialOrd,
salsa::Supertype,
salsa::Update,
get_size2::GetSize,
)]
pub enum ClassType<'db> {
NonGeneric(ClassLiteral<'db>),
@ -749,6 +762,9 @@ pub struct ClassLiteral<'db> {
pub(crate) dataclass_transformer_params: Option<DataclassTransformerParams>,
}
// The Salsa heap is tracked separately.
impl get_size2::GetSize for ClassLiteral<'_> {}
#[expect(clippy::trivially_copy_pass_by_ref, clippy::ref_option)]
fn pep695_generic_context_cycle_recover<'db>(
_db: &'db dyn Db,
@ -795,7 +811,7 @@ impl<'db> ClassLiteral<'db> {
self.pep695_generic_context(db).is_some()
}
#[salsa::tracked(cycle_fn=pep695_generic_context_cycle_recover, cycle_initial=pep695_generic_context_cycle_initial)]
#[salsa::tracked(cycle_fn=pep695_generic_context_cycle_recover, cycle_initial=pep695_generic_context_cycle_initial, heap_size=get_size2::GetSize::get_heap_size)]
pub(crate) fn pep695_generic_context(self, db: &'db dyn Db) -> Option<GenericContext<'db>> {
let scope = self.body_scope(db);
let parsed = parsed_module(db.upcast(), scope.file(db)).load(db.upcast());
@ -905,7 +921,7 @@ impl<'db> ClassLiteral<'db> {
///
/// Were this not a salsa query, then the calling query
/// would depend on the class's AST and rerun for every change in that file.
#[salsa::tracked(returns(deref), cycle_fn=explicit_bases_cycle_recover, cycle_initial=explicit_bases_cycle_initial)]
#[salsa::tracked(returns(deref), cycle_fn=explicit_bases_cycle_recover, cycle_initial=explicit_bases_cycle_initial, heap_size=get_size2::GetSize::get_heap_size)]
pub(super) fn explicit_bases(self, db: &'db dyn Db) -> Box<[Type<'db>]> {
tracing::trace!("ClassLiteral::explicit_bases_query: {}", self.name(db));
@ -981,7 +997,7 @@ impl<'db> ClassLiteral<'db> {
}
/// Return the types of the decorators on this class
#[salsa::tracked(returns(deref))]
#[salsa::tracked(returns(deref), heap_size=get_size2::GetSize::get_heap_size)]
fn decorators(self, db: &'db dyn Db) -> Box<[Type<'db>]> {
tracing::trace!("ClassLiteral::decorators: {}", self.name(db));
@ -1029,7 +1045,7 @@ impl<'db> ClassLiteral<'db> {
/// attribute on a class at runtime.
///
/// [method resolution order]: https://docs.python.org/3/glossary.html#term-method-resolution-order
#[salsa::tracked(returns(as_ref), cycle_fn=try_mro_cycle_recover, cycle_initial=try_mro_cycle_initial)]
#[salsa::tracked(returns(as_ref), cycle_fn=try_mro_cycle_recover, cycle_initial=try_mro_cycle_initial, heap_size=get_size2::GetSize::get_heap_size)]
pub(super) fn try_mro(
self,
db: &'db dyn Db,
@ -1109,6 +1125,7 @@ impl<'db> ClassLiteral<'db> {
#[salsa::tracked(
cycle_fn=try_metaclass_cycle_recover,
cycle_initial=try_metaclass_cycle_initial,
heap_size=get_size2::GetSize::get_heap_size,
)]
pub(super) fn try_metaclass(
self,
@ -2097,7 +2114,7 @@ impl<'db> ClassLiteral<'db> {
///
/// A class definition like this will fail at runtime,
/// but we must be resilient to it or we could panic.
#[salsa::tracked(cycle_fn=inheritance_cycle_recover, cycle_initial=inheritance_cycle_initial)]
#[salsa::tracked(cycle_fn=inheritance_cycle_recover, cycle_initial=inheritance_cycle_initial, heap_size=get_size2::GetSize::get_heap_size)]
pub(super) fn inheritance_cycle(self, db: &'db dyn Db) -> Option<InheritanceCycle> {
/// Return `true` if the class is cyclically defined.
///
@ -2181,7 +2198,7 @@ impl<'db> From<ClassLiteral<'db>> for Type<'db> {
}
}
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash, get_size2::GetSize)]
pub(super) enum InheritanceCycle {
/// The class is cyclically defined and is a participant in the cycle.
/// i.e., it inherits either directly or indirectly from itself.
@ -3554,7 +3571,7 @@ impl<'db> Type<'db> {
}
}
#[derive(Debug, Clone, PartialEq, Eq, salsa::Update)]
#[derive(Debug, Clone, PartialEq, Eq, salsa::Update, get_size2::GetSize)]
pub(super) struct MetaclassError<'db> {
kind: MetaclassErrorKind<'db>,
}
@ -3566,7 +3583,7 @@ impl<'db> MetaclassError<'db> {
}
}
#[derive(Debug, Clone, PartialEq, Eq, salsa::Update)]
#[derive(Debug, Clone, PartialEq, Eq, salsa::Update, get_size2::GetSize)]
pub(super) enum MetaclassErrorKind<'db> {
/// The class has incompatible metaclasses in its inheritance hierarchy.
///

View file

@ -13,7 +13,7 @@ use crate::types::{
/// Note that a non-specialized generic class _cannot_ be a class base. When we see a
/// non-specialized generic class in any type expression (including the list of base classes), we
/// automatically construct the default specialization for that class.
#[derive(Debug, Copy, Clone, Hash, PartialEq, Eq, salsa::Update)]
#[derive(Debug, Copy, Clone, Hash, PartialEq, Eq, salsa::Update, get_size2::GetSize)]
pub enum ClassBase<'db> {
Dynamic(DynamicType),
Class(ClassType<'db>),

View file

@ -1561,7 +1561,7 @@ declare_lint! {
}
/// A collection of type check diagnostics.
#[derive(Default, Eq, PartialEq)]
#[derive(Default, Eq, PartialEq, get_size2::GetSize)]
pub struct TypeCheckDiagnostics {
diagnostics: Vec<Diagnostic>,
used_suppressions: FxHashSet<FileSuppressionId>,

View file

@ -131,6 +131,8 @@ bitflags! {
}
}
impl get_size2::GetSize for DataclassTransformerParams {}
impl Default for DataclassTransformerParams {
fn default() -> Self {
Self::EQ_DEFAULT
@ -168,6 +170,9 @@ pub struct OverloadLiteral<'db> {
pub(crate) dataclass_transformer_params: Option<DataclassTransformerParams>,
}
// The Salsa heap is tracked separately.
impl get_size2::GetSize for OverloadLiteral<'_> {}
#[salsa::tracked]
impl<'db> OverloadLiteral<'db> {
fn with_dataclass_transformer_params(
@ -432,7 +437,7 @@ impl<'db> FunctionLiteral<'db> {
self.last_definition(db).spans(db)
}
#[salsa::tracked(returns(ref))]
#[salsa::tracked(returns(ref), heap_size=get_size2::GetSize::get_heap_size)]
fn overloads_and_implementation(
self,
db: &'db dyn Db,
@ -530,6 +535,9 @@ pub struct FunctionType<'db> {
type_mappings: Box<[TypeMapping<'db, 'db>]>,
}
// The Salsa heap is tracked separately.
impl get_size2::GetSize for FunctionType<'_> {}
#[salsa::tracked]
impl<'db> FunctionType<'db> {
pub(crate) fn with_inherited_generic_context(
@ -699,7 +707,7 @@ impl<'db> FunctionType<'db> {
///
/// Were this not a salsa query, then the calling query
/// would depend on the function's AST and rerun for every change in that file.
#[salsa::tracked(returns(ref), cycle_fn=signature_cycle_recover, cycle_initial=signature_cycle_initial)]
#[salsa::tracked(returns(ref), cycle_fn=signature_cycle_recover, cycle_initial=signature_cycle_initial, heap_size=get_size2::GetSize::get_heap_size)]
pub(crate) fn signature(self, db: &'db dyn Db) -> CallableSignature<'db> {
self.literal(db).signature(db, self.type_mappings(db))
}

View file

@ -30,6 +30,9 @@ pub struct GenericContext<'db> {
pub(crate) variables: FxOrderSet<TypeVarInstance<'db>>,
}
// The Salsa heap is tracked separately.
impl get_size2::GetSize for GenericContext<'_> {}
impl<'db> GenericContext<'db> {
/// Creates a generic context from a list of PEP-695 type parameters.
pub(crate) fn from_type_params(

View file

@ -129,7 +129,7 @@ use super::{ClassBase, NominalInstanceType, add_inferred_python_version_hint_to_
/// Infer all types for a [`ScopeId`], including all definitions and expressions in that scope.
/// Use when checking a scope, or needing to provide a type for an arbitrary expression in the
/// scope.
#[salsa::tracked(returns(ref), cycle_fn=scope_cycle_recover, cycle_initial=scope_cycle_initial)]
#[salsa::tracked(returns(ref), cycle_fn=scope_cycle_recover, cycle_initial=scope_cycle_initial, heap_size=get_size2::GetSize::get_heap_size)]
pub(crate) fn infer_scope_types<'db>(db: &'db dyn Db, scope: ScopeId<'db>) -> TypeInference<'db> {
let file = scope.file(db);
let _span = tracing::trace_span!("infer_scope_types", scope=?scope.as_id(), ?file).entered();
@ -158,7 +158,7 @@ fn scope_cycle_initial<'db>(_db: &'db dyn Db, scope: ScopeId<'db>) -> TypeInfere
/// Infer all types for a [`Definition`] (including sub-expressions).
/// Use when resolving a place use or public type of a place.
#[salsa::tracked(returns(ref), cycle_fn=definition_cycle_recover, cycle_initial=definition_cycle_initial)]
#[salsa::tracked(returns(ref), cycle_fn=definition_cycle_recover, cycle_initial=definition_cycle_initial, heap_size=get_size2::GetSize::get_heap_size)]
pub(crate) fn infer_definition_types<'db>(
db: &'db dyn Db,
definition: Definition<'db>,
@ -197,7 +197,7 @@ fn definition_cycle_initial<'db>(
///
/// Deferred expressions are type expressions (annotations, base classes, aliases...) in a stub
/// file, or in a file with `from __future__ import annotations`, or stringified annotations.
#[salsa::tracked(returns(ref), cycle_fn=deferred_cycle_recover, cycle_initial=deferred_cycle_initial)]
#[salsa::tracked(returns(ref), cycle_fn=deferred_cycle_recover, cycle_initial=deferred_cycle_initial, heap_size=get_size2::GetSize::get_heap_size)]
pub(crate) fn infer_deferred_types<'db>(
db: &'db dyn Db,
definition: Definition<'db>,
@ -234,7 +234,7 @@ fn deferred_cycle_initial<'db>(db: &'db dyn Db, definition: Definition<'db>) ->
/// Use rarely; only for cases where we'd otherwise risk double-inferring an expression: RHS of an
/// assignment, which might be unpacking/multi-target and thus part of multiple definitions, or a
/// type narrowing guard expression (e.g. if statement test node).
#[salsa::tracked(returns(ref), cycle_fn=expression_cycle_recover, cycle_initial=expression_cycle_initial)]
#[salsa::tracked(returns(ref), cycle_fn=expression_cycle_recover, cycle_initial=expression_cycle_initial, heap_size=get_size2::GetSize::get_heap_size)]
pub(crate) fn infer_expression_types<'db>(
db: &'db dyn Db,
expression: Expression<'db>,
@ -296,7 +296,7 @@ pub(super) fn infer_same_file_expression_type<'db>(
///
/// Use [`infer_same_file_expression_type`] if it is guaranteed that `expression` is in the same
/// to avoid unnecessary salsa ingredients. This is normally the case inside the `TypeInferenceBuilder`.
#[salsa::tracked(cycle_fn=single_expression_cycle_recover, cycle_initial=single_expression_cycle_initial)]
#[salsa::tracked(cycle_fn=single_expression_cycle_recover, cycle_initial=single_expression_cycle_initial, heap_size=get_size2::GetSize::get_heap_size)]
pub(crate) fn infer_expression_type<'db>(
db: &'db dyn Db,
expression: Expression<'db>,
@ -330,7 +330,7 @@ fn single_expression_cycle_initial<'db>(
/// involved in an unpacking operation. It returns a result-like object that can be used to get the
/// type of the variables involved in this unpacking along with any violations that are detected
/// during this unpacking.
#[salsa::tracked(returns(ref), cycle_fn=unpack_cycle_recover, cycle_initial=unpack_cycle_initial)]
#[salsa::tracked(returns(ref), cycle_fn=unpack_cycle_recover, cycle_initial=unpack_cycle_initial, heap_size=get_size2::GetSize::get_heap_size)]
pub(super) fn infer_unpack_types<'db>(db: &'db dyn Db, unpack: Unpack<'db>) -> UnpackResult<'db> {
let file = unpack.file(db);
let module = parsed_module(db.upcast(), file).load(db.upcast());
@ -414,7 +414,7 @@ struct TypeAndRange<'db> {
}
/// The inferred types for a single region.
#[derive(Debug, Eq, PartialEq, salsa::Update)]
#[derive(Debug, Eq, PartialEq, salsa::Update, get_size2::GetSize)]
pub(crate) struct TypeInference<'db> {
/// The types of every expression in this region.
expressions: FxHashMap<ScopedExpressionId, Type<'db>>,

View file

@ -64,7 +64,7 @@ impl<'db> Type<'db> {
}
/// A type representing the set of runtime objects which are instances of a certain nominal class.
#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash, salsa::Update)]
#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash, salsa::Update, get_size2::GetSize)]
pub struct NominalInstanceType<'db> {
pub(super) class: ClassType<'db>,
@ -147,7 +147,9 @@ impl<'db> From<NominalInstanceType<'db>> for Type<'db> {
/// A `ProtocolInstanceType` represents the set of all possible runtime objects
/// that conform to the interface described by a certain protocol.
#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash, salsa::Update, PartialOrd, Ord)]
#[derive(
Copy, Clone, Debug, Eq, PartialEq, Hash, salsa::Update, PartialOrd, Ord, get_size2::GetSize,
)]
pub struct ProtocolInstanceType<'db> {
pub(super) inner: Protocol<'db>,
@ -324,7 +326,9 @@ impl<'db> ProtocolInstanceType<'db> {
/// An enumeration of the two kinds of protocol types: those that originate from a class
/// definition in source code, and those that are synthesized from a set of members.
#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash, salsa::Update, PartialOrd, Ord)]
#[derive(
Copy, Clone, Debug, Eq, PartialEq, Hash, salsa::Update, PartialOrd, Ord, get_size2::GetSize,
)]
pub(super) enum Protocol<'db> {
FromClass(ClassType<'db>),
Synthesized(SynthesizedProtocolType<'db>),
@ -359,7 +363,9 @@ mod synthesized_protocol {
///
/// The constructor method of this type maintains the invariant that a synthesized protocol type
/// is always constructed from a *normalized* protocol interface.
#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash, salsa::Update, PartialOrd, Ord)]
#[derive(
Copy, Clone, Debug, Eq, PartialEq, Hash, salsa::Update, PartialOrd, Ord, get_size2::GetSize,
)]
pub(in crate::types) struct SynthesizedProtocolType<'db>(ProtocolInterface<'db>);
impl<'db> SynthesizedProtocolType<'db> {

View file

@ -28,7 +28,7 @@ use crate::types::{ClassLiteral, ClassType, KnownInstanceType, SpecialFormType,
/// ```
///
/// See [`ClassType::iter_mro`] for more details.
#[derive(PartialEq, Eq, Clone, Debug, salsa::Update)]
#[derive(PartialEq, Eq, Clone, Debug, salsa::Update, get_size2::GetSize)]
pub(super) struct Mro<'db>(Box<[ClassBase<'db>]>);
impl<'db> Mro<'db> {
@ -413,7 +413,7 @@ impl<'db> Iterator for MroIterator<'db> {
impl std::iter::FusedIterator for MroIterator<'_> {}
#[derive(Debug, PartialEq, Eq, salsa::Update)]
#[derive(Debug, PartialEq, Eq, salsa::Update, get_size2::GetSize)]
pub(super) struct MroError<'db> {
kind: MroErrorKind<'db>,
fallback_mro: Mro<'db>,
@ -442,7 +442,7 @@ impl<'db> MroError<'db> {
}
/// Possible ways in which attempting to resolve the MRO of a class might fail.
#[derive(Debug, PartialEq, Eq, salsa::Update)]
#[derive(Debug, PartialEq, Eq, salsa::Update, get_size2::GetSize)]
pub(super) enum MroErrorKind<'db> {
/// The class inherits from one or more invalid bases.
///
@ -483,7 +483,7 @@ impl<'db> MroErrorKind<'db> {
}
/// Error recording the fact that a class definition was found to have duplicate bases.
#[derive(Debug, PartialEq, Eq, salsa::Update)]
#[derive(Debug, PartialEq, Eq, salsa::Update, get_size2::GetSize)]
pub(super) struct DuplicateBaseError<'db> {
/// The base that is duplicated in the class's bases list.
pub(super) duplicate_base: ClassBase<'db>,

View file

@ -69,7 +69,7 @@ pub(crate) fn infer_narrowing_constraint<'db>(
}
}
#[salsa::tracked(returns(as_ref))]
#[salsa::tracked(returns(as_ref), heap_size=get_size2::GetSize::get_heap_size)]
fn all_narrowing_constraints_for_pattern<'db>(
db: &'db dyn Db,
pattern: PatternPredicate<'db>,
@ -82,6 +82,7 @@ fn all_narrowing_constraints_for_pattern<'db>(
returns(as_ref),
cycle_fn=constraints_for_expression_cycle_recover,
cycle_initial=constraints_for_expression_cycle_initial,
heap_size=get_size2::GetSize::get_heap_size,
)]
fn all_narrowing_constraints_for_expression<'db>(
db: &'db dyn Db,
@ -96,6 +97,7 @@ fn all_narrowing_constraints_for_expression<'db>(
returns(as_ref),
cycle_fn=negative_constraints_for_expression_cycle_recover,
cycle_initial=negative_constraints_for_expression_cycle_initial,
heap_size=get_size2::GetSize::get_heap_size,
)]
fn all_negative_narrowing_constraints_for_expression<'db>(
db: &'db dyn Db,
@ -106,7 +108,7 @@ fn all_negative_narrowing_constraints_for_expression<'db>(
.finish()
}
#[salsa::tracked(returns(as_ref))]
#[salsa::tracked(returns(as_ref), heap_size=get_size2::GetSize::get_heap_size)]
fn all_negative_narrowing_constraints_for_pattern<'db>(
db: &'db dyn Db,
pattern: PatternPredicate<'db>,

View file

@ -106,7 +106,7 @@ enum ParamKind {
KeywordVariadic,
}
#[salsa::tracked]
#[salsa::tracked(heap_size=get_size2::GetSize::get_heap_size)]
fn create_bound_method<'db>(
db: &'db dyn Db,
function: Type<'db>,

View file

@ -70,8 +70,12 @@ pub(super) struct ProtocolInterfaceMembers<'db> {
inner: BTreeMap<Name, ProtocolMemberData<'db>>,
}
impl get_size2::GetSize for ProtocolInterfaceMembers<'_> {}
/// The interface of a protocol: the members of that protocol, and the types of those members.
#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash, salsa::Update, PartialOrd, Ord)]
#[derive(
Copy, Clone, Debug, Eq, PartialEq, Hash, salsa::Update, PartialOrd, Ord, get_size2::GetSize,
)]
pub(super) enum ProtocolInterface<'db> {
Members(ProtocolInterfaceMembers<'db>),
SelfReference,
@ -327,7 +331,7 @@ fn excluded_from_proto_members(member: &str) -> bool {
}
/// Inner Salsa query for [`ProtocolClassLiteral::interface`].
#[salsa::tracked(cycle_fn=proto_interface_cycle_recover, cycle_initial=proto_interface_cycle_initial)]
#[salsa::tracked(cycle_fn=proto_interface_cycle_recover, cycle_initial=proto_interface_cycle_initial, heap_size=get_size2::GetSize::get_heap_size)]
fn cached_protocol_interface<'db>(
db: &'db dyn Db,
class: ClassLiteral<'db>,

View file

@ -24,7 +24,7 @@ use ruff_python_ast::{self as ast, name::Name};
/// The signature of a single callable. If the callable is overloaded, there is a separate
/// [`Signature`] for each overload.
#[derive(Clone, Debug, PartialEq, Eq, Hash, salsa::Update)]
#[derive(Clone, Debug, PartialEq, Eq, Hash, salsa::Update, get_size2::GetSize)]
pub struct CallableSignature<'db> {
/// The signatures of each overload of this callable. Will be empty if the type is not
/// callable.
@ -220,7 +220,7 @@ impl<'a, 'db> IntoIterator for &'a CallableSignature<'db> {
}
/// The signature of one of the overloads of a callable.
#[derive(Clone, Debug, PartialEq, Eq, Hash, salsa::Update)]
#[derive(Clone, Debug, PartialEq, Eq, Hash, salsa::Update, get_size2::GetSize)]
pub struct Signature<'db> {
/// The generic context for this overload, if it is generic.
pub(crate) generic_context: Option<GenericContext<'db>>,
@ -897,7 +897,7 @@ impl<'db> Signature<'db> {
}
}
#[derive(Clone, Debug, PartialEq, Eq, Hash, salsa::Update)]
#[derive(Clone, Debug, PartialEq, Eq, Hash, salsa::Update, get_size2::GetSize)]
pub(crate) struct Parameters<'db> {
// TODO: use SmallVec here once invariance bug is fixed
value: Vec<Parameter<'db>>,
@ -1196,7 +1196,7 @@ impl<'db> std::ops::Index<usize> for Parameters<'db> {
}
}
#[derive(Clone, Debug, PartialEq, Eq, Hash, salsa::Update)]
#[derive(Clone, Debug, PartialEq, Eq, Hash, salsa::Update, get_size2::GetSize)]
pub(crate) struct Parameter<'db> {
/// Annotated type of the parameter.
annotated_type: Option<Type<'db>>,
@ -1454,7 +1454,7 @@ impl<'db> Parameter<'db> {
}
}
#[derive(Clone, Debug, PartialEq, Eq, Hash, salsa::Update)]
#[derive(Clone, Debug, PartialEq, Eq, Hash, salsa::Update, get_size2::GetSize)]
pub(crate) enum ParameterKind<'db> {
/// Positional-only parameter, e.g. `def f(x, /): ...`
PositionalOnly {
@ -1520,7 +1520,7 @@ impl<'db> ParameterKind<'db> {
}
/// Whether a parameter is used as a value or a type form.
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq, get_size2::GetSize)]
pub(crate) enum ParameterForm {
Value,
Type,

View file

@ -24,6 +24,7 @@ use std::str::FromStr;
PartialOrd,
Ord,
strum_macros::EnumString,
get_size2::GetSize,
)]
pub enum SpecialFormType {
/// The symbol `typing.Annotated` (which can also be found as `typing_extensions.Annotated`)

View file

@ -10,7 +10,7 @@ use crate::{Db, FxOrderSet};
use super::{TypeVarBoundOrConstraints, TypeVarKind, TypeVarVariance};
/// A type that represents `type[C]`, i.e. the class object `C` and class objects that are subclasses of `C`.
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, salsa::Update)]
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, salsa::Update, get_size2::GetSize)]
pub struct SubclassOfType<'db> {
// Keep this field private, so that the only way of constructing the struct is through the `from` method.
subclass_of: SubclassOfInner<'db>,
@ -199,7 +199,7 @@ impl<'db> SubclassOfType<'db> {
/// Note that this enum is similar to the [`super::ClassBase`] enum,
/// but does not include the `ClassBase::Protocol` and `ClassBase::Generic` variants
/// (`type[Protocol]` and `type[Generic]` are not valid types).
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, salsa::Update)]
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, salsa::Update, get_size2::GetSize)]
pub(crate) enum SubclassOfInner<'db> {
Class(ClassType<'db>),
Dynamic(DynamicType),

View file

@ -33,6 +33,9 @@ pub struct TupleType<'db> {
pub(crate) tuple: TupleSpec<'db>,
}
// The Salsa heap is tracked separately.
impl get_size2::GetSize for TupleType<'_> {}
impl<'db> Type<'db> {
pub(crate) fn tuple(db: &'db dyn Db, tuple: TupleType<'db>) -> Self {
// If a fixed-length (i.e., mandatory) element of the tuple is `Never`, then it's not

View file

@ -343,7 +343,7 @@ impl<'db, 'ast> Unpacker<'db, 'ast> {
}
}
#[derive(Debug, Default, PartialEq, Eq, salsa::Update)]
#[derive(Debug, Default, PartialEq, Eq, salsa::Update, get_size2::GetSize)]
pub(crate) struct UnpackResult<'db> {
targets: FxHashMap<ScopedExpressionId, Type<'db>>,
diagnostics: TypeCheckDiagnostics,

View file

@ -0,0 +1,15 @@
use std::sync::Arc;
use get_size2::GetSize;
/// By default, `Arc<T>: GetSize` requires `T: 'static` to enable tracking references
/// of the `Arc` and avoid double-counting. This method opts out of that behavior and
/// removes the `'static` requirement.
///
/// This method will just return the heap-size of the inner `T`.
pub(crate) fn untracked_arc_size<T>(arc: &Arc<T>) -> usize
where
T: GetSize,
{
T::get_heap_size(&**arc)
}

View file

@ -1,2 +1,3 @@
pub(crate) mod diagnostics;
pub(crate) mod get_size;
pub(crate) mod subscript;