1717from mypy .nodes import ARG_NAMED , ARG_NAMED_OPT , ARG_OPT , ARG_POS , ARG_STAR , ARG_STAR2 , ArgKind
1818from mypy .operators import op_methods_to_symbols , reverse_op_method_names , reverse_op_methods
1919from mypyc .codegen .emit import AssignHandler , Emitter , ErrorHandler , GotoHandler , ReturnHandler
20- from mypyc .common import DUNDER_PREFIX , NATIVE_PREFIX , PREFIX , use_vectorcall
20+ from mypyc .common import (
21+ BITMAP_BITS ,
22+ BITMAP_TYPE ,
23+ DUNDER_PREFIX ,
24+ NATIVE_PREFIX ,
25+ PREFIX ,
26+ bitmap_name ,
27+ use_vectorcall ,
28+ )
2129from mypyc .ir .class_ir import ClassIR
2230from mypyc .ir .func_ir import FUNC_STATICMETHOD , FuncIR , RuntimeArg
2331from mypyc .ir .rtypes import (
2432 RInstance ,
2533 RType ,
2634 is_bool_rprimitive ,
35+ is_fixed_width_rtype ,
2736 is_int_rprimitive ,
2837 is_object_rprimitive ,
2938 object_rprimitive ,
@@ -135,6 +144,8 @@ def generate_wrapper_function(
135144
136145 # If fn is a method, then the first argument is a self param
137146 real_args = list (fn .args )
147+ if fn .sig .num_bitmap_args :
148+ real_args = real_args [: - fn .sig .num_bitmap_args ]
138149 if fn .class_name and not fn .decl .kind == FUNC_STATICMETHOD :
139150 arg = real_args .pop (0 )
140151 emitter .emit_line (f"PyObject *obj_{ arg .name } = self;" )
@@ -185,6 +196,9 @@ def generate_wrapper_function(
185196 "return NULL;" ,
186197 "}" ,
187198 )
199+ for i in range (fn .sig .num_bitmap_args ):
200+ name = bitmap_name (i )
201+ emitter .emit_line (f"{ BITMAP_TYPE } { name } = 0;" )
188202 traceback_code = generate_traceback_code (fn , emitter , source_path , module_name )
189203 generate_wrapper_core (
190204 fn ,
@@ -223,6 +237,8 @@ def generate_legacy_wrapper_function(
223237
224238 # If fn is a method, then the first argument is a self param
225239 real_args = list (fn .args )
240+ if fn .sig .num_bitmap_args :
241+ real_args = real_args [: - fn .sig .num_bitmap_args ]
226242 if fn .class_name and not fn .decl .kind == FUNC_STATICMETHOD :
227243 arg = real_args .pop (0 )
228244 emitter .emit_line (f"PyObject *obj_{ arg .name } = self;" )
@@ -254,6 +270,9 @@ def generate_legacy_wrapper_function(
254270 "return NULL;" ,
255271 "}" ,
256272 )
273+ for i in range (fn .sig .num_bitmap_args ):
274+ name = bitmap_name (i )
275+ emitter .emit_line (f"{ BITMAP_TYPE } { name } = 0;" )
257276 traceback_code = generate_traceback_code (fn , emitter , source_path , module_name )
258277 generate_wrapper_core (
259278 fn ,
@@ -669,7 +688,8 @@ def generate_wrapper_core(
669688 """
670689 gen = WrapperGenerator (None , emitter )
671690 gen .set_target (fn )
672- gen .arg_names = arg_names or [arg .name for arg in fn .args ]
691+ if arg_names :
692+ gen .arg_names = arg_names
673693 gen .cleanups = cleanups or []
674694 gen .optional_args = optional_args or []
675695 gen .traceback_code = traceback_code or ""
@@ -688,6 +708,7 @@ def generate_arg_check(
688708 * ,
689709 optional : bool = False ,
690710 raise_exception : bool = True ,
711+ bitmap_arg_index : int = 0 ,
691712) -> None :
692713 """Insert a runtime check for argument and unbox if necessary.
693714
@@ -697,17 +718,34 @@ def generate_arg_check(
697718 """
698719 error = error or AssignHandler ()
699720 if typ .is_unboxed :
700- # Borrow when unboxing to avoid reference count manipulation.
701- emitter .emit_unbox (
702- f"obj_{ name } " ,
703- f"arg_{ name } " ,
704- typ ,
705- declare_dest = True ,
706- raise_exception = raise_exception ,
707- error = error ,
708- borrow = True ,
709- optional = optional ,
710- )
721+ if is_fixed_width_rtype (typ ) and optional :
722+ # Update bitmap is value is provided.
723+ emitter .emit_line (f"{ emitter .ctype (typ )} arg_{ name } = 0;" )
724+ emitter .emit_line (f"if (obj_{ name } != NULL) {{" )
725+ bitmap = bitmap_name (bitmap_arg_index // BITMAP_BITS )
726+ emitter .emit_line (f"{ bitmap } |= 1 << { bitmap_arg_index & (BITMAP_BITS - 1 )} ;" )
727+ emitter .emit_unbox (
728+ f"obj_{ name } " ,
729+ f"arg_{ name } " ,
730+ typ ,
731+ declare_dest = False ,
732+ raise_exception = raise_exception ,
733+ error = error ,
734+ borrow = True ,
735+ )
736+ emitter .emit_line ("}" )
737+ else :
738+ # Borrow when unboxing to avoid reference count manipulation.
739+ emitter .emit_unbox (
740+ f"obj_{ name } " ,
741+ f"arg_{ name } " ,
742+ typ ,
743+ declare_dest = True ,
744+ raise_exception = raise_exception ,
745+ error = error ,
746+ borrow = True ,
747+ optional = optional ,
748+ )
711749 elif is_object_rprimitive (typ ):
712750 # Object is trivial since any object is valid
713751 if optional :
@@ -749,8 +787,12 @@ def set_target(self, fn: FuncIR) -> None:
749787 """
750788 self .target_name = fn .name
751789 self .target_cname = fn .cname (self .emitter .names )
752- self .arg_names = [arg .name for arg in fn .args ]
753- self .args = fn .args [:]
790+ self .num_bitmap_args = fn .sig .num_bitmap_args
791+ if self .num_bitmap_args :
792+ self .args = fn .args [: - self .num_bitmap_args ]
793+ else :
794+ self .args = fn .args
795+ self .arg_names = [arg .name for arg in self .args ]
754796 self .ret_type = fn .ret_type
755797
756798 def wrapper_name (self ) -> str :
@@ -779,17 +821,22 @@ def emit_arg_processing(
779821 ) -> None :
780822 """Emit validation and unboxing of arguments."""
781823 error = error or self .error ()
824+ bitmap_arg_index = 0
782825 for arg_name , arg in zip (self .arg_names , self .args ):
783826 # Suppress the argument check for *args/**kwargs, since we know it must be right.
784827 typ = arg .type if arg .kind not in (ARG_STAR , ARG_STAR2 ) else object_rprimitive
828+ optional = arg in self .optional_args
785829 generate_arg_check (
786830 arg_name ,
787831 typ ,
788832 self .emitter ,
789833 error ,
790834 raise_exception = raise_exception ,
791- optional = arg in self .optional_args ,
835+ optional = optional ,
836+ bitmap_arg_index = bitmap_arg_index ,
792837 )
838+ if optional and is_fixed_width_rtype (typ ):
839+ bitmap_arg_index += 1
793840
794841 def emit_call (self , not_implemented_handler : str = "" ) -> None :
795842 """Emit call to the wrapper function.
@@ -798,6 +845,12 @@ def emit_call(self, not_implemented_handler: str = "") -> None:
798845 a NotImplemented return value (if it's possible based on the return type).
799846 """
800847 native_args = ", " .join (f"arg_{ arg } " for arg in self .arg_names )
848+ if self .num_bitmap_args :
849+ bitmap_args = ", " .join (
850+ [bitmap_name (i ) for i in reversed (range (self .num_bitmap_args ))]
851+ )
852+ native_args = f"{ native_args } , { bitmap_args } "
853+
801854 ret_type = self .ret_type
802855 emitter = self .emitter
803856 if ret_type .is_unboxed or self .use_goto ():
0 commit comments