# Buggy code
def _extract_loop_lifting_candidates(cfg, blocks):
    """
    Returns a list of loops that are candidate for loop lifting
    """

    # check well-formed-ness of the loop
    def same_exit_point(loop):
        "all exits must point to the same location"
        outedges = set()
        for k in loop.exits:
            outedges |= set(x for x, _ in cfg.successors(k))
        return len(outedges) == 1

    def one_entry(loop):
        "there is one entry"
        return len(loop.entries) == 1

    def cannot_yield(loop):
        "cannot have yield inside the loop"
        insiders = set(loop.body) | set(loop.entries) | set(loop.exits)
        for blk in map(blocks.__getitem__, insiders):
            for inst in blk.body:
                if isinstance(inst, ir.Assign):
                    if isinstance(inst.value, ir.Yield):
                        return False
        return True

    return [
        loop
        for loop in find_top_level_loops(cfg)
        if same_exit_point(loop) and one_entry(loop) and cannot_yield(loop)
    ]


# Traceback (ValueError)
Traceback (most recent call last):
File "numbabug.py", line 11, in <module>
numbafunc([])
File "/home/tuukka/.local/lib/python3.5/site-packages/numba/dispatcher.py", line 307, in _compile_for_args
return self.compile(tuple(argtypes))
File "/home/tuukka/.local/lib/python3.5/site-packages/numba/dispatcher.py", line 579, in compile
cres = self._compiler.compile(args, return_type)
File "/home/tuukka/.local/lib/python3.5/site-packages/numba/dispatcher.py", line 80, in compile
flags=flags, locals=self.locals)
File "/home/tuukka/.local/lib/python3.5/site-packages/numba/compiler.py", line 763, in compile_extra
return pipeline.compile_extra(func)
File "/home/tuukka/.local/lib/python3.5/site-packages/numba/compiler.py", line 360, in compile_extra
return self._compile_bytecode()
File "/home/tuukka/.local/lib/python3.5/site-packages/numba/compiler.py", line 722, in _compile_bytecode
return self._compile_core()
File "/home/tuukka/.local/lib/python3.5/site-packages/numba/compiler.py", line 709, in _compile_core
res = pm.run(self.status)
File "/home/tuukka/.local/lib/python3.5/site-packages/numba/compiler.py", line 246, in run
raise patched_exception
File "/home/tuukka/.local/lib/python3.5/site-packages/numba/compiler.py", line 238, in run
stage()
File "/home/tuukka/.local/lib/python3.5/site-packages/numba/compiler.py", line 431, in stage_objectmode_frontend
cres = self.frontend_looplift()
File "/home/tuukka/.local/lib/python3.5/site-packages/numba/compiler.py", line 411, in frontend_looplift
flags=loop_flags)
File "/home/tuukka/.local/lib/python3.5/site-packages/numba/transforms.py", line 191, in loop_lifting
func_ir.variable_lifetime.livemap)
File "/home/tuukka/.local/lib/python3.5/site-packages/numba/transforms.py", line 59, in _loop_lift_get_candidate_infos
[(returnto, _)] = cfg.successors(an_exit)  # requirement checked earlier
ValueError: Failed at object (object mode frontend)
not enough values to unpack (expected 1, got 0)

# Fixed code
def _extract_loop_lifting_candidates(cfg, blocks):
    """
    Returns a list of loops that are candidate for loop lifting
    """

    # check well-formed-ness of the loop
    def same_exit_point(loop):
        "all exits must point to the same location"
        outedges = set()
        for k in loop.exits:
            succs = set(x for x, _ in cfg.successors(k))
            if not succs:
                # If the exit point has no successor, it contains an return
                # statement, which is not handled by the looplifting code.
                # Thus, this loop is not a candidate.
                return False
            outedges |= succs
        return len(outedges) == 1

    def one_entry(loop):
        "there is one entry"
        return len(loop.entries) == 1

    def cannot_yield(loop):
        "cannot have yield inside the loop"
        insiders = set(loop.body) | set(loop.entries) | set(loop.exits)
        for blk in map(blocks.__getitem__, insiders):
            for inst in blk.body:
                if isinstance(inst, ir.Assign):
                    if isinstance(inst.value, ir.Yield):
                        return False
        return True

    return [
        loop
        for loop in find_top_level_loops(cfg)
        if same_exit_point(loop) and one_entry(loop) and cannot_yield(loop)
    ]