Repository: numba/numba

Issue:
Initialization of lists and a scalar on the same line fails
Hello team, my apologies if it's not a bug, but procedure 

```python
def test(a,b):
    x,y,data,loss=[],[],[],0.0
    for i in range(len(a)):
        x.append(a[i])
        y.append(b[i])
        loss=loss+abs(a[i]-b[i])
    return x,y,loss
test(np.asarray([1,2,3]),np.asarray([4,5,6]))
```
gives
> ([1, 2, 3], [4, 5, 6], 9.0),

and its njitted version
```python
njit(test)(np.asarray([1,2,3]),np.asarray([4,5,6]))
```

fails in Numba 0.43.0 with

> TypingError: Failed in nopython mode pipeline (step: nopython frontend)
> Internal error at <numba.typeinfer.StaticGetItemConstraint object at 0x000002835D8BEB70>:
> --%<----------------------------------------------------------------------------
> Traceback (most recent call last):
>   File "C:\ProgramData\Anaconda3\lib\site-packages\numba\errors.py", line 627, in new_error_context
>     yield
>   File "C:\ProgramData\Anaconda3\lib\site-packages\numba\typeinfer.py", line 348, in __call__
>     assert itemty.is_precise()
> AssertionError
> 
> During handling of the above exception, another exception occurred:
> 
> Traceback (most recent call last):
>   File "C:\ProgramData\Anaconda3\lib\site-packages\numba\typeinfer.py", line 144, in propagate
>     constraint(typeinfer)
>   File "C:\ProgramData\Anaconda3\lib\site-packages\numba\typeinfer.py", line 351, in __call__
>     self.fallback(typeinfer)
>   File "C:\ProgramData\Anaconda3\lib\contextlib.py", line 130, in __exit__
>     self.gen.throw(type, value, traceback)
>   File "C:\ProgramData\Anaconda3\lib\site-packages\numba\errors.py", line 635, in new_error_context
>     six.reraise(type(newerr), newerr, tb)
>   File "C:\ProgramData\Anaconda3\lib\site-packages\numba\six.py", line 659, in reraise
>     raise value
> numba.errors.InternalError: 
> [1] During: typing of static-get-item at <ipython-input-564-f68363d9d85d> (2)
> --%<----------------------------------------------------------------------------
> 
> 
> File "<ipython-input-564-f68363d9d85d>", line 2:
> def test(a,b):
>     x,y,data,loss=[],[],[],0.0

I know it looks ugly to init variables like this, but since it's syntactically valid in vanilla python, maybe it can also be expected to be compilable by Numba?


Discussion:
I'm curious how multiple assignment shows up in the bytecode.  Does Python actually build and immediately unpack a tuple?  (If it does, that would explain why Numba has a problem.)
It looks like:
```
  5           0 BUILD_LIST               0
              2 BUILD_LIST               0
              4 BUILD_LIST               0
              6 LOAD_CONST               1 (0.0)
              8 BUILD_TUPLE              4
             10 UNPACK_SEQUENCE          4
             12 STORE_FAST               2 (x)
             14 STORE_FAST               3 (y)
             16 STORE_FAST               4 (data)
             18 STORE_FAST               5 (loss)
```
the issue is that there's `list(undefined)` being fetched from a static getitem from the unpack tuple. I think it might be ok to remove that assert now as the undefined list would get caught in the legalization pass and a more suitable complaint issued.

If we could rewrite that assignment into:
```
x = []
y = []
data = []
loss= 0.0
```
Then I think type inference would be able to figure out what the list element types are based on the loop body.
I'm not sure that's needed? I think it's that the list `data` is undefined (it's dead) which is the problem, and because the multiple assignment is handled via a static getitem it hits a code path that isn't travelled often which has that assert on it. Were that assert removed the legalization pass would pick up that `data` is dead and complain about it being an undefined list type?

This seems ok:
```python
from numba import njit
import numpy as np

def test(a,b):
    x, y, loss = [], [], 0.0
    for i in range(len(a)):
        x.append(a[i])
        y.append(b[i])
        loss=loss+abs(a[i]-b[i])
    return x,y,loss

test(np.asarray([1,2,3]),np.asarray([4,5,6]))
njit(test)(np.asarray([1,2,3]), np.asarray([4,5,6]))
```

Oh, I see.  I missed that `data` was unused.  Makes sense!

Resolving patch:
diff --git a/numba/typeinfer.py b/numba/typeinfer.py
--- a/numba/typeinfer.py
+++ b/numba/typeinfer.py
@@ -345,7 +345,8 @@ def __call__(self, typeinfer):
 
                 if sig is not None:
                     itemty = sig.return_type
-                    assert itemty.is_precise()
+                    # if the itemty is not precise, let it through, unification
+                    # will catch it and produce a better error message
                     typeinfer.add_type(self.target, itemty, loc=self.loc)
                 elif self.fallback is not None:
                     self.fallback(typeinfer)


Test patch:
diff --git a/numba/tests/test_tuples.py b/numba/tests/test_tuples.py
--- a/numba/tests/test_tuples.py
+++ b/numba/tests/test_tuples.py
@@ -95,6 +95,13 @@ def identity(tup):
 def index_method_usecase(tup, value):
     return tup.index(value)
 
+def tuple_unpack_static_getitem_err():
+    # see issue3895, `c` is imprecise
+    a, b, c, d = [], [], [], 0.0
+    a.append(1)
+    b.append(1)
+    return
+
 
 class TestTupleReturn(TestCase):
 
@@ -223,6 +230,15 @@ def test_index(self):
         with self.assertTypingError():
             cr = compile_isolated(pyfunc, (typ,))
 
+        # test unpack, staticgetitem with imprecise type (issue #3895)
+        pyfunc = tuple_unpack_static_getitem_err
+        with self.assertTypingError() as raises:
+            cr = compile_isolated(pyfunc, ())
+        msg = ("Cannot infer the type of variable 'c', have imprecise type: "
+               "list(undefined).")
+        self.assertIn(msg, str(raises.exception))
+
+
     def test_in(self):
         pyfunc = in_usecase
         cr = compile_isolated(pyfunc,