Repository: numba/numba

Issue:
Setting array elements in parallel after increment fails silently
<!--

Thanks for opening an issue! To help the Numba team handle your information
efficiently, please first ensure that there is no other issue present that
already describes the issue you have
(search at https://github.com/numba/numba/issues?&q=is%3Aissue).

-->

## Reporting a bug

<!--

Before submitting a bug report please ensure that you can check off these boxes:

-->

- [x] I have tried using the latest released version of Numba (most recent is
 visible in the change log (https://github.com/numba/numba/blob/master/CHANGE_LOG).
- [x] I have included a self contained code sample to reproduce the problem.
  i.e. it's possible to run as 'python bug.py'.

<!--

Please include details of the bug here, including, if applicable, what you
expected to happen!

-->

Setting all elements of an array with the `arr[:] = 1` syntax doesn't seem to work if there is a previous increment statement, *and* the function is compiled with `parallel=True`.  Here's an example:
```python
import numpy as np
import numba

@numba.njit(parallel=True)
def increment_then_set(a):
    a += 1
    a[:] = 3

x = np.ones(1)
increment_then_set(x)
print(x)  # expect 3, get 2
```

Interestingly, numba warns me that no parallel transformations were possible, so I wouldn't expect it to have done anything to the code, but it still seems to introduce the bug!

I saw there were some related-looking parallel bugs in the issue tracker that were fixed by #7171, so I tested on that branch, and it still seems to exhibit the bug (master too).


Discussion:
Thank you for reporting the issue. I can confirm that on #7171 and on master (0c499bfff)
Also fails (might just be a trivial transformation that numba is doing internally in the first example anyway):
```python
import numpy as np
import numba

@numba.njit(parallel=True)
def increment_then_set(a):
    a += 1
    for i in numba.prange(len(a)):
        a[i] = 3

x = np.ones(1)
increment_then_set(x)
print(x)  # expect 3, get 2
```

Resolving patch:
diff --git a/numba/core/ir_utils.py b/numba/core/ir_utils.py
--- a/numba/core/ir_utils.py
+++ b/numba/core/ir_utils.py
@@ -825,6 +825,8 @@ def find_potential_aliases(blocks, args, typemap, func_ir, alias_map=None,
                 if (isinstance(expr, ir.Expr) and (expr.op == 'cast' or
                     expr.op in ['getitem', 'static_getitem'])):
                     _add_alias(lhs, expr.value.name, alias_map, arg_aliases)
+                if isinstance(expr, ir.Expr) and expr.op == 'inplace_binop':
+                    _add_alias(lhs, expr.lhs.name, alias_map, arg_aliases)
                 # array attributes like A.T
                 if (isinstance(expr, ir.Expr) and expr.op == 'getattr'
                         and expr.attr in ['T', 'ctypes', 'flat']):


Test patch:
diff --git a/numba/tests/test_parfors.py b/numba/tests/test_parfors.py
--- a/numba/tests/test_parfors.py
+++ b/numba/tests/test_parfors.py
@@ -805,6 +805,18 @@ def test_impl(v1, v2, m1, m2):
 
         self.check(test_impl, *self.simple_args)
 
+    def test_inplace_alias(self):
+        # issue7201
+        def test_impl(a):
+            a += 1
+            a[:] = 3
+
+        def comparer(a, b):
+            np.testing.assert_equal(a, b)
+
+        x = np.ones(1)
+        self.check(test_impl, x, check_arg_equality=[comparer])
+
 
 @skip_parfors_unsupported
 class TestParforNumericalMisc(TestParforsBase):