15
15
TYPE_VAR_PREFIX ,
16
16
)
17
17
from 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
19
19
from mypyc .ir .ops import (
20
20
ERR_FALSE ,
21
21
NAMESPACE_MODULE ,
71
71
)
72
72
from mypyc .ir .pprint import generate_names_for_ir
73
73
from mypyc .ir .rtypes import (
74
- PyObject ,
75
74
RArray ,
76
75
RInstance ,
77
76
RInstanceValue ,
78
77
RStruct ,
79
78
RTuple ,
80
79
RType ,
81
- c_pyssize_t_rprimitive ,
82
80
is_int32_rprimitive ,
83
81
is_int64_rprimitive ,
84
82
is_int_rprimitive ,
87
85
)
88
86
89
87
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
-
102
88
def native_function_type (fn : FuncIR , emitter : Emitter ) -> str :
103
89
args = ", " .join (emitter .ctype (arg .type ) for arg in fn .args ) or "void"
104
90
ret = emitter .ctype (fn .ret_type )
@@ -295,7 +281,7 @@ def visit_assign(self, op: Assign) -> None:
295
281
# clang whines about self assignment (which we might generate
296
282
# for some casts), so don't emit it.
297
283
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
299
285
# to a real pointer, and C compilers insist on a cast.
300
286
if op .src .type .is_unboxed and not op .dest .type .is_unboxed :
301
287
src = f"(void *){ src } "
@@ -406,20 +392,12 @@ def visit_get_attr(self, op: GetAttr) -> None:
406
392
attr_expr = self .get_attr_expr (obj , op , decl_cl )
407
393
always_defined = cl .is_always_defined (op .attr )
408
394
# 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 } ;" )
418
396
419
397
merged_branch = None
420
398
if not always_defined :
421
399
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
423
401
)
424
402
branch = self .next_branch ()
425
403
if branch is not None :
@@ -466,7 +444,8 @@ def visit_set_attr(self, op: SetAttr) -> None:
466
444
dest = self .reg (op )
467
445
obj = self .reg (op .obj )
468
446
src = self .reg (op .src )
469
- rtype = op .class_type
447
+ rtype = op .obj .type
448
+ assert isinstance (rtype , RInstance )
470
449
cl = rtype .class_ir
471
450
attr_rtype , decl_cl = cl .attr_details (op .attr )
472
451
if cl .get_method (op .attr ):
@@ -501,23 +480,18 @@ def visit_set_attr(self, op: SetAttr) -> None:
501
480
always_defined = cl .is_always_defined (op .attr )
502
481
if not always_defined :
503
482
self .emitter .emit_undefined_attr_check (
504
- attr_rtype , attr_expr , "!=" , obj , op .attr , cl
483
+ attr_rtype , attr_expr , "!=" , obj , op .attr , rtype
505
484
)
506
485
self .emitter .emit_dec_ref (attr_expr , attr_rtype )
507
486
if not always_defined :
508
487
self .emitter .emit_line ("}" )
509
488
elif attr_rtype .error_overlap and not cl .is_always_defined (op .attr ):
510
489
# If there is overlap with the error value, update bitmap to mark
511
490
# 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 )
513
492
514
493
# 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 } ;" )
521
495
if op .error_kind == ERR_FALSE :
522
496
self .emitter .emit_line (f"{ dest } = 1;" )
523
497
@@ -589,6 +563,20 @@ def emit_method_call(self, dest: str, op_obj: Value, name: str, op_args: list[Va
589
563
if method .decl .kind == FUNC_STATICMETHOD
590
564
else [f"(PyObject *)Py_TYPE({ obj } )" ] if method .decl .kind == FUNC_CLASSMETHOD else [obj ]
591
565
)
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
+
592
580
args = ", " .join (obj_args + [self .reg (arg ) for arg in op_args ])
593
581
mtype = native_function_type (method , self .emitter )
594
582
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
613
601
)
614
602
)
615
603
604
+ if need_box_obj :
605
+ self .emitter .emit_dec_ref (obj_boxed , RInstance (rtype .class_ir ))
606
+
616
607
def visit_inc_ref (self , op : IncRef ) -> None :
617
608
src = self .reg (op .src )
618
609
self .emit_inc_ref (src , op .src .type )
0 commit comments