Repository: numba/numba

Issue:
Tuples containing bools do not work with `numba.typed.List` or `numba.typed.Dict`
On the latest release (v0.35.1) on Python 3.7, the following:


```
import numba
numba.typed.List.empty_list(numba.typeof(("hello", True)))
```

fails with:

<details>
<summary>Stack Trace</summary>

```
TypingError                               Traceback (most recent call last)
<ipython-input-45-d29ae2daf2f2> in <module>
----> 1 l = numba.typed.List.empty_list(numba.typeof((0.0, "hello", True)))

/opt/anaconda/envs/test/lib/python3.7/site-packages/numba/typed/typedlist.py in empty_list(cls, item_type)
    149         of the list .
    150         """
--> 151         return cls(lsttype=ListType(item_type))
    152 
    153     def __init__(self, **kwargs):

/opt/anaconda/envs/test/lib/python3.7/site-packages/numba/typed/typedlist.py in __init__(self, **kwargs)
    164         """
    165         if kwargs:
--> 166             self._list_type, self._opaque = self._parse_arg(**kwargs)
    167         else:
    168             self._list_type = None

/opt/anaconda/envs/test/lib/python3.7/site-packages/numba/typed/typedlist.py in _parse_arg(self, lsttype, meminfo)
    175             opaque = meminfo
    176         else:
--> 177             opaque = _make_list(lsttype.item_type)
    178         return lsttype, opaque
    179 

/opt/anaconda/envs/test/lib/python3.7/site-packages/numba/dispatcher.py in _compile_for_args(self, *args, **kws)
    374                 e.patch_message(msg)
    375 
--> 376             error_rewrite(e, 'typing')
    377         except errors.UnsupportedError as e:
    378             # Something unsupported is present in the user code, add help info

/opt/anaconda/envs/test/lib/python3.7/site-packages/numba/dispatcher.py in error_rewrite(e, issue_type)
    341                 raise e
    342             else:
--> 343                 reraise(type(e), e, None)
    344 
    345         argtypes = []

/opt/anaconda/envs/test/lib/python3.7/site-packages/numba/six.py in reraise(tp, value, tb)
    656             value = tp()
    657         if value.__traceback__ is not tb:
--> 658             raise value.with_traceback(tb)
    659         raise value
    660 


TypingError: Failed in nopython mode pipeline (step: nopython frontend)
Invalid use of Function(<function new_list at 0x7f29d63d4510>) with argument(s) of type(s): (typeref[(unicode_type, bool)])
 * parameterized
In definition 0:
    LoweringError: Failed in nopython mode pipeline (step: nopython mode backend)
expecting {{i8*, i64, i32, i32, i64, i8*, i8*}, i1} but got {{i8*, i64, i32, i32, i64, i8*, i8*}, i8}

File "../../opt/anaconda/envs/test/lib/python3.7/site-packages/numba/listobject.py", line 347:
    def imp(item):
        <source elided>
        lp = _list_new(itemty)
        _list_set_method_table(lp, itemty)
        ^

[1] During: lowering "$0.7 = call $0.4(lp, $0.6, func=$0.4, args=[Var(lp, /opt/anaconda/envs/test/lib/python3.7/site-packages/numba/listobject.py (346)), Var($0.6, /opt/anaconda/envs/test/lib/python3.7/site-packages/numba/listobject.py (347))], kws=(), vararg=None)" at /opt/anaconda/envs/test/lib/python3.7/site-packages/numba/listobject.py (347)
    raised from /opt/anaconda/envs/test/lib/python3.7/site-packages/numba/six.py:659
In definition 1:
    LoweringError: Failed in nopython mode pipeline (step: nopython mode backend)
expecting {{i8*, i64, i32, i32, i64, i8*, i8*}, i1} but got {{i8*, i64, i32, i32, i64, i8*, i8*}, i8}

File "../../opt/anaconda/envs/test/lib/python3.7/site-packages/numba/listobject.py", line 347:
    def imp(item):
        <source elided>
        lp = _list_new(itemty)
        _list_set_method_table(lp, itemty)
        ^

[1] During: lowering "$0.7 = call $0.4(lp, $0.6, func=$0.4, args=[Var(lp, /opt/anaconda/envs/test/lib/python3.7/site-packages/numba/listobject.py (346)), Var($0.6, /opt/anaconda/envs/test/lib/python3.7/site-packages/numba/listobject.py (347))], kws=(), vararg=None)" at /opt/anaconda/envs/test/lib/python3.7/site-packages/numba/listobject.py (347)
    raised from /opt/anaconda/envs/test/lib/python3.7/site-packages/numba/six.py:659
This error is usually caused by passing an argument of a type that is unsupported by the named function.
[1] During: resolving callee type: Function(<function new_list at 0x7f29d63d4510>)
[2] During: typing of call at /opt/anaconda/envs/test/lib/python3.7/site-packages/numba/typed/typedlist.py (29)

```

</details>


It looks like using a tuple of `(int32, bool)` works fine, however.


## Reporting a bug

<!--

Before submitting a bug report please ensure that you can check off these boxes:

-->

- [x] I am 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 below a minimal working reproducer (if you are unsure how
 to write one see http://matthewrocklin.com/blog/work/2018/02/28/minimal-bug-reports).

<!--

Please include details of the bug here, including, if applicable, what you
expected to happen!

-->



Discussion:
Yes, I am confirm that this is a bug.  

> expecting {{i8*, i64, i32, i32, i64, i8*, i8*}, i1} but got {{i8*, i64, i32, i32, i64, i8*, i8*}, i8}

It's missing a conversion to addressable representation

Resolving patch:
diff --git a/numba/typedobjectutils.py b/numba/typedobjectutils.py
--- a/numba/typedobjectutils.py
+++ b/numba/typedobjectutils.py
@@ -128,8 +128,12 @@ def _get_incref_decref(context, module, datamodel, container_type):
         refct_fnty,
         name='.numba_{}_incref${}'.format(container_type, fe_type),
     )
+
     builder = ir.IRBuilder(incref_fn.append_basic_block())
-    context.nrt.incref(builder, fe_type, builder.load(incref_fn.args[0]))
+    context.nrt.incref(
+        builder, fe_type,
+        datamodel.load_from_data_pointer(builder, incref_fn.args[0]),
+    )
     builder.ret_void()
 
     decref_fn = module.get_or_insert_function(
@@ -137,7 +141,10 @@ def _get_incref_decref(context, module, datamodel, container_type):
         name='.numba_{}_decref${}'.format(container_type, fe_type),
     )
     builder = ir.IRBuilder(decref_fn.append_basic_block())
-    context.nrt.decref(builder, fe_type, builder.load(decref_fn.args[0]))
+    context.nrt.decref(
+        builder, fe_type,
+        datamodel.load_from_data_pointer(builder, decref_fn.args[0]),
+    )
     builder.ret_void()
 
     return incref_fn, decref_fn


Test patch:
diff --git a/numba/tests/test_dictobject.py b/numba/tests/test_dictobject.py
--- a/numba/tests/test_dictobject.py
+++ b/numba/tests/test_dictobject.py
@@ -1229,6 +1229,23 @@ def foo(d):
         # Value is correctly updated
         self.assertPreciseEqual(d[1], np.arange(10, dtype=np.int64) + 100)
 
+    @skip_py2
+    def test_storage_model_mismatch(self):
+        # https://github.com/numba/numba/issues/4520
+        # check for storage model mismatch in refcount ops generation
+        dct = Dict()
+        ref = [
+            ("a", True, "a"),
+            ("b", False, "b"),
+            ("c", False, "c"),
+        ]
+        # populate
+        for x in ref:
+            dct[x] = x
+        # test
+        for i, x in enumerate(ref):
+            self.assertEqual(dct[x], x)
+
 
 class TestDictForbiddenTypes(TestCase):
     def assert_disallow(self, expect, callable):
diff --git a/numba/tests/test_typedlist.py b/numba/tests/test_typedlist.py
--- a/numba/tests/test_typedlist.py
+++ b/numba/tests/test_typedlist.py
@@ -742,3 +742,20 @@ def bag_equal(one, two):
             np.testing.assert_allclose(one.array, two.array)
 
         [bag_equal(a, b) for a, b in zip(expected, got)]
+
+    @skip_py2
+    def test_storage_model_mismatch(self):
+        # https://github.com/numba/numba/issues/4520
+        # check for storage model mismatch in refcount ops generation
+        lst = List()
+        ref = [
+            ("a", True, "a"),
+            ("b", False, "b"),
+            ("c", False, "c"),
+        ]
+        # populate
+        for x in ref:
+            lst.append(x)
+        # test
+        for i, x in enumerate(ref):
+            self.assertEqual(lst[i], ref[i])