# Buggy code
def has_no_side_effect(rhs, lives, call_table):
    """Returns True if this expression has no side effects that
    would prevent re-ordering.
    """
    if isinstance(rhs, ir.Expr) and rhs.op == "call":
        func_name = rhs.func.name
        if func_name not in call_table or call_table[func_name] == []:
            return False
        call_list = call_table[func_name]
        if (
            call_list == ["empty", numpy]
            or call_list == [slice]
            or call_list == ["stencil", numba]
            or call_list == ["log", numpy]
            or call_list == [numba.array_analysis.wrap_index]
        ):
            return True
        elif isinstance(call_list[0], numba.extending._Intrinsic) and (
            call_list[0]._name == "empty_inferred"
            or call_list[0]._name == "unsafe_empty_inferred"
        ):
            return True
        from numba.targets.registry import CPUDispatcher
        from numba.targets.linalg import dot_3_mv_check_args

        if isinstance(call_list[0], CPUDispatcher):
            py_func = call_list[0].py_func
            if py_func == dot_3_mv_check_args:
                return True
        for f in remove_call_handlers:
            if f(rhs, lives, call_list):
                return True
        return False
    if isinstance(rhs, ir.Expr) and rhs.op == "inplace_binop":
        return rhs.lhs.name not in lives
    if isinstance(rhs, ir.Yield):
        return False
    if isinstance(rhs, ir.Expr) and rhs.op == "pair_first":
        # don't remove pair_first since prange looks for it
        return False
    return True


# Traceback (numba.errors.TypingError)
Traceback (most recent call last):
File "./prange.py", line 10, in <module>
func(np.ones(10))
File "/home/bmerry/work/sdp/env3/lib/python3.5/site-packages/numba/dispatcher.py", line 344, in _compile_for_args
reraise(type(e), e, None)
File "/home/bmerry/work/sdp/env3/lib/python3.5/site-packages/numba/six.py", line 658, in reraise
raise value.with_traceback(tb)
numba.errors.TypingError: Failed at nopython (nopython mode backend)
Failed at nopython (nopython frontend)
Unknown attribute 'type' of type class(float64)

File "prange.py", line 8:
def func(a):
<source elided>
for i in numba.prange(a.shape[0]):
a[i] = a.dtype.type(0)
^

[1] During: typing of get attribute at ./prange.py (8)

File "prange.py", line 8:
def func(a):
<source elided>
for i in numba.prange(a.shape[0]):
a[i] = a.dtype.type(0)
^

[1] During: lowering "id=0[LoopNest(index_variable = parfor_index.5, range = (0, $3.6, 1))]{26: <ir.Block at ./prange.py (7)>}Var(parfor_index.5, ./prange.py (7))" at ./prange.py (7)

# Fixed code
def has_no_side_effect(rhs, lives, call_table):
    """Returns True if this expression has no side effects that
    would prevent re-ordering.
    """
    if isinstance(rhs, ir.Expr) and rhs.op == "call":
        func_name = rhs.func.name
        if func_name not in call_table or call_table[func_name] == []:
            return False
        call_list = call_table[func_name]
        if (
            call_list == ["empty", numpy]
            or call_list == [slice]
            or call_list == ["stencil", numba]
            or call_list == ["log", numpy]
            or call_list == ["dtype", numpy]
            or call_list == [numba.array_analysis.wrap_index]
        ):
            return True
        elif isinstance(call_list[0], numba.extending._Intrinsic) and (
            call_list[0]._name == "empty_inferred"
            or call_list[0]._name == "unsafe_empty_inferred"
        ):
            return True
        from numba.targets.registry import CPUDispatcher
        from numba.targets.linalg import dot_3_mv_check_args

        if isinstance(call_list[0], CPUDispatcher):
            py_func = call_list[0].py_func
            if py_func == dot_3_mv_check_args:
                return True
        for f in remove_call_handlers:
            if f(rhs, lives, call_list):
                return True
        return False
    if isinstance(rhs, ir.Expr) and rhs.op == "inplace_binop":
        return rhs.lhs.name not in lives
    if isinstance(rhs, ir.Yield):
        return False
    if isinstance(rhs, ir.Expr) and rhs.op == "pair_first":
        # don't remove pair_first since prange looks for it
        return False
    return True