Skip to content

Commit a8a0614

Browse files
[ty] Avoid retaining duplicate function signatures (#25609)
## Summary A `FunctionType` currently retains a potentially updated public callable signature and a potentially updated signature for its last definition. For ordinary functions and overload-only functions, the last definition is already part of the public callable signature; only an overloaded function with a separate implementation needs an additional retained signature. Represent the additional field as an implementation-only signature. Ordinary functions and overload-only functions recover their last-definition signature from the updated public signature, while overloaded functions with a separate implementation continue to retain that implementation signature explicitly.
1 parent d14149d commit a8a0614

1 file changed

Lines changed: 44 additions & 27 deletions

File tree

crates/ty_python_semantic/src/types/function.rs

Lines changed: 44 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -786,6 +786,11 @@ impl<'db> FunctionLiteral<'db> {
786786
(overloads.as_ref(), *implementation)
787787
}
788788

789+
fn has_separate_implementation(self, db: &'db dyn Db) -> bool {
790+
!self.last_definition.is_overload(db)
791+
&& self.last_definition.previous_overload(db).is_some()
792+
}
793+
789794
fn iter_overloads_and_implementation(
790795
self,
791796
db: &'db dyn Db,
@@ -958,12 +963,12 @@ pub struct FunctionType<'db> {
958963
#[returns(as_ref)]
959964
updated_signature: Option<CallableSignature<'db>>,
960965

961-
/// Contains a potentially modified signature for the last overload or the implementation of this
962-
/// function literal, in case certain operations (like type mappings) have been applied to it.
966+
/// Contains a potentially modified signature for the implementation of an overloaded function,
967+
/// in case certain operations (like type mappings) have been applied to it.
963968
///
964969
/// See also: [`FunctionLiteral::last_definition_signature`].
965970
#[returns(as_ref)]
966-
updated_last_definition_signature: Option<Signature<'db>>,
971+
updated_implementation_signature: Option<Signature<'db>>,
967972
}
968973

969974
// The Salsa heap is tracked separately.
@@ -979,7 +984,7 @@ pub(super) fn walk_function_type<'db, V: super::visitor::TypeVisitor<'db> + ?Siz
979984
walk_signature(db, signature, visitor);
980985
}
981986
}
982-
if let Some(signature) = function.updated_last_definition_signature(db) {
987+
if let Some(signature) = function.updated_implementation_signature(db) {
983988
walk_signature(db, signature, visitor);
984989
}
985990
}
@@ -994,15 +999,17 @@ impl<'db> FunctionType<'db> {
994999
let updated_signature = self
9951000
.signature(db)
9961001
.with_inherited_generic_context(db, inherited_generic_context);
997-
let updated_last_definition_signature = self
998-
.last_definition_signature(db)
999-
.clone()
1000-
.with_inherited_generic_context(db, inherited_generic_context);
1002+
let literal = self.literal(db);
1003+
let updated_implementation_signature = literal.has_separate_implementation(db).then(|| {
1004+
self.last_definition_signature(db)
1005+
.clone()
1006+
.with_inherited_generic_context(db, inherited_generic_context)
1007+
});
10011008
Self::new(
10021009
db,
1003-
self.literal(db),
1010+
literal,
10041011
Some(updated_signature),
1005-
Some(updated_last_definition_signature),
1012+
updated_implementation_signature,
10061013
)
10071014
}
10081015

@@ -1015,7 +1022,8 @@ impl<'db> FunctionType<'db> {
10151022
) -> Self {
10161023
// Returned-callable rescoping and type-alias specialization should not rebuild signatures from the
10171024
// function literal; doing so can re-enter recursive `TypeOf` evaluation.
1018-
let (updated_signature, updated_last_definition_signature) = if matches!(
1025+
let literal = self.literal(db);
1026+
let (updated_signature, updated_implementation_signature) = if matches!(
10191027
type_mapping,
10201028
TypeMapping::ApplySpecialization(
10211029
ApplySpecialization::ReturnCallables(_) | ApplySpecialization::TypeAlias(_)
@@ -1029,7 +1037,7 @@ impl<'db> FunctionType<'db> {
10291037
self.updated_signature(db).map(|signature| {
10301038
signature.apply_type_mapping_impl(db, type_mapping, tcx, visitor)
10311039
}),
1032-
self.updated_last_definition_signature(db).map(|signature| {
1040+
self.updated_implementation_signature(db).map(|signature| {
10331041
signature.apply_type_mapping_impl(db, type_mapping, tcx, visitor)
10341042
}),
10351043
)
@@ -1039,23 +1047,25 @@ impl<'db> FunctionType<'db> {
10391047
self.signature(db)
10401048
.apply_type_mapping_impl(db, type_mapping, tcx, visitor),
10411049
),
1042-
Some(self.last_definition_signature(db).apply_type_mapping_impl(
1043-
db,
1044-
type_mapping,
1045-
tcx,
1046-
visitor,
1047-
)),
1050+
literal.has_separate_implementation(db).then(|| {
1051+
self.last_definition_signature(db).apply_type_mapping_impl(
1052+
db,
1053+
type_mapping,
1054+
tcx,
1055+
visitor,
1056+
)
1057+
}),
10481058
)
10491059
};
10501060

1051-
if updated_signature.is_none() && updated_last_definition_signature.is_none() {
1061+
if updated_signature.is_none() && updated_implementation_signature.is_none() {
10521062
self
10531063
} else {
10541064
Self::new(
10551065
db,
1056-
self.literal(db),
1066+
literal,
10571067
updated_signature,
1058-
updated_last_definition_signature,
1068+
updated_implementation_signature,
10591069
)
10601070
}
10611071
}
@@ -1317,9 +1327,16 @@ impl<'db> FunctionType<'db> {
13171327
heap_size=ruff_memory_usage::heap_size,
13181328
)]
13191329
pub(crate) fn last_definition_signature(self, db: &'db dyn Db) -> Signature<'db> {
1320-
self.updated_last_definition_signature(db)
1321-
.cloned()
1322-
.unwrap_or_else(|| self.literal(db).last_definition_signature(db))
1330+
let literal = self.literal(db);
1331+
if literal.has_separate_implementation(db) {
1332+
self.updated_implementation_signature(db)
1333+
.cloned()
1334+
.unwrap_or_else(|| literal.last_definition_signature(db))
1335+
} else {
1336+
self.updated_signature(db)
1337+
.and_then(|signature| signature.overloads.last().cloned())
1338+
.unwrap_or_else(|| literal.last_definition_signature(db))
1339+
}
13231340
}
13241341

13251342
/// Typed externally-visible "raw" signature of the last overload or implementation of this function.
@@ -1402,8 +1419,8 @@ impl<'db> FunctionType<'db> {
14021419
}
14031420
None => None,
14041421
};
1405-
let updated_last_definition_signature =
1406-
match self.updated_last_definition_signature(db) {
1422+
let updated_implementation_signature =
1423+
match self.updated_implementation_signature(db) {
14071424
Some(signature) => {
14081425
Some(signature.recursive_type_normalized_impl(db, div, nested)?)
14091426
}
@@ -1413,7 +1430,7 @@ impl<'db> FunctionType<'db> {
14131430
db,
14141431
literal,
14151432
updated_signature,
1416-
updated_last_definition_signature,
1433+
updated_implementation_signature,
14171434
))
14181435
},
14191436
)

0 commit comments

Comments
 (0)