@@ -1592,7 +1592,9 @@ impl<'db> ClassLiteral<'db> {
15921592
15931593 let field_policy = CodeGeneratorKind :: from_class ( db, self ) ?;
15941594
1595- let signature_from_fields = |mut parameters : Vec < _ > | {
1595+ let signature_from_fields = |mut parameters : Vec < _ > ,
1596+ return_ty : Option < Type < ' db > > ,
1597+ for_replace : bool | {
15961598 let mut kw_only_field_seen = false ;
15971599 for (
15981600 field_name,
@@ -1659,21 +1661,27 @@ impl<'db> ClassLiteral<'db> {
16591661 }
16601662 }
16611663
1662- let mut parameter = if kw_only_field_seen {
1664+ // For the `__replace__` signature, force to kw only
1665+ let mut parameter = if kw_only_field_seen || for_replace {
16631666 Parameter :: keyword_only ( field_name)
16641667 } else {
16651668 Parameter :: positional_or_keyword ( field_name)
16661669 }
16671670 . with_annotated_type ( field_ty) ;
16681671
1669- if let Some ( default_ty) = default_ty {
1672+ // When replacing, we know there is a default value for the field
1673+ // (the value that is currently assigned to the field)
1674+ // assume this to be the declared type of the field
1675+ if for_replace {
1676+ parameter = parameter. with_default_type ( field_ty) ;
1677+ } else if let Some ( default_ty) = default_ty {
16701678 parameter = parameter. with_default_type ( default_ty) ;
16711679 }
16721680
16731681 parameters. push ( parameter) ;
16741682 }
16751683
1676- let mut signature = Signature :: new ( Parameters :: new ( parameters) , Some ( Type :: none ( db ) ) ) ;
1684+ let mut signature = Signature :: new ( Parameters :: new ( parameters) , return_ty ) ;
16771685 signature. inherited_generic_context = self . generic_context ( db) ;
16781686 Some ( CallableType :: function_like ( db, signature) )
16791687 } ;
@@ -1695,12 +1703,12 @@ impl<'db> ClassLiteral<'db> {
16951703 db,
16961704 self . apply_optional_specialization ( db, specialization) ,
16971705 ) ) ;
1698- signature_from_fields ( vec ! [ self_parameter] )
1706+ signature_from_fields ( vec ! [ self_parameter] , Some ( Type :: none ( db ) ) , false )
16991707 }
17001708 ( CodeGeneratorKind :: NamedTuple , "__new__" ) => {
17011709 let cls_parameter = Parameter :: positional_or_keyword ( Name :: new_static ( "cls" ) )
17021710 . with_annotated_type ( KnownClass :: Type . to_instance ( db) ) ;
1703- signature_from_fields ( vec ! [ cls_parameter] )
1711+ signature_from_fields ( vec ! [ cls_parameter] , Some ( Type :: none ( db ) ) , false )
17041712 }
17051713 ( CodeGeneratorKind :: DataclassLike , "__lt__" | "__le__" | "__gt__" | "__ge__" ) => {
17061714 if !has_dataclass_param ( DataclassParams :: ORDER ) {
@@ -1735,6 +1743,20 @@ impl<'db> ClassLiteral<'db> {
17351743 . place
17361744 . ignore_possibly_unbound ( )
17371745 }
1746+ ( CodeGeneratorKind :: DataclassLike , "__replace__" ) => {
1747+ if Program :: get ( db) . python_version ( db) < PythonVersion :: PY313 {
1748+ return None ;
1749+ }
1750+
1751+ let self_parameter =
1752+ Parameter :: positional_or_keyword ( Name :: new_static ( "self" ) ) . with_annotated_type (
1753+ Type :: instance ( db, self . apply_optional_specialization ( db, specialization) ) ,
1754+ ) ;
1755+ let instance_ty =
1756+ Type :: instance ( db, self . apply_optional_specialization ( db, specialization) ) ;
1757+
1758+ signature_from_fields ( vec ! [ self_parameter] , Some ( instance_ty) , true )
1759+ }
17381760 ( CodeGeneratorKind :: DataclassLike , "__setattr__" ) => {
17391761 if has_dataclass_param ( DataclassParams :: FROZEN ) {
17401762 let signature = Signature :: new (
0 commit comments