|
53 | 53 | setup_func_for_recursive_call
|
54 | 54 | )
|
55 | 55 |
|
| 56 | +from mypyc.primitives.registry import builtin_names |
| 57 | + |
56 | 58 |
|
57 | 59 | # Top-level transform functions
|
58 | 60 |
|
@@ -219,9 +221,12 @@ def c() -> None:
|
219 | 221 | in_non_ext = not ir.is_ext_class
|
220 | 222 | class_name = cdef.name
|
221 | 223 |
|
222 |
| - builder.enter(FuncInfo(fitem, name, class_name, gen_func_ns(builder), |
223 |
| - is_nested, contains_nested, is_decorated, in_non_ext, |
224 |
| - is_singledispatch)) |
| 224 | + if is_singledispatch: |
| 225 | + func_name = '__mypyc_singledispatch_main_function_{}__'.format(name) |
| 226 | + else: |
| 227 | + func_name = name |
| 228 | + builder.enter(FuncInfo(fitem, func_name, class_name, gen_func_ns(builder), |
| 229 | + is_nested, contains_nested, is_decorated, in_non_ext)) |
225 | 230 |
|
226 | 231 | # Functions that contain nested functions need an environment class to store variables that
|
227 | 232 | # are free in their nested functions. Generator functions need an environment class to
|
@@ -254,9 +259,6 @@ def c() -> None:
|
254 | 259 | if builder.fn_info.contains_nested and not builder.fn_info.is_generator:
|
255 | 260 | finalize_env_class(builder)
|
256 | 261 |
|
257 |
| - if builder.fn_info.is_singledispatch: |
258 |
| - add_singledispatch_registered_impls(builder) |
259 |
| - |
260 | 262 | builder.ret_types[-1] = sig.ret_type
|
261 | 263 |
|
262 | 264 | # Add all variables and functions that are declared/defined within this
|
@@ -313,6 +315,15 @@ def c() -> None:
|
313 | 315 | # calculate them *once* when the function definition is evaluated.
|
314 | 316 | calculate_arg_defaults(builder, fn_info, func_reg, symtable)
|
315 | 317 |
|
| 318 | + if is_singledispatch: |
| 319 | + # add the generated main singledispatch function |
| 320 | + builder.functions.append(func_ir) |
| 321 | + # create the dispatch function |
| 322 | + assert isinstance(fitem, FuncDef) |
| 323 | + dispatch_name = decorator_helper_name(name) if is_decorated else name |
| 324 | + dispatch_func_ir = gen_dispatch_func_ir(builder, fitem, fn_info.name, dispatch_name, sig) |
| 325 | + return dispatch_func_ir, None |
| 326 | + |
316 | 327 | return (func_ir, func_reg)
|
317 | 328 |
|
318 | 329 |
|
@@ -768,28 +779,62 @@ def check_if_isinstance(builder: IRBuilder, obj: Value, typ: TypeInfo, line: int
|
768 | 779 | class_ir = builder.mapper.type_to_ir[typ]
|
769 | 780 | return builder.builder.isinstance_native(obj, class_ir, line)
|
770 | 781 | else:
|
771 |
| - class_obj = builder.load_module_attr_by_fullname(typ.fullname, line) |
| 782 | + if typ.fullname in builtin_names: |
| 783 | + builtin_addr_type, src = builtin_names[typ.fullname] |
| 784 | + class_obj = builder.add(LoadAddress(builtin_addr_type, src, line)) |
| 785 | + else: |
| 786 | + class_obj = builder.load_global_str(typ.name, line) |
772 | 787 | return builder.call_c(slow_isinstance_op, [obj, class_obj], line)
|
773 | 788 |
|
774 | 789 |
|
775 |
| -def add_singledispatch_registered_impls(builder: IRBuilder) -> None: |
776 |
| - fitem = builder.fn_info.fitem |
777 |
| - assert isinstance(fitem, FuncDef) |
| 790 | +def generate_singledispatch_dispatch_function( |
| 791 | + builder: IRBuilder, |
| 792 | + main_singledispatch_function_name: str, |
| 793 | + fitem: FuncDef, |
| 794 | +) -> None: |
778 | 795 | impls = builder.singledispatch_impls[fitem]
|
779 | 796 | line = fitem.line
|
780 | 797 | current_func_decl = builder.mapper.func_to_decl[fitem]
|
781 | 798 | arg_info = get_args(builder, current_func_decl.sig.args, line)
|
782 |
| - for dispatch_type, impl in impls: |
783 |
| - func_decl = builder.mapper.func_to_decl[impl] |
| 799 | + |
| 800 | + def gen_func_call_and_return(func_name: str) -> None: |
| 801 | + func = builder.load_global_str(func_name, line) |
| 802 | + # TODO: don't pass optional arguments if they weren't passed to this function |
| 803 | + ret_val = builder.builder.py_call( |
| 804 | + func, arg_info.args, line, arg_info.arg_kinds, arg_info.arg_names |
| 805 | + ) |
| 806 | + coerced = builder.coerce(ret_val, current_func_decl.sig.ret_type, line) |
| 807 | + builder.nonlocal_control[-1].gen_return(builder, coerced, line) |
| 808 | + |
| 809 | + # Reverse the list of registered implementations so we use the implementations defined later |
| 810 | + # if there are multiple overlapping implementations |
| 811 | + for dispatch_type, impl in reversed(impls): |
784 | 812 | call_impl, next_impl = BasicBlock(), BasicBlock()
|
785 | 813 | should_call_impl = check_if_isinstance(builder, arg_info.args[0], dispatch_type, line)
|
786 | 814 | builder.add_bool_branch(should_call_impl, call_impl, next_impl)
|
787 | 815 |
|
788 | 816 | # Call the registered implementation
|
789 | 817 | builder.activate_block(call_impl)
|
790 | 818 |
|
791 |
| - ret_val = builder.builder.call( |
792 |
| - func_decl, arg_info.args, arg_info.arg_kinds, arg_info.arg_names, line |
793 |
| - ) |
794 |
| - builder.nonlocal_control[-1].gen_return(builder, ret_val, line) |
| 819 | + gen_func_call_and_return(impl.name) |
795 | 820 | builder.activate_block(next_impl)
|
| 821 | + |
| 822 | + gen_func_call_and_return(main_singledispatch_function_name) |
| 823 | + |
| 824 | + |
| 825 | +def gen_dispatch_func_ir( |
| 826 | + builder: IRBuilder, |
| 827 | + fitem: FuncDef, |
| 828 | + main_func_name: str, |
| 829 | + dispatch_name: str, |
| 830 | + sig: FuncSignature, |
| 831 | +) -> FuncIR: |
| 832 | + """Create a dispatch function (a function that checks the first argument type and dispatches |
| 833 | + to the correct implementation) |
| 834 | + """ |
| 835 | + builder.enter() |
| 836 | + generate_singledispatch_dispatch_function(builder, main_func_name, fitem) |
| 837 | + args, _, blocks, _, fn_info = builder.leave() |
| 838 | + func_decl = FuncDecl(dispatch_name, None, builder.module_name, sig) |
| 839 | + dispatch_func_ir = FuncIR(func_decl, args, blocks) |
| 840 | + return dispatch_func_ir |
0 commit comments