@@ -1596,7 +1596,7 @@ impl<'db> ClassLiteral<'db> {
15961596
15971597 let field_policy = CodeGeneratorKind :: from_class ( db, self ) ?;
15981598
1599- let signature_from_fields = |mut parameters : Vec < _ > | {
1599+ let signature_from_fields = |mut parameters : Vec < _ > , return_ty : Option < Type < ' db > > | {
16001600 let mut kw_only_field_seen = false ;
16011601 for (
16021602 field_name,
@@ -1669,21 +1669,27 @@ impl<'db> ClassLiteral<'db> {
16691669 }
16701670 }
16711671
1672- let mut parameter = if kw_only_field_seen {
1672+ // For the `__replace__` signature, force to kw only
1673+ let mut parameter = if kw_only_field_seen || name == "__replace__" {
16731674 Parameter :: keyword_only ( field_name)
16741675 } else {
16751676 Parameter :: positional_or_keyword ( field_name)
16761677 }
16771678 . with_annotated_type ( field_ty) ;
16781679
1679- if let Some ( default_ty) = default_ty {
1680+ if name == "__replace__" {
1681+ // When replacing, we know there is a default value for the field
1682+ // (the value that is currently assigned to the field)
1683+ // assume this to be the declared type of the field
1684+ parameter = parameter. with_default_type ( field_ty) ;
1685+ } else if let Some ( default_ty) = default_ty {
16801686 parameter = parameter. with_default_type ( default_ty) ;
16811687 }
16821688
16831689 parameters. push ( parameter) ;
16841690 }
16851691
1686- let mut signature = Signature :: new ( Parameters :: new ( parameters) , Some ( Type :: none ( db ) ) ) ;
1692+ let mut signature = Signature :: new ( Parameters :: new ( parameters) , return_ty ) ;
16871693 signature. inherited_generic_context = self . generic_context ( db) ;
16881694 Some ( CallableType :: function_like ( db, signature) )
16891695 } ;
@@ -1705,12 +1711,12 @@ impl<'db> ClassLiteral<'db> {
17051711 db,
17061712 self . apply_optional_specialization ( db, specialization) ,
17071713 ) ) ;
1708- signature_from_fields ( vec ! [ self_parameter] )
1714+ signature_from_fields ( vec ! [ self_parameter] , Some ( Type :: none ( db ) ) )
17091715 }
17101716 ( CodeGeneratorKind :: NamedTuple , "__new__" ) => {
17111717 let cls_parameter = Parameter :: positional_or_keyword ( Name :: new_static ( "cls" ) )
17121718 . with_annotated_type ( KnownClass :: Type . to_instance ( db) ) ;
1713- signature_from_fields ( vec ! [ cls_parameter] )
1719+ signature_from_fields ( vec ! [ cls_parameter] , Some ( Type :: none ( db ) ) )
17141720 }
17151721 ( CodeGeneratorKind :: DataclassLike , "__lt__" | "__le__" | "__gt__" | "__ge__" ) => {
17161722 if !has_dataclass_param ( DataclassParams :: ORDER ) {
@@ -1745,6 +1751,18 @@ impl<'db> ClassLiteral<'db> {
17451751 . place
17461752 . ignore_possibly_unbound ( )
17471753 }
1754+ ( CodeGeneratorKind :: DataclassLike , "__replace__" )
1755+ if Program :: get ( db) . python_version ( db) >= PythonVersion :: PY313 =>
1756+ {
1757+ let self_parameter =
1758+ Parameter :: positional_or_keyword ( Name :: new_static ( "self" ) ) . with_annotated_type (
1759+ Type :: instance ( db, self . apply_optional_specialization ( db, specialization) ) ,
1760+ ) ;
1761+ let instance_ty =
1762+ Type :: instance ( db, self . apply_optional_specialization ( db, specialization) ) ;
1763+
1764+ signature_from_fields ( vec ! [ self_parameter] , Some ( instance_ty) )
1765+ }
17481766 ( CodeGeneratorKind :: DataclassLike , "__setattr__" ) => {
17491767 if has_dataclass_param ( DataclassParams :: FROZEN ) {
17501768 let signature = Signature :: new (
0 commit comments