Skip to content

Commit 59555e4

Browse files
committed
Generate dispatch function separately from original function
Instead of adding the logic to dispatch to the correct function to the main singledispatch function itself, generate 2 separate functions: one that compiles the logic of the undecorated function normally, and a separate dispatch function that checks the first argument's type and dispatches either to one of the registered implementations or the fallback. That makes it easier to generate code when the main singledispatch function is a generator or some other kind of special function, as the code generation can generate the main singledispatch function the same way it would otherwise. Because we're no longer changing how that main singledispatch function is generated based on whether it's a singledispatch function, we don't need to store whether the current function is a singledispatch function in FuncInfo.
1 parent 099b047 commit 59555e4

File tree

2 files changed

+28
-12
lines changed

2 files changed

+28
-12
lines changed

mypyc/irbuild/context.py

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -22,8 +22,7 @@ def __init__(self,
2222
is_nested: bool = False,
2323
contains_nested: bool = False,
2424
is_decorated: bool = False,
25-
in_non_ext: bool = False,
26-
is_singledispatch: bool = False) -> None:
25+
in_non_ext: bool = False) -> None:
2726
self.fitem = fitem
2827
self.name = name if not is_decorated else decorator_helper_name(name)
2928
self.class_name = class_name
@@ -48,7 +47,6 @@ def __init__(self,
4847
self.contains_nested = contains_nested
4948
self.is_decorated = is_decorated
5049
self.in_non_ext = in_non_ext
51-
self.is_singledispatch = is_singledispatch
5250

5351
# TODO: add field for ret_type: RType = none_rprimitive
5452

mypyc/irbuild/function.py

Lines changed: 27 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -219,9 +219,12 @@ def c() -> None:
219219
in_non_ext = not ir.is_ext_class
220220
class_name = cdef.name
221221

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))
222+
if is_singledispatch:
223+
func_name = '__mypyc_singledispatch_main_function_{}__'.format(name)
224+
else:
225+
func_name = name
226+
builder.enter(FuncInfo(fitem, func_name, class_name, gen_func_ns(builder),
227+
is_nested, contains_nested, is_decorated, in_non_ext))
225228

226229
# Functions that contain nested functions need an environment class to store variables that
227230
# are free in their nested functions. Generator functions need an environment class to
@@ -254,9 +257,6 @@ def c() -> None:
254257
if builder.fn_info.contains_nested and not builder.fn_info.is_generator:
255258
finalize_env_class(builder)
256259

257-
if builder.fn_info.is_singledispatch:
258-
add_singledispatch_registered_impls(builder)
259-
260260
builder.ret_types[-1] = sig.ret_type
261261

262262
# Add all variables and functions that are declared/defined within this
@@ -313,6 +313,20 @@ def c() -> None:
313313
# calculate them *once* when the function definition is evaluated.
314314
calculate_arg_defaults(builder, fn_info, func_reg, symtable)
315315

316+
if is_singledispatch:
317+
# add the generated main singledispatch function
318+
builder.functions.append(func_ir)
319+
# create a dispatch function (a function that checks the first argument type and dispatches
320+
# to the correct implementation)
321+
builder.enter()
322+
assert isinstance(fitem, FuncDef)
323+
generate_singledispatch_dispatch_function(builder, fn_info.name, fitem)
324+
args, _, blocks, _, fn_info = builder.leave()
325+
dispatch_name = decorator_helper_name(name) if is_decorated else name
326+
func_decl = FuncDecl(dispatch_name, None, builder.module_name, sig)
327+
dispatch_func_ir = FuncIR(func_decl, args, blocks)
328+
return dispatch_func_ir, None
329+
316330
return (func_ir, func_reg)
317331

318332

@@ -772,9 +786,11 @@ def check_if_isinstance(builder: IRBuilder, obj: Value, typ: TypeInfo, line: int
772786
return builder.call_c(slow_isinstance_op, [obj, class_obj], line)
773787

774788

775-
def add_singledispatch_registered_impls(builder: IRBuilder) -> None:
776-
fitem = builder.fn_info.fitem
777-
assert isinstance(fitem, FuncDef)
789+
def generate_singledispatch_dispatch_function(
790+
builder: IRBuilder,
791+
main_singledispatch_function_name: str,
792+
fitem: FuncDef,
793+
) -> None:
778794
impls = builder.singledispatch_impls[fitem]
779795
line = fitem.line
780796
current_func_decl = builder.mapper.func_to_decl[fitem]
@@ -801,3 +817,5 @@ def gen_func_call_and_return(func_name: str) -> None:
801817

802818
gen_func_call_and_return(impl.name)
803819
builder.activate_block(next_impl)
820+
821+
gen_func_call_and_return(main_singledispatch_function_name)

0 commit comments

Comments
 (0)