diff --git a/Cargo.lock b/Cargo.lock index b0e9121a72..ded61d1378 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -169,6 +169,36 @@ dependencies = [ "tempfile", ] +[[package]] +name = "attribute-derive" +version = "0.10.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0053e96dd3bec5b4879c23a138d6ef26f2cb936c9cdc96274ac2b9ed44b5bb54" +dependencies = [ + "attribute-derive-macro", + "derive-where", + "manyhow", + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "attribute-derive-macro" +version = "0.10.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "463b53ad0fd5b460af4b1915fe045ff4d946d025fb6c4dc3337752eaa980f71b" +dependencies = [ + "collection_literals", + "interpolator", + "manyhow", + "proc-macro-utils", + "proc-macro2", + "quote", + "quote-use", + "syn", +] + [[package]] name = "autocfg" version = "1.4.0" @@ -519,6 +549,12 @@ dependencies = [ "regex-lite", ] +[[package]] +name = "collection_literals" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "186dce98367766de751c42c4f03970fc60fc012296e706ccbb9d5df9b6c1e271" + [[package]] name = "colorchoice" version = "1.0.3" @@ -808,6 +844,17 @@ dependencies = [ "parking_lot_core", ] +[[package]] +name = "derive-where" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "510c292c8cf384b1a340b816a9a6cf2599eb8f566a44949024af88418000c50b" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "diff" version = "0.1.13" @@ -1067,6 +1114,29 @@ dependencies = [ "version_check", ] +[[package]] +name = "get-size-derive2" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ea12180b12b82e9b7c01dfe91138208604961bb2bd7e93058d6786e5d770b104" +dependencies = [ + "attribute-derive", + "quote", + "syn", +] + +[[package]] +name = "get-size2" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3a37e4d438f7550dbd4938f1bcde41538653616513678d647665a7332ea3c030" +dependencies = [ + "compact_str", + "get-size-derive2", + "hashbrown 0.15.4", + "smallvec", +] + [[package]] name = "getopts" version = "0.2.21" @@ -1455,6 +1525,12 @@ dependencies = [ "serde_json", ] +[[package]] +name = "interpolator" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "71dd52191aae121e8611f1e8dc3e324dd0dd1dee1e6dd91d10ee07a3cfb4d9d8" + [[package]] name = "intrusive-collections" version = "0.9.7" @@ -1716,9 +1792,9 @@ checksum = "241eaef5fd12c88705a01fc1066c48c4b36e0dd4377dcdc7ec3942cea7a69956" [[package]] name = "lock_api" -version = "0.4.12" +version = "0.4.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "07af8b9cdd281b7915f413fa73f29ebd5d55d0d3f0155584dade1ff18cea1b17" +checksum = "96936507f153605bddfcda068dd804796c84324ed2510809e5b2a624c81da765" dependencies = [ "autocfg", "scopeguard", @@ -1755,6 +1831,29 @@ dependencies = [ "url", ] +[[package]] +name = "manyhow" +version = "0.11.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b33efb3ca6d3b07393750d4030418d594ab1139cee518f0dc88db70fec873587" +dependencies = [ + "manyhow-macros", + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "manyhow-macros" +version = "0.11.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "46fce34d199b78b6e6073abf984c9cf5fd3e9330145a93ee0738a7443e371495" +dependencies = [ + "proc-macro-utils", + "proc-macro2", + "quote", +] + [[package]] name = "markdown" version = "1.0.0" @@ -2315,6 +2414,17 @@ dependencies = [ "toml_edit", ] +[[package]] +name = "proc-macro-utils" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eeaf08a13de400bc215877b5bdc088f241b12eb42f0a548d3390dc1c56bb7071" +dependencies = [ + "proc-macro2", + "quote", + "smallvec", +] + [[package]] name = "proc-macro2" version = "1.0.95" @@ -2391,6 +2501,28 @@ dependencies = [ "proc-macro2", ] +[[package]] +name = "quote-use" +version = "0.8.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9619db1197b497a36178cfc736dc96b271fe918875fbf1344c436a7e93d0321e" +dependencies = [ + "quote", + "quote-use-macros", +] + +[[package]] +name = "quote-use-macros" +version = "0.8.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "82ebfb7faafadc06a7ab141a6f67bcfb24cb8beb158c6fe933f2f035afa99f35" +dependencies = [ + "proc-macro-utils", + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "r-efi" version = "5.2.0" @@ -2680,6 +2812,7 @@ dependencies = [ "dunce", "etcetera", "filetime", + "get-size2", "glob", "ignore", "insta", @@ -2795,6 +2928,7 @@ dependencies = [ name = "ruff_index" version = "0.0.0" dependencies = [ + "get-size2", "ruff_macros", "salsa", "static_assertions", @@ -2907,6 +3041,7 @@ dependencies = [ "aho-corasick", "bitflags 2.9.1", "compact_str", + "get-size2", "is-macro", "itertools 0.14.0", "memchr", @@ -3006,6 +3141,7 @@ dependencies = [ "bitflags 2.9.1", "bstr", "compact_str", + "get-size2", "insta", "memchr", "ruff_annotate_snippets", @@ -3112,6 +3248,7 @@ dependencies = [ name = "ruff_source_file" version = "0.0.0" dependencies = [ + "get-size2", "memchr", "ruff_text_size", "serde", @@ -3121,6 +3258,7 @@ dependencies = [ name = "ruff_text_size" version = "0.0.0" dependencies = [ + "get-size2", "schemars", "serde", "serde_test", @@ -3249,7 +3387,7 @@ checksum = "28d3b2b1366ec20994f1fd18c3c594f05c5dd4bc44d8bb0c1c632c8d6829481f" [[package]] name = "salsa" version = "0.22.0" -source = "git+https://github.com/salsa-rs/salsa.git?rev=09627e450566f894956710a3fd923dc80462ae6d#09627e450566f894956710a3fd923dc80462ae6d" +source = "git+https://github.com/salsa-rs/salsa?rev=0666e2018bc35376b1ac4f98906f2d04d11e5fe4#0666e2018bc35376b1ac4f98906f2d04d11e5fe4" dependencies = [ "boxcar", "compact_str", @@ -3273,12 +3411,12 @@ dependencies = [ [[package]] name = "salsa-macro-rules" version = "0.22.0" -source = "git+https://github.com/salsa-rs/salsa.git?rev=09627e450566f894956710a3fd923dc80462ae6d#09627e450566f894956710a3fd923dc80462ae6d" +source = "git+https://github.com/salsa-rs/salsa?rev=0666e2018bc35376b1ac4f98906f2d04d11e5fe4#0666e2018bc35376b1ac4f98906f2d04d11e5fe4" [[package]] name = "salsa-macros" version = "0.22.0" -source = "git+https://github.com/salsa-rs/salsa.git?rev=09627e450566f894956710a3fd923dc80462ae6d#09627e450566f894956710a3fd923dc80462ae6d" +source = "git+https://github.com/salsa-rs/salsa?rev=0666e2018bc35376b1ac4f98906f2d04d11e5fe4#0666e2018bc35376b1ac4f98906f2d04d11e5fe4" dependencies = [ "proc-macro2", "quote", @@ -3991,6 +4129,7 @@ dependencies = [ "camino", "colored 3.0.0", "crossbeam", + "get-size2", "globset", "insta", "notify", @@ -4030,6 +4169,7 @@ dependencies = [ "countme", "dir-test", "drop_bomb", + "get-size2", "glob", "hashbrown 0.15.4", "indexmap", diff --git a/Cargo.toml b/Cargo.toml index b9de8e5209..ccc6bb3728 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -79,6 +79,12 @@ etcetera = { version = "0.10.0" } fern = { version = "0.7.0" } filetime = { version = "0.2.23" } getrandom = { version = "0.3.1" } +get-size2 = { version = "0.5.0", features = [ + "derive", + "smallvec", + "hashbrown", + "compact-str" +] } glob = { version = "0.3.1" } globset = { version = "0.4.14" } globwalk = { version = "0.9.1" } @@ -131,7 +137,7 @@ regex-automata = { version = "0.4.9" } rustc-hash = { version = "2.0.0" } rustc-stable-hash = { version = "0.1.2" } # When updating salsa, make sure to also update the revision in `fuzz/Cargo.toml` -salsa = { git = "https://github.com/salsa-rs/salsa.git", rev = "09627e450566f894956710a3fd923dc80462ae6d" } +salsa = { git = "https://github.com/salsa-rs/salsa", rev = "0666e2018bc35376b1ac4f98906f2d04d11e5fe4" } schemars = { version = "0.8.16" } seahash = { version = "4.1.0" } serde = { version = "1.0.197", features = ["derive"] } diff --git a/crates/ruff_db/Cargo.toml b/crates/ruff_db/Cargo.toml index 270b35d448..fa73022e93 100644 --- a/crates/ruff_db/Cargo.toml +++ b/crates/ruff_db/Cargo.toml @@ -14,10 +14,10 @@ license = { workspace = true } ruff_annotate_snippets = { workspace = true } ruff_cache = { workspace = true, optional = true } ruff_notebook = { workspace = true } -ruff_python_ast = { workspace = true } +ruff_python_ast = { workspace = true, features = ["get-size"] } ruff_python_parser = { workspace = true } ruff_python_trivia = { workspace = true } -ruff_source_file = { workspace = true } +ruff_source_file = { workspace = true, features = ["get-size"] } ruff_text_size = { workspace = true } anstyle = { workspace = true } @@ -27,6 +27,7 @@ countme = { workspace = true } dashmap = { workspace = true } dunce = { workspace = true } filetime = { workspace = true } +get-size2 = { workspace = true } glob = { workspace = true } ignore = { workspace = true, optional = true } matchit = { workspace = true } diff --git a/crates/ruff_db/src/diagnostic/mod.rs b/crates/ruff_db/src/diagnostic/mod.rs index bb4633a9b2..f4d5d4fb9c 100644 --- a/crates/ruff_db/src/diagnostic/mod.rs +++ b/crates/ruff_db/src/diagnostic/mod.rs @@ -19,7 +19,7 @@ mod stylesheet; /// characteristics in the inputs given to the tool. Typically, but not always, /// a characteristic is a deficiency. An example of a characteristic that is /// _not_ a deficiency is the `reveal_type` diagnostic for our type checker. -#[derive(Debug, Clone, Eq, PartialEq)] +#[derive(Debug, Clone, Eq, PartialEq, get_size2::GetSize)] pub struct Diagnostic { /// The actual diagnostic. /// @@ -270,7 +270,7 @@ impl Diagnostic { } } -#[derive(Debug, Clone, Eq, PartialEq)] +#[derive(Debug, Clone, Eq, PartialEq, get_size2::GetSize)] struct DiagnosticInner { id: DiagnosticId, severity: Severity, @@ -342,7 +342,7 @@ impl Eq for RenderingSortKey<'_> {} /// Currently, the order in which sub-diagnostics are rendered relative to one /// another (for a single parent diagnostic) is the order in which they were /// attached to the diagnostic. -#[derive(Debug, Clone, Eq, PartialEq)] +#[derive(Debug, Clone, Eq, PartialEq, get_size2::GetSize)] pub struct SubDiagnostic { /// Like with `Diagnostic`, we box the `SubDiagnostic` to make it /// pointer-sized. @@ -443,7 +443,7 @@ impl SubDiagnostic { } } -#[derive(Debug, Clone, Eq, PartialEq)] +#[derive(Debug, Clone, Eq, PartialEq, get_size2::GetSize)] struct SubDiagnosticInner { severity: Severity, message: DiagnosticMessage, @@ -471,7 +471,7 @@ struct SubDiagnosticInner { /// /// Messages attached to annotations should also be as brief and specific as /// possible. Long messages could negative impact the quality of rendering. -#[derive(Debug, Clone, Eq, PartialEq)] +#[derive(Debug, Clone, Eq, PartialEq, get_size2::GetSize)] pub struct Annotation { /// The span of this annotation, corresponding to some subsequence of the /// user's input that we want to highlight. @@ -591,7 +591,7 @@ impl Annotation { /// /// These tags are used to provide additional information about the annotation. /// and are passed through to the language server protocol. -#[derive(Debug, Clone, Eq, PartialEq)] +#[derive(Debug, Clone, Eq, PartialEq, get_size2::GetSize)] pub enum DiagnosticTag { /// Unused or unnecessary code. Used for unused parameters, unreachable code, etc. Unnecessary, @@ -605,7 +605,7 @@ pub enum DiagnosticTag { /// be in kebab case, e.g. `no-foo` (all lower case). /// /// Rules use kebab case, e.g. `no-foo`. -#[derive(Debug, Copy, Clone, PartialOrd, Ord, PartialEq, Eq, Hash)] +#[derive(Debug, Copy, Clone, PartialOrd, Ord, PartialEq, Eq, Hash, get_size2::GetSize)] pub struct LintName(&'static str); impl LintName { @@ -645,7 +645,7 @@ impl PartialEq<&str> for LintName { } /// Uniquely identifies the kind of a diagnostic. -#[derive(Debug, Copy, Clone, Eq, PartialEq, PartialOrd, Ord, Hash)] +#[derive(Debug, Copy, Clone, Eq, PartialEq, PartialOrd, Ord, Hash, get_size2::GetSize)] pub enum DiagnosticId { Panic, @@ -800,7 +800,7 @@ impl std::fmt::Display for DiagnosticId { /// /// This enum presents a unified interface to these two types for the sake of creating [`Span`]s and /// emitting diagnostics from both ty and ruff. -#[derive(Debug, Clone, PartialEq, Eq)] +#[derive(Debug, Clone, PartialEq, Eq, get_size2::GetSize)] pub enum UnifiedFile { Ty(File), Ruff(SourceFile), @@ -852,7 +852,7 @@ impl DiagnosticSource { /// It consists of a `File` and an optional range into that file. When the /// range isn't present, it semantically implies that the diagnostic refers to /// the entire file. For example, when the file should be executable but isn't. -#[derive(Debug, Clone, PartialEq, Eq)] +#[derive(Debug, Clone, PartialEq, Eq, get_size2::GetSize)] pub struct Span { file: UnifiedFile, range: Option, @@ -924,7 +924,7 @@ impl From for Span { } } -#[derive(Debug, Clone, Copy, PartialEq, Eq, Ord, PartialOrd)] +#[derive(Debug, Clone, Copy, PartialEq, Eq, Ord, PartialOrd, get_size2::GetSize)] pub enum Severity { Info, Warning, @@ -1087,7 +1087,7 @@ impl std::fmt::Display for ConciseMessage<'_> { /// In most cases, callers shouldn't need to use this. Instead, there is /// a blanket trait implementation for `IntoDiagnosticMessage` for /// anything that implements `std::fmt::Display`. -#[derive(Clone, Debug, Eq, PartialEq)] +#[derive(Clone, Debug, Eq, PartialEq, get_size2::GetSize)] pub struct DiagnosticMessage(Box); impl DiagnosticMessage { diff --git a/crates/ruff_db/src/files.rs b/crates/ruff_db/src/files.rs index cae4b51853..34c86626eb 100644 --- a/crates/ruff_db/src/files.rs +++ b/crates/ruff_db/src/files.rs @@ -308,6 +308,9 @@ pub struct File { count: Count, } +// The Salsa heap is tracked separately. +impl get_size2::GetSize for File {} + impl File { /// Reads the content of the file into a [`String`]. /// diff --git a/crates/ruff_db/src/parsed.rs b/crates/ruff_db/src/parsed.rs index f28d280f7e..dd98114e3a 100644 --- a/crates/ruff_db/src/parsed.rs +++ b/crates/ruff_db/src/parsed.rs @@ -2,6 +2,7 @@ use std::fmt::Formatter; use std::sync::Arc; use arc_swap::ArcSwapOption; +use get_size2::GetSize; use ruff_python_ast::{AnyRootNodeRef, ModModule, NodeIndex}; use ruff_python_parser::{ParseOptions, Parsed, parse_unchecked}; @@ -20,7 +21,7 @@ use crate::source::source_text; /// reflected in the changed AST offsets. /// The other reason is that Ruff's AST doesn't implement `Eq` which Salsa requires /// for determining if a query result is unchanged. -#[salsa::tracked(returns(ref), no_eq)] +#[salsa::tracked(returns(ref), no_eq, heap_size=get_size2::GetSize::get_heap_size)] pub fn parsed_module(db: &dyn Db, file: File) -> ParsedModule { let _span = tracing::trace_span!("parsed_module", ?file).entered(); @@ -44,9 +45,10 @@ pub fn parsed_module_impl(db: &dyn Db, file: File) -> Parsed { /// /// This type manages instances of the module AST. A particular instance of the AST /// is represented with the [`ParsedModuleRef`] type. -#[derive(Clone)] +#[derive(Clone, get_size2::GetSize)] pub struct ParsedModule { file: File, + #[get_size(size_fn = arc_swap_size)] inner: Arc>, } @@ -142,6 +144,18 @@ impl std::ops::Deref for ParsedModuleRef { } } +/// Returns the heap-size of the currently stored `T` in the `ArcSwap`. +fn arc_swap_size(arc_swap: &Arc>) -> usize +where + T: GetSize, +{ + if let Some(value) = &*arc_swap.load() { + T::get_heap_size(value) + } else { + 0 + } +} + mod indexed { use std::sync::Arc; @@ -150,7 +164,7 @@ mod indexed { use ruff_python_parser::Parsed; /// A wrapper around the AST that allows access to AST nodes by index. - #[derive(Debug)] + #[derive(Debug, get_size2::GetSize)] pub struct IndexedModule { index: Box<[AnyRootNodeRef<'static>]>, pub parsed: Parsed, diff --git a/crates/ruff_db/src/source.rs b/crates/ruff_db/src/source.rs index aac59a6060..824c17cae4 100644 --- a/crates/ruff_db/src/source.rs +++ b/crates/ruff_db/src/source.rs @@ -11,7 +11,7 @@ use crate::Db; use crate::files::{File, FilePath}; /// Reads the source text of a python text file (must be valid UTF8) or notebook. -#[salsa::tracked] +#[salsa::tracked(heap_size=get_size2::GetSize::get_heap_size)] pub fn source_text(db: &dyn Db, file: File) -> SourceText { let path = file.path(db); let _span = tracing::trace_span!("source_text", file = %path).entered(); @@ -65,7 +65,7 @@ fn is_notebook(path: &FilePath) -> bool { /// The file containing the source text can either be a text file or a notebook. /// /// Cheap cloneable in `O(1)`. -#[derive(Clone, Eq, PartialEq)] +#[derive(Clone, Eq, PartialEq, get_size2::GetSize)] pub struct SourceText { inner: Arc, } @@ -123,8 +123,9 @@ impl std::fmt::Debug for SourceText { } } -#[derive(Eq, PartialEq)] +#[derive(Eq, PartialEq, get_size2::GetSize)] struct SourceTextInner { + #[get_size(ignore)] count: Count, kind: SourceTextKind, read_error: Option, @@ -136,6 +137,19 @@ enum SourceTextKind { Notebook(Box), } +impl get_size2::GetSize for SourceTextKind { + fn get_heap_size(&self) -> usize { + match self { + SourceTextKind::Text(text) => text.get_heap_size(), + // TODO: The `get-size` derive does not support ignoring enum variants. + // + // Jupyter notebooks are not very relevant for memory profiling, and contain + // arbitrary JSON values that do not implement the `GetSize` trait. + SourceTextKind::Notebook(_) => 0, + } + } +} + impl From for SourceTextKind { fn from(value: String) -> Self { SourceTextKind::Text(value) @@ -148,7 +162,7 @@ impl From for SourceTextKind { } } -#[derive(Debug, thiserror::Error, PartialEq, Eq, Clone)] +#[derive(Debug, thiserror::Error, PartialEq, Eq, Clone, get_size2::GetSize)] pub enum SourceTextError { #[error("Failed to read notebook: {0}`")] FailedToReadNotebook(String), @@ -157,7 +171,7 @@ pub enum SourceTextError { } /// Computes the [`LineIndex`] for `file`. -#[salsa::tracked] +#[salsa::tracked(heap_size=get_size2::GetSize::get_heap_size)] pub fn line_index(db: &dyn Db, file: File) -> LineIndex { let _span = tracing::trace_span!("line_index", ?file).entered(); diff --git a/crates/ruff_db/src/system/path.rs b/crates/ruff_db/src/system/path.rs index 07ea7d0b71..fbba17ebce 100644 --- a/crates/ruff_db/src/system/path.rs +++ b/crates/ruff_db/src/system/path.rs @@ -503,6 +503,12 @@ impl ToOwned for SystemPath { #[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))] pub struct SystemPathBuf(#[cfg_attr(feature = "schemars", schemars(with = "String"))] Utf8PathBuf); +impl get_size2::GetSize for SystemPathBuf { + fn get_heap_size(&self) -> usize { + self.0.capacity() + } +} + impl SystemPathBuf { pub fn new() -> Self { Self(Utf8PathBuf::new()) diff --git a/crates/ruff_db/src/vendored/path.rs b/crates/ruff_db/src/vendored/path.rs index a8cb07a672..f32ce08239 100644 --- a/crates/ruff_db/src/vendored/path.rs +++ b/crates/ruff_db/src/vendored/path.rs @@ -87,6 +87,12 @@ impl ToOwned for VendoredPath { #[derive(Debug, Eq, PartialEq, Clone, Hash)] pub struct VendoredPathBuf(Utf8PathBuf); +impl get_size2::GetSize for VendoredPathBuf { + fn get_heap_size(&self) -> usize { + self.0.capacity() + } +} + impl Default for VendoredPathBuf { fn default() -> Self { Self::new() diff --git a/crates/ruff_index/Cargo.toml b/crates/ruff_index/Cargo.toml index a96fa738f6..df11c268cf 100644 --- a/crates/ruff_index/Cargo.toml +++ b/crates/ruff_index/Cargo.toml @@ -14,6 +14,7 @@ license = { workspace = true } doctest = false [dependencies] +get-size2 = { workspace = true } ruff_macros = { workspace = true } salsa = { workspace = true, optional = true } diff --git a/crates/ruff_index/src/vec.rs b/crates/ruff_index/src/vec.rs index fcbd878ae7..6c96e763ae 100644 --- a/crates/ruff_index/src/vec.rs +++ b/crates/ruff_index/src/vec.rs @@ -6,7 +6,7 @@ use std::marker::PhantomData; use std::ops::{Deref, DerefMut, RangeBounds}; /// An owned sequence of `T` indexed by `I` -#[derive(Clone, PartialEq, Eq, Hash)] +#[derive(Clone, PartialEq, Eq, Hash, get_size2::GetSize)] #[repr(transparent)] pub struct IndexVec { pub raw: Vec, diff --git a/crates/ruff_python_ast/Cargo.toml b/crates/ruff_python_ast/Cargo.toml index 305d85097b..1b049102f6 100644 --- a/crates/ruff_python_ast/Cargo.toml +++ b/crates/ruff_python_ast/Cargo.toml @@ -22,6 +22,7 @@ ruff_text_size = { workspace = true } aho-corasick = { workspace = true } bitflags = { workspace = true } compact_str = { workspace = true } +get-size2 = { workspace = true, optional = true } is-macro = { workspace = true } itertools = { workspace = true } memchr = { workspace = true } @@ -40,6 +41,7 @@ serde = [ "dep:ruff_cache", "compact_str/serde", ] +get-size = ["dep:get-size2"] [lints] workspace = true diff --git a/crates/ruff_python_ast/generate.py b/crates/ruff_python_ast/generate.py index fd62df619e..2b8687b233 100644 --- a/crates/ruff_python_ast/generate.py +++ b/crates/ruff_python_ast/generate.py @@ -316,6 +316,7 @@ def write_owned_enum(out: list[str], ast: Ast) -> None: if group.doc is not None: write_rustdoc(out, group.doc) out.append("#[derive(Clone, Debug, PartialEq)]") + out.append('#[cfg_attr(feature = "get-size", derive(get_size2::GetSize))]') out.append(f"pub enum {group.owned_enum_ty} {{") for node in group.nodes: out.append(f"{node.variant}({node.ty}),") @@ -515,6 +516,7 @@ def write_ref_enum(out: list[str], ast: Ast) -> None: if group.doc is not None: write_rustdoc(out, group.doc) out.append("""#[derive(Clone, Copy, Debug, PartialEq, is_macro::Is)]""") + out.append('#[cfg_attr(feature = "get-size", derive(get_size2::GetSize))]') out.append(f"""pub enum {group.ref_enum_ty}<'a> {{""") for node in group.nodes: if group.add_suffix_to_is_methods: @@ -604,6 +606,7 @@ def write_anynoderef(out: list[str], ast: Ast) -> None: out.append(""" /// A flattened enumeration of all AST nodes. #[derive(Copy, Clone, Debug, is_macro::Is, PartialEq)] + #[cfg_attr(feature = "get-size", derive(get_size2::GetSize))] pub enum AnyNodeRef<'a> { """) for node in ast.all_nodes: @@ -782,6 +785,7 @@ def write_root_anynoderef(out: list[str], ast: Ast) -> None: /// `AnyNodeRef` has top-level `AnyNodeRef::ModModule` and `AnyNodeRef::ModExpression` /// variants. #[derive(Copy, Clone, Debug, PartialEq)] + #[cfg_attr(feature = "get-size", derive(get_size2::GetSize))] pub enum AnyRootNodeRef<'a> { """) for group in ast.groups: @@ -963,6 +967,7 @@ def write_node(out: list[str], ast: Ast) -> None: + "".join(f", {derive}" for derive in node.derives) + ")]" ) + out.append('#[cfg_attr(feature = "get-size", derive(get_size2::GetSize))]') name = node.name out.append(f"pub struct {name} {{") out.append("pub node_index: crate::AtomicNodeIndex,") diff --git a/crates/ruff_python_ast/src/generated.rs b/crates/ruff_python_ast/src/generated.rs index cedf608921..935595705d 100644 --- a/crates/ruff_python_ast/src/generated.rs +++ b/crates/ruff_python_ast/src/generated.rs @@ -6,6 +6,7 @@ use crate::visitor::source_order::SourceOrderVisitor; /// See also [mod](https://docs.python.org/3/library/ast.html#ast.mod) #[derive(Clone, Debug, PartialEq)] +#[cfg_attr(feature = "get-size", derive(get_size2::GetSize))] pub enum Mod { Module(crate::ModModule), Expression(crate::ModExpression), @@ -120,6 +121,7 @@ impl Mod { /// See also [stmt](https://docs.python.org/3/library/ast.html#ast.stmt) #[derive(Clone, Debug, PartialEq)] +#[cfg_attr(feature = "get-size", derive(get_size2::GetSize))] pub enum Stmt { FunctionDef(crate::StmtFunctionDef), ClassDef(crate::StmtClassDef), @@ -1292,6 +1294,7 @@ impl Stmt { /// See also [expr](https://docs.python.org/3/library/ast.html#ast.expr) #[derive(Clone, Debug, PartialEq)] +#[cfg_attr(feature = "get-size", derive(get_size2::GetSize))] pub enum Expr { BoolOp(crate::ExprBoolOp), Named(crate::ExprNamed), @@ -2832,6 +2835,7 @@ impl Expr { /// See also [excepthandler](https://docs.python.org/3/library/ast.html#ast.excepthandler) #[derive(Clone, Debug, PartialEq)] +#[cfg_attr(feature = "get-size", derive(get_size2::GetSize))] pub enum ExceptHandler { ExceptHandler(crate::ExceptHandlerExceptHandler), } @@ -2895,6 +2899,7 @@ impl ExceptHandler { } #[derive(Clone, Debug, PartialEq)] +#[cfg_attr(feature = "get-size", derive(get_size2::GetSize))] pub enum InterpolatedStringElement { Interpolation(crate::InterpolatedElement), Literal(crate::InterpolatedStringLiteralElement), @@ -3009,6 +3014,7 @@ impl InterpolatedStringElement { /// See also [pattern](https://docs.python.org/3/library/ast.html#ast.pattern) #[derive(Clone, Debug, PartialEq)] +#[cfg_attr(feature = "get-size", derive(get_size2::GetSize))] pub enum Pattern { MatchValue(crate::PatternMatchValue), MatchSingleton(crate::PatternMatchSingleton), @@ -3399,6 +3405,7 @@ impl Pattern { /// See also [type_param](https://docs.python.org/3/library/ast.html#ast.type_param) #[derive(Clone, Debug, PartialEq)] +#[cfg_attr(feature = "get-size", derive(get_size2::GetSize))] pub enum TypeParam { TypeVar(crate::TypeParamTypeVar), TypeVarTuple(crate::TypeParamTypeVarTuple), @@ -4838,6 +4845,7 @@ impl TypeParam { /// See also [mod](https://docs.python.org/3/library/ast.html#ast.mod) #[derive(Clone, Copy, Debug, PartialEq, is_macro::Is)] +#[cfg_attr(feature = "get-size", derive(get_size2::GetSize))] pub enum ModRef<'a> { Module(&'a crate::ModModule), Expression(&'a crate::ModExpression), @@ -4884,6 +4892,7 @@ impl crate::HasNodeIndex for ModRef<'_> { /// See also [stmt](https://docs.python.org/3/library/ast.html#ast.stmt) #[derive(Clone, Copy, Debug, PartialEq, is_macro::Is)] +#[cfg_attr(feature = "get-size", derive(get_size2::GetSize))] pub enum StmtRef<'a> { #[is(name = "function_def_stmt")] FunctionDef(&'a crate::StmtFunctionDef), @@ -5185,6 +5194,7 @@ impl crate::HasNodeIndex for StmtRef<'_> { /// See also [expr](https://docs.python.org/3/library/ast.html#ast.expr) #[derive(Clone, Copy, Debug, PartialEq, is_macro::Is)] +#[cfg_attr(feature = "get-size", derive(get_size2::GetSize))] pub enum ExprRef<'a> { #[is(name = "bool_op_expr")] BoolOp(&'a crate::ExprBoolOp), @@ -5574,6 +5584,7 @@ impl crate::HasNodeIndex for ExprRef<'_> { /// See also [excepthandler](https://docs.python.org/3/library/ast.html#ast.excepthandler) #[derive(Clone, Copy, Debug, PartialEq, is_macro::Is)] +#[cfg_attr(feature = "get-size", derive(get_size2::GetSize))] pub enum ExceptHandlerRef<'a> { ExceptHandler(&'a crate::ExceptHandlerExceptHandler), } @@ -5609,6 +5620,7 @@ impl crate::HasNodeIndex for ExceptHandlerRef<'_> { } #[derive(Clone, Copy, Debug, PartialEq, is_macro::Is)] +#[cfg_attr(feature = "get-size", derive(get_size2::GetSize))] pub enum InterpolatedStringElementRef<'a> { Interpolation(&'a crate::InterpolatedElement), Literal(&'a crate::InterpolatedStringLiteralElement), @@ -5657,6 +5669,7 @@ impl crate::HasNodeIndex for InterpolatedStringElementRef<'_> { /// See also [pattern](https://docs.python.org/3/library/ast.html#ast.pattern) #[derive(Clone, Copy, Debug, PartialEq, is_macro::Is)] +#[cfg_attr(feature = "get-size", derive(get_size2::GetSize))] pub enum PatternRef<'a> { MatchValue(&'a crate::PatternMatchValue), MatchSingleton(&'a crate::PatternMatchSingleton), @@ -5763,6 +5776,7 @@ impl crate::HasNodeIndex for PatternRef<'_> { /// See also [type_param](https://docs.python.org/3/library/ast.html#ast.type_param) #[derive(Clone, Copy, Debug, PartialEq, is_macro::Is)] +#[cfg_attr(feature = "get-size", derive(get_size2::GetSize))] pub enum TypeParamRef<'a> { TypeVar(&'a crate::TypeParamTypeVar), TypeVarTuple(&'a crate::TypeParamTypeVarTuple), @@ -5819,6 +5833,7 @@ impl crate::HasNodeIndex for TypeParamRef<'_> { /// A flattened enumeration of all AST nodes. #[derive(Copy, Clone, Debug, is_macro::Is, PartialEq)] +#[cfg_attr(feature = "get-size", derive(get_size2::GetSize))] pub enum AnyNodeRef<'a> { ModModule(&'a crate::ModModule), ModExpression(&'a crate::ModExpression), @@ -7418,6 +7433,7 @@ impl AnyNodeRef<'_> { /// `AnyNodeRef` has top-level `AnyNodeRef::ModModule` and `AnyNodeRef::ModExpression` /// variants. #[derive(Copy, Clone, Debug, PartialEq)] +#[cfg_attr(feature = "get-size", derive(get_size2::GetSize))] pub enum AnyRootNodeRef<'a> { Mod(&'a Mod), Stmt(&'a Stmt), @@ -8935,6 +8951,7 @@ impl AnyNodeRef<'_> { /// See also [Module](https://docs.python.org/3/library/ast.html#ast.Module) #[derive(Clone, Debug, PartialEq)] +#[cfg_attr(feature = "get-size", derive(get_size2::GetSize))] pub struct ModModule { pub node_index: crate::AtomicNodeIndex, pub range: ruff_text_size::TextRange, @@ -8943,6 +8960,7 @@ pub struct ModModule { /// See also [Module](https://docs.python.org/3/library/ast.html#ast.Module) #[derive(Clone, Debug, PartialEq)] +#[cfg_attr(feature = "get-size", derive(get_size2::GetSize))] pub struct ModExpression { pub node_index: crate::AtomicNodeIndex, pub range: ruff_text_size::TextRange, @@ -8954,6 +8972,7 @@ pub struct ModExpression { /// /// This type differs from the original Python AST, as it collapses the synchronous and asynchronous variants into a single type. #[derive(Clone, Debug, PartialEq)] +#[cfg_attr(feature = "get-size", derive(get_size2::GetSize))] pub struct StmtFunctionDef { pub node_index: crate::AtomicNodeIndex, pub range: ruff_text_size::TextRange, @@ -8968,6 +8987,7 @@ pub struct StmtFunctionDef { /// See also [ClassDef](https://docs.python.org/3/library/ast.html#ast.ClassDef) #[derive(Clone, Debug, PartialEq)] +#[cfg_attr(feature = "get-size", derive(get_size2::GetSize))] pub struct StmtClassDef { pub node_index: crate::AtomicNodeIndex, pub range: ruff_text_size::TextRange, @@ -8980,6 +9000,7 @@ pub struct StmtClassDef { /// See also [Return](https://docs.python.org/3/library/ast.html#ast.Return) #[derive(Clone, Debug, PartialEq)] +#[cfg_attr(feature = "get-size", derive(get_size2::GetSize))] pub struct StmtReturn { pub node_index: crate::AtomicNodeIndex, pub range: ruff_text_size::TextRange, @@ -8988,6 +9009,7 @@ pub struct StmtReturn { /// See also [Delete](https://docs.python.org/3/library/ast.html#ast.Delete) #[derive(Clone, Debug, PartialEq)] +#[cfg_attr(feature = "get-size", derive(get_size2::GetSize))] pub struct StmtDelete { pub node_index: crate::AtomicNodeIndex, pub range: ruff_text_size::TextRange, @@ -8996,6 +9018,7 @@ pub struct StmtDelete { /// See also [TypeAlias](https://docs.python.org/3/library/ast.html#ast.TypeAlias) #[derive(Clone, Debug, PartialEq)] +#[cfg_attr(feature = "get-size", derive(get_size2::GetSize))] pub struct StmtTypeAlias { pub node_index: crate::AtomicNodeIndex, pub range: ruff_text_size::TextRange, @@ -9006,6 +9029,7 @@ pub struct StmtTypeAlias { /// See also [Assign](https://docs.python.org/3/library/ast.html#ast.Assign) #[derive(Clone, Debug, PartialEq)] +#[cfg_attr(feature = "get-size", derive(get_size2::GetSize))] pub struct StmtAssign { pub node_index: crate::AtomicNodeIndex, pub range: ruff_text_size::TextRange, @@ -9015,6 +9039,7 @@ pub struct StmtAssign { /// See also [AugAssign](https://docs.python.org/3/library/ast.html#ast.AugAssign) #[derive(Clone, Debug, PartialEq)] +#[cfg_attr(feature = "get-size", derive(get_size2::GetSize))] pub struct StmtAugAssign { pub node_index: crate::AtomicNodeIndex, pub range: ruff_text_size::TextRange, @@ -9025,6 +9050,7 @@ pub struct StmtAugAssign { /// See also [AnnAssign](https://docs.python.org/3/library/ast.html#ast.AnnAssign) #[derive(Clone, Debug, PartialEq)] +#[cfg_attr(feature = "get-size", derive(get_size2::GetSize))] pub struct StmtAnnAssign { pub node_index: crate::AtomicNodeIndex, pub range: ruff_text_size::TextRange, @@ -9039,6 +9065,7 @@ pub struct StmtAnnAssign { /// /// This type differs from the original Python AST, as it collapses the synchronous and asynchronous variants into a single type. #[derive(Clone, Debug, PartialEq)] +#[cfg_attr(feature = "get-size", derive(get_size2::GetSize))] pub struct StmtFor { pub node_index: crate::AtomicNodeIndex, pub range: ruff_text_size::TextRange, @@ -9052,6 +9079,7 @@ pub struct StmtFor { /// See also [While](https://docs.python.org/3/library/ast.html#ast.While) /// and [AsyncWhile](https://docs.python.org/3/library/ast.html#ast.AsyncWhile). #[derive(Clone, Debug, PartialEq)] +#[cfg_attr(feature = "get-size", derive(get_size2::GetSize))] pub struct StmtWhile { pub node_index: crate::AtomicNodeIndex, pub range: ruff_text_size::TextRange, @@ -9062,6 +9090,7 @@ pub struct StmtWhile { /// See also [If](https://docs.python.org/3/library/ast.html#ast.If) #[derive(Clone, Debug, PartialEq)] +#[cfg_attr(feature = "get-size", derive(get_size2::GetSize))] pub struct StmtIf { pub node_index: crate::AtomicNodeIndex, pub range: ruff_text_size::TextRange, @@ -9075,6 +9104,7 @@ pub struct StmtIf { /// /// This type differs from the original Python AST, as it collapses the synchronous and asynchronous variants into a single type. #[derive(Clone, Debug, PartialEq)] +#[cfg_attr(feature = "get-size", derive(get_size2::GetSize))] pub struct StmtWith { pub node_index: crate::AtomicNodeIndex, pub range: ruff_text_size::TextRange, @@ -9085,6 +9115,7 @@ pub struct StmtWith { /// See also [Match](https://docs.python.org/3/library/ast.html#ast.Match) #[derive(Clone, Debug, PartialEq)] +#[cfg_attr(feature = "get-size", derive(get_size2::GetSize))] pub struct StmtMatch { pub node_index: crate::AtomicNodeIndex, pub range: ruff_text_size::TextRange, @@ -9094,6 +9125,7 @@ pub struct StmtMatch { /// See also [Raise](https://docs.python.org/3/library/ast.html#ast.Raise) #[derive(Clone, Debug, PartialEq)] +#[cfg_attr(feature = "get-size", derive(get_size2::GetSize))] pub struct StmtRaise { pub node_index: crate::AtomicNodeIndex, pub range: ruff_text_size::TextRange, @@ -9104,6 +9136,7 @@ pub struct StmtRaise { /// See also [Try](https://docs.python.org/3/library/ast.html#ast.Try) /// and [TryStar](https://docs.python.org/3/library/ast.html#ast.TryStar) #[derive(Clone, Debug, PartialEq)] +#[cfg_attr(feature = "get-size", derive(get_size2::GetSize))] pub struct StmtTry { pub node_index: crate::AtomicNodeIndex, pub range: ruff_text_size::TextRange, @@ -9116,6 +9149,7 @@ pub struct StmtTry { /// See also [Assert](https://docs.python.org/3/library/ast.html#ast.Assert) #[derive(Clone, Debug, PartialEq)] +#[cfg_attr(feature = "get-size", derive(get_size2::GetSize))] pub struct StmtAssert { pub node_index: crate::AtomicNodeIndex, pub range: ruff_text_size::TextRange, @@ -9125,6 +9159,7 @@ pub struct StmtAssert { /// See also [Import](https://docs.python.org/3/library/ast.html#ast.Import) #[derive(Clone, Debug, PartialEq)] +#[cfg_attr(feature = "get-size", derive(get_size2::GetSize))] pub struct StmtImport { pub node_index: crate::AtomicNodeIndex, pub range: ruff_text_size::TextRange, @@ -9133,6 +9168,7 @@ pub struct StmtImport { /// See also [ImportFrom](https://docs.python.org/3/library/ast.html#ast.ImportFrom) #[derive(Clone, Debug, PartialEq)] +#[cfg_attr(feature = "get-size", derive(get_size2::GetSize))] pub struct StmtImportFrom { pub node_index: crate::AtomicNodeIndex, pub range: ruff_text_size::TextRange, @@ -9143,6 +9179,7 @@ pub struct StmtImportFrom { /// See also [Global](https://docs.python.org/3/library/ast.html#ast.Global) #[derive(Clone, Debug, PartialEq)] +#[cfg_attr(feature = "get-size", derive(get_size2::GetSize))] pub struct StmtGlobal { pub node_index: crate::AtomicNodeIndex, pub range: ruff_text_size::TextRange, @@ -9151,6 +9188,7 @@ pub struct StmtGlobal { /// See also [Nonlocal](https://docs.python.org/3/library/ast.html#ast.Nonlocal) #[derive(Clone, Debug, PartialEq)] +#[cfg_attr(feature = "get-size", derive(get_size2::GetSize))] pub struct StmtNonlocal { pub node_index: crate::AtomicNodeIndex, pub range: ruff_text_size::TextRange, @@ -9159,6 +9197,7 @@ pub struct StmtNonlocal { /// See also [Expr](https://docs.python.org/3/library/ast.html#ast.Expr) #[derive(Clone, Debug, PartialEq)] +#[cfg_attr(feature = "get-size", derive(get_size2::GetSize))] pub struct StmtExpr { pub node_index: crate::AtomicNodeIndex, pub range: ruff_text_size::TextRange, @@ -9167,6 +9206,7 @@ pub struct StmtExpr { /// See also [Pass](https://docs.python.org/3/library/ast.html#ast.Pass) #[derive(Clone, Debug, PartialEq)] +#[cfg_attr(feature = "get-size", derive(get_size2::GetSize))] pub struct StmtPass { pub node_index: crate::AtomicNodeIndex, pub range: ruff_text_size::TextRange, @@ -9174,6 +9214,7 @@ pub struct StmtPass { /// See also [Break](https://docs.python.org/3/library/ast.html#ast.Break) #[derive(Clone, Debug, PartialEq)] +#[cfg_attr(feature = "get-size", derive(get_size2::GetSize))] pub struct StmtBreak { pub node_index: crate::AtomicNodeIndex, pub range: ruff_text_size::TextRange, @@ -9181,6 +9222,7 @@ pub struct StmtBreak { /// See also [Continue](https://docs.python.org/3/library/ast.html#ast.Continue) #[derive(Clone, Debug, PartialEq)] +#[cfg_attr(feature = "get-size", derive(get_size2::GetSize))] pub struct StmtContinue { pub node_index: crate::AtomicNodeIndex, pub range: ruff_text_size::TextRange, @@ -9241,6 +9283,7 @@ pub struct StmtContinue { /// [Escape kind]: crate::IpyEscapeKind /// #[derive(Clone, Debug, PartialEq)] +#[cfg_attr(feature = "get-size", derive(get_size2::GetSize))] pub struct StmtIpyEscapeCommand { pub node_index: crate::AtomicNodeIndex, pub range: ruff_text_size::TextRange, @@ -9250,6 +9293,7 @@ pub struct StmtIpyEscapeCommand { /// See also [BoolOp](https://docs.python.org/3/library/ast.html#ast.BoolOp) #[derive(Clone, Debug, PartialEq)] +#[cfg_attr(feature = "get-size", derive(get_size2::GetSize))] pub struct ExprBoolOp { pub node_index: crate::AtomicNodeIndex, pub range: ruff_text_size::TextRange, @@ -9259,6 +9303,7 @@ pub struct ExprBoolOp { /// See also [NamedExpr](https://docs.python.org/3/library/ast.html#ast.NamedExpr) #[derive(Clone, Debug, PartialEq)] +#[cfg_attr(feature = "get-size", derive(get_size2::GetSize))] pub struct ExprNamed { pub node_index: crate::AtomicNodeIndex, pub range: ruff_text_size::TextRange, @@ -9268,6 +9313,7 @@ pub struct ExprNamed { /// See also [BinOp](https://docs.python.org/3/library/ast.html#ast.BinOp) #[derive(Clone, Debug, PartialEq)] +#[cfg_attr(feature = "get-size", derive(get_size2::GetSize))] pub struct ExprBinOp { pub node_index: crate::AtomicNodeIndex, pub range: ruff_text_size::TextRange, @@ -9278,6 +9324,7 @@ pub struct ExprBinOp { /// See also [UnaryOp](https://docs.python.org/3/library/ast.html#ast.UnaryOp) #[derive(Clone, Debug, PartialEq)] +#[cfg_attr(feature = "get-size", derive(get_size2::GetSize))] pub struct ExprUnaryOp { pub node_index: crate::AtomicNodeIndex, pub range: ruff_text_size::TextRange, @@ -9287,6 +9334,7 @@ pub struct ExprUnaryOp { /// See also [Lambda](https://docs.python.org/3/library/ast.html#ast.Lambda) #[derive(Clone, Debug, PartialEq)] +#[cfg_attr(feature = "get-size", derive(get_size2::GetSize))] pub struct ExprLambda { pub node_index: crate::AtomicNodeIndex, pub range: ruff_text_size::TextRange, @@ -9296,6 +9344,7 @@ pub struct ExprLambda { /// See also [IfExp](https://docs.python.org/3/library/ast.html#ast.IfExp) #[derive(Clone, Debug, PartialEq)] +#[cfg_attr(feature = "get-size", derive(get_size2::GetSize))] pub struct ExprIf { pub node_index: crate::AtomicNodeIndex, pub range: ruff_text_size::TextRange, @@ -9306,6 +9355,7 @@ pub struct ExprIf { /// See also [Dict](https://docs.python.org/3/library/ast.html#ast.Dict) #[derive(Clone, Debug, PartialEq)] +#[cfg_attr(feature = "get-size", derive(get_size2::GetSize))] pub struct ExprDict { pub node_index: crate::AtomicNodeIndex, pub range: ruff_text_size::TextRange, @@ -9314,6 +9364,7 @@ pub struct ExprDict { /// See also [Set](https://docs.python.org/3/library/ast.html#ast.Set) #[derive(Clone, Debug, PartialEq)] +#[cfg_attr(feature = "get-size", derive(get_size2::GetSize))] pub struct ExprSet { pub node_index: crate::AtomicNodeIndex, pub range: ruff_text_size::TextRange, @@ -9322,6 +9373,7 @@ pub struct ExprSet { /// See also [ListComp](https://docs.python.org/3/library/ast.html#ast.ListComp) #[derive(Clone, Debug, PartialEq)] +#[cfg_attr(feature = "get-size", derive(get_size2::GetSize))] pub struct ExprListComp { pub node_index: crate::AtomicNodeIndex, pub range: ruff_text_size::TextRange, @@ -9331,6 +9383,7 @@ pub struct ExprListComp { /// See also [SetComp](https://docs.python.org/3/library/ast.html#ast.SetComp) #[derive(Clone, Debug, PartialEq)] +#[cfg_attr(feature = "get-size", derive(get_size2::GetSize))] pub struct ExprSetComp { pub node_index: crate::AtomicNodeIndex, pub range: ruff_text_size::TextRange, @@ -9340,6 +9393,7 @@ pub struct ExprSetComp { /// See also [DictComp](https://docs.python.org/3/library/ast.html#ast.DictComp) #[derive(Clone, Debug, PartialEq)] +#[cfg_attr(feature = "get-size", derive(get_size2::GetSize))] pub struct ExprDictComp { pub node_index: crate::AtomicNodeIndex, pub range: ruff_text_size::TextRange, @@ -9350,6 +9404,7 @@ pub struct ExprDictComp { /// See also [GeneratorExp](https://docs.python.org/3/library/ast.html#ast.GeneratorExp) #[derive(Clone, Debug, PartialEq)] +#[cfg_attr(feature = "get-size", derive(get_size2::GetSize))] pub struct ExprGenerator { pub node_index: crate::AtomicNodeIndex, pub range: ruff_text_size::TextRange, @@ -9360,6 +9415,7 @@ pub struct ExprGenerator { /// See also [Await](https://docs.python.org/3/library/ast.html#ast.Await) #[derive(Clone, Debug, PartialEq)] +#[cfg_attr(feature = "get-size", derive(get_size2::GetSize))] pub struct ExprAwait { pub node_index: crate::AtomicNodeIndex, pub range: ruff_text_size::TextRange, @@ -9368,6 +9424,7 @@ pub struct ExprAwait { /// See also [Yield](https://docs.python.org/3/library/ast.html#ast.Yield) #[derive(Clone, Debug, PartialEq)] +#[cfg_attr(feature = "get-size", derive(get_size2::GetSize))] pub struct ExprYield { pub node_index: crate::AtomicNodeIndex, pub range: ruff_text_size::TextRange, @@ -9376,6 +9433,7 @@ pub struct ExprYield { /// See also [YieldFrom](https://docs.python.org/3/library/ast.html#ast.YieldFrom) #[derive(Clone, Debug, PartialEq)] +#[cfg_attr(feature = "get-size", derive(get_size2::GetSize))] pub struct ExprYieldFrom { pub node_index: crate::AtomicNodeIndex, pub range: ruff_text_size::TextRange, @@ -9384,6 +9442,7 @@ pub struct ExprYieldFrom { /// See also [Compare](https://docs.python.org/3/library/ast.html#ast.Compare) #[derive(Clone, Debug, PartialEq)] +#[cfg_attr(feature = "get-size", derive(get_size2::GetSize))] pub struct ExprCompare { pub node_index: crate::AtomicNodeIndex, pub range: ruff_text_size::TextRange, @@ -9394,6 +9453,7 @@ pub struct ExprCompare { /// See also [Call](https://docs.python.org/3/library/ast.html#ast.Call) #[derive(Clone, Debug, PartialEq)] +#[cfg_attr(feature = "get-size", derive(get_size2::GetSize))] pub struct ExprCall { pub node_index: crate::AtomicNodeIndex, pub range: ruff_text_size::TextRange, @@ -9410,6 +9470,7 @@ pub struct ExprCall { /// /// See also [JoinedStr](https://docs.python.org/3/library/ast.html#ast.JoinedStr) #[derive(Clone, Debug, PartialEq)] +#[cfg_attr(feature = "get-size", derive(get_size2::GetSize))] pub struct ExprFString { pub node_index: crate::AtomicNodeIndex, pub range: ruff_text_size::TextRange, @@ -9425,6 +9486,7 @@ pub struct ExprFString { /// /// See also [TemplateStr](https://docs.python.org/3/library/ast.html#ast.TemplateStr) #[derive(Clone, Debug, PartialEq)] +#[cfg_attr(feature = "get-size", derive(get_size2::GetSize))] pub struct ExprTString { pub node_index: crate::AtomicNodeIndex, pub range: ruff_text_size::TextRange, @@ -9434,6 +9496,7 @@ pub struct ExprTString { /// An AST node that represents either a single-part string literal /// or an implicitly concatenated string literal. #[derive(Clone, Debug, PartialEq)] +#[cfg_attr(feature = "get-size", derive(get_size2::GetSize))] pub struct ExprStringLiteral { pub node_index: crate::AtomicNodeIndex, pub range: ruff_text_size::TextRange, @@ -9443,6 +9506,7 @@ pub struct ExprStringLiteral { /// An AST node that represents either a single-part bytestring literal /// or an implicitly concatenated bytestring literal. #[derive(Clone, Debug, PartialEq)] +#[cfg_attr(feature = "get-size", derive(get_size2::GetSize))] pub struct ExprBytesLiteral { pub node_index: crate::AtomicNodeIndex, pub range: ruff_text_size::TextRange, @@ -9450,6 +9514,7 @@ pub struct ExprBytesLiteral { } #[derive(Clone, Debug, PartialEq)] +#[cfg_attr(feature = "get-size", derive(get_size2::GetSize))] pub struct ExprNumberLiteral { pub node_index: crate::AtomicNodeIndex, pub range: ruff_text_size::TextRange, @@ -9457,6 +9522,7 @@ pub struct ExprNumberLiteral { } #[derive(Clone, Debug, PartialEq, Default)] +#[cfg_attr(feature = "get-size", derive(get_size2::GetSize))] pub struct ExprBooleanLiteral { pub node_index: crate::AtomicNodeIndex, pub range: ruff_text_size::TextRange, @@ -9464,12 +9530,14 @@ pub struct ExprBooleanLiteral { } #[derive(Clone, Debug, PartialEq, Default)] +#[cfg_attr(feature = "get-size", derive(get_size2::GetSize))] pub struct ExprNoneLiteral { pub node_index: crate::AtomicNodeIndex, pub range: ruff_text_size::TextRange, } #[derive(Clone, Debug, PartialEq, Default)] +#[cfg_attr(feature = "get-size", derive(get_size2::GetSize))] pub struct ExprEllipsisLiteral { pub node_index: crate::AtomicNodeIndex, pub range: ruff_text_size::TextRange, @@ -9477,6 +9545,7 @@ pub struct ExprEllipsisLiteral { /// See also [Attribute](https://docs.python.org/3/library/ast.html#ast.Attribute) #[derive(Clone, Debug, PartialEq)] +#[cfg_attr(feature = "get-size", derive(get_size2::GetSize))] pub struct ExprAttribute { pub node_index: crate::AtomicNodeIndex, pub range: ruff_text_size::TextRange, @@ -9487,6 +9556,7 @@ pub struct ExprAttribute { /// See also [Subscript](https://docs.python.org/3/library/ast.html#ast.Subscript) #[derive(Clone, Debug, PartialEq)] +#[cfg_attr(feature = "get-size", derive(get_size2::GetSize))] pub struct ExprSubscript { pub node_index: crate::AtomicNodeIndex, pub range: ruff_text_size::TextRange, @@ -9497,6 +9567,7 @@ pub struct ExprSubscript { /// See also [Starred](https://docs.python.org/3/library/ast.html#ast.Starred) #[derive(Clone, Debug, PartialEq)] +#[cfg_attr(feature = "get-size", derive(get_size2::GetSize))] pub struct ExprStarred { pub node_index: crate::AtomicNodeIndex, pub range: ruff_text_size::TextRange, @@ -9506,6 +9577,7 @@ pub struct ExprStarred { /// See also [Name](https://docs.python.org/3/library/ast.html#ast.Name) #[derive(Clone, Debug, PartialEq)] +#[cfg_attr(feature = "get-size", derive(get_size2::GetSize))] pub struct ExprName { pub node_index: crate::AtomicNodeIndex, pub range: ruff_text_size::TextRange, @@ -9515,6 +9587,7 @@ pub struct ExprName { /// See also [List](https://docs.python.org/3/library/ast.html#ast.List) #[derive(Clone, Debug, PartialEq)] +#[cfg_attr(feature = "get-size", derive(get_size2::GetSize))] pub struct ExprList { pub node_index: crate::AtomicNodeIndex, pub range: ruff_text_size::TextRange, @@ -9524,6 +9597,7 @@ pub struct ExprList { /// See also [Tuple](https://docs.python.org/3/library/ast.html#ast.Tuple) #[derive(Clone, Debug, PartialEq)] +#[cfg_attr(feature = "get-size", derive(get_size2::GetSize))] pub struct ExprTuple { pub node_index: crate::AtomicNodeIndex, pub range: ruff_text_size::TextRange, @@ -9534,6 +9608,7 @@ pub struct ExprTuple { /// See also [Slice](https://docs.python.org/3/library/ast.html#ast.Slice) #[derive(Clone, Debug, PartialEq)] +#[cfg_attr(feature = "get-size", derive(get_size2::GetSize))] pub struct ExprSlice { pub node_index: crate::AtomicNodeIndex, pub range: ruff_text_size::TextRange, @@ -9554,6 +9629,7 @@ pub struct ExprSlice { /// For more information related to terminology and syntax of escape commands, /// see [`StmtIpyEscapeCommand`]. #[derive(Clone, Debug, PartialEq)] +#[cfg_attr(feature = "get-size", derive(get_size2::GetSize))] pub struct ExprIpyEscapeCommand { pub node_index: crate::AtomicNodeIndex, pub range: ruff_text_size::TextRange, diff --git a/crates/ruff_python_ast/src/int.rs b/crates/ruff_python_ast/src/int.rs index 4d918f5574..eacfd8b54a 100644 --- a/crates/ruff_python_ast/src/int.rs +++ b/crates/ruff_python_ast/src/int.rs @@ -3,6 +3,7 @@ use std::str::FromStr; /// A Python integer literal. Represents both small (fits in an `i64`) and large integers. #[derive(Clone, PartialEq, Eq, Hash)] +#[cfg_attr(feature = "get-size", derive(get_size2::GetSize))] pub struct Int(Number); impl FromStr for Int { @@ -216,6 +217,7 @@ impl From for Int { } #[derive(Debug, Clone, PartialEq, Eq, Hash)] +#[cfg_attr(feature = "get-size", derive(get_size2::GetSize))] enum Number { /// A "small" number that can be represented as an `u64`. Small(u64), diff --git a/crates/ruff_python_ast/src/name.rs b/crates/ruff_python_ast/src/name.rs index 725576a249..598257529b 100644 --- a/crates/ruff_python_ast/src/name.rs +++ b/crates/ruff_python_ast/src/name.rs @@ -10,6 +10,7 @@ use crate::generated::ExprName; #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] #[cfg_attr(feature = "cache", derive(ruff_macros::CacheKey))] #[cfg_attr(feature = "salsa", derive(salsa::Update))] +#[cfg_attr(feature = "get-size", derive(get_size2::GetSize))] pub struct Name(compact_str::CompactString); impl Name { diff --git a/crates/ruff_python_ast/src/node_index.rs b/crates/ruff_python_ast/src/node_index.rs index d7d4e8614c..794a332b4e 100644 --- a/crates/ruff_python_ast/src/node_index.rs +++ b/crates/ruff_python_ast/src/node_index.rs @@ -19,7 +19,7 @@ where /// /// This type is interiorly mutable to allow assigning node indices /// on-demand after parsing. -#[derive(Default)] +#[derive(Default, get_size2::GetSize)] pub struct AtomicNodeIndex(AtomicU32); impl AtomicNodeIndex { @@ -41,6 +41,7 @@ impl AtomicNodeIndex { /// A unique index for a node within an AST. #[derive(PartialEq, Eq, Debug, PartialOrd, Ord, Clone, Copy, Hash)] +#[cfg_attr(feature = "get-size", derive(get_size2::GetSize))] pub struct NodeIndex(u32); impl NodeIndex { diff --git a/crates/ruff_python_ast/src/nodes.rs b/crates/ruff_python_ast/src/nodes.rs index 6217b27720..a3ad37faed 100644 --- a/crates/ruff_python_ast/src/nodes.rs +++ b/crates/ruff_python_ast/src/nodes.rs @@ -47,6 +47,7 @@ impl StmtClassDef { } #[derive(Clone, Debug, PartialEq)] +#[cfg_attr(feature = "get-size", derive(get_size2::GetSize))] pub struct ElifElseClause { pub range: TextRange, pub node_index: AtomicNodeIndex, @@ -133,6 +134,7 @@ impl ExprRef<'_> { /// /// [1]: https://docs.python.org/3/reference/expressions.html#displays-for-lists-sets-and-dictionaries #[derive(Debug, Clone, PartialEq)] +#[cfg_attr(feature = "get-size", derive(get_size2::GetSize))] pub struct DictItem { pub key: Option, pub value: Expr, @@ -316,6 +318,7 @@ impl<'a> IntoIterator for &'a ExprSet { } #[derive(Clone, Debug, PartialEq)] +#[cfg_attr(feature = "get-size", derive(get_size2::GetSize))] pub struct InterpolatedStringFormatSpec { pub range: TextRange, pub node_index: AtomicNodeIndex, @@ -324,6 +327,7 @@ pub struct InterpolatedStringFormatSpec { /// See also [FormattedValue](https://docs.python.org/3/library/ast.html#ast.FormattedValue) #[derive(Clone, Debug, PartialEq)] +#[cfg_attr(feature = "get-size", derive(get_size2::GetSize))] pub struct InterpolatedElement { pub range: TextRange, pub node_index: AtomicNodeIndex, @@ -335,6 +339,7 @@ pub struct InterpolatedElement { /// An `FStringLiteralElement` with an empty `value` is an invalid f-string element. #[derive(Clone, Debug, PartialEq)] +#[cfg_attr(feature = "get-size", derive(get_size2::GetSize))] pub struct InterpolatedStringLiteralElement { pub range: TextRange, pub node_index: AtomicNodeIndex, @@ -357,6 +362,7 @@ impl Deref for InterpolatedStringLiteralElement { /// Transforms a value prior to formatting it. #[derive(Copy, Clone, Debug, Hash, PartialEq, Eq, is_macro::Is)] +#[cfg_attr(feature = "get-size", derive(get_size2::GetSize))] #[repr(i8)] #[expect(clippy::cast_possible_wrap)] pub enum ConversionFlag { @@ -383,6 +389,7 @@ impl ConversionFlag { } #[derive(Clone, Debug, PartialEq, Eq, Hash)] +#[cfg_attr(feature = "get-size", derive(get_size2::GetSize))] pub struct DebugText { /// The text between the `{` and the expression node. pub leading: String, @@ -403,6 +410,7 @@ impl ExprFString { /// The value representing an [`ExprFString`]. #[derive(Clone, Debug, PartialEq)] +#[cfg_attr(feature = "get-size", derive(get_size2::GetSize))] pub struct FStringValue { inner: FStringValueInner, } @@ -539,6 +547,7 @@ impl<'a> IntoIterator for &'a mut FStringValue { /// An internal representation of [`FStringValue`]. #[derive(Clone, Debug, PartialEq)] +#[cfg_attr(feature = "get-size", derive(get_size2::GetSize))] enum FStringValueInner { /// A single f-string i.e., `f"foo"`. /// @@ -552,6 +561,7 @@ enum FStringValueInner { /// An f-string part which is either a string literal or an f-string. #[derive(Clone, Debug, PartialEq, is_macro::Is)] +#[cfg_attr(feature = "get-size", derive(get_size2::GetSize))] pub enum FStringPart { Literal(StringLiteral), FString(FString), @@ -595,6 +605,7 @@ impl ExprTString { /// The value representing an [`ExprTString`]. #[derive(Clone, Debug, PartialEq)] +#[cfg_attr(feature = "get-size", derive(get_size2::GetSize))] pub struct TStringValue { inner: TStringValueInner, } @@ -717,6 +728,7 @@ impl<'a> IntoIterator for &'a mut TStringValue { /// An internal representation of [`TStringValue`]. #[derive(Clone, Debug, PartialEq)] +#[cfg_attr(feature = "get-size", derive(get_size2::GetSize))] enum TStringValueInner { /// A single t-string i.e., `t"foo"`. /// @@ -731,6 +743,7 @@ enum TStringValueInner { /// An t-string part which is either a string literal, an f-string, /// or a t-string. #[derive(Clone, Debug, PartialEq, is_macro::Is)] +#[cfg_attr(feature = "get-size", derive(get_size2::GetSize))] pub enum TStringPart { Literal(StringLiteral), FString(FString), @@ -862,6 +875,8 @@ bitflags! { } } +impl get_size2::GetSize for InterpolatedStringFlagsInner {} + /// Flags that can be queried to obtain information /// regarding the prefixes and quotes used for an f-string. /// @@ -879,6 +894,7 @@ bitflags! { /// will properly handle nested f-strings. For usage that doesn't fit into one of these categories, /// the public constructor [`FStringFlags::empty`] can be used. #[derive(Copy, Clone, Eq, PartialEq, Hash)] +#[cfg_attr(feature = "get-size", derive(get_size2::GetSize))] pub struct FStringFlags(InterpolatedStringFlagsInner); impl FStringFlags { @@ -975,6 +991,7 @@ impl FStringFlags { /// will properly handle nested t-strings. For usage that doesn't fit into one of these categories, /// the public constructor [`TStringFlags::empty`] can be used. #[derive(Copy, Clone, Eq, PartialEq, Hash)] +#[cfg_attr(feature = "get-size", derive(get_size2::GetSize))] pub struct TStringFlags(InterpolatedStringFlagsInner); impl TStringFlags { @@ -1129,6 +1146,7 @@ impl fmt::Debug for TStringFlags { /// An AST node that represents a single f-string which is part of an [`ExprFString`]. #[derive(Clone, Debug, PartialEq)] +#[cfg_attr(feature = "get-size", derive(get_size2::GetSize))] pub struct FString { pub range: TextRange, pub node_index: AtomicNodeIndex, @@ -1149,6 +1167,7 @@ impl From for Expr { /// A newtype wrapper around a list of [`InterpolatedStringElement`]. #[derive(Clone, Default, PartialEq)] +#[cfg_attr(feature = "get-size", derive(get_size2::GetSize))] pub struct InterpolatedStringElements(Vec); impl InterpolatedStringElements { @@ -1209,6 +1228,7 @@ impl fmt::Debug for InterpolatedStringElements { /// An AST node that represents a single t-string which is part of an [`ExprTString`]. #[derive(Clone, Debug, PartialEq)] +#[cfg_attr(feature = "get-size", derive(get_size2::GetSize))] pub struct TString { pub range: TextRange, pub node_index: AtomicNodeIndex, @@ -1240,6 +1260,7 @@ impl ExprStringLiteral { /// The value representing a [`ExprStringLiteral`]. #[derive(Clone, Debug, PartialEq)] +#[cfg_attr(feature = "get-size", derive(get_size2::GetSize))] pub struct StringLiteralValue { inner: StringLiteralValueInner, } @@ -1397,6 +1418,7 @@ impl fmt::Display for StringLiteralValue { /// An internal representation of [`StringLiteralValue`]. #[derive(Clone, Debug, PartialEq)] +#[cfg_attr(feature = "get-size", derive(get_size2::GetSize))] enum StringLiteralValueInner { /// A single string literal i.e., `"foo"`. Single(StringLiteral), @@ -1440,6 +1462,8 @@ bitflags! { } } +impl get_size2::GetSize for StringLiteralFlagsInner {} + /// Flags that can be queried to obtain information /// regarding the prefixes and quotes used for a string literal. /// @@ -1453,6 +1477,7 @@ bitflags! { /// handle surrounding f-strings. For usage that doesn't fit into one of these categories, the /// public constructor [`StringLiteralFlags::empty`] can be used. #[derive(Copy, Clone, Eq, PartialEq, Hash)] +#[cfg_attr(feature = "get-size", derive(get_size2::GetSize))] pub struct StringLiteralFlags(StringLiteralFlagsInner); impl StringLiteralFlags { @@ -1581,6 +1606,7 @@ impl fmt::Debug for StringLiteralFlags { /// An AST node that represents a single string literal which is part of an /// [`ExprStringLiteral`]. #[derive(Clone, Debug, PartialEq)] +#[cfg_attr(feature = "get-size", derive(get_size2::GetSize))] pub struct StringLiteral { pub range: TextRange, pub node_index: AtomicNodeIndex, @@ -1637,6 +1663,7 @@ impl From for Expr { /// An internal representation of [`StringLiteral`] that represents an /// implicitly concatenated string. #[derive(Clone)] +#[cfg_attr(feature = "get-size", derive(get_size2::GetSize))] struct ConcatenatedStringLiteral { /// The individual [`StringLiteral`] parts that make up the concatenated string. strings: Vec, @@ -1689,6 +1716,7 @@ impl ExprBytesLiteral { /// The value representing a [`ExprBytesLiteral`]. #[derive(Clone, Debug, PartialEq)] +#[cfg_attr(feature = "get-size", derive(get_size2::GetSize))] pub struct BytesLiteralValue { inner: BytesLiteralValueInner, } @@ -1817,6 +1845,7 @@ impl<'a> From<&'a BytesLiteralValue> for Cow<'a, [u8]> { /// An internal representation of [`BytesLiteralValue`]. #[derive(Clone, Debug, PartialEq)] +#[cfg_attr(feature = "get-size", derive(get_size2::GetSize))] enum BytesLiteralValueInner { /// A single-part bytestring literal i.e., `b"foo"`. Single(BytesLiteral), @@ -1851,6 +1880,8 @@ bitflags! { } } +impl get_size2::GetSize for BytesLiteralFlagsInner {} + /// Flags that can be queried to obtain information /// regarding the prefixes and quotes used for a bytes literal. /// @@ -1863,6 +1894,7 @@ bitflags! { /// will properly handle surrounding f-strings. For usage that doesn't fit into one of these /// categories, the public constructor [`BytesLiteralFlags::empty`] can be used. #[derive(Copy, Clone, Eq, PartialEq, Hash)] +#[cfg_attr(feature = "get-size", derive(get_size2::GetSize))] pub struct BytesLiteralFlags(BytesLiteralFlagsInner); impl BytesLiteralFlags { @@ -1972,6 +2004,7 @@ impl fmt::Debug for BytesLiteralFlags { /// An AST node that represents a single bytes literal which is part of an /// [`ExprBytesLiteral`]. #[derive(Clone, Debug, PartialEq)] +#[cfg_attr(feature = "get-size", derive(get_size2::GetSize))] pub struct BytesLiteral { pub range: TextRange, pub node_index: AtomicNodeIndex, @@ -2328,6 +2361,7 @@ impl From for AnyStringFlags { } #[derive(Clone, Debug, PartialEq, is_macro::Is)] +#[cfg_attr(feature = "get-size", derive(get_size2::GetSize))] pub enum Number { Int(int::Int), Float(f64), @@ -2395,6 +2429,7 @@ impl<'a> IntoIterator for &'a ExprTuple { /// See also [expr_context](https://docs.python.org/3/library/ast.html#ast.expr_context) #[derive(Clone, Debug, PartialEq, is_macro::Is, Copy, Hash, Eq)] +#[cfg_attr(feature = "get-size", derive(get_size2::GetSize))] pub enum ExprContext { Load, Store, @@ -2404,6 +2439,7 @@ pub enum ExprContext { /// See also [boolop](https://docs.python.org/3/library/ast.html#ast.BoolOp) #[derive(Clone, Debug, PartialEq, is_macro::Is, Copy, Hash, Eq)] +#[cfg_attr(feature = "get-size", derive(get_size2::GetSize))] pub enum BoolOp { And, Or, @@ -2426,6 +2462,7 @@ impl fmt::Display for BoolOp { /// See also [operator](https://docs.python.org/3/library/ast.html#ast.operator) #[derive(Clone, Debug, PartialEq, is_macro::Is, Copy, Hash, Eq)] +#[cfg_attr(feature = "get-size", derive(get_size2::GetSize))] pub enum Operator { Add, Sub, @@ -2527,6 +2564,7 @@ impl fmt::Display for Operator { /// See also [unaryop](https://docs.python.org/3/library/ast.html#ast.unaryop) #[derive(Clone, Debug, PartialEq, is_macro::Is, Copy, Hash, Eq)] +#[cfg_attr(feature = "get-size", derive(get_size2::GetSize))] pub enum UnaryOp { Invert, Not, @@ -2553,6 +2591,7 @@ impl fmt::Display for UnaryOp { /// See also [cmpop](https://docs.python.org/3/library/ast.html#ast.cmpop) #[derive(Clone, Debug, PartialEq, is_macro::Is, Copy, Hash, Eq)] +#[cfg_attr(feature = "get-size", derive(get_size2::GetSize))] pub enum CmpOp { Eq, NotEq, @@ -2607,6 +2646,7 @@ impl fmt::Display for CmpOp { /// See also [comprehension](https://docs.python.org/3/library/ast.html#ast.comprehension) #[derive(Clone, Debug, PartialEq)] +#[cfg_attr(feature = "get-size", derive(get_size2::GetSize))] pub struct Comprehension { pub range: TextRange, pub node_index: AtomicNodeIndex, @@ -2618,6 +2658,7 @@ pub struct Comprehension { /// See also [ExceptHandler](https://docs.python.org/3/library/ast.html#ast.ExceptHandler) #[derive(Clone, Debug, PartialEq)] +#[cfg_attr(feature = "get-size", derive(get_size2::GetSize))] pub struct ExceptHandlerExceptHandler { pub range: TextRange, pub node_index: AtomicNodeIndex, @@ -2628,6 +2669,7 @@ pub struct ExceptHandlerExceptHandler { /// See also [arg](https://docs.python.org/3/library/ast.html#ast.arg) #[derive(Clone, Debug, PartialEq)] +#[cfg_attr(feature = "get-size", derive(get_size2::GetSize))] pub struct Parameter { pub range: TextRange, pub node_index: AtomicNodeIndex, @@ -2647,6 +2689,7 @@ impl Parameter { /// See also [keyword](https://docs.python.org/3/library/ast.html#ast.keyword) #[derive(Clone, Debug, PartialEq)] +#[cfg_attr(feature = "get-size", derive(get_size2::GetSize))] pub struct Keyword { pub range: TextRange, pub node_index: AtomicNodeIndex, @@ -2656,6 +2699,7 @@ pub struct Keyword { /// See also [alias](https://docs.python.org/3/library/ast.html#ast.alias) #[derive(Clone, Debug, PartialEq)] +#[cfg_attr(feature = "get-size", derive(get_size2::GetSize))] pub struct Alias { pub range: TextRange, pub node_index: AtomicNodeIndex, @@ -2665,6 +2709,7 @@ pub struct Alias { /// See also [withitem](https://docs.python.org/3/library/ast.html#ast.withitem) #[derive(Clone, Debug, PartialEq)] +#[cfg_attr(feature = "get-size", derive(get_size2::GetSize))] pub struct WithItem { pub range: TextRange, pub node_index: AtomicNodeIndex, @@ -2674,6 +2719,7 @@ pub struct WithItem { /// See also [match_case](https://docs.python.org/3/library/ast.html#ast.match_case) #[derive(Clone, Debug, PartialEq)] +#[cfg_attr(feature = "get-size", derive(get_size2::GetSize))] pub struct MatchCase { pub range: TextRange, pub node_index: AtomicNodeIndex, @@ -2751,6 +2797,7 @@ pub struct IrrefutablePattern { } #[derive(Debug, Clone, PartialEq, Eq, Hash)] +#[cfg_attr(feature = "get-size", derive(get_size2::GetSize))] pub enum IrrefutablePatternKind { Name(Name), Wildcard, @@ -2758,6 +2805,7 @@ pub enum IrrefutablePatternKind { /// See also [MatchValue](https://docs.python.org/3/library/ast.html#ast.MatchValue) #[derive(Clone, Debug, PartialEq)] +#[cfg_attr(feature = "get-size", derive(get_size2::GetSize))] pub struct PatternMatchValue { pub range: TextRange, pub node_index: AtomicNodeIndex, @@ -2766,6 +2814,7 @@ pub struct PatternMatchValue { /// See also [MatchSingleton](https://docs.python.org/3/library/ast.html#ast.MatchSingleton) #[derive(Clone, Debug, PartialEq)] +#[cfg_attr(feature = "get-size", derive(get_size2::GetSize))] pub struct PatternMatchSingleton { pub range: TextRange, pub node_index: AtomicNodeIndex, @@ -2774,6 +2823,7 @@ pub struct PatternMatchSingleton { /// See also [MatchSequence](https://docs.python.org/3/library/ast.html#ast.MatchSequence) #[derive(Clone, Debug, PartialEq)] +#[cfg_attr(feature = "get-size", derive(get_size2::GetSize))] pub struct PatternMatchSequence { pub range: TextRange, pub node_index: AtomicNodeIndex, @@ -2782,6 +2832,7 @@ pub struct PatternMatchSequence { /// See also [MatchMapping](https://docs.python.org/3/library/ast.html#ast.MatchMapping) #[derive(Clone, Debug, PartialEq)] +#[cfg_attr(feature = "get-size", derive(get_size2::GetSize))] pub struct PatternMatchMapping { pub range: TextRange, pub node_index: AtomicNodeIndex, @@ -2792,6 +2843,7 @@ pub struct PatternMatchMapping { /// See also [MatchClass](https://docs.python.org/3/library/ast.html#ast.MatchClass) #[derive(Clone, Debug, PartialEq)] +#[cfg_attr(feature = "get-size", derive(get_size2::GetSize))] pub struct PatternMatchClass { pub range: TextRange, pub node_index: AtomicNodeIndex, @@ -2804,6 +2856,7 @@ pub struct PatternMatchClass { /// /// Like [`Arguments`], but for [`PatternMatchClass`]. #[derive(Clone, Debug, PartialEq)] +#[cfg_attr(feature = "get-size", derive(get_size2::GetSize))] pub struct PatternArguments { pub range: TextRange, pub node_index: AtomicNodeIndex, @@ -2816,6 +2869,7 @@ pub struct PatternArguments { /// /// Like [`Keyword`], but for [`PatternMatchClass`]. #[derive(Clone, Debug, PartialEq)] +#[cfg_attr(feature = "get-size", derive(get_size2::GetSize))] pub struct PatternKeyword { pub range: TextRange, pub node_index: AtomicNodeIndex, @@ -2825,6 +2879,7 @@ pub struct PatternKeyword { /// See also [MatchStar](https://docs.python.org/3/library/ast.html#ast.MatchStar) #[derive(Clone, Debug, PartialEq)] +#[cfg_attr(feature = "get-size", derive(get_size2::GetSize))] pub struct PatternMatchStar { pub range: TextRange, pub node_index: AtomicNodeIndex, @@ -2833,6 +2888,7 @@ pub struct PatternMatchStar { /// See also [MatchAs](https://docs.python.org/3/library/ast.html#ast.MatchAs) #[derive(Clone, Debug, PartialEq)] +#[cfg_attr(feature = "get-size", derive(get_size2::GetSize))] pub struct PatternMatchAs { pub range: TextRange, pub node_index: AtomicNodeIndex, @@ -2842,6 +2898,7 @@ pub struct PatternMatchAs { /// See also [MatchOr](https://docs.python.org/3/library/ast.html#ast.MatchOr) #[derive(Clone, Debug, PartialEq)] +#[cfg_attr(feature = "get-size", derive(get_size2::GetSize))] pub struct PatternMatchOr { pub range: TextRange, pub node_index: AtomicNodeIndex, @@ -2868,6 +2925,7 @@ impl TypeParam { /// See also [TypeVar](https://docs.python.org/3/library/ast.html#ast.TypeVar) #[derive(Clone, Debug, PartialEq)] +#[cfg_attr(feature = "get-size", derive(get_size2::GetSize))] pub struct TypeParamTypeVar { pub range: TextRange, pub node_index: AtomicNodeIndex, @@ -2878,6 +2936,7 @@ pub struct TypeParamTypeVar { /// See also [ParamSpec](https://docs.python.org/3/library/ast.html#ast.ParamSpec) #[derive(Clone, Debug, PartialEq)] +#[cfg_attr(feature = "get-size", derive(get_size2::GetSize))] pub struct TypeParamParamSpec { pub range: TextRange, pub node_index: AtomicNodeIndex, @@ -2887,6 +2946,7 @@ pub struct TypeParamParamSpec { /// See also [TypeVarTuple](https://docs.python.org/3/library/ast.html#ast.TypeVarTuple) #[derive(Clone, Debug, PartialEq)] +#[cfg_attr(feature = "get-size", derive(get_size2::GetSize))] pub struct TypeParamTypeVarTuple { pub range: TextRange, pub node_index: AtomicNodeIndex, @@ -2896,6 +2956,7 @@ pub struct TypeParamTypeVarTuple { /// See also [decorator](https://docs.python.org/3/library/ast.html#ast.decorator) #[derive(Clone, Debug, PartialEq)] +#[cfg_attr(feature = "get-size", derive(get_size2::GetSize))] pub struct Decorator { pub range: TextRange, pub node_index: AtomicNodeIndex, @@ -2970,6 +3031,7 @@ impl Ranged for AnyParameterRef<'_> { /// NOTE: This type differs from the original Python AST. See: [arguments](https://docs.python.org/3/library/ast.html#ast.arguments). #[derive(Clone, Debug, PartialEq, Default)] +#[cfg_attr(feature = "get-size", derive(get_size2::GetSize))] pub struct Parameters { pub range: TextRange, pub node_index: AtomicNodeIndex, @@ -3189,6 +3251,7 @@ impl<'a> IntoIterator for &'a Box { /// NOTE: This type is different from original Python AST. #[derive(Clone, Debug, PartialEq)] +#[cfg_attr(feature = "get-size", derive(get_size2::GetSize))] pub struct ParameterWithDefault { pub range: TextRange, pub node_index: AtomicNodeIndex, @@ -3233,6 +3296,7 @@ impl ParameterWithDefault { /// typically used for `metaclass`, with any additional arguments being passed to the `metaclass`. #[derive(Clone, Debug, PartialEq)] +#[cfg_attr(feature = "get-size", derive(get_size2::GetSize))] pub struct Arguments { pub range: TextRange, pub node_index: AtomicNodeIndex, @@ -3383,6 +3447,7 @@ impl Arguments { /// the `T`, `U`, and `V` type parameters in the order they appear in the source code. #[derive(Clone, Debug, PartialEq)] +#[cfg_attr(feature = "get-size", derive(get_size2::GetSize))] pub struct TypeParams { pub range: TextRange, pub node_index: AtomicNodeIndex, @@ -3406,6 +3471,7 @@ pub type Suite = Vec; /// /// [IPython Syntax]: https://github.com/ipython/ipython/blob/635815e8f1ded5b764d66cacc80bbe25e9e2587f/IPython/core/inputtransformer2.py#L335-L343 #[derive(PartialEq, Eq, Debug, Clone, Hash, Copy)] +#[cfg_attr(feature = "get-size", derive(get_size2::GetSize))] pub enum IpyEscapeKind { /// Send line to underlying system shell (`!`). Shell, @@ -3497,6 +3563,7 @@ impl IpyEscapeKind { /// ... /// ``` #[derive(Clone, Debug, PartialEq, Eq, Hash)] +#[cfg_attr(feature = "get-size", derive(get_size2::GetSize))] pub struct Identifier { pub id: Name, pub range: TextRange, @@ -3572,6 +3639,7 @@ impl From for Name { } #[derive(Clone, Copy, Debug, Hash, PartialEq)] +#[cfg_attr(feature = "get-size", derive(get_size2::GetSize))] pub enum Singleton { None, True, diff --git a/crates/ruff_python_ast/src/python_version.rs b/crates/ruff_python_ast/src/python_version.rs index 2a3b79594b..7eab154ad1 100644 --- a/crates/ruff_python_ast/src/python_version.rs +++ b/crates/ruff_python_ast/src/python_version.rs @@ -5,6 +5,7 @@ use std::{fmt, str::FromStr}; /// N.B. This does not necessarily represent a Python version that we actually support. #[derive(Debug, Clone, Copy, Eq, PartialEq, Ord, PartialOrd, Hash)] #[cfg_attr(feature = "cache", derive(ruff_macros::CacheKey))] +#[cfg_attr(feature = "get-size", derive(get_size2::GetSize))] pub struct PythonVersion { pub major: u8, pub minor: u8, diff --git a/crates/ruff_python_parser/Cargo.toml b/crates/ruff_python_parser/Cargo.toml index e6e96335bc..ae45871866 100644 --- a/crates/ruff_python_parser/Cargo.toml +++ b/crates/ruff_python_parser/Cargo.toml @@ -13,13 +13,14 @@ license = { workspace = true } [lib] [dependencies] -ruff_python_ast = { workspace = true } +ruff_python_ast = { workspace = true, features = ["get-size"] } ruff_python_trivia = { workspace = true } -ruff_text_size = { workspace = true } +ruff_text_size = { workspace = true, features = ["get-size"] } bitflags = { workspace = true } bstr = { workspace = true } compact_str = { workspace = true } +get-size2 = { workspace = true } memchr = { workspace = true } rustc-hash = { workspace = true } static_assertions = { workspace = true } diff --git a/crates/ruff_python_parser/src/error.rs b/crates/ruff_python_parser/src/error.rs index 03dd0132c2..8b3fc463e1 100644 --- a/crates/ruff_python_parser/src/error.rs +++ b/crates/ruff_python_parser/src/error.rs @@ -7,7 +7,7 @@ use crate::{TokenKind, string::InterpolatedStringKind}; /// Represents represent errors that occur during parsing and are /// returned by the `parse_*` functions. -#[derive(Debug, PartialEq, Eq, Clone)] +#[derive(Debug, PartialEq, Eq, Clone, get_size2::GetSize)] pub struct ParseError { pub error: ParseErrorType, pub location: TextRange, @@ -49,7 +49,7 @@ impl ParseError { } /// Represents the different types of errors that can occur during parsing of an f-string or t-string. -#[derive(Debug, Clone, PartialEq, Eq)] +#[derive(Debug, Clone, PartialEq, Eq, get_size2::GetSize)] pub enum InterpolatedStringErrorType { /// Expected a right brace after an opened left brace. UnclosedLbrace, @@ -95,7 +95,7 @@ impl std::fmt::Display for InterpolatedStringErrorType { } /// Represents the different types of errors that can occur during parsing. -#[derive(Debug, PartialEq, Eq, Clone)] +#[derive(Debug, PartialEq, Eq, Clone, get_size2::GetSize)] pub enum ParseErrorType { /// An unexpected error occurred. OtherError(String), @@ -384,7 +384,7 @@ impl std::fmt::Display for LexicalError { } /// Represents the different types of errors that can occur during lexing. -#[derive(Debug, Clone, PartialEq, Eq)] +#[derive(Debug, Clone, PartialEq, Eq, get_size2::GetSize)] pub enum LexicalErrorType { // TODO: Can probably be removed, the places it is used seem to be able // to use the `UnicodeError` variant instead. @@ -468,7 +468,7 @@ impl std::fmt::Display for LexicalErrorType { /// /// An example of a version-related error is the use of a `match` statement before Python 3.10, when /// it was first introduced. See [`UnsupportedSyntaxErrorKind`] for other kinds of errors. -#[derive(Debug, PartialEq, Clone)] +#[derive(Debug, PartialEq, Clone, get_size2::GetSize)] pub struct UnsupportedSyntaxError { pub kind: UnsupportedSyntaxErrorKind, pub range: TextRange, @@ -483,28 +483,28 @@ impl Ranged for UnsupportedSyntaxError { } /// The type of tuple unpacking for [`UnsupportedSyntaxErrorKind::StarTuple`]. -#[derive(Debug, PartialEq, Eq, Hash, Clone, Copy)] +#[derive(Debug, PartialEq, Eq, Hash, Clone, Copy, get_size2::GetSize)] pub enum StarTupleKind { Return, Yield, } /// The type of PEP 701 f-string error for [`UnsupportedSyntaxErrorKind::Pep701FString`]. -#[derive(Debug, PartialEq, Eq, Hash, Clone, Copy)] +#[derive(Debug, PartialEq, Eq, Hash, Clone, Copy, get_size2::GetSize)] pub enum FStringKind { Backslash, Comment, NestedQuote, } -#[derive(Debug, PartialEq, Eq, Hash, Clone, Copy)] +#[derive(Debug, PartialEq, Eq, Hash, Clone, Copy, get_size2::GetSize)] pub enum UnparenthesizedNamedExprKind { SequenceIndex, SetLiteral, SetComprehension, } -#[derive(Debug, PartialEq, Eq, Hash, Clone, Copy)] +#[derive(Debug, PartialEq, Eq, Hash, Clone, Copy, get_size2::GetSize)] pub enum UnsupportedSyntaxErrorKind { Match, Walrus, @@ -988,7 +988,7 @@ impl Display for UnsupportedSyntaxError { } } -#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, get_size2::GetSize)] pub enum RelaxedDecoratorError { CallExpression, Other(&'static str), diff --git a/crates/ruff_python_parser/src/lib.rs b/crates/ruff_python_parser/src/lib.rs index 4825c2adce..54061c58e8 100644 --- a/crates/ruff_python_parser/src/lib.rs +++ b/crates/ruff_python_parser/src/lib.rs @@ -304,7 +304,7 @@ pub fn parse_unchecked_source(source: &str, source_type: PySourceType) -> Parsed } /// Represents the parsed source code. -#[derive(Debug, PartialEq, Clone)] +#[derive(Debug, PartialEq, Clone, get_size2::GetSize)] pub struct Parsed { syntax: T, tokens: Tokens, @@ -474,7 +474,7 @@ impl Parsed { } /// Tokens represents a vector of lexed [`Token`]. -#[derive(Debug, Clone, PartialEq, Eq)] +#[derive(Debug, Clone, PartialEq, Eq, get_size2::GetSize)] pub struct Tokens { raw: Vec, } diff --git a/crates/ruff_python_parser/src/semantic_errors.rs b/crates/ruff_python_parser/src/semantic_errors.rs index c8d7fb458f..73368fce77 100644 --- a/crates/ruff_python_parser/src/semantic_errors.rs +++ b/crates/ruff_python_parser/src/semantic_errors.rs @@ -890,7 +890,7 @@ impl SemanticSyntaxChecker { } } -#[derive(Debug, Clone, PartialEq, Eq, Hash)] +#[derive(Debug, Clone, PartialEq, Eq, Hash, get_size2::GetSize)] pub struct SemanticSyntaxError { pub kind: SemanticSyntaxErrorKind, pub range: TextRange, @@ -981,7 +981,7 @@ impl Display for SemanticSyntaxError { } } -#[derive(Debug, Clone, PartialEq, Eq, Hash)] +#[derive(Debug, Clone, PartialEq, Eq, Hash, get_size2::GetSize)] pub enum SemanticSyntaxErrorKind { /// Represents the use of a `__future__` import after the beginning of a file. /// @@ -1303,7 +1303,7 @@ pub enum SemanticSyntaxErrorKind { NonlocalDeclarationAtModuleLevel, } -#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, get_size2::GetSize)] pub enum AwaitOutsideAsyncFunctionKind { Await, AsyncFor, @@ -1322,7 +1322,7 @@ impl Display for AwaitOutsideAsyncFunctionKind { } } -#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, get_size2::GetSize)] pub enum YieldOutsideFunctionKind { Yield, YieldFrom, @@ -1345,7 +1345,7 @@ impl Display for YieldOutsideFunctionKind { } } -#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, get_size2::GetSize)] pub enum InvalidExpressionPosition { TypeVarBound, TypeVarDefault, @@ -1370,7 +1370,7 @@ impl Display for InvalidExpressionPosition { } } -#[derive(Debug, Clone, PartialEq, Eq, Hash)] +#[derive(Debug, Clone, PartialEq, Eq, Hash, get_size2::GetSize)] pub enum InvalidExpressionKind { Yield, NamedExpr, @@ -1387,7 +1387,7 @@ impl Display for InvalidExpressionKind { } } -#[derive(Debug, Clone, PartialEq, Eq, Hash)] +#[derive(Debug, Clone, PartialEq, Eq, Hash, get_size2::GetSize)] pub enum WriteToDebugKind { Store, Delete(PythonVersion), diff --git a/crates/ruff_python_parser/src/token.rs b/crates/ruff_python_parser/src/token.rs index 59e4c0581c..240e015a3b 100644 --- a/crates/ruff_python_parser/src/token.rs +++ b/crates/ruff_python_parser/src/token.rs @@ -17,7 +17,7 @@ use ruff_python_ast::str_prefix::{ use ruff_python_ast::{AnyStringFlags, BoolOp, Int, IpyEscapeKind, Operator, StringFlags, UnaryOp}; use ruff_text_size::{Ranged, TextRange}; -#[derive(Clone, Copy, PartialEq, Eq)] +#[derive(Clone, Copy, PartialEq, Eq, get_size2::GetSize)] pub struct Token { /// The kind of the token. kind: TokenKind, @@ -124,7 +124,7 @@ impl fmt::Debug for Token { } /// A kind of a token. -#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug, PartialOrd, Ord)] +#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug, PartialOrd, Ord, get_size2::GetSize)] pub enum TokenKind { /// Token kind for a name, commonly known as an identifier. Name, @@ -754,6 +754,8 @@ bitflags! { } } +impl get_size2::GetSize for TokenFlags {} + impl StringFlags for TokenFlags { fn quote_style(self) -> Quote { if self.intersects(TokenFlags::DOUBLE_QUOTES) { diff --git a/crates/ruff_source_file/Cargo.toml b/crates/ruff_source_file/Cargo.toml index 0f82f37169..ffc41ca462 100644 --- a/crates/ruff_source_file/Cargo.toml +++ b/crates/ruff_source_file/Cargo.toml @@ -15,12 +15,14 @@ license = { workspace = true } [dependencies] ruff_text_size = { workspace = true } +get-size2 = { workspace = true, optional = true } memchr = { workspace = true } serde = { workspace = true, optional = true } [dev-dependencies] [features] +get-size = ["dep:get-size2"] serde = ["dep:serde", "ruff_text_size/serde"] [lints] diff --git a/crates/ruff_source_file/src/lib.rs b/crates/ruff_source_file/src/lib.rs index 4df0b2a20a..c7c652bc64 100644 --- a/crates/ruff_source_file/src/lib.rs +++ b/crates/ruff_source_file/src/lib.rs @@ -163,6 +163,7 @@ impl SourceFileBuilder { /// /// Cloning a [`SourceFile`] is cheap, because it only requires bumping a reference count. #[derive(Clone, Eq, PartialEq)] +#[cfg_attr(feature = "get-size", derive(get_size2::GetSize))] pub struct SourceFile { inner: Arc, } @@ -225,6 +226,7 @@ impl Ord for SourceFile { } } +#[cfg_attr(feature = "get-size", derive(get_size2::GetSize))] struct SourceFileInner { name: Box, code: Box, diff --git a/crates/ruff_source_file/src/line_index.rs b/crates/ruff_source_file/src/line_index.rs index 54d82b1ab9..8da47e0dba 100644 --- a/crates/ruff_source_file/src/line_index.rs +++ b/crates/ruff_source_file/src/line_index.rs @@ -14,11 +14,13 @@ use serde::{Deserialize, Serialize}; /// /// Cloning a [`LineIndex`] is cheap because it only requires bumping a reference count. #[derive(Clone, Eq, PartialEq)] +#[cfg_attr(feature = "get-size", derive(get_size2::GetSize))] pub struct LineIndex { inner: Arc, } #[derive(Eq, PartialEq)] +#[cfg_attr(feature = "get-size", derive(get_size2::GetSize))] struct LineIndexInner { line_starts: Vec, kind: IndexKind, @@ -534,6 +536,7 @@ impl Debug for LineIndex { } #[derive(Debug, Clone, Copy, Eq, PartialEq)] +#[cfg_attr(feature = "get-size", derive(get_size2::GetSize))] enum IndexKind { /// Optimized index for an ASCII only document Ascii, diff --git a/crates/ruff_text_size/Cargo.toml b/crates/ruff_text_size/Cargo.toml index 19de486464..d658fe4db3 100644 --- a/crates/ruff_text_size/Cargo.toml +++ b/crates/ruff_text_size/Cargo.toml @@ -12,6 +12,7 @@ license = { workspace = true } [dependencies] serde = { workspace = true, optional = true } +get-size2 = { workspace = true, optional = true } schemars = { workspace = true, optional = true } [dev-dependencies] @@ -20,6 +21,7 @@ static_assertions = { workspace = true } [features] serde = ["dep:serde"] +get-size = ["dep:get-size2"] [lints] workspace = true diff --git a/crates/ruff_text_size/src/range.rs b/crates/ruff_text_size/src/range.rs index f2767c3d75..895cfea530 100644 --- a/crates/ruff_text_size/src/range.rs +++ b/crates/ruff_text_size/src/range.rs @@ -12,6 +12,7 @@ use { /// /// It is a logic error for `start` to be greater than `end`. #[derive(Default, Copy, Clone, Eq, PartialEq, Hash)] +#[cfg_attr(feature = "get-size", derive(get_size2::GetSize))] pub struct TextRange { // Invariant: start <= end start: TextSize, diff --git a/crates/ruff_text_size/src/size.rs b/crates/ruff_text_size/src/size.rs index 1b597698d3..dda5ded61d 100644 --- a/crates/ruff_text_size/src/size.rs +++ b/crates/ruff_text_size/src/size.rs @@ -21,6 +21,7 @@ use { /// These escape hatches are primarily required for unit testing and when /// converting from UTF-8 size to another coordinate space, such as UTF-16. #[derive(Clone, Copy, Default, PartialEq, Eq, PartialOrd, Ord, Hash)] +#[cfg_attr(feature = "get-size", derive(get_size2::GetSize))] pub struct TextSize { pub(crate) raw: u32, } diff --git a/crates/ty/src/lib.rs b/crates/ty/src/lib.rs index aa00d2e374..4b3709d6d0 100644 --- a/crates/ty/src/lib.rs +++ b/crates/ty/src/lib.rs @@ -143,6 +143,13 @@ fn run_check(args: CheckCommand) -> anyhow::Result { main_loop.run(&mut db)? }; + let mut stdout = stdout().lock(); + match std::env::var("TY_MEMORY_REPORT").as_deref() { + Ok("short") => write!(stdout, "{}", db.salsa_memory_dump().display_short())?, + Ok("full") => write!(stdout, "{}", db.salsa_memory_dump().display_full())?, + _ => {} + } + tracing::trace!("Counts for entire CLI run:\n{}", countme::get_all()); std::mem::forget(db); diff --git a/crates/ty_project/Cargo.toml b/crates/ty_project/Cargo.toml index d0648255fd..dcef49bd4a 100644 --- a/crates/ty_project/Cargo.toml +++ b/crates/ty_project/Cargo.toml @@ -27,6 +27,7 @@ anyhow = { workspace = true } camino = { workspace = true } colored = { workspace = true } crossbeam = { workspace = true } +get-size2 = { workspace = true } globset = { workspace = true } notify = { workspace = true } pep440_rs = { workspace = true, features = ["version-ranges"] } diff --git a/crates/ty_project/src/db.rs b/crates/ty_project/src/db.rs index dc9f282109..e614f3e73b 100644 --- a/crates/ty_project/src/db.rs +++ b/crates/ty_project/src/db.rs @@ -1,5 +1,6 @@ use std::panic::{AssertUnwindSafe, RefUnwindSafe}; use std::sync::Arc; +use std::{cmp, fmt}; use crate::metadata::settings::file_settings; use crate::{DEFAULT_LINT_REGISTRY, DummyReporter}; @@ -108,6 +109,171 @@ impl ProjectDatabase { Arc::get_mut(&mut self.system) .expect("ref count should be 1 because `zalsa_mut` drops all other DB references.") } + + /// Returns a [`SalsaMemoryDump`] that can be use to dump Salsa memory usage information + /// to the CLI after a typechecker run. + pub fn salsa_memory_dump(&self) -> SalsaMemoryDump { + let salsa_db = self as &dyn salsa::Database; + + let mut ingredients = salsa_db.structs_info(); + let mut memos = salsa_db.queries_info().into_iter().collect::>(); + + ingredients.sort_by_key(|ingredient| cmp::Reverse(ingredient.size_of_fields())); + memos.sort_by_key(|(_, memo)| cmp::Reverse(memo.size_of_fields())); + + SalsaMemoryDump { ingredients, memos } + } +} + +/// Stores memory usage information. +pub struct SalsaMemoryDump { + ingredients: Vec, + memos: Vec<(&'static str, salsa::IngredientInfo)>, +} + +#[allow(clippy::cast_precision_loss)] +impl SalsaMemoryDump { + /// Returns a short report that provides total memory usage information. + pub fn display_short(&self) -> impl fmt::Display + '_ { + struct DisplayShort<'a>(&'a SalsaMemoryDump); + + impl fmt::Display for DisplayShort<'_> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + let mut total_fields = 0; + let mut total_metadata = 0; + for ingredient in &self.0.ingredients { + total_metadata += ingredient.size_of_metadata(); + total_fields += ingredient.size_of_fields(); + } + + let mut total_memo_fields = 0; + let mut total_memo_metadata = 0; + for (_, memo) in &self.0.memos { + total_memo_fields += memo.size_of_fields(); + total_memo_metadata += memo.size_of_metadata(); + } + + writeln!(f, "=======SALSA SUMMARY=======")?; + + writeln!( + f, + "TOTAL MEMORY USAGE: {:.2}MB", + (total_metadata + total_fields + total_memo_fields + total_memo_metadata) + as f64 + / 1_000_000., + )?; + + writeln!( + f, + " struct metadata = {:.2}MB", + total_metadata as f64 / 1_000_000., + )?; + writeln!( + f, + " struct fields = {:.2}MB", + total_fields as f64 / 1_000_000., + )?; + writeln!( + f, + " memo metadata = {:.2}MB", + total_memo_metadata as f64 / 1_000_000., + )?; + writeln!( + f, + " memo fields = {:.2}MB", + total_memo_fields as f64 / 1_000_000. + )?; + + writeln!(f, "QUERY COUNT: {}", self.0.memos.len())?; + writeln!(f, "STRUCT COUNT: {}", self.0.ingredients.len())?; + + Ok(()) + } + } + + DisplayShort(self) + } + + /// Returns a short report that provides fine-grained memory usage information per + /// Salsa ingredient. + pub fn display_full(&self) -> impl fmt::Display + '_ { + struct DisplayFull<'a>(&'a SalsaMemoryDump); + + impl fmt::Display for DisplayFull<'_> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + writeln!(f, "=======SALSA STRUCTS=======")?; + + let mut total_fields = 0; + let mut total_metadata = 0; + for ingredient in &self.0.ingredients { + total_metadata += ingredient.size_of_metadata(); + total_fields += ingredient.size_of_fields(); + + writeln!( + f, + "{:<50} metadata={:<8} fields={:<8} count={}", + format!("`{}`", ingredient.debug_name()), + format!("{:.2}MB", ingredient.size_of_metadata() as f64 / 1_000_000.), + format!("{:.2}MB", ingredient.size_of_fields() as f64 / 1_000_000.), + ingredient.count() + )?; + } + + writeln!(f, "=======SALSA QUERIES=======")?; + + let mut total_memo_fields = 0; + let mut total_memo_metadata = 0; + for (query_fn, memo) in &self.0.memos { + total_memo_fields += memo.size_of_fields(); + total_memo_metadata += memo.size_of_metadata(); + + writeln!(f, "`{query_fn} -> {}`", memo.debug_name())?; + + writeln!( + f, + " metadata={:<8} fields={:<8} count={}", + format!("{:.2}MB", memo.size_of_metadata() as f64 / 1_000_000.), + format!("{:.2}MB", memo.size_of_fields() as f64 / 1_000_000.), + memo.count() + )?; + } + + writeln!(f, "=======SALSA SUMMARY=======")?; + writeln!( + f, + "TOTAL MEMORY USAGE: {:.2}MB", + (total_metadata + total_fields + total_memo_fields + total_memo_metadata) + as f64 + / 1_000_000., + )?; + + writeln!( + f, + " struct metadata = {:.2}MB", + total_metadata as f64 / 1_000_000., + )?; + writeln!( + f, + " struct fields = {:.2}MB", + total_fields as f64 / 1_000_000., + )?; + writeln!( + f, + " memo metadata = {:.2}MB", + total_memo_metadata as f64 / 1_000_000., + )?; + writeln!( + f, + " memo fields = {:.2}MB", + total_memo_fields as f64 / 1_000_000. + )?; + + Ok(()) + } + } + + DisplayFull(self) + } } impl Upcast for ProjectDatabase { diff --git a/crates/ty_project/src/lib.rs b/crates/ty_project/src/lib.rs index 11834036ab..4dce06e90a 100644 --- a/crates/ty_project/src/lib.rs +++ b/crates/ty_project/src/lib.rs @@ -1,7 +1,7 @@ use crate::glob::{GlobFilterCheckMode, IncludeResult}; use crate::metadata::options::{OptionDiagnostic, ToSettingsError}; use crate::walk::{ProjectFilesFilter, ProjectFilesWalker}; -pub use db::{Db, ProjectDatabase}; +pub use db::{Db, ProjectDatabase, SalsaMemoryDump}; use files::{Index, Indexed, IndexedFiles}; use metadata::settings::Settings; pub use metadata::{ProjectMetadata, ProjectMetadataError}; @@ -159,7 +159,7 @@ impl Project { /// This is a salsa query to prevent re-computing queries if other, unrelated /// settings change. For example, we don't want that changing the terminal settings /// invalidates any type checking queries. - #[salsa::tracked(returns(deref))] + #[salsa::tracked(returns(deref), heap_size=get_size2::GetSize::get_heap_size)] pub fn rules(self, db: &dyn Db) -> Arc { self.settings(db).to_rules() } diff --git a/crates/ty_project/src/metadata/settings.rs b/crates/ty_project/src/metadata/settings.rs index 1c8424fd9c..98cef0f74c 100644 --- a/crates/ty_project/src/metadata/settings.rs +++ b/crates/ty_project/src/metadata/settings.rs @@ -96,7 +96,7 @@ impl Override { } /// Resolves the settings for a given file. -#[salsa::tracked(returns(ref))] +#[salsa::tracked(returns(ref), heap_size=get_size2::GetSize::get_heap_size)] pub(crate) fn file_settings(db: &dyn Db, file: File) -> FileSettings { let settings = db.project().settings(db); @@ -155,7 +155,7 @@ pub(crate) fn file_settings(db: &dyn Db, file: File) -> FileSettings { /// This is to make Salsa happy because it requires that queries with only a single argument /// take a salsa-struct as argument, which isn't the case here. The `()` enables salsa's /// automatic interning for the arguments. -#[salsa::tracked] +#[salsa::tracked(heap_size=get_size2::GetSize::get_heap_size)] fn merge_overrides(db: &dyn Db, overrides: Vec>, _: ()) -> FileSettings { let mut overrides = overrides.into_iter().rev(); let mut merged = (*overrides.next().unwrap()).clone(); @@ -179,7 +179,7 @@ fn merge_overrides(db: &dyn Db, overrides: Vec>, _: () } /// The resolved settings for a file. -#[derive(Debug, Eq, PartialEq, Clone)] +#[derive(Debug, Eq, PartialEq, Clone, get_size2::GetSize)] pub enum FileSettings { /// The file uses the global settings. Global, @@ -197,7 +197,7 @@ impl FileSettings { } } -#[derive(Debug, Eq, PartialEq, Clone)] +#[derive(Debug, Eq, PartialEq, Clone, get_size2::GetSize)] pub struct OverrideSettings { pub(super) rules: RuleSelection, } diff --git a/crates/ty_python_semantic/Cargo.toml b/crates/ty_python_semantic/Cargo.toml index 7c5268299d..a4d5c6a6eb 100644 --- a/crates/ty_python_semantic/Cargo.toml +++ b/crates/ty_python_semantic/Cargo.toml @@ -30,6 +30,7 @@ colored = { workspace = true } compact_str = { workspace = true } countme = { workspace = true } drop_bomb = { workspace = true } +get-size2 = { workspace = true } indexmap = { workspace = true } itertools = { workspace = true } ordermap = { workspace = true } diff --git a/crates/ty_python_semantic/src/ast_node_ref.rs b/crates/ty_python_semantic/src/ast_node_ref.rs index 3c15435f92..c5f7f115cc 100644 --- a/crates/ty_python_semantic/src/ast_node_ref.rs +++ b/crates/ty_python_semantic/src/ast_node_ref.rs @@ -89,6 +89,8 @@ where } } +impl get_size2::GetSize for AstNodeRef {} + #[allow(clippy::missing_fields_in_debug)] impl Debug for AstNodeRef where diff --git a/crates/ty_python_semantic/src/dunder_all.rs b/crates/ty_python_semantic/src/dunder_all.rs index 78ceb1250d..4ed0aee93f 100644 --- a/crates/ty_python_semantic/src/dunder_all.rs +++ b/crates/ty_python_semantic/src/dunder_all.rs @@ -28,7 +28,7 @@ fn dunder_all_names_cycle_initial(_db: &dyn Db, _file: File) -> Option Option> { let _span = tracing::trace_span!("dunder_all_names", file=?file.path(db)).entered(); diff --git a/crates/ty_python_semantic/src/lint.rs b/crates/ty_python_semantic/src/lint.rs index 247bae7d78..0800ee5983 100644 --- a/crates/ty_python_semantic/src/lint.rs +++ b/crates/ty_python_semantic/src/lint.rs @@ -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] diff --git a/crates/ty_python_semantic/src/list.rs b/crates/ty_python_semantic/src/list.rs index 38061787d0..093d6e6376 100644 --- a/crates/ty_python_semantic/src/list.rs +++ b/crates/ty_python_semantic/src/list.rs @@ -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 { last: Option, _phantom: PhantomData<(K, V)>, @@ -95,12 +95,12 @@ impl Default for List { } #[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 { cells: IndexVec>, } @@ -111,7 +111,7 @@ pub(crate) struct ListStorage { /// **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 { rest: Option, key: K, diff --git a/crates/ty_python_semantic/src/module_name.rs b/crates/ty_python_semantic/src/module_name.rs index a4a0251fcd..eb6ec828de 100644 --- a/crates/ty_python_semantic/src/module_name.rs +++ b/crates/ty_python_semantic/src/module_name.rs @@ -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 { diff --git a/crates/ty_python_semantic/src/module_resolver/module.rs b/crates/ty_python_semantic/src/module_resolver/module.rs index 8ffd477622..38b59a3c3b 100644 --- a/crates/ty_python_semantic/src/module_resolver/module.rs +++ b/crates/ty_python_semantic/src/module_resolver/module.rs @@ -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, } @@ -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 { diff --git a/crates/ty_python_semantic/src/module_resolver/path.rs b/crates/ty_python_semantic/src/module_resolver/path.rs index c128a233f9..37eb8c7b8e 100644 --- a/crates/ty_python_semantic/src/module_resolver/path.rs +++ b/crates/ty_python_semantic/src/module_resolver/path.rs @@ -371,7 +371,7 @@ impl From for SearchPathValidationError { type SearchPathResult = Result; -#[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); impl SearchPath { diff --git a/crates/ty_python_semantic/src/module_resolver/resolver.rs b/crates/ty_python_semantic/src/module_resolver/resolver.rs index b0c7dc2349..239a9f64c5 100644 --- a/crates/ty_python_semantic/src/module_resolver/resolver.rs +++ b/crates/ty_python_semantic/src/module_resolver/resolver.rs @@ -30,7 +30,7 @@ pub fn resolve_module(db: &dyn Db, module_name: &ModuleName) -> Option { /// /// 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 { 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 { tracing::debug!("Resolving dynamic module resolution paths"); diff --git a/crates/ty_python_semantic/src/node_key.rs b/crates/ty_python_semantic/src/node_key.rs index 470ef35df2..18edfe1a04 100644 --- a/crates/ty_python_semantic/src/node_key.rs +++ b/crates/ty_python_semantic/src/node_key.rs @@ -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 { diff --git a/crates/ty_python_semantic/src/place.rs b/crates/ty_python_semantic/src/place.rs index 64c5f80271..4b6c194e28 100644 --- a/crates/ty_python_semantic/src/place.rs +++ b/crates/ty_python_semantic/src/place.rs @@ -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) diff --git a/crates/ty_python_semantic/src/semantic_index.rs b/crates/ty_python_semantic/src/semantic_index.rs index 009674ba26..0bee998f57 100644 --- a/crates/ty_python_semantic/src/semantic_index.rs +++ b/crates/ty_python_semantic/src/semantic_index.rs @@ -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; /// 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 { 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(db: &'db dyn Db, file: File) -> Arc> { semantic_index(db, file).imported_modules.clone() } @@ -90,8 +91,8 @@ pub(crate) fn imported_modules<'db>(db: &'db dyn Db, file: File) -> Arc(db: &'db dyn Db, scope: ScopeId<'db>) -> Arc> { +#[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>, @@ -193,7 +197,7 @@ pub(crate) struct SemanticIndex<'db> { globals_by_scope: FxHashMap>, /// Use-def map for each scope in this file. - use_def_maps: IndexVec>>, + use_def_maps: IndexVec>, /// 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 { + 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>, +} + +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, next_id: Option, diff --git a/crates/ty_python_semantic/src/semantic_index/ast_ids.rs b/crates/ty_python_semantic/src/semantic_index/ast_ids.rs index 191be73c23..829c62c877 100644 --- a/crates/ty_python_semantic/src/semantic_index/ast_ids.rs +++ b/crates/ty_python_semantic/src/semantic_index/ast_ids.rs @@ -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, @@ -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> for ExpressionNodeKey { diff --git a/crates/ty_python_semantic/src/semantic_index/builder.rs b/crates/ty_python_semantic/src/semantic_index/builder.rs index dcaff07143..3b4384c750 100644 --- a/crates/ty_python_semantic/src/semantic_index/builder.rs +++ b/crates/ty_python_semantic/src/semantic_index/builder.rs @@ -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 diff --git a/crates/ty_python_semantic/src/semantic_index/definition.rs b/crates/ty_python_semantic/src/semantic_index/definition.rs index 869944eba5..e070dce353 100644 --- a/crates/ty_python_semantic/src/semantic_index/definition.rs +++ b/crates/ty_python_semantic/src/semantic_index/definition.rs @@ -44,6 +44,9 @@ pub struct Definition<'db> { count: countme::Count>, } +// 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 { diff --git a/crates/ty_python_semantic/src/semantic_index/expression.rs b/crates/ty_python_semantic/src/semantic_index/expression.rs index 18a64b54e7..476255d6d5 100644 --- a/crates/ty_python_semantic/src/semantic_index/expression.rs +++ b/crates/ty_python_semantic/src/semantic_index/expression.rs @@ -62,6 +62,9 @@ pub(crate) struct Expression<'db> { count: countme::Count>, } +// The Salsa heap is tracked separately. +impl get_size2::GetSize for Expression<'_> {} + impl<'db> Expression<'db> { pub(crate) fn node_ref<'ast>( self, diff --git a/crates/ty_python_semantic/src/semantic_index/narrowing_constraints.rs b/crates/ty_python_semantic/src/semantic_index/narrowing_constraints.rs index 48297e1da6..54155a6ff3 100644 --- a/crates/ty_python_semantic/src/semantic_index/narrowing_constraints.rs +++ b/crates/ty_python_semantic/src/semantic_index/narrowing_constraints.rs @@ -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 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, } diff --git a/crates/ty_python_semantic/src/semantic_index/place.rs b/crates/ty_python_semantic/src/semantic_index/place.rs index 6b26cd4b7f..9dec0488ce 100644 --- a/crates/ty_python_semantic/src/semantic_index/place.rs +++ b/crates/ty_python_semantic/src/semantic_index/place.rs @@ -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 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>, } +// 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, 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, @@ -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), @@ -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), diff --git a/crates/ty_python_semantic/src/semantic_index/predicate.rs b/crates/ty_python_semantic/src/semantic_index/predicate.rs index 9259ab72e4..6009914ac4 100644 --- a/crates/ty_python_semantic/src/semantic_index/predicate.rs +++ b/crates/ty_python_semantic/src/semantic_index/predicate.rs @@ -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>, } +// 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`]: diff --git a/crates/ty_python_semantic/src/semantic_index/re_exports.rs b/crates/ty_python_semantic/src/semantic_index/re_exports.rs index 275e13d7a7..733ec5d262 100644 --- a/crates/ty_python_semantic/src/semantic_index/re_exports.rs +++ b/crates/ty_python_semantic/src/semantic_index/re_exports.rs @@ -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); diff --git a/crates/ty_python_semantic/src/semantic_index/reachability_constraints.rs b/crates/ty_python_semantic/src/semantic_index/reachability_constraints.rs index 2cef92945b..e7fd1d6914 100644 --- a/crates/ty_python_semantic/src/semantic_index/reachability_constraints.rs +++ b/crates/ty_python_semantic/src/semantic_index/reachability_constraints.rs @@ -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, } diff --git a/crates/ty_python_semantic/src/semantic_index/use_def.rs b/crates/ty_python_semantic/src/semantic_index/use_def.rs index e216d51e60..3e20b8dbf3 100644 --- a/crates/ty_python_semantic/src/semantic_index/use_def.rs +++ b/crates/ty_python_semantic/src/semantic_index/use_def.rs @@ -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, diff --git a/crates/ty_python_semantic/src/semantic_index/use_def/place_state.rs b/crates/ty_python_semantic/src/semantic_index/use_def/place_state.rs index dc10dc7ef2..b3f34577b9 100644 --- a/crates/ty_python_semantic/src/semantic_index/use_def/place_state.rs +++ b/crates/ty_python_semantic/src/semantic_index/use_def/place_state.rs @@ -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, diff --git a/crates/ty_python_semantic/src/suppression.rs b/crates/ty_python_semantic/src/suppression.rs index b5103f6581..823cd1223b 100644 --- a/crates/ty_python_semantic/src/suppression.rs +++ b/crates/ty_python_semantic/src/suppression.rs @@ -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>, } -#[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")] diff --git a/crates/ty_python_semantic/src/types.rs b/crates/ty_python_semantic/src/types.rs index 94c2852790..3c2c475d23 100644 --- a/crates/ty_python_semantic/src/types.rs +++ b/crates/ty_python_semantic/src/types.rs @@ -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>, } +// 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 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> { @@ -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>, } +// 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, } +// 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 { let (scope, place) = self.place_info(db)?; diff --git a/crates/ty_python_semantic/src/types/class.rs b/crates/ty_python_semantic/src/types/class.rs index e479bd020b..d5ef1b9fea 100644 --- a/crates/ty_python_semantic/src/types/class.rs +++ b/crates/ty_python_semantic/src/types/class.rs @@ -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> 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, } +// 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> { 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 { /// Return `true` if the class is cyclically defined. /// @@ -2181,7 +2198,7 @@ impl<'db> From> 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. /// diff --git a/crates/ty_python_semantic/src/types/class_base.rs b/crates/ty_python_semantic/src/types/class_base.rs index 8a9d685693..d738edfaf6 100644 --- a/crates/ty_python_semantic/src/types/class_base.rs +++ b/crates/ty_python_semantic/src/types/class_base.rs @@ -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>), diff --git a/crates/ty_python_semantic/src/types/diagnostic.rs b/crates/ty_python_semantic/src/types/diagnostic.rs index 683b20f9a0..5e0ba48b79 100644 --- a/crates/ty_python_semantic/src/types/diagnostic.rs +++ b/crates/ty_python_semantic/src/types/diagnostic.rs @@ -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, used_suppressions: FxHashSet, diff --git a/crates/ty_python_semantic/src/types/function.rs b/crates/ty_python_semantic/src/types/function.rs index 504f84dbd9..523a09123b 100644 --- a/crates/ty_python_semantic/src/types/function.rs +++ b/crates/ty_python_semantic/src/types/function.rs @@ -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, } +// 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)) } diff --git a/crates/ty_python_semantic/src/types/generics.rs b/crates/ty_python_semantic/src/types/generics.rs index 32c844dc72..983b5caf7d 100644 --- a/crates/ty_python_semantic/src/types/generics.rs +++ b/crates/ty_python_semantic/src/types/generics.rs @@ -30,6 +30,9 @@ pub struct GenericContext<'db> { pub(crate) variables: FxOrderSet>, } +// 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( diff --git a/crates/ty_python_semantic/src/types/infer.rs b/crates/ty_python_semantic/src/types/infer.rs index 7eef066796..f464325d02 100644 --- a/crates/ty_python_semantic/src/types/infer.rs +++ b/crates/ty_python_semantic/src/types/infer.rs @@ -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>, diff --git a/crates/ty_python_semantic/src/types/instance.rs b/crates/ty_python_semantic/src/types/instance.rs index 2ad17b2949..957bb91387 100644 --- a/crates/ty_python_semantic/src/types/instance.rs +++ b/crates/ty_python_semantic/src/types/instance.rs @@ -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> 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> { diff --git a/crates/ty_python_semantic/src/types/mro.rs b/crates/ty_python_semantic/src/types/mro.rs index 4b45888524..632a513b7b 100644 --- a/crates/ty_python_semantic/src/types/mro.rs +++ b/crates/ty_python_semantic/src/types/mro.rs @@ -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>, diff --git a/crates/ty_python_semantic/src/types/narrow.rs b/crates/ty_python_semantic/src/types/narrow.rs index ca03a38f41..dc3dbd68ac 100644 --- a/crates/ty_python_semantic/src/types/narrow.rs +++ b/crates/ty_python_semantic/src/types/narrow.rs @@ -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>, diff --git a/crates/ty_python_semantic/src/types/property_tests/type_generation.rs b/crates/ty_python_semantic/src/types/property_tests/type_generation.rs index 6643ca884e..1f5a69f88d 100644 --- a/crates/ty_python_semantic/src/types/property_tests/type_generation.rs +++ b/crates/ty_python_semantic/src/types/property_tests/type_generation.rs @@ -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>, diff --git a/crates/ty_python_semantic/src/types/protocol_class.rs b/crates/ty_python_semantic/src/types/protocol_class.rs index db8d344d50..2c4b167072 100644 --- a/crates/ty_python_semantic/src/types/protocol_class.rs +++ b/crates/ty_python_semantic/src/types/protocol_class.rs @@ -70,8 +70,12 @@ pub(super) struct ProtocolInterfaceMembers<'db> { inner: BTreeMap>, } +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>, diff --git a/crates/ty_python_semantic/src/types/signatures.rs b/crates/ty_python_semantic/src/types/signatures.rs index 473781f18d..ce8bda10c8 100644 --- a/crates/ty_python_semantic/src/types/signatures.rs +++ b/crates/ty_python_semantic/src/types/signatures.rs @@ -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>, @@ -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>, @@ -1196,7 +1196,7 @@ impl<'db> std::ops::Index 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>, @@ -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, diff --git a/crates/ty_python_semantic/src/types/special_form.rs b/crates/ty_python_semantic/src/types/special_form.rs index be8995018d..f960f3058f 100644 --- a/crates/ty_python_semantic/src/types/special_form.rs +++ b/crates/ty_python_semantic/src/types/special_form.rs @@ -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`) diff --git a/crates/ty_python_semantic/src/types/subclass_of.rs b/crates/ty_python_semantic/src/types/subclass_of.rs index 0351f27cd3..bb16be2a9d 100644 --- a/crates/ty_python_semantic/src/types/subclass_of.rs +++ b/crates/ty_python_semantic/src/types/subclass_of.rs @@ -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), diff --git a/crates/ty_python_semantic/src/types/tuple.rs b/crates/ty_python_semantic/src/types/tuple.rs index b26730334b..48d6a7d536 100644 --- a/crates/ty_python_semantic/src/types/tuple.rs +++ b/crates/ty_python_semantic/src/types/tuple.rs @@ -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 diff --git a/crates/ty_python_semantic/src/types/unpacker.rs b/crates/ty_python_semantic/src/types/unpacker.rs index f963fb0255..3674e55647 100644 --- a/crates/ty_python_semantic/src/types/unpacker.rs +++ b/crates/ty_python_semantic/src/types/unpacker.rs @@ -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>, diagnostics: TypeCheckDiagnostics, diff --git a/crates/ty_python_semantic/src/util/get_size.rs b/crates/ty_python_semantic/src/util/get_size.rs new file mode 100644 index 0000000000..d77cf5c14c --- /dev/null +++ b/crates/ty_python_semantic/src/util/get_size.rs @@ -0,0 +1,15 @@ +use std::sync::Arc; + +use get_size2::GetSize; + +/// By default, `Arc: 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(arc: &Arc) -> usize +where + T: GetSize, +{ + T::get_heap_size(&**arc) +} diff --git a/crates/ty_python_semantic/src/util/mod.rs b/crates/ty_python_semantic/src/util/mod.rs index 54555cd617..5ba24ddaac 100644 --- a/crates/ty_python_semantic/src/util/mod.rs +++ b/crates/ty_python_semantic/src/util/mod.rs @@ -1,2 +1,3 @@ pub(crate) mod diagnostics; +pub(crate) mod get_size; pub(crate) mod subscript; diff --git a/fuzz/Cargo.toml b/fuzz/Cargo.toml index e5b2572349..0df27e82b9 100644 --- a/fuzz/Cargo.toml +++ b/fuzz/Cargo.toml @@ -30,7 +30,7 @@ ty_python_semantic = { path = "../crates/ty_python_semantic" } ty_vendored = { path = "../crates/ty_vendored" } libfuzzer-sys = { git = "https://github.com/rust-fuzz/libfuzzer", default-features = false } -salsa = { git = "https://github.com/salsa-rs/salsa.git", rev = "09627e450566f894956710a3fd923dc80462ae6d" } +salsa = { git = "https://github.com/salsa-rs/salsa", rev = "0666e2018bc35376b1ac4f98906f2d04d11e5fe4" } similar = { version = "2.5.0" } tracing = { version = "0.1.40" }