Skip to content

Commit 3288ac2

Browse files
authored
[ty] Add caching to CodeGeneratorKind::matches() (#19912)
1 parent 1167ed6 commit 3288ac2

File tree

1 file changed

+49
-22
lines changed
  • crates/ty_python_semantic/src/types

1 file changed

+49
-22
lines changed

crates/ty_python_semantic/src/types/class.rs

Lines changed: 49 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -168,7 +168,7 @@ fn try_metaclass_cycle_initial<'db>(
168168
}
169169

170170
/// A category of classes with code generation capabilities (with synthesized methods).
171-
#[derive(Clone, Copy, Debug, PartialEq)]
171+
#[derive(Clone, Copy, Debug, PartialEq, salsa::Update, get_size2::GetSize)]
172172
pub(crate) enum CodeGeneratorKind {
173173
/// Classes decorated with `@dataclass` or similar dataclass-like decorators
174174
DataclassLike,
@@ -180,31 +180,58 @@ pub(crate) enum CodeGeneratorKind {
180180

181181
impl CodeGeneratorKind {
182182
pub(crate) fn from_class(db: &dyn Db, class: ClassLiteral<'_>) -> Option<Self> {
183-
if CodeGeneratorKind::DataclassLike.matches(db, class) {
184-
Some(CodeGeneratorKind::DataclassLike)
185-
} else if CodeGeneratorKind::NamedTuple.matches(db, class) {
186-
Some(CodeGeneratorKind::NamedTuple)
187-
} else if CodeGeneratorKind::TypedDict.matches(db, class) {
188-
Some(CodeGeneratorKind::TypedDict)
189-
} else {
183+
#[salsa::tracked(
184+
cycle_fn=code_generator_of_class_recover,
185+
cycle_initial=code_generator_of_class_initial,
186+
heap_size=ruff_memory_usage::heap_size
187+
)]
188+
fn code_generator_of_class<'db>(
189+
db: &'db dyn Db,
190+
class: ClassLiteral<'db>,
191+
) -> Option<CodeGeneratorKind> {
192+
if class.dataclass_params(db).is_some()
193+
|| class
194+
.try_metaclass(db)
195+
.is_ok_and(|(_, transformer_params)| transformer_params.is_some())
196+
{
197+
Some(CodeGeneratorKind::DataclassLike)
198+
} else if class
199+
.explicit_bases(db)
200+
.iter()
201+
.copied()
202+
.filter_map(Type::into_class_literal)
203+
.any(|class| class.is_known(db, KnownClass::NamedTuple))
204+
{
205+
Some(CodeGeneratorKind::NamedTuple)
206+
} else if class.is_typed_dict(db) {
207+
Some(CodeGeneratorKind::TypedDict)
208+
} else {
209+
None
210+
}
211+
}
212+
213+
fn code_generator_of_class_initial(
214+
_db: &dyn Db,
215+
_class: ClassLiteral<'_>,
216+
) -> Option<CodeGeneratorKind> {
190217
None
191218
}
192-
}
193219

194-
fn matches<'db>(self, db: &'db dyn Db, class: ClassLiteral<'db>) -> bool {
195-
match self {
196-
Self::DataclassLike => {
197-
class.dataclass_params(db).is_some()
198-
|| class
199-
.try_metaclass(db)
200-
.is_ok_and(|(_, transformer_params)| transformer_params.is_some())
201-
}
202-
Self::NamedTuple => class.explicit_bases(db).iter().any(|base| {
203-
base.into_class_literal()
204-
.is_some_and(|c| c.is_known(db, KnownClass::NamedTuple))
205-
}),
206-
Self::TypedDict => class.is_typed_dict(db),
220+
#[expect(clippy::ref_option, clippy::trivially_copy_pass_by_ref)]
221+
fn code_generator_of_class_recover(
222+
_db: &dyn Db,
223+
_value: &Option<CodeGeneratorKind>,
224+
_count: u32,
225+
_class: ClassLiteral<'_>,
226+
) -> salsa::CycleRecoveryAction<Option<CodeGeneratorKind>> {
227+
salsa::CycleRecoveryAction::Iterate
207228
}
229+
230+
code_generator_of_class(db, class)
231+
}
232+
233+
fn matches(self, db: &dyn Db, class: ClassLiteral<'_>) -> bool {
234+
CodeGeneratorKind::from_class(db, class) == Some(self)
208235
}
209236
}
210237

0 commit comments

Comments
 (0)