# Buggy code
def _lower_array_expr(lowerer, expr):
    """Lower an array expression built by RewriteArrayExprs."""
    expr_name = "__numba_array_expr_%s" % (hex(hash(expr)).replace("-", "_"))
    expr_filename = expr.loc.filename
    expr_var_list = expr.list_vars()
    # The expression may use a given variable several times, but we
    # should only create one parameter for it.
    expr_var_unique = sorted(set(expr_var_list), key=lambda var: var.name)

    # Arguments are the names external to the new closure
    expr_args = [var.name for var in expr_var_unique]

    # 1. Create an AST tree from the array expression.

    with _legalize_parameter_names(expr_var_unique) as expr_params:
        if hasattr(ast, "arg"):
            # Should be Python 3.x
            ast_args = [ast.arg(param_name, None) for param_name in expr_params]
        else:
            # Should be Python 2.x
            ast_args = [ast.Name(param_name, ast.Param()) for param_name in expr_params]
        # Parse a stub function to ensure the AST is populated with
        # reasonable defaults for the Python version.
        ast_module = ast.parse(
            "def {0}(): return".format(expr_name), expr_filename, "exec"
        )
        assert hasattr(ast_module, "body") and len(ast_module.body) == 1
        ast_fn = ast_module.body[0]
        ast_fn.args.args = ast_args
        ast_fn.body[0].value, namespace = _arr_expr_to_ast(expr.expr)
        ast.fix_missing_locations(ast_module)

    # 2. Compile the AST module and extract the Python function.

    code_obj = compile(ast_module, expr_filename, "exec")
    six.exec_(code_obj, namespace)
    impl = namespace[expr_name]

    # 3. Now compile a ufunc using the Python function as kernel.

    context = lowerer.context
    builder = lowerer.builder
    outer_sig = expr.ty(*(lowerer.typeof(name) for name in expr_args))
    inner_sig_args = []
    for argty in outer_sig.args:
        if isinstance(argty, types.Array):
            inner_sig_args.append(argty.dtype)
        else:
            inner_sig_args.append(argty)
    inner_sig = outer_sig.return_type.dtype(*inner_sig_args)

    # Follow the Numpy error model.  Note this also allows e.g. vectorizing
    # division (issue #1223).
    flags = compiler.Flags()
    flags.set("error_model", "numpy")
    cres = context.compile_subroutine(
        builder, impl, inner_sig, flags=flags, caching=False
    )

    # Create kernel subclass calling our native function
    from ..targets import npyimpl

    class ExprKernel(npyimpl._Kernel):
        def generate(self, *args):
            arg_zip = zip(args, self.outer_sig.args, inner_sig.args)
            cast_args = [self.cast(val, inty, outty) for val, inty, outty in arg_zip]
            result = self.context.call_internal(
                builder, cres.fndesc, inner_sig, cast_args
            )
            return self.cast(result, inner_sig.return_type, self.outer_sig.return_type)

    args = [lowerer.loadvar(name) for name in expr_args]
    return npyimpl.numpy_ufunc_kernel(
        context, builder, outer_sig, args, ExprKernel, explicit_output=False
    )


# Traceback (numba.errors.TypingError)
@njit((float_[:], optional(float_[:])))
... def f(x, y):
...     if y is None:
...         return x
...     return x + y
...
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "/Users/lizli/anaconda3/lib/python3.7/site-packages/numba/decorators.py", line 198, in wrapper
disp.compile(sig)
File "/Users/lizli/anaconda3/lib/python3.7/site-packages/numba/compiler_lock.py", line 32, in _acquire_compile_lock
return func(*args, **kwargs)
File "/Users/lizli/anaconda3/lib/python3.7/site-packages/numba/dispatcher.py", line 655, in compile
cres = self._compiler.compile(args, return_type)
File "/Users/lizli/anaconda3/lib/python3.7/site-packages/numba/dispatcher.py", line 82, in compile
pipeline_class=self.pipeline_class)
File "/Users/lizli/anaconda3/lib/python3.7/site-packages/numba/compiler.py", line 926, in compile_extra
return pipeline.compile_extra(func)
File "/Users/lizli/anaconda3/lib/python3.7/site-packages/numba/compiler.py", line 374, in compile_extra
return self._compile_bytecode()
File "/Users/lizli/anaconda3/lib/python3.7/site-packages/numba/compiler.py", line 857, in _compile_bytecode
return self._compile_core()
File "/Users/lizli/anaconda3/lib/python3.7/site-packages/numba/compiler.py", line 844, in _compile_core
res = pm.run(self.status)
File "/Users/lizli/anaconda3/lib/python3.7/site-packages/numba/compiler_lock.py", line 32, in _acquire_compile_lock
return func(*args, **kwargs)
File "/Users/lizli/anaconda3/lib/python3.7/site-packages/numba/compiler.py", line 255, in run
raise patched_exception
File "/Users/lizli/anaconda3/lib/python3.7/site-packages/numba/compiler.py", line 246, in run
stage()
File "/Users/lizli/anaconda3/lib/python3.7/site-packages/numba/compiler.py", line 717, in stage_nopython_backend
self._backend(lowerfn, objectmode=False)
File "/Users/lizli/anaconda3/lib/python3.7/site-packages/numba/compiler.py", line 666, in _backend
lowered = lowerfn()
File "/Users/lizli/anaconda3/lib/python3.7/site-packages/numba/compiler.py", line 653, in backend_nopython_mode
self.metadata)
File "/Users/lizli/anaconda3/lib/python3.7/site-packages/numba/compiler.py", line 1048, in native_lowering_stage
lower.lower()
File "/Users/lizli/anaconda3/lib/python3.7/site-packages/numba/lowering.py", line 178, in lower
self.lower_normal_function(self.fndesc)
File "/Users/lizli/anaconda3/lib/python3.7/site-packages/numba/lowering.py", line 219, in lower_normal_function
entry_block_tail = self.lower_function_body()
File "/Users/lizli/anaconda3/lib/python3.7/site-packages/numba/lowering.py", line 244, in lower_function_body
self.lower_block(block)
File "/Users/lizli/anaconda3/lib/python3.7/site-packages/numba/lowering.py", line 259, in lower_block
self.lower_inst(inst)
File "/Users/lizli/anaconda3/lib/python3.7/site-packages/numba/lowering.py", line 308, in lower_inst
val = self.lower_assign(ty, inst)
File "/Users/lizli/anaconda3/lib/python3.7/site-packages/numba/lowering.py", line 454, in lower_assign
return self.lower_expr(ty, value)
File "/Users/lizli/anaconda3/lib/python3.7/site-packages/numba/lowering.py", line 1045, in lower_expr
res = self.context.special_ops[expr.op](self, expr)
File "/Users/lizli/anaconda3/lib/python3.7/site-packages/numba/npyufunc/array_exprs.py", line 393, in _lower_array_expr
caching=False)
File "/Users/lizli/anaconda3/lib/python3.7/site-packages/numba/targets/base.py", line 843, in compile_subroutine
flags=flags)
File "/Users/lizli/anaconda3/lib/python3.7/site-packages/numba/targets/base.py", line 815, in _compile_subroutine_no_cache
locals=locals)
File "/Users/lizli/anaconda3/lib/python3.7/site-packages/numba/compiler.py", line 951, in compile_internal
return pipeline.compile_extra(func)
File "/Users/lizli/anaconda3/lib/python3.7/site-packages/numba/compiler.py", line 374, in compile_extra
return self._compile_bytecode()
File "/Users/lizli/anaconda3/lib/python3.7/site-packages/numba/compiler.py", line 857, in _compile_bytecode
return self._compile_core()
File "/Users/lizli/anaconda3/lib/python3.7/site-packages/numba/compiler.py", line 844, in _compile_core
res = pm.run(self.status)
File "/Users/lizli/anaconda3/lib/python3.7/site-packages/numba/compiler_lock.py", line 32, in _acquire_compile_lock
return func(*args, **kwargs)
File "/Users/lizli/anaconda3/lib/python3.7/site-packages/numba/compiler.py", line 255, in run
raise patched_exception
File "/Users/lizli/anaconda3/lib/python3.7/site-packages/numba/compiler.py", line 246, in run
stage()
File "/Users/lizli/anaconda3/lib/python3.7/site-packages/numba/compiler.py", line 485, in stage_nopython_frontend
self.locals)
File "/Users/lizli/anaconda3/lib/python3.7/site-packages/numba/compiler.py", line 1029, in type_inference_stage
infer.propagate()
File "/Users/lizli/anaconda3/lib/python3.7/site-packages/numba/typeinfer.py", line 860, in propagate
raise errors[0]
numba.errors.TypingError: Failed in nopython mode pipeline (step: nopython mode backend)
Failed in nopython mode pipeline (step: nopython frontend)
No conversion from array(float32, 1d, C) to float32 for '$0.4', defined at None

File "<stdin>", line 3:
<source missing, REPL/exec in use?>

[1] During: typing of assignment at <stdin> (3)

File "<stdin>", line 3:
<source missing, REPL/exec in use?>

[1] During: lowering "$12.3 = arrayexpr(expr=(<built-in function add>, [Var(x, <stdin> (3)), Var(y, <stdin> (3))]), ty=array(float32, 1d, C))" at <stdin> (5)

# Fixed code
def _lower_array_expr(lowerer, expr):
    """Lower an array expression built by RewriteArrayExprs."""
    expr_name = "__numba_array_expr_%s" % (hex(hash(expr)).replace("-", "_"))
    expr_filename = expr.loc.filename
    expr_var_list = expr.list_vars()
    # The expression may use a given variable several times, but we
    # should only create one parameter for it.
    expr_var_unique = sorted(set(expr_var_list), key=lambda var: var.name)

    # Arguments are the names external to the new closure
    expr_args = [var.name for var in expr_var_unique]

    # 1. Create an AST tree from the array expression.

    with _legalize_parameter_names(expr_var_unique) as expr_params:
        if hasattr(ast, "arg"):
            # Should be Python 3.x
            ast_args = [ast.arg(param_name, None) for param_name in expr_params]
        else:
            # Should be Python 2.x
            ast_args = [ast.Name(param_name, ast.Param()) for param_name in expr_params]
        # Parse a stub function to ensure the AST is populated with
        # reasonable defaults for the Python version.
        ast_module = ast.parse(
            "def {0}(): return".format(expr_name), expr_filename, "exec"
        )
        assert hasattr(ast_module, "body") and len(ast_module.body) == 1
        ast_fn = ast_module.body[0]
        ast_fn.args.args = ast_args
        ast_fn.body[0].value, namespace = _arr_expr_to_ast(expr.expr)
        ast.fix_missing_locations(ast_module)

    # 2. Compile the AST module and extract the Python function.

    code_obj = compile(ast_module, expr_filename, "exec")
    six.exec_(code_obj, namespace)
    impl = namespace[expr_name]

    # 3. Now compile a ufunc using the Python function as kernel.

    context = lowerer.context
    builder = lowerer.builder
    outer_sig = expr.ty(*(lowerer.typeof(name) for name in expr_args))
    inner_sig_args = []
    for argty in outer_sig.args:
        if isinstance(argty, types.Optional):
            argty = argty.type
        if isinstance(argty, types.Array):
            inner_sig_args.append(argty.dtype)
        else:
            inner_sig_args.append(argty)
    inner_sig = outer_sig.return_type.dtype(*inner_sig_args)

    # Follow the Numpy error model.  Note this also allows e.g. vectorizing
    # division (issue #1223).
    flags = compiler.Flags()
    flags.set("error_model", "numpy")
    cres = context.compile_subroutine(
        builder, impl, inner_sig, flags=flags, caching=False
    )

    # Create kernel subclass calling our native function
    from ..targets import npyimpl

    class ExprKernel(npyimpl._Kernel):
        def generate(self, *args):
            arg_zip = zip(args, self.outer_sig.args, inner_sig.args)
            cast_args = [self.cast(val, inty, outty) for val, inty, outty in arg_zip]
            result = self.context.call_internal(
                builder, cres.fndesc, inner_sig, cast_args
            )
            return self.cast(result, inner_sig.return_type, self.outer_sig.return_type)

    args = [lowerer.loadvar(name) for name in expr_args]
    return npyimpl.numpy_ufunc_kernel(
        context, builder, outer_sig, args, ExprKernel, explicit_output=False
    )