def gen_switch(self, data, index):
        """
        Generates a function with a switch table like
        def foo():
            if PLACEHOLDER_INDEX in (<integers>):
                SENTINEL = None
            elif PLACEHOLDER_INDEX in (<integers>):
                SENTINEL = None
            ...
            else:
                raise RuntimeError

        The data is a map of (type : indexes) for example:
        (int64, int64, float64)
        might give:
        {int64: [0, 1], float64: [2]}

        The index is the index variable for the driving range loop over the
        mixed tuple.
        """
        elif_tplt = "\n\telif PLACEHOLDER_INDEX in (%s,):\n\t\tSENTINEL = None"

        # Note regarding the insertion of the garbage/defeat variables below:
        # These values have been designed and inserted to defeat a specific
        # behaviour of the cpython optimizer. The optimization was introduced
        # in Python 3.10.

        # The URL for the BPO is:
        # https://bugs.python.org/issue44626
        # The code for the optimization can be found at:
        # https://github.com/python/cpython/blob/d41abe8/Python/compile.c#L7533-L7557

        # Essentially the CPython optimizer will inline the exit block under
        # certain circumstances and thus replace the jump with a return if the
        # exit block is small enough.  This is an issue for unroller, as it
        # looks for a jump, not a return, when it inserts the generated switch
        # table.

        # Part of the condition for this optimization to be applied is that the
        # exit block not exceed a certain (4 at the time of writing) number of
        # bytecode instructions. We defeat the optimizer by inserting a
        # sufficient number of instructions so that the exit block is big
        # enough. We don't care about this garbage, because the generated exit
        # block is discarded anyway when we smash the switch table into the
        # original function and so all the inserted garbage is dropped again.

        # The final lines of the stacktrace w/o this will look like:
        #
        #  File "/numba/numba/core/untyped_passes.py", line 830, \
        #       in inject_loop_body
        #   sentinel_exits.add(blk.body[-1].target)
        # AttributeError: Failed in nopython mode pipeline \
        #       (step: handles literal_unroll)
        # Failed in literal_unroll_subpipeline mode pipeline \
        #       (step: performs mixed container unroll)
        # 'Return' object has no attribute 'target'
        #
        # Which indicates that a Return has been found instead of a Jump

        b = ('def foo():\n\tif PLACEHOLDER_INDEX in (%s,):\n\t\t'
             'SENTINEL = None\n%s\n\telse:\n\t\t'
             'raise RuntimeError("Unreachable")\n\t'
             'py310_defeat1 = 1\n\t'
             'py310_defeat2 = 2\n\t'
             'py310_defeat3 = 3\n\t'
             'py310_defeat4 = 4\n\t'
             )
        keys = [k for k in data.keys()]

        elifs = []
        for i in range(1, len(keys)):
            elifs.append(elif_tplt % ','.join(map(str, data[keys[i]])))
        src = b % (','.join(map(str, data[keys[0]])), ''.join(elifs))
        wstr = src
        l = {}
        exec(wstr, {}, l)
        bfunc = l['foo']
        branches = compile_to_numba_ir(bfunc, {})
        for lbl, blk in branches.blocks.items():
            for stmt in blk.body:
                if isinstance(stmt, ir.Assign):
                    if isinstance(stmt.value, ir.Global):
                        if stmt.value.name == "PLACEHOLDER_INDEX":
                            stmt.value = index
        return branches

        Generates a function with a switch table like
        def foo():
            if PLACEHOLDER_INDEX in (<integers>):
                SENTINEL = None
            elif PLACEHOLDER_INDEX in (<integers>):
                SENTINEL = None
            ...
            else:
                raise RuntimeError

        The data is a map of (type : indexes) for example:
        (int64, int64, float64)
        might give:
        {int64: [0, 1], float64: [2]}

        The index is the index variable for the driving range loop over the
        mixed tuple.
        
numba/core/untyped_passes.py