4242 Integer ,
4343 RaiseStandardError ,
4444 Register ,
45+ SetAttr ,
4546 Truncate ,
4647 Unreachable ,
4748 Value ,
100101 isinstance_dict ,
101102)
102103from mypyc .primitives .float_ops import isinstance_float
104+ from mypyc .primitives .generic_ops import generic_setattr
103105from mypyc .primitives .int_ops import isinstance_int
104106from mypyc .primitives .list_ops import isinstance_list , new_list_set_item_op
105107from mypyc .primitives .misc_ops import isinstance_bool
@@ -1051,19 +1053,24 @@ def translate_ord(builder: IRBuilder, expr: CallExpr, callee: RefExpr) -> Value
10511053 return None
10521054
10531055
1054- @specialize_function ("__new__" , object_rprimitive )
1055- def translate_object_new (builder : IRBuilder , expr : CallExpr , callee : RefExpr ) -> Value | None :
1056- fn = builder .fn_info
1057- if fn .name != "__new__" :
1058- return None
1059-
1060- is_super_new = isinstance (expr .callee , SuperExpr )
1061- is_object_new = (
1056+ def is_object (callee : RefExpr ) -> bool :
1057+ """Returns True for object.<name> calls."""
1058+ return (
10621059 isinstance (callee , MemberExpr )
10631060 and isinstance (callee .expr , NameExpr )
10641061 and callee .expr .fullname == "builtins.object"
10651062 )
1066- if not (is_super_new or is_object_new ):
1063+
1064+
1065+ def is_super_or_object (expr : CallExpr , callee : RefExpr ) -> bool :
1066+ """Returns True for super().<name> or object.<name> calls."""
1067+ return isinstance (expr .callee , SuperExpr ) or is_object (callee )
1068+
1069+
1070+ @specialize_function ("__new__" , object_rprimitive )
1071+ def translate_object_new (builder : IRBuilder , expr : CallExpr , callee : RefExpr ) -> Value | None :
1072+ fn = builder .fn_info
1073+ if fn .name != "__new__" or not is_super_or_object (expr , callee ):
10671074 return None
10681075
10691076 ir = builder .get_current_class_ir ()
@@ -1090,3 +1097,30 @@ def translate_object_new(builder: IRBuilder, expr: CallExpr, callee: RefExpr) ->
10901097 return builder .add (Call (ir .setup , [subtype ], expr .line ))
10911098
10921099 return None
1100+
1101+
1102+ @specialize_function ("__setattr__" , object_rprimitive )
1103+ def translate_object_setattr (builder : IRBuilder , expr : CallExpr , callee : RefExpr ) -> Value | None :
1104+ is_super = isinstance (expr .callee , SuperExpr )
1105+ is_object_callee = is_object (callee )
1106+ if not ((is_super and len (expr .args ) >= 2 ) or (is_object_callee and len (expr .args ) >= 3 )):
1107+ return None
1108+
1109+ self_reg = builder .accept (expr .args [0 ]) if is_object_callee else builder .self ()
1110+ ir = builder .get_current_class_ir ()
1111+ if ir and (not ir .is_ext_class or ir .builtin_base or ir .inherits_python ):
1112+ return None
1113+ # Need to offset by 1 for super().__setattr__ calls because there is no self arg in this case.
1114+ name_idx = 0 if is_super else 1
1115+ value_idx = 1 if is_super else 2
1116+ attr_name = expr .args [name_idx ]
1117+ attr_value = expr .args [value_idx ]
1118+ value = builder .accept (attr_value )
1119+
1120+ if isinstance (attr_name , StrExpr ) and ir and ir .has_attr (attr_name .value ):
1121+ name = attr_name .value
1122+ value = builder .coerce (value , ir .attributes [name ], expr .line )
1123+ return builder .add (SetAttr (self_reg , name , value , expr .line ))
1124+
1125+ name_reg = builder .accept (attr_name )
1126+ return builder .call_c (generic_setattr , [self_reg , name_reg , value ], expr .line )
0 commit comments