# Buggy code
def unified_function_type(numba_types, require_precise=True):
    """Returns a unified Numba function type if possible.

    Parameters
    ----------
    numba_types : tuple
      Numba type instances.
    require_precise : bool
      If True, the returned Numba function type must be precise.

    Returns
    -------
    typ : {numba.core.types.Type, None}
      A unified Numba function type. Or ``None`` when the Numba types
      cannot be unified, e.g. when the ``numba_types`` contains at
      least two different Numba function type instances.

    If ``numba_types`` contains a Numba dispatcher type, the unified
    Numba function type will be an imprecise ``UndefinedFunctionType``
    instance, or None when ``require_precise=True`` is specified.

    Specifying ``require_precise=False`` enables unifying imprecise
    Numba dispatcher instances when used in tuples or if-then branches
    when the precise Numba function cannot be determined on the first
    occurrence that is not a call expression.
    """
    from numba.core.errors import NumbaExperimentalFeatureWarning

    if not (
        numba_types
        and isinstance(numba_types[0], (types.Dispatcher, types.FunctionType))
    ):
        return

    warnings.warn(
        "First-class function type feature is experimental",
        category=NumbaExperimentalFeatureWarning,
    )

    mnargs, mxargs = None, None
    dispatchers = set()
    function = None
    undefined_function = None

    for t in numba_types:
        if isinstance(t, types.Dispatcher):
            mnargs1, mxargs1 = get_nargs_range(t.dispatcher.py_func)
            if mnargs is None:
                mnargs, mxargs = mnargs1, mxargs1
            elif not (mnargs, mxargs) == (mnargs1, mxargs1):
                return
            dispatchers.add(t.dispatcher)
            t = t.dispatcher.get_function_type()
            if t is None:
                continue
        if isinstance(t, types.FunctionType):
            if mnargs is None:
                mnargs = mxargs = t.nargs
            elif not (mnargs == mxargs == t.nargs):
                return numba_types
            if isinstance(t, types.UndefinedFunctionType):
                if undefined_function is None:
                    undefined_function = t
                elif 0:
                    assert undefined_function == t
                dispatchers.update(t.dispatchers)
            else:
                if function is None:
                    function = t
                else:
                    assert function == t
        else:
            return
    if require_precise and (function is None or undefined_function is not None):
        return
    if function is not None:
        if undefined_function is not None:
            assert function.nargs == undefined_function.nargs
            function = undefined_function
    elif undefined_function is not None:
        undefined_function.dispatchers.update(dispatchers)
        function = undefined_function
    else:
        function = types.UndefinedFunctionType(mnargs, dispatchers)

    return function


# Traceback (numba.core.errors.LoweringError)
0.50.0dev0+128.g82c7d37ad
<path>/numba/core/utils.py:508: NumbaExperimentalFeatureWarning: First-class function type feature is experimental
warnings.warn("First-class function type feature is experimental",
gi196.py:22: NumbaExperimentalFeatureWarning: First-class function type feature is experimental
for t in literal_unroll(fcs):
gi196.py:22: NumbaExperimentalFeatureWarning: First-class function type feature is experimental
for t in literal_unroll(fcs):
gi196.py:23: NumbaExperimentalFeatureWarning: First-class function type feature is experimental
i, j = t
<path>/numba/core/utils.py:508: NumbaExperimentalFeatureWarning: First-class function type feature is experimental
warnings.warn("First-class function type feature is experimental",
Traceback (most recent call last):
File "<path>/numba/core/errors.py", line 726, in new_error_context
yield
File "<path>/numba/core/lowering.py", line 267, in lower_block
self.lower_inst(inst)
File "<path>/numba/core/lowering.py", line 364, in lower_inst
val = self.lower_assign(ty, inst)
File "<path>/numba/core/lowering.py", line 538, in lower_assign
return self.lower_expr(ty, value)
File "<path>/numba/core/lowering.py", line 1193, in lower_expr
return impl(self.builder, (self.loadvar(expr.value.name),
File "<path>/numba/core/base.py", line 1155, in __call__
res = self._imp(self._context, builder, self._sig, args, loc=loc)
File "<path>/numba/core/base.py", line 1185, in wrapper
return fn(*args, **kwargs)
File "<path>/numba/cpython/tupleobj.py", line 253, in getitem_typed
DOCAST = context.typing_context.unify_types(sig.args[0][i],
File "<path>/numba/core/typing/context.py", line 630, in unify_types
unified = self.unify_pairs(unified, tp)
File "<path>/numba/core/typing/context.py", line 649, in unify_pairs
unified = first.unify(self, second)
File "<path>/numba/core/types/containers.py", line 319, in unify
return Tuple(unified)
File "<path>/numba/core/types/abstract.py", line 65, in __call__
inst = type.__call__(cls, *args, **kwargs)
File "<path>/numba/core/types/containers.py", line 280, in __new__
t = utils.unified_function_type(types, require_precise=True)
File "<path>/numba/core/utils.py", line 536, in unified_function_type
assert undefined_function == t
AssertionError

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
File "gi196.py", line 28, in <module>
print(bar(tup))
File "<path>/numba/core/dispatcher.py", line 420, in _compile_for_args
raise e
File "<path>/numba/core/dispatcher.py", line 353, in _compile_for_args
return self.compile(tuple(argtypes))
File "<path>/numba/core/compiler_lock.py", line 32, in _acquire_compile_lock
return func(*args, **kwargs)
File "<path>/numba/core/dispatcher.py", line 794, in compile
cres = self._compiler.compile(args, return_type)
File "<path>/numba/core/dispatcher.py", line 77, in compile
status, retval = self._compile_cached(args, return_type)
File "<path>/numba/core/dispatcher.py", line 91, in _compile_cached
retval = self._compile_core(args, return_type)
File "<path>/numba/core/dispatcher.py", line 104, in _compile_core
cres = compiler.compile_extra(self.targetdescr.typing_context,
File "<path>/numba/core/compiler.py", line 568, in compile_extra
return pipeline.compile_extra(func)
File "<path>/numba/core/compiler.py", line 339, in compile_extra
return self._compile_bytecode()
File "<path>/numba/core/compiler.py", line 401, in _compile_bytecode
return self._compile_core()
File "<path>/numba/core/compiler.py", line 381, in _compile_core
raise e
File "<path>/numba/core/compiler.py", line 372, in _compile_core
pm.run(self.state)
File "<path>/numba/core/compiler_machinery.py", line 341, in run
raise patched_exception
File "<path>/numba/core/compiler_machinery.py", line 332, in run
self._runPass(idx, pass_inst, state)
File "<path>/numba/core/compiler_lock.py", line 32, in _acquire_compile_lock
return func(*args, **kwargs)
File "<path>/numba/core/compiler_machinery.py", line 291, in _runPass
mutated |= check(pss.run_pass, internal_state)
File "<path>/numba/core/compiler_machinery.py", line 264, in check
mangled = func(compiler_state)
File "<path>/numba/core/typed_passes.py", line 442, in run_pass
NativeLowering().run_pass(state)
File "<path>/numba/core/typed_passes.py", line 370, in run_pass
lower.lower()
File "<path>/numba/core/lowering.py", line 179, in lower
self.lower_normal_function(self.fndesc)
File "<path>/numba/core/lowering.py", line 227, in lower_normal_function
entry_block_tail = self.lower_function_body()
File "<path>/numba/core/lowering.py", line 253, in lower_function_body
self.lower_block(block)
File "<path>/numba/core/lowering.py", line 267, in lower_block
self.lower_inst(inst)
File "<env>/lib/python3.8/contextlib.py", line 131, in __exit__
self.gen.throw(type, value, traceback)
File "<path>/numba/core/errors.py", line 733, in new_error_context
reraise(type(newerr), newerr, tb)
File "<path>/numba/core/utils.py", line 80, in reraise
raise value
numba.core.errors.LoweringError: Failed in nopython mode pipeline (step: nopython mode backend)


File "gi196.py", line 22:
def bar(fcs):
<source elided>
a = 10
for t in literal_unroll(fcs):
^

[1] During: lowering "t.25 = typed_getitem(value=$14call_function.4, dtype=Tuple(type(CPUDispatcher(<function foo1 at 0x7f7d000f5ca0>)), type(CPUDispatcher(<function foo2 at 0x7f7ceeec6d30>))), index=$phi20.1)" at gi196.py (22)

# Fixed code
def unified_function_type(numba_types, require_precise=True):
    """Returns a unified Numba function type if possible.

    Parameters
    ----------
    numba_types : tuple
      Numba type instances.
    require_precise : bool
      If True, the returned Numba function type must be precise.

    Returns
    -------
    typ : {numba.core.types.Type, None}
      A unified Numba function type. Or ``None`` when the Numba types
      cannot be unified, e.g. when the ``numba_types`` contains at
      least two different Numba function type instances.

    If ``numba_types`` contains a Numba dispatcher type, the unified
    Numba function type will be an imprecise ``UndefinedFunctionType``
    instance, or None when ``require_precise=True`` is specified.

    Specifying ``require_precise=False`` enables unifying imprecise
    Numba dispatcher instances when used in tuples or if-then branches
    when the precise Numba function cannot be determined on the first
    occurrence that is not a call expression.
    """
    from numba.core.errors import NumbaExperimentalFeatureWarning

    if not (
        numba_types
        and isinstance(numba_types[0], (types.Dispatcher, types.FunctionType))
    ):
        return

    warnings.warn(
        "First-class function type feature is experimental",
        category=NumbaExperimentalFeatureWarning,
    )

    mnargs, mxargs = None, None
    dispatchers = set()
    function = None
    undefined_function = None

    for t in numba_types:
        if isinstance(t, types.Dispatcher):
            mnargs1, mxargs1 = get_nargs_range(t.dispatcher.py_func)
            if mnargs is None:
                mnargs, mxargs = mnargs1, mxargs1
            elif not (mnargs, mxargs) == (mnargs1, mxargs1):
                return
            dispatchers.add(t.dispatcher)
            t = t.dispatcher.get_function_type()
            if t is None:
                continue
        if isinstance(t, types.FunctionType):
            if mnargs is None:
                mnargs = mxargs = t.nargs
            elif not (mnargs == mxargs == t.nargs):
                return numba_types
            if isinstance(t, types.UndefinedFunctionType):
                if undefined_function is None:
                    undefined_function = t
                dispatchers.update(t.dispatchers)
            else:
                if function is None:
                    function = t
                else:
                    assert function == t
        else:
            return
    if require_precise and (function is None or undefined_function is not None):
        return
    if function is not None:
        if undefined_function is not None:
            assert function.nargs == undefined_function.nargs
            function = undefined_function
    elif undefined_function is not None:
        undefined_function.dispatchers.update(dispatchers)
        function = undefined_function
    else:
        function = types.UndefinedFunctionType(mnargs, dispatchers)

    return function