1515 TYPE_VAR_PREFIX ,
1616)
1717from mypyc .ir .class_ir import ClassIR
18- from mypyc .ir .func_ir import FUNC_CLASSMETHOD , FUNC_STATICMETHOD , FuncDecl , FuncIR , all_values
18+ from mypyc .ir .func_ir import FUNC_CLASSMETHOD , FUNC_STATICMETHOD , FuncDecl , FuncIR , all_values , FUNC_NORMAL
1919from mypyc .ir .ops import (
2020 ERR_FALSE ,
2121 NAMESPACE_MODULE ,
7171)
7272from mypyc .ir .pprint import generate_names_for_ir
7373from mypyc .ir .rtypes import (
74- PyObject ,
7574 RArray ,
7675 RInstance ,
7776 RInstanceValue ,
7877 RStruct ,
7978 RTuple ,
8079 RType ,
81- c_pyssize_t_rprimitive ,
8280 is_int32_rprimitive ,
8381 is_int64_rprimitive ,
8482 is_int_rprimitive ,
8785)
8886
8987
90- def struct_type (class_ir : ClassIR , emitter : Emitter ) -> RStruct :
91- """Return the struct type for this instance type."""
92- python_fields : list [tuple [str , RType ]] = [
93- ("head" , PyObject ),
94- ("vtable" , c_pyssize_t_rprimitive ),
95- ]
96- class_fields = list (class_ir .attributes .items ())
97- attr_names = [emitter .attr (name ) for name , _ in python_fields + class_fields ]
98- attr_types = [rtype for _ , rtype in python_fields + class_fields ]
99- return RStruct (class_ir .struct_name (emitter .names ), attr_names , attr_types )
100-
101-
10288def native_function_type (fn : FuncIR , emitter : Emitter ) -> str :
10389 args = ", " .join (emitter .ctype (arg .type ) for arg in fn .args ) or "void"
10490 ret = emitter .ctype (fn .ret_type )
@@ -295,7 +281,7 @@ def visit_assign(self, op: Assign) -> None:
295281 # clang whines about self assignment (which we might generate
296282 # for some casts), so don't emit it.
297283 if dest != src :
298- # We sometimes assign from an integer prepresentation of a pointer
284+ # We sometimes assign from an integer representation of a pointer
299285 # to a real pointer, and C compilers insist on a cast.
300286 if op .src .type .is_unboxed and not op .dest .type .is_unboxed :
301287 src = f"(void *){ src } "
@@ -406,20 +392,12 @@ def visit_get_attr(self, op: GetAttr) -> None:
406392 attr_expr = self .get_attr_expr (obj , op , decl_cl )
407393 always_defined = cl .is_always_defined (op .attr )
408394 # This steals the reference to src, so we don't need to increment the arg
409- if isinstance (attr_rtype , RInstance ) and attr_rtype .class_ir .is_value_type :
410- # special case for value types, it is unboxed in the struct
411- struct_name = attr_rtype .class_ir .struct_name (self .names )
412- temp = self .emitter .temp_name ()
413- self .emitter .emit_line (f"{ struct_name } { temp } = { attr_expr } ;" )
414- self .emitter .emit_line (f"{ dest } = (PyObject *)&{ temp } ;" )
415- always_defined = True
416- else :
417- self .emitter .emit_line (f"{ dest } = { attr_expr } ;" )
395+ self .emitter .emit_line (f"{ dest } = { attr_expr } ;" )
418396
419397 merged_branch = None
420398 if not always_defined :
421399 self .emitter .emit_undefined_attr_check (
422- attr_rtype , dest , "==" , obj , op .attr , cl , unlikely = True
400+ attr_rtype , dest , "==" , obj , op .attr , rtype , unlikely = True
423401 )
424402 branch = self .next_branch ()
425403 if branch is not None :
@@ -466,7 +444,8 @@ def visit_set_attr(self, op: SetAttr) -> None:
466444 dest = self .reg (op )
467445 obj = self .reg (op .obj )
468446 src = self .reg (op .src )
469- rtype = op .class_type
447+ rtype = op .obj .type
448+ assert isinstance (rtype , RInstance )
470449 cl = rtype .class_ir
471450 attr_rtype , decl_cl = cl .attr_details (op .attr )
472451 if cl .get_method (op .attr ):
@@ -501,23 +480,18 @@ def visit_set_attr(self, op: SetAttr) -> None:
501480 always_defined = cl .is_always_defined (op .attr )
502481 if not always_defined :
503482 self .emitter .emit_undefined_attr_check (
504- attr_rtype , attr_expr , "!=" , obj , op .attr , cl
483+ attr_rtype , attr_expr , "!=" , obj , op .attr , rtype
505484 )
506485 self .emitter .emit_dec_ref (attr_expr , attr_rtype )
507486 if not always_defined :
508487 self .emitter .emit_line ("}" )
509488 elif attr_rtype .error_overlap and not cl .is_always_defined (op .attr ):
510489 # If there is overlap with the error value, update bitmap to mark
511490 # attribute as defined.
512- self .emitter .emit_attr_bitmap_set (src , obj , attr_rtype , cl , op .attr )
491+ self .emitter .emit_attr_bitmap_set (src , obj , attr_rtype , rtype , op .attr )
513492
514493 # This steals the reference to src, so we don't need to increment the arg
515- if isinstance (attr_rtype , RInstance ) and attr_rtype .class_ir .is_value_type :
516- # special case for value types, it is unboxed in the struct
517- struct_name = attr_rtype .class_ir .struct_name (self .names )
518- self .emitter .emit_line (f"{ attr_expr } = *({ struct_name } *)({ src } );" )
519- else :
520- self .emitter .emit_line (f"{ attr_expr } = { src } ;" )
494+ self .emitter .emit_line (f"{ attr_expr } = { src } ;" )
521495 if op .error_kind == ERR_FALSE :
522496 self .emitter .emit_line (f"{ dest } = 1;" )
523497
@@ -589,6 +563,20 @@ def emit_method_call(self, dest: str, op_obj: Value, name: str, op_args: list[Va
589563 if method .decl .kind == FUNC_STATICMETHOD
590564 else [f"(PyObject *)Py_TYPE({ obj } )" ] if method .decl .kind == FUNC_CLASSMETHOD else [obj ]
591565 )
566+ need_box_obj = (
567+ method .decl .kind == FUNC_NORMAL
568+ and rtype .is_unboxed
569+ and not method .args [0 ].type .is_unboxed
570+ )
571+ obj_boxed = ""
572+ if need_box_obj :
573+ # for cases where obj.method(...) is called and obj is unboxed, but method
574+ # expects a boxed due inheritance or trait. e.g. obj is a value type
575+ # but method comes from a parent which not
576+ obj_boxed = self .temp_name ()
577+ self .emitter .emit_box (obj , obj_boxed , rtype , declare_dest = True )
578+ obj_args = [obj_boxed ]
579+
592580 args = ", " .join (obj_args + [self .reg (arg ) for arg in op_args ])
593581 mtype = native_function_type (method , self .emitter )
594582 version = "_TRAIT" if rtype .class_ir .is_trait else ""
@@ -613,6 +601,9 @@ def emit_method_call(self, dest: str, op_obj: Value, name: str, op_args: list[Va
613601 )
614602 )
615603
604+ if need_box_obj :
605+ self .emitter .emit_dec_ref (obj_boxed , RInstance (rtype .class_ir ))
606+
616607 def visit_inc_ref (self , op : IncRef ) -> None :
617608 src = self .reg (op .src )
618609 self .emit_inc_ref (src , op .src .type )
0 commit comments