42
42
Integer ,
43
43
RaiseStandardError ,
44
44
Register ,
45
+ SetAttr ,
45
46
Truncate ,
46
47
Unreachable ,
47
48
Value ,
100
101
isinstance_dict ,
101
102
)
102
103
from mypyc .primitives .float_ops import isinstance_float
104
+ from mypyc .primitives .generic_ops import generic_setattr
103
105
from mypyc .primitives .int_ops import isinstance_int
104
106
from mypyc .primitives .list_ops import isinstance_list , new_list_set_item_op
105
107
from mypyc .primitives .misc_ops import isinstance_bool
@@ -1051,19 +1053,24 @@ def translate_ord(builder: IRBuilder, expr: CallExpr, callee: RefExpr) -> Value
1051
1053
return None
1052
1054
1053
1055
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 (
1062
1059
isinstance (callee , MemberExpr )
1063
1060
and isinstance (callee .expr , NameExpr )
1064
1061
and callee .expr .fullname == "builtins.object"
1065
1062
)
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 ):
1067
1074
return None
1068
1075
1069
1076
ir = builder .get_current_class_ir ()
@@ -1090,3 +1097,30 @@ def translate_object_new(builder: IRBuilder, expr: CallExpr, callee: RefExpr) ->
1090
1097
return builder .add (Call (ir .setup , [subtype ], expr .line ))
1091
1098
1092
1099
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