# Buggy code
def push_call_vars(blocks, saved_globals, saved_getattrs, nested=False):
    """push call variables to right before their call site.
    assuming one global/getattr is created for each call site and control flow
    doesn't change it.
    """
    for block in blocks.values():
        new_body = []
        # global/attr variables that are defined in this block already,
        #   no need to reassign them
        block_defs = set()
        for stmt in block.body:

            def process_assign(stmt):
                if isinstance(stmt, ir.Assign):
                    rhs = stmt.value
                    lhs = stmt.target
                    if isinstance(rhs, ir.Global):
                        saved_globals[lhs.name] = stmt
                        block_defs.add(lhs.name)
                    elif isinstance(rhs, ir.Expr) and rhs.op == "getattr":
                        if (
                            rhs.value.name in saved_globals
                            or rhs.value.name in saved_getattrs
                        ):
                            saved_getattrs[lhs.name] = stmt
                            block_defs.add(lhs.name)

            if not nested and isinstance(stmt, Parfor):
                for s in stmt.init_block.body:
                    process_assign(s)
                pblocks = stmt.loop_body.copy()
                push_call_vars(pblocks, saved_globals, saved_getattrs, nested=True)
                new_body.append(stmt)
                continue
            else:
                process_assign(stmt)
            for v in stmt.list_vars():
                new_body += _get_saved_call_nodes(
                    v.name, saved_globals, saved_getattrs, block_defs
                )
            new_body.append(stmt)
        block.body = new_body

    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 push_call_vars(blocks, saved_globals, saved_getattrs, typemap, nested=False):
    """push call variables to right before their call site.
    assuming one global/getattr is created for each call site and control flow
    doesn't change it.
    """
    for block in blocks.values():
        new_body = []
        # global/attr variables that are defined in this block already,
        #   no need to reassign them
        block_defs = set()
        # Some definitions are copied right before the call but then we
        # need to rename that symbol in that block so that typing won't
        # generate an error trying to lock the save var twice.
        # In rename_dict, we collect the symbols that must be renamed in
        # this block.  We collect them then apply the renaming at the end.
        rename_dict = {}
        for stmt in block.body:

            def process_assign(stmt):
                if isinstance(stmt, ir.Assign):
                    rhs = stmt.value
                    lhs = stmt.target
                    if isinstance(rhs, ir.Global):
                        saved_globals[lhs.name] = stmt
                        block_defs.add(lhs.name)
                    elif isinstance(rhs, ir.Expr) and rhs.op == "getattr":
                        if (
                            rhs.value.name in saved_globals
                            or rhs.value.name in saved_getattrs
                        ):
                            saved_getattrs[lhs.name] = stmt
                            block_defs.add(lhs.name)

            if not nested and isinstance(stmt, Parfor):
                for s in stmt.init_block.body:
                    process_assign(s)
                pblocks = stmt.loop_body.copy()
                push_call_vars(
                    pblocks, saved_globals, saved_getattrs, typemap, nested=True
                )
                new_body.append(stmt)
                continue
            else:
                process_assign(stmt)
            for v in stmt.list_vars():
                new_body += _get_saved_call_nodes(
                    v.name, saved_globals, saved_getattrs, block_defs, rename_dict
                )
            new_body.append(stmt)
        block.body = new_body
        # If there is anything to rename then apply the renaming here.
        if len(rename_dict) > 0:
            # Fix-up the typing for the renamed vars.
            for k, v in rename_dict.items():
                typemap[v] = typemap[k]
            # This is only to call replace_var_names which takes a dict.
            temp_blocks = {0: block}
            replace_var_names(temp_blocks, rename_dict)

    return