2121 REG_PREFIX ,
2222 STATIC_PREFIX ,
2323 TYPE_PREFIX ,
24+ TYPE_VAR_PREFIX ,
2425)
2526from mypyc .ir .class_ir import ClassIR , all_concrete_classes
2627from mypyc .ir .func_ir import FUNC_STATICMETHOD , FuncDecl , FuncIR , get_text_signature
27- from mypyc .ir .ops import BasicBlock , Value
28+ from mypyc .ir .ops import (
29+ NAMESPACE_MODULE ,
30+ NAMESPACE_STATIC ,
31+ NAMESPACE_TYPE ,
32+ NAMESPACE_TYPE_VAR ,
33+ BasicBlock ,
34+ Value ,
35+ )
2836from mypyc .ir .rtypes import (
2937 RInstance ,
3038 RPrimitive ,
3139 RTuple ,
3240 RType ,
3341 RUnion ,
42+ RVec ,
3443 int_rprimitive ,
3544 is_bool_or_bit_rprimitive ,
3645 is_bytearray_rprimitive ,
5665 is_uint8_rprimitive ,
5766 object_rprimitive ,
5867 optional_value_type ,
68+ vec_api_by_item_type ,
69+ vec_item_type_tags ,
5970)
6071from mypyc .namegen import NameGenerator , exported_name
72+ from mypyc .primitives .registry import builtin_names
6173from mypyc .sametype import is_same_type
6274
6375# Whether to insert debug asserts for all error handling, to quickly
6476# catch errors propagating without exceptions set.
6577DEBUG_ERRORS : Final = False
6678
79+ PREFIX_MAP : Final = {
80+ NAMESPACE_STATIC : STATIC_PREFIX ,
81+ NAMESPACE_TYPE : TYPE_PREFIX ,
82+ NAMESPACE_MODULE : MODULE_PREFIX ,
83+ NAMESPACE_TYPE_VAR : TYPE_VAR_PREFIX ,
84+ }
85+
6786
6887class HeaderDeclaration :
6988 """A representation of a declaration in C.
@@ -326,13 +345,22 @@ def ctype_spaced(self, rtype: RType) -> str:
326345 else :
327346 return ctype + " "
328347
348+ def set_undefined_value (self , target : str , rtype : RType ) -> None :
349+ if isinstance (rtype , RVec ):
350+ self .emit_line (f"{ target } .len = -1;" )
351+ self .emit_line (f"{ target } .buf = NULL;" )
352+ else :
353+ self .emit_line (f"{ target } = { self .c_undefined_value (rtype )} ;" )
354+
329355 def c_undefined_value (self , rtype : RType ) -> str :
330356 if not rtype .is_unboxed :
331357 return "NULL"
332358 elif isinstance (rtype , RPrimitive ):
333359 return rtype .c_undefined
334360 elif isinstance (rtype , RTuple ):
335361 return self .tuple_undefined_value (rtype )
362+ elif isinstance (rtype , RVec ):
363+ return f"({ self .ctype (rtype )} ) {{ -1, NULL }}"
336364 assert False , rtype
337365
338366 def c_error_value (self , rtype : RType ) -> str :
@@ -435,6 +463,12 @@ def error_value_check(self, rtype: RType, value: str, compare: str) -> str:
435463 return self .tuple_undefined_check_cond (
436464 rtype , value , self .c_error_value , compare , check_exception = False
437465 )
466+ elif isinstance (rtype , RVec ):
467+ if compare == "==" :
468+ return f"{ value } .len < 0"
469+ elif compare == "!=" :
470+ return f"{ value } .len >= 0"
471+ assert False , compare
438472 else :
439473 return f"{ value } { compare } { self .c_error_value (rtype )} "
440474
@@ -466,6 +500,8 @@ def tuple_undefined_check_cond(
466500 return self .tuple_undefined_check_cond (
467501 item_type , tuple_expr_in_c + f".f{ i } " , c_type_compare_val , compare
468502 )
503+ elif isinstance (item_type , RVec ):
504+ return f"{ tuple_expr_in_c } .f{ i } .len { compare } -1"
469505 else :
470506 check = f"{ tuple_expr_in_c } .f{ i } { compare } { c_type_compare_val (item_type )} "
471507 if rtuple .error_overlap and check_exception :
@@ -485,6 +521,8 @@ def c_initializer_undefined_value(self, rtype: RType) -> str:
485521 return f"{{ { int_rprimitive .c_undefined } }}"
486522 items = ", " .join ([self .c_initializer_undefined_value (t ) for t in rtype .types ])
487523 return f"{{ { items } }}"
524+ elif isinstance (rtype , RVec ):
525+ return "{ -1, NULL }"
488526 else :
489527 return self .c_undefined_value (rtype )
490528
@@ -518,6 +556,9 @@ def emit_inc_ref(self, dest: str, rtype: RType, *, rare: bool = False) -> None:
518556 elif isinstance (rtype , RTuple ):
519557 for i , item_type in enumerate (rtype .types ):
520558 self .emit_inc_ref (f"{ dest } .f{ i } " , item_type )
559+ elif isinstance (rtype , RVec ):
560+ # TODO: Only use the X variant if buf can be NULL
561+ self .emit_line (f"Py_XINCREF({ dest } .buf);" )
521562 elif not rtype .is_unboxed :
522563 # Always inline, since this is a simple but very hot op
523564 if rtype .may_be_immortal or not HAVE_IMMORTAL :
@@ -546,6 +587,12 @@ def emit_dec_ref(
546587 elif isinstance (rtype , RTuple ):
547588 for i , item_type in enumerate (rtype .types ):
548589 self .emit_dec_ref (f"{ dest } .f{ i } " , item_type , is_xdec = is_xdec , rare = rare )
590+ elif isinstance (rtype , RVec ):
591+ # TODO: Only use the X variant if buf can be NULL
592+ if rare :
593+ self .emit_line (f"CPy_XDecRef({ dest } .buf);" )
594+ else :
595+ self .emit_line (f"CPy_XDECREF({ dest } .buf);" )
549596 elif not rtype .is_unboxed :
550597 if rare :
551598 self .emit_line (f"CPy_{ x } DecRef({ dest } );" )
@@ -555,6 +602,8 @@ def emit_dec_ref(
555602 self .emit_line (f"CPy_{ x } DECREF({ dest } );" )
556603 else :
557604 self .emit_line (f"CPy_{ x } DECREF_NO_IMM({ dest } );" )
605+ elif rtype .is_refcounted :
606+ assert False , f"dec_ref not implemented for { rtype } "
558607 # Otherwise assume it's an unboxed, pointerless value and do nothing.
559608
560609 def pretty_name (self , typ : RType ) -> str :
@@ -751,6 +800,40 @@ def emit_cast(
751800 elif isinstance (typ , RTuple ):
752801 assert not optional
753802 self .emit_tuple_cast (src , dest , typ , declare_dest , error , src_type )
803+ elif isinstance (typ , RVec ):
804+ if declare_dest :
805+ self .emit_line (f"PyObject *{ dest } ;" )
806+ # Build type check expression based on vec kind
807+ api_name = vec_api_by_item_type .get (typ .item_type )
808+ depth = typ .depth ()
809+ if api_name :
810+ # Specialized vec types (vec[i64], vec[i32], etc.)
811+ check = f"(Py_TYPE({ src } ) == { api_name } .boxed_type)"
812+ elif depth == 0 :
813+ # Generic vec types (vec[T], vec[T | None]) with reference type items
814+ item_type_c = self .vec_item_type_c (typ )
815+ check = (
816+ f"(Py_TYPE({ src } ) == VecTApi.boxed_type && "
817+ f"((VecTObject *){ src } )->vec.buf->item_type == { item_type_c } )"
818+ )
819+ else :
820+ # Nested vec types (vec[vec[...]]). Check boxed type, item type, and depth.
821+ unwrapped = typ .unwrap_item_type ()
822+ if unwrapped in vec_item_type_tags :
823+ type_value = str (vec_item_type_tags [unwrapped ])
824+ else :
825+ type_value = self .vec_item_type_c (typ )
826+ check = (
827+ f"(Py_TYPE({ src } ) == VecNestedApi.boxed_type && "
828+ f"((VecNestedObject *){ src } )->vec.buf->item_type == { type_value } && "
829+ f"((VecNestedObject *){ src } )->vec.buf->depth == { depth } )"
830+ )
831+ if likely :
832+ check = f"(likely{ check } )"
833+ self .emit_arg_check (src , dest , typ , check , optional )
834+ self .emit_lines (f" { dest } = { src } ;" , "else {" )
835+ self .emit_cast_error_handler (error , src , dest , typ , raise_exception )
836+ self .emit_line ("}" )
754837 else :
755838 assert False , "Cast not implemented: %s" % typ
756839
@@ -894,6 +977,7 @@ def emit_unbox(
894977 declare_dest: If True, also declare the variable 'dest'
895978 error: What happens on error
896979 raise_exception: If True, also raise TypeError on failure
980+ optional: If True, NULL src value is allowed and will map to error value
897981 borrow: If True, create a borrowed reference
898982
899983 """
@@ -1025,10 +1109,56 @@ def emit_unbox(
10251109 self .emit_line ("}" )
10261110 if optional :
10271111 self .emit_line ("}" )
1112+ elif isinstance (typ , RVec ):
1113+ if declare_dest :
1114+ self .emit_line (f"{ self .ctype (typ )} { dest } ;" )
1115+
1116+ if optional :
1117+ self .emit_line (f"if ({ src } == NULL) {{" )
1118+ self .emit_line (f"{ dest } = { self .c_error_value (typ )} ;" )
1119+ self .emit_line ("} else {" )
1120+
1121+ specialized_api_name = vec_api_by_item_type .get (typ .item_type )
1122+ if specialized_api_name is not None :
1123+ self .emit_line (f"{ dest } = { specialized_api_name } .unbox({ src } );" )
1124+ else :
1125+ depth = typ .depth ()
1126+ unwrapped = typ .unwrap_item_type ()
1127+ if unwrapped in vec_item_type_tags :
1128+ type_value = str (vec_item_type_tags [unwrapped ])
1129+ else :
1130+ type_value = self .vec_item_type_c (typ )
1131+ if depth == 0 :
1132+ self .emit_line (f"{ dest } = VecTApi.unbox({ src } , { type_value } );" )
1133+ else :
1134+ self .emit_line (f"{ dest } = VecNestedApi.unbox({ src } , { type_value } , { depth } );" )
10281135
1136+ self .emit_line (f"if (VEC_IS_ERROR({ dest } )) {{" )
1137+ self .emit_line (failure )
1138+ self .emit_line ("}" )
1139+
1140+ if optional :
1141+ self .emit_line ("}" )
10291142 else :
10301143 assert False , "Unboxing not implemented: %s" % typ
10311144
1145+ def vec_item_type_c (self , typ : RVec ) -> str :
1146+ item_type = typ .unwrap_item_type ()
1147+ type_c_ptr = self .type_c_ptr (item_type )
1148+ # Can never be None, since we unwrapped the item type above
1149+ assert type_c_ptr is not None
1150+ type_value = f"(size_t){ type_c_ptr } "
1151+ if typ .is_optional ():
1152+ type_value = f"({ type_value } | 1)"
1153+ return type_value
1154+
1155+ def type_c_ptr (self , typ : RPrimitive | RInstance ) -> str | None :
1156+ if isinstance (typ , RPrimitive ) and typ .is_refcounted :
1157+ return "&" + builtin_names [typ .name ][1 ]
1158+ elif isinstance (typ , RInstance ):
1159+ return self .type_struct_name (typ .class_ir )
1160+ return None
1161+
10321162 def emit_box (
10331163 self , src : str , dest : str , typ : RType , declare_dest : bool = False , can_borrow : bool = False
10341164 ) -> None :
@@ -1083,6 +1213,20 @@ def emit_box(
10831213 inner_name = self .temp_name ()
10841214 self .emit_box (f"{ src } .f{ i } " , inner_name , typ .types [i ], declare_dest = True )
10851215 self .emit_line (f"PyTuple_SET_ITEM({ dest } , { i } , { inner_name } );" )
1216+ elif isinstance (typ , RVec ):
1217+ specialized_api_name = vec_api_by_item_type .get (typ .item_type )
1218+ if specialized_api_name is not None :
1219+ api = specialized_api_name
1220+ elif typ .depth () > 0 :
1221+ api = "VecNestedApi"
1222+ else :
1223+ api = "VecTApi"
1224+ # Empty vecs of this sort don't describe item type, so it needs to be
1225+ # passed explicitly.
1226+ item_type = self .vec_item_type_c (typ )
1227+ self .emit_line (f"{ declaration } { dest } = { api } .box({ src } , { item_type } );" )
1228+ return
1229+ self .emit_line (f"{ declaration } { dest } = { api } .box({ src } );" )
10861230 else :
10871231 assert not typ .is_unboxed
10881232 # Type is boxed -- trivially just assign.
@@ -1096,6 +1240,8 @@ def emit_error_check(self, value: str, rtype: RType, failure: str) -> None:
10961240 else :
10971241 cond = self .tuple_undefined_check_cond (rtype , value , self .c_error_value , "==" )
10981242 self .emit_line (f"if ({ cond } ) {{" )
1243+ elif isinstance (rtype , RVec ):
1244+ self .emit_line (f"if ({ value } .len < 0) {{" )
10991245 elif rtype .error_overlap :
11001246 # The error value is also valid as a normal value, so we need to also check
11011247 # for a raised exception.
@@ -1120,6 +1266,8 @@ def emit_gc_visit(self, target: str, rtype: RType) -> None:
11201266 elif isinstance (rtype , RTuple ):
11211267 for i , item_type in enumerate (rtype .types ):
11221268 self .emit_gc_visit (f"{ target } .f{ i } " , item_type )
1269+ elif isinstance (rtype , RVec ):
1270+ self .emit_line (f"Py_VISIT({ target } .buf);" )
11231271 elif self .ctype (rtype ) == "PyObject *" :
11241272 # The simplest case.
11251273 self .emit_line (f"Py_VISIT({ target } );" )
@@ -1144,6 +1292,8 @@ def emit_gc_clear(self, target: str, rtype: RType) -> None:
11441292 elif isinstance (rtype , RTuple ):
11451293 for i , item_type in enumerate (rtype .types ):
11461294 self .emit_gc_clear (f"{ target } .f{ i } " , item_type )
1295+ elif isinstance (rtype , RVec ):
1296+ self .emit_line (f"Py_CLEAR({ target } .buf);" )
11471297 elif self .ctype (rtype ) == "PyObject *" and self .c_undefined_value (rtype ) == "NULL" :
11481298 # The simplest case.
11491299 self .emit_line (f"Py_CLEAR({ target } );" )
0 commit comments