# Buggy code
def run(self):
    """run parfor conversion pass: replace Numpy calls
    with Parfors when possible and optimize the IR."""
    # run array analysis, a pre-requisite for parfor translation
    remove_dels(self.func_ir.blocks)
    self.array_analysis.run(self.func_ir.blocks)
    # run stencil translation to parfor
    if self.options.stencil:
        stencil_pass = StencilPass(
            self.func_ir,
            self.typemap,
            self.calltypes,
            self.array_analysis,
            self.typingctx,
            self.flags,
        )
        stencil_pass.run()
    if self.options.setitem:
        self._convert_setitem(self.func_ir.blocks)
    if self.options.numpy:
        self._convert_numpy(self.func_ir.blocks)
    if self.options.reduction:
        self._convert_reduce(self.func_ir.blocks)
    if self.options.prange:
        self._convert_loop(self.func_ir.blocks)

    # setup diagnostics now parfors are found
    self.diagnostics.setup(self.func_ir, self.options.fusion)

    dprint_func_ir(self.func_ir, "after parfor pass")

    # simplify CFG of parfor body loops since nested parfors with extra
    # jumps can be created with prange conversion
    simplify_parfor_body_CFG(self.func_ir.blocks)
    # simplify before fusion
    simplify(self.func_ir, self.typemap, self.calltypes)
    # need two rounds of copy propagation to enable fusion of long sequences
    # of parfors like test_fuse_argmin (some PYTHONHASHSEED values since
    # apply_copies_parfor depends on set order for creating dummy assigns)
    simplify(self.func_ir, self.typemap, self.calltypes)

    if self.options.fusion:
        self.func_ir._definitions = build_definitions(self.func_ir.blocks)
        self.array_analysis.equiv_sets = dict()
        self.array_analysis.run(self.func_ir.blocks)
        # reorder statements to maximize fusion
        # push non-parfors down
        maximize_fusion(
            self.func_ir, self.func_ir.blocks, self.typemap, up_direction=False
        )
        dprint_func_ir(self.func_ir, "after maximize fusion down")
        self.fuse_parfors(self.array_analysis, self.func_ir.blocks)
        # push non-parfors up
        maximize_fusion(self.func_ir, self.func_ir.blocks, self.typemap)
        dprint_func_ir(self.func_ir, "after maximize fusion up")
        # try fuse again after maximize
        self.fuse_parfors(self.array_analysis, self.func_ir.blocks)
        dprint_func_ir(self.func_ir, "after fusion")
    # simplify again
    simplify(self.func_ir, self.typemap, self.calltypes)
    # push function call variables inside parfors so gufunc function
    # wouldn't need function variables as argument
    push_call_vars(self.func_ir.blocks, {}, {})
    # simplify again
    simplify(self.func_ir, self.typemap, self.calltypes)
    dprint_func_ir(self.func_ir, "after optimization")
    if config.DEBUG_ARRAY_OPT >= 1:
        print("variable types: ", sorted(self.typemap.items()))
        print("call types: ", self.calltypes)

    if config.DEBUG_ARRAY_OPT >= 3:
        for block_label, block in self.func_ir.blocks.items():
            new_block = []
            scope = block.scope
            for stmt in block.body:
                new_block.append(stmt)
                if isinstance(stmt, ir.Assign):
                    loc = stmt.loc
                    lhs = stmt.target
                    rhs = stmt.value
                    lhs_typ = self.typemap[lhs.name]
                    print(
                        "Adding print for assignment to ",
                        lhs.name,
                        lhs_typ,
                        type(lhs_typ),
                    )
                    if lhs_typ in types.number_domain or isinstance(
                        lhs_typ, types.Literal
                    ):
                        str_var = ir.Var(scope, mk_unique_var("str_var"), loc)
                        self.typemap[str_var.name] = types.StringLiteral(lhs.name)
                        lhs_const = ir.Const(lhs.name, loc)
                        str_assign = ir.Assign(lhs_const, str_var, loc)
                        new_block.append(str_assign)
                        str_print = ir.Print([str_var], None, loc)
                        self.calltypes[str_print] = signature(
                            types.none, self.typemap[str_var.name]
                        )
                        new_block.append(str_print)
                        ir_print = ir.Print([lhs], None, loc)
                        self.calltypes[ir_print] = signature(types.none, lhs_typ)
                        new_block.append(ir_print)
            block.body = new_block

    # run post processor again to generate Del nodes
    post_proc = postproc.PostProcessor(self.func_ir)
    post_proc.run()
    if self.func_ir.is_generator:
        fix_generator_types(self.func_ir.generator_info, self.return_type, self.typemap)
    if sequential_parfor_lowering:
        lower_parfor_sequential(
            self.typingctx, self.func_ir, self.typemap, self.calltypes
        )
    else:
        # prepare for parallel lowering
        # add parfor params to parfors here since lowering is destructive
        # changing the IR after this is not allowed
        parfor_ids, parfors = get_parfor_params(
            self.func_ir.blocks, self.options.fusion, self.nested_fusion_info
        )
        for p in parfors:
            numba.parfor.get_parfor_reductions(
                self.func_ir, p, p.params, self.calltypes
            )
        if config.DEBUG_ARRAY_OPT_STATS:
            name = self.func_ir.func_id.func_qualname
            n_parfors = len(parfor_ids)
            if n_parfors > 0:
                after_fusion = (
                    "After fusion" if self.options.fusion else "With fusion disabled"
                )
                print(
                    ("{}, function {} has {} parallel for-loop(s) #{}.").format(
                        after_fusion, name, n_parfors, parfor_ids
                    )
                )
            else:
                print("Function {} has no Parfor.".format(name))

    return


# Traceback (AssertionError)
---------------------------------------------------------------------------
AssertionError                            Traceback (most recent call last)
~/anaconda3/lib/python3.7/site-packages/numba/errors.py in new_error_context(fmt_, *args, **kwargs)
716     try:
--> 717         yield
718     except NumbaError as e:

~/anaconda3/lib/python3.7/site-packages/numba/lowering.py in lower_block(self, block)
259                                    loc=self.loc, errcls_=defaulterrcls):
--> 260                 self.lower_inst(inst)
261

~/anaconda3/lib/python3.7/site-packages/numba/lowering.py in lower_inst(self, inst)
413                 if isinstance(inst, _class):
--> 414                     func(self, inst)
415                     return

~/anaconda3/lib/python3.7/site-packages/numba/npyufunc/parfor.py in _lower_parfor_parallel(lowerer, parfor)
239         lowerer, parfor, typemap, typingctx, targetctx, flags, {},
--> 240         bool(alias_map), index_var_typ, parfor.races)
241     numba.parfor.sequential_parfor_lowering = False

~/anaconda3/lib/python3.7/site-packages/numba/npyufunc/parfor.py in _create_gufunc_for_parfor_body(lowerer, parfor, typemap, typingctx, targetctx, flags, locals, has_aliases, index_var_typ, races)
1124         flags,
-> 1125         locals)
1126

~/anaconda3/lib/python3.7/site-packages/numba/compiler.py in compile_ir(typingctx, targetctx, func_ir, args, return_type, flags, locals, lifted, lifted_from, is_lifted_loop, library, pipeline_class)
591         return pipeline.compile_ir(func_ir=func_ir, lifted=lifted,
--> 592                                    lifted_from=lifted_from)
593

~/anaconda3/lib/python3.7/site-packages/numba/compiler.py in compile_ir(self, func_ir, lifted, lifted_from)
335         FixupArgs().run_pass(self.state)
--> 336         return self._compile_ir()
337

~/anaconda3/lib/python3.7/site-packages/numba/compiler.py in _compile_ir(self)
391         assert self.state.func_ir is not None
--> 392         return self._compile_core()
393

~/anaconda3/lib/python3.7/site-packages/numba/compiler.py in _compile_core(self)
364                 if is_final_pipeline:
--> 365                     raise e
366         else:

~/anaconda3/lib/python3.7/site-packages/numba/compiler.py in _compile_core(self)
355             try:
--> 356                 pm.run(self.state)
357                 if self.state.cr is not None:

~/anaconda3/lib/python3.7/site-packages/numba/compiler_machinery.py in run(self, state)
327                 patched_exception = self._patch_error(msg, e)
--> 328                 raise patched_exception
329

~/anaconda3/lib/python3.7/site-packages/numba/compiler_machinery.py in run(self, state)
318                 if isinstance(pass_inst, CompilerPass):
--> 319                     self._runPass(idx, pass_inst, state)
320                 else:

~/anaconda3/lib/python3.7/site-packages/numba/compiler_lock.py in _acquire_compile_lock(*args, **kwargs)
31             with self:
---> 32                 return func(*args, **kwargs)
33         return _acquire_compile_lock

~/anaconda3/lib/python3.7/site-packages/numba/compiler_machinery.py in _runPass(self, index, pss, internal_state)
280         with SimpleTimer() as pass_time:
--> 281             mutated |= check(pss.run_pass, internal_state)
282         with SimpleTimer() as finalize_time:

~/anaconda3/lib/python3.7/site-packages/numba/compiler_machinery.py in check(func, compiler_state)
267         def check(func, compiler_state):
--> 268             mangled = func(compiler_state)
269             if mangled not in (True, False):

~/anaconda3/lib/python3.7/site-packages/numba/typed_passes.py in run_pass(self, state)
93                 state.return_type,
---> 94                 state.locals)
95             state.typemap = typemap

~/anaconda3/lib/python3.7/site-packages/numba/typed_passes.py in type_inference_stage(typingctx, interp, args, return_type, locals)
64
---> 65         infer.build_constraint()
66         infer.propagate()

~/anaconda3/lib/python3.7/site-packages/numba/typeinfer.py in build_constraint(self)
903             for inst in blk.body:
--> 904                 self.constrain_statement(inst)
905

~/anaconda3/lib/python3.7/site-packages/numba/typeinfer.py in constrain_statement(self, inst)
1187         if isinstance(inst, ir.Assign):
-> 1188             self.typeof_assign(inst)
1189         elif isinstance(inst, ir.SetItem):

~/anaconda3/lib/python3.7/site-packages/numba/typeinfer.py in typeof_assign(self, inst)
1258         elif isinstance(value, (ir.Global, ir.FreeVar)):
-> 1259             self.typeof_global(inst, inst.target, value)
1260         elif isinstance(value, ir.Arg):

~/anaconda3/lib/python3.7/site-packages/numba/typeinfer.py in typeof_global(self, inst, target, gvar)
1399         lit = types.maybe_literal(gvar.value)
-> 1400         self.lock_type(target.name, lit or typ, loc=inst.loc)
1401         self.assumed_immutables.add(inst)

~/anaconda3/lib/python3.7/site-packages/numba/typeinfer.py in lock_type(self, var, tp, loc, literal_value)
975         tv = self.typevars[var]
--> 976         tv.lock(tp, loc=loc, literal_value=literal_value)
977

~/anaconda3/lib/python3.7/site-packages/numba/typeinfer.py in lock(self, tp, loc, literal_value)
82         assert isinstance(tp, types.Type), type(tp)
---> 83         assert not self.locked
84

AssertionError: Failed in nopython mode pipeline (step: nopython frontend)


During handling of the above exception, another exception occurred:

LoweringError                             Traceback (most recent call last)
<ipython-input-1-1ddce8bd8630> in <module>
51
52 # nb.njit()(foo)(zz, xx, yyh, yyhi, vv, vvi, tc, s, w, h, k)
---> 53 nb.njit(parallel=True)(foo)(zz, xx, yyh, yyhi, vv, vvi, tc, s, w, h, k)

~/anaconda3/lib/python3.7/site-packages/numba/dispatcher.py in _compile_for_args(self, *args, **kws)
418                     e.patch_message('\n'.join((str(e).rstrip(), help_msg)))
419             # ignore the FULL_TRACEBACKS config, this needs reporting!
--> 420             raise e
421
422     def inspect_llvm(self, signature=None):

~/anaconda3/lib/python3.7/site-packages/numba/dispatcher.py in _compile_for_args(self, *args, **kws)
351                 argtypes.append(self.typeof_pyval(a))
352         try:
--> 353             return self.compile(tuple(argtypes))
354         except errors.ForceLiteralArg as e:
355             # Received request for compiler re-entry with the list of arguments

~/anaconda3/lib/python3.7/site-packages/numba/compiler_lock.py in _acquire_compile_lock(*args, **kwargs)
30         def _acquire_compile_lock(*args, **kwargs):
31             with self:
---> 32                 return func(*args, **kwargs)
33         return _acquire_compile_lock
34

~/anaconda3/lib/python3.7/site-packages/numba/dispatcher.py in compile(self, sig)
766             self._cache_misses[sig] += 1
767             try:
--> 768                 cres = self._compiler.compile(args, return_type)
769             except errors.ForceLiteralArg as e:
770                 def folded(args, kws):

~/anaconda3/lib/python3.7/site-packages/numba/dispatcher.py in compile(self, args, return_type)
75
76     def compile(self, args, return_type):
---> 77         status, retval = self._compile_cached(args, return_type)
78         if status:
79             return retval

~/anaconda3/lib/python3.7/site-packages/numba/dispatcher.py in _compile_cached(self, args, return_type)
89
90         try:
---> 91             retval = self._compile_core(args, return_type)
92         except errors.TypingError as e:
93             self._failed_cache[key] = e

~/anaconda3/lib/python3.7/site-packages/numba/dispatcher.py in _compile_core(self, args, return_type)
107                                       args=args, return_type=return_type,
108                                       flags=flags, locals=self.locals,
--> 109                                       pipeline_class=self.pipeline_class)
110         # Check typing error if object mode is used
111         if cres.typing_error is not None and not flags.enable_pyobject:

~/anaconda3/lib/python3.7/site-packages/numba/compiler.py in compile_extra(typingctx, targetctx, func, args, return_type, flags, locals, library, pipeline_class)
526     pipeline = pipeline_class(typingctx, targetctx, library,
527                               args, return_type, flags, locals)
--> 528     return pipeline.compile_extra(func)
529
530

~/anaconda3/lib/python3.7/site-packages/numba/compiler.py in compile_extra(self, func)
324         self.state.lifted = ()
325         self.state.lifted_from = None
--> 326         return self._compile_bytecode()
327
328     def compile_ir(self, func_ir, lifted=(), lifted_from=None):

~/anaconda3/lib/python3.7/site-packages/numba/compiler.py in _compile_bytecode(self)
383         """
384         assert self.state.func_ir is None
--> 385         return self._compile_core()
386
387     def _compile_ir(self):

~/anaconda3/lib/python3.7/site-packages/numba/compiler.py in _compile_core(self)
363                 self.state.status.fail_reason = e
364                 if is_final_pipeline:
--> 365                     raise e
366         else:
367             raise CompilerError("All available pipelines exhausted")

~/anaconda3/lib/python3.7/site-packages/numba/compiler.py in _compile_core(self)
354             res = None
355             try:
--> 356                 pm.run(self.state)
357                 if self.state.cr is not None:
358                     break

~/anaconda3/lib/python3.7/site-packages/numba/compiler_machinery.py in run(self, state)
326                     (self.pipeline_name, pass_desc)
327                 patched_exception = self._patch_error(msg, e)
--> 328                 raise patched_exception
329
330     def dependency_analysis(self):

~/anaconda3/lib/python3.7/site-packages/numba/compiler_machinery.py in run(self, state)
317                 pass_inst = _pass_registry.get(pss).pass_inst
318                 if isinstance(pass_inst, CompilerPass):
--> 319                     self._runPass(idx, pass_inst, state)
320                 else:
321                     raise BaseException("Legacy pass in use")

~/anaconda3/lib/python3.7/site-packages/numba/compiler_lock.py in _acquire_compile_lock(*args, **kwargs)
30         def _acquire_compile_lock(*args, **kwargs):
31             with self:
---> 32                 return func(*args, **kwargs)
33         return _acquire_compile_lock
34

~/anaconda3/lib/python3.7/site-packages/numba/compiler_machinery.py in _runPass(self, index, pss, internal_state)
279             mutated |= check(pss.run_initialization, internal_state)
280         with SimpleTimer() as pass_time:
--> 281             mutated |= check(pss.run_pass, internal_state)
282         with SimpleTimer() as finalize_time:
283             mutated |= check(pss.run_finalizer, internal_state)

~/anaconda3/lib/python3.7/site-packages/numba/compiler_machinery.py in check(func, compiler_state)
266
267         def check(func, compiler_state):
--> 268             mangled = func(compiler_state)
269             if mangled not in (True, False):
270                 msg = ("CompilerPass implementations should return True/False. "

~/anaconda3/lib/python3.7/site-packages/numba/typed_passes.py in run_pass(self, state)
378             state.library.enable_object_caching()
379
--> 380         NativeLowering().run_pass(state) # TODO: Pull this out into the pipeline
381         lowered = state['cr']
382         signature = typing.signature(state.return_type, *state.args)

~/anaconda3/lib/python3.7/site-packages/numba/typed_passes.py in run_pass(self, state)
323                 lower = lowering.Lower(targetctx, library, fndesc, interp,
324                                        metadata=metadata)
--> 325                 lower.lower()
326                 if not flags.no_cpython_wrapper:
327                     lower.create_cpython_wrapper(flags.release_gil)

~/anaconda3/lib/python3.7/site-packages/numba/lowering.py in lower(self)
177         if self.generator_info is None:
178             self.genlower = None
--> 179             self.lower_normal_function(self.fndesc)
180         else:
181             self.genlower = self.GeneratorLower(self)

~/anaconda3/lib/python3.7/site-packages/numba/lowering.py in lower_normal_function(self, fndesc)
218         # Init argument values
219         self.extract_function_arguments()
--> 220         entry_block_tail = self.lower_function_body()
221
222         # Close tail of entry block

~/anaconda3/lib/python3.7/site-packages/numba/lowering.py in lower_function_body(self)
243             bb = self.blkmap[offset]
244             self.builder.position_at_end(bb)
--> 245             self.lower_block(block)
246
247         self.post_lower()

~/anaconda3/lib/python3.7/site-packages/numba/lowering.py in lower_block(self, block)
258             with new_error_context('lowering "{inst}" at {loc}', inst=inst,
259                                    loc=self.loc, errcls_=defaulterrcls):
--> 260                 self.lower_inst(inst)
261
262     def create_cpython_wrapper(self, release_gil=False):

~/anaconda3/lib/python3.7/contextlib.py in __exit__(self, type, value, traceback)
128                 value = type()
129             try:
--> 130                 self.gen.throw(type, value, traceback)
131             except StopIteration as exc:
132                 # Suppress StopIteration *unless* it's the same exception that

~/anaconda3/lib/python3.7/site-packages/numba/errors.py in new_error_context(fmt_, *args, **kwargs)
723         from numba import config
724         tb = sys.exc_info()[2] if config.FULL_TRACEBACKS else None
--> 725         six.reraise(type(newerr), newerr, tb)
726
727

~/anaconda3/lib/python3.7/site-packages/numba/six.py in reraise(tp, value, tb)
667         if value.__traceback__ is not tb:
668             raise value.with_traceback(tb)
--> 669         raise value
670
671 else:

LoweringError: Failed in nopython mode pipeline (step: nopython mode backend)
Failed in nopython mode pipeline (step: nopython frontend)


File "<ipython-input-1-1ddce8bd8630>", line 14:
def foo(zz, xx, yyh, yyhi, vv, vvi, tc, s, w, h, k):
<source elided>

for i in nb.prange(n):
^

[1] During: lowering "id=5[LoopNest(index_variable = parfor_index.104, range = (0, $n.119, 1))]{256: <ir.Block at <ipython-input-1-1ddce8bd8630> (23)>, 258: <ir.Block at <ipython-input-1-1ddce8bd8630> (25)>, 130: <ir.Block at <ipython-input-1-1ddce8bd8630> (18)>, 132: <ir.Block at <ipython-input-1-1ddce8bd8630> (18)>, 268: <ir.Block at <ipython-input-1-1ddce8bd8630> (25)>, 146: <ir.Block at <ipython-input-1-1ddce8bd8630> (19)>, 278: <ir.Block at <ipython-input-1-1ddce8bd8630> (27)>, 156: <ir.Block at <ipython-input-1-1ddce8bd8630> (18)>, 158: <ir.Block at <ipython-input-1-1ddce8bd8630> (20)>, 286: <ir.Block at <ipython-input-1-1ddce8bd8630> (27)>, 166: <ir.Block at <ipython-input-1-1ddce8bd8630> (20)>, 296: <ir.Block at <ipython-input-1-1ddce8bd8630> (27)>, 298: <ir.Block at <ipython-input-1-1ddce8bd8630> (28)>, 174: <ir.Block at <ipython-input-1-1ddce8bd8630> (22)>, 184: <ir.Block at <ipython-input-1-1ddce8bd8630> (22)>, 314: <ir.Block at <ipython-input-1-1ddce8bd8630> (28)>, 194: <ir.Block at <ipython-input-1-1ddce8bd8630> (22)>, 196: <ir.Block at <ipython-input-1-1ddce8bd8630> (23)>, 78: <ir.Block at <ipython-input-1-1ddce8bd8630> (14)>, 344: <ir.Block at <ipython-input-1-1ddce8bd8630> (29)>, 348: <ir.Block at <ipython-input-1-1ddce8bd8630> (28)>, 351: <ir.Block at <ipython-input-1-1ddce8bd8630> (30)>, 352: <ir.Block at <ipython-input-1-1ddce8bd8630> (14)>, 96: <ir.Block at <ipython-input-1-1ddce8bd8630> (17)>, 104: <ir.Block at <ipython-input-1-1ddce8bd8630> (17)>, 112: <ir.Block at <ipython-input-1-1ddce8bd8630> (17)>, 120: <ir.Block at <ipython-input-1-1ddce8bd8630> (17)>}Var(parfor_index.104, <ipython-input-1-1ddce8bd8630> (14))" at <ipython-input-1-1ddce8bd8630> (14)

# Fixed code
def run(self):
    """run parfor conversion pass: replace Numpy calls
    with Parfors when possible and optimize the IR."""
    # run array analysis, a pre-requisite for parfor translation
    remove_dels(self.func_ir.blocks)
    self.array_analysis.run(self.func_ir.blocks)
    # run stencil translation to parfor
    if self.options.stencil:
        stencil_pass = StencilPass(
            self.func_ir,
            self.typemap,
            self.calltypes,
            self.array_analysis,
            self.typingctx,
            self.flags,
        )
        stencil_pass.run()
    if self.options.setitem:
        self._convert_setitem(self.func_ir.blocks)
    if self.options.numpy:
        self._convert_numpy(self.func_ir.blocks)
    if self.options.reduction:
        self._convert_reduce(self.func_ir.blocks)
    if self.options.prange:
        self._convert_loop(self.func_ir.blocks)

    # setup diagnostics now parfors are found
    self.diagnostics.setup(self.func_ir, self.options.fusion)

    dprint_func_ir(self.func_ir, "after parfor pass")

    # simplify CFG of parfor body loops since nested parfors with extra
    # jumps can be created with prange conversion
    simplify_parfor_body_CFG(self.func_ir.blocks)
    # simplify before fusion
    simplify(self.func_ir, self.typemap, self.calltypes)
    # need two rounds of copy propagation to enable fusion of long sequences
    # of parfors like test_fuse_argmin (some PYTHONHASHSEED values since
    # apply_copies_parfor depends on set order for creating dummy assigns)
    simplify(self.func_ir, self.typemap, self.calltypes)

    if self.options.fusion:
        self.func_ir._definitions = build_definitions(self.func_ir.blocks)
        self.array_analysis.equiv_sets = dict()
        self.array_analysis.run(self.func_ir.blocks)
        # reorder statements to maximize fusion
        # push non-parfors down
        maximize_fusion(
            self.func_ir, self.func_ir.blocks, self.typemap, up_direction=False
        )
        dprint_func_ir(self.func_ir, "after maximize fusion down")
        self.fuse_parfors(self.array_analysis, self.func_ir.blocks)
        # push non-parfors up
        maximize_fusion(self.func_ir, self.func_ir.blocks, self.typemap)
        dprint_func_ir(self.func_ir, "after maximize fusion up")
        # try fuse again after maximize
        self.fuse_parfors(self.array_analysis, self.func_ir.blocks)
        dprint_func_ir(self.func_ir, "after fusion")
    # simplify again
    simplify(self.func_ir, self.typemap, self.calltypes)
    # push function call variables inside parfors so gufunc function
    # wouldn't need function variables as argument
    push_call_vars(self.func_ir.blocks, {}, {}, self.typemap)
    # simplify again
    simplify(self.func_ir, self.typemap, self.calltypes)
    dprint_func_ir(self.func_ir, "after optimization")
    if config.DEBUG_ARRAY_OPT >= 1:
        print("variable types: ", sorted(self.typemap.items()))
        print("call types: ", self.calltypes)

    if config.DEBUG_ARRAY_OPT >= 3:
        for block_label, block in self.func_ir.blocks.items():
            new_block = []
            scope = block.scope
            for stmt in block.body:
                new_block.append(stmt)
                if isinstance(stmt, ir.Assign):
                    loc = stmt.loc
                    lhs = stmt.target
                    rhs = stmt.value
                    lhs_typ = self.typemap[lhs.name]
                    print(
                        "Adding print for assignment to ",
                        lhs.name,
                        lhs_typ,
                        type(lhs_typ),
                    )
                    if lhs_typ in types.number_domain or isinstance(
                        lhs_typ, types.Literal
                    ):
                        str_var = ir.Var(scope, mk_unique_var("str_var"), loc)
                        self.typemap[str_var.name] = types.StringLiteral(lhs.name)
                        lhs_const = ir.Const(lhs.name, loc)
                        str_assign = ir.Assign(lhs_const, str_var, loc)
                        new_block.append(str_assign)
                        str_print = ir.Print([str_var], None, loc)
                        self.calltypes[str_print] = signature(
                            types.none, self.typemap[str_var.name]
                        )
                        new_block.append(str_print)
                        ir_print = ir.Print([lhs], None, loc)
                        self.calltypes[ir_print] = signature(types.none, lhs_typ)
                        new_block.append(ir_print)
            block.body = new_block

    # run post processor again to generate Del nodes
    post_proc = postproc.PostProcessor(self.func_ir)
    post_proc.run()
    if self.func_ir.is_generator:
        fix_generator_types(self.func_ir.generator_info, self.return_type, self.typemap)
    if sequential_parfor_lowering:
        lower_parfor_sequential(
            self.typingctx, self.func_ir, self.typemap, self.calltypes
        )
    else:
        # prepare for parallel lowering
        # add parfor params to parfors here since lowering is destructive
        # changing the IR after this is not allowed
        parfor_ids, parfors = get_parfor_params(
            self.func_ir.blocks, self.options.fusion, self.nested_fusion_info
        )
        for p in parfors:
            numba.parfor.get_parfor_reductions(
                self.func_ir, p, p.params, self.calltypes
            )
        if config.DEBUG_ARRAY_OPT_STATS:
            name = self.func_ir.func_id.func_qualname
            n_parfors = len(parfor_ids)
            if n_parfors > 0:
                after_fusion = (
                    "After fusion" if self.options.fusion else "With fusion disabled"
                )
                print(
                    ("{}, function {} has {} parallel for-loop(s) #{}.").format(
                        after_fusion, name, n_parfors, parfor_ids
                    )
                )
            else:
                print("Function {} has no Parfor.".format(name))

    return