Repository: numba/numba

Issue:
typed.Dict values() returns wrong results when dict key_type is np.int64
Hi,

I noticed the following issue in Numba typed.Dict: when using dict with key_type=np.int64 getting the values from it using corresponding view might return keys instead. The following simple test works as a reproducer for me:

```
    def test_numba_dict2(self):
        import numpy as np
        from collections import OrderedDict
        import numba
        from numba.typed import Dict
        def test_impl(data):

            value_counts_dict = Dict.empty(
                key_type=np.int64,
                value_type=types.intp
            )
            for key in data:
                value_counts_dict[key] = value_counts_dict.get(key, 0) + 1

            return value_counts_dict, list(value_counts_dict.keys()), list(value_counts_dict.values())
        jitted_func = numba.njit(test_impl)

        data_to_test = np.asarray([0, 1, -1], dtype=np.int64)
        results = jitted_func(data_to_test)
        expected_dict = OrderedDict([(0, 1), (1, 1), (-1, 1)])
        print("DEBUG: results=", results)
        self.assertEqual(results[0], expected_dict)
        self.assertEqual(results[1], list(expected_dict.keys()))
        self.assertEqual(results[2], list(expected_dict.values()))
```
producing the following output:

> DEBUG: results= (DictType[int64,int64]({0: 1, 1: 1, -1: 1}), [0, 1, -1], [0, 1, -1])
> FAIL: test_numba_dict2 (sdc.tests.test_numba.TestNumba)
> Traceback (most recent call last):
>   File "C:\Users\akozlov\AppData\Local\Continuum\anaconda3\hpat\sdc\tests\test_numba.py", l
> ine 308, in test_numba_dict2
>     self.assertEqual(results[2], list(expected_dict.values()))
> AssertionError: Lists differ: [0, 1, -1] != [1, 1, 1]
> 

At the same time if key_type and dtype of data_to_test are np.int32 the test passes:

> DEBUG: results= (DictType[int32,int64]({0: 1, 1: 1, -1: 1}), [0, 1, -1], [1, 1, 1])
> Ran 1 test in 0.994s
> 
> OK
> 

I suspect some memory corruption, since it's not always a case of obtaining incorrect values from the correct dictionary, but it might also be that the computed dictionary itself is corrupted:
```
    def test_numba_dict3(self):
        import numpy as np
        from collections import OrderedDict
        import numba
        from numba.typed import Dict
        def test_impl(data):

            value_counts_dict = Dict.empty(
                key_type=np.int64,
                value_type=types.intp
            )
            for key in data:
                value_counts_dict[key] = value_counts_dict.get(key, 0) + 1

            dict_values = list(value_counts_dict.values())
            return value_counts_dict, dict_values
        jitted_func = numba.njit(test_impl)

        data_to_test = np.asarray([0, 1, -1], dtype=np.int64)
        results = jitted_func(data_to_test)
        expected_dict = OrderedDict([(0, 1), (1, 1), (-1, 1)])
        print("DEBUG: results=", results)
        self.assertEqual(results[0], expected_dict)
        self.assertEqual(results[1], list(expected_dict.values()))
```

gives:

> DEBUG: results= (DictType[int64,int64]({1: 1, 1: 1, 1: 1}), [1, 1, 1])
> FAIL: test_numba_dict3 (sdc.tests.test_numba.TestNumba)
> Traceback (most recent call last):
>   File "C:\Users\akozlov\AppData\Local\Continuum\anaconda3\hpat\sdc\tests\test_numba.py", l
> ine 333, in test_numba_dict3
>     self.assertEqual(results[0], expected_dict)
> AssertionError: DictType[int64,int64]({1: 1, 1: 1, 1: 1}) != OrderedDict([(0, 1), (1, 1), (
> -1, 1)])
> 
> Ran 1 test in 1.017s
> 
> FAILED (failures=1)


I was using Numba:
# Name                    Version                   Build  Channel
numba                     0.47.0.dev0+710.g18fe91598           dev_0    <develop>

Specifically the following commit:
commit 18fe9159849a0d512f1fb284d7cdc6bbf72ceab3 (HEAD -> sdc/latest)

Best Regards,
Alexey.


Discussion:
Thanks for the report. I can reproduce and also suspect corruption, not sure where it's coming from yet. This just segfaults for me:
```python
import numpy as np
from collections import OrderedDict
import numba
from numba import types
from numba.typed import Dict
def test_impl(data):

    value_counts_dict = Dict.empty(
        key_type=np.int64,
        value_type=types.intp
    )
    for key in data:
        print('-' * 80)
        value_counts_dict[key] = value_counts_dict.get(key, 0) + 1
        print(key)
        print(value_counts_dict.get(key, 0))
        print(value_counts_dict)

        #print([x for x in value_counts_dict.values()]) # uncomment to segfault

    return value_counts_dict, list(value_counts_dict.keys()), list(value_counts_dict.values())

jitted_func = numba.njit(test_impl)

data_to_test = np.asarray([0, 1, -1], dtype=np.int64)
results = jitted_func(data_to_test)
expected_dict = OrderedDict([(0, 1), (1, 1), (-1, 1)])
print("DEBUG: results=", results)
assert results[0] == expected_dict
assert results[1] == list(expected_dict.keys())
assert results[2] == list(expected_dict.values()), "%s != %s" % (results[2], list(expected_dict.values()))
```
I also tried swapping reflected for typed lists to see if there was something going wrong in relation to reflection, but the result is the same, corruption/segfault.

```
(gdb) bt
#0  PyUnicode_AsUTF8AndSize () at /tmp/build/80754af9/python_1572016129546/work/Objects/unicodeobject.c:3818
#1  0x00007f5be0f42b29 in __main__::test_impl$241(Array<long long, 1, C, mutable, aligned>) () at segfault.py:18
#2  0x00007f5be0f44b10 in cpython::__main__::test_impl$241(Array<long long, 1, C, mutable, aligned>) ()
```

It seems that values() always return keys when key and value types are same. 

```
import numba

@numba.njit
def get():
    m = { numba.int8(1): numba.int8(10),  numba.int8(2): numba.int8(20)}
    return m

@numba.njit
def print_values(m):
    for v in m.values():
        print(v)
m = get()
print_values(m) # Output = 1 2
```

Resolving patch:
diff --git a/numba/core/types/containers.py b/numba/core/types/containers.py
--- a/numba/core/types/containers.py
+++ b/numba/core/types/containers.py
@@ -624,6 +624,7 @@ def __init__(self, parent):
         self.parent = parent
         self.yield_type = self.parent.keyvalue_type
         name = "items[{}]".format(self.parent.name)
+        self.name = name
         iterator_type = DictIteratorType(self)
         super(DictItemsIterableType, self).__init__(name, iterator_type)
 
@@ -636,6 +637,7 @@ def __init__(self, parent):
         self.parent = parent
         self.yield_type = self.parent.key_type
         name = "keys[{}]".format(self.parent.name)
+        self.name = name
         iterator_type = DictIteratorType(self)
         super(DictKeysIterableType, self).__init__(name, iterator_type)
 
@@ -648,6 +650,7 @@ def __init__(self, parent):
         self.parent = parent
         self.yield_type = self.parent.value_type
         name = "values[{}]".format(self.parent.name)
+        self.name = name
         iterator_type = DictIteratorType(self)
         super(DictValuesIterableType, self).__init__(name, iterator_type)
 
@@ -657,5 +660,6 @@ def __init__(self, iterable):
         self.parent = iterable.parent
         self.iterable = iterable
         yield_type = iterable.yield_type
-        name = "iter[{}->{}]".format(iterable.parent, yield_type)
+        name = "iter[{}->{}],{}".format(iterable.parent, yield_type,
+                                        iterable.name)
         super(DictIteratorType, self).__init__(name, yield_type)


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
@@ -1599,3 +1599,33 @@ def test_dict_create_no_jit_using_empty(self):
             with forbid_codegen():
                 d = Dict.empty(types.int32, types.float32)
                 self.assertEqual(type(d), dict)
+
+
+class TestDictIterator(TestCase):
+    def test_dict_iterator(self):
+        @njit
+        def fun1():
+            dd = Dict.empty(key_type=types.intp,
+                            value_type=types.intp)
+            dd[0] = 10
+            dd[1] = 20
+            dd[2] = 30
+
+            return list(dd.keys()), list(dd.values())
+
+        @njit
+        def fun2():
+            dd = Dict.empty(key_type=types.intp,
+                            value_type=types.intp)
+            dd[4] = 77
+            dd[5] = 88
+            dd[6] = 99
+
+            return list(dd.keys()), list(dd.values())
+        res1 = fun1()
+        res2 = fun2()
+
+        self.assertEqual([0,1,2], res1[0])
+        self.assertEqual([10,20,30], res1[1])
+        self.assertEqual([4,5,6], res2[0])
+        self.assertEqual([77,88,99], res2[1])