4242 Integer ,
4343 RaiseStandardError ,
4444 Register ,
45+ SetAttr ,
4546 Truncate ,
4647 Unreachable ,
4748 Value ,
9798 isinstance_dict ,
9899)
99100from mypyc .primitives .float_ops import isinstance_float
101+ from mypyc .primitives .generic_ops import generic_setattr
100102from mypyc .primitives .int_ops import isinstance_int
101103from mypyc .primitives .list_ops import isinstance_list , new_list_set_item_op
102104from mypyc .primitives .misc_ops import isinstance_bool
@@ -1007,19 +1009,24 @@ def translate_ord(builder: IRBuilder, expr: CallExpr, callee: RefExpr) -> Value
10071009 return None
10081010
10091011
1010- @specialize_function ("__new__" , object_rprimitive )
1011- def translate_object_new (builder : IRBuilder , expr : CallExpr , callee : RefExpr ) -> Value | None :
1012- fn = builder .fn_info
1013- if fn .name != "__new__" :
1014- return None
1015-
1016- is_super_new = isinstance (expr .callee , SuperExpr )
1017- is_object_new = (
1012+ def is_object (callee : RefExpr ) -> bool :
1013+ """Returns True for object.<name> calls."""
1014+ return (
10181015 isinstance (callee , MemberExpr )
10191016 and isinstance (callee .expr , NameExpr )
10201017 and callee .expr .fullname == "builtins.object"
10211018 )
1022- if not (is_super_new or is_object_new ):
1019+
1020+
1021+ def is_super_or_object (expr : CallExpr , callee : RefExpr ) -> bool :
1022+ """Returns True for super().<name> or object.<name> calls."""
1023+ return isinstance (expr .callee , SuperExpr ) or is_object (callee )
1024+
1025+
1026+ @specialize_function ("__new__" , object_rprimitive )
1027+ def translate_object_new (builder : IRBuilder , expr : CallExpr , callee : RefExpr ) -> Value | None :
1028+ fn = builder .fn_info
1029+ if fn .name != "__new__" or not is_super_or_object (expr , callee ):
10231030 return None
10241031
10251032 ir = builder .get_current_class_ir ()
@@ -1046,3 +1053,30 @@ def translate_object_new(builder: IRBuilder, expr: CallExpr, callee: RefExpr) ->
10461053 return builder .add (Call (ir .setup , [subtype ], expr .line ))
10471054
10481055 return None
1056+
1057+
1058+ @specialize_function ("__setattr__" , object_rprimitive )
1059+ def translate_object_setattr (builder : IRBuilder , expr : CallExpr , callee : RefExpr ) -> Value | None :
1060+ is_super = isinstance (expr .callee , SuperExpr )
1061+ is_object_callee = is_object (callee )
1062+ if not ((is_super and len (expr .args ) >= 2 ) or (is_object_callee and len (expr .args ) >= 3 )):
1063+ return None
1064+
1065+ self_reg = builder .accept (expr .args [0 ]) if is_object_callee else builder .self ()
1066+ ir = builder .get_current_class_ir ()
1067+ if ir and (not ir .is_ext_class or ir .builtin_base or ir .inherits_python ):
1068+ return None
1069+ # Need to offset by 1 for super().__setattr__ calls because there is no self arg in this case.
1070+ name_idx = 0 if is_super else 1
1071+ value_idx = 1 if is_super else 2
1072+ attr_name = expr .args [name_idx ]
1073+ attr_value = expr .args [value_idx ]
1074+ value = builder .accept (attr_value )
1075+
1076+ if isinstance (attr_name , StrExpr ) and ir and ir .has_attr (attr_name .value ):
1077+ name = attr_name .value
1078+ value = builder .coerce (value , ir .attributes [name ], expr .line )
1079+ return builder .add (SetAttr (self_reg , name , value , expr .line ))
1080+
1081+ name_reg = builder .accept (attr_name )
1082+ return builder .call_c (generic_setattr , [self_reg , name_reg , value ], expr .line )
0 commit comments