Repository: numba/numba

Issue:
problem typing a global tuple of specific integer types as literal
<!--

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).

For more general "how do I do X?" type questions, please speak to us in real
time on https://gitter.im/numba/numba or post to the Numba mailing list
https://groups.google.com/a/continuum.io/forum/#!forum/numba-users.

-->

## Reporting a bug

<!--

Before submitting a bug report please ensure that you can check off these boxes:

-->

- [x] I am using the ~latest released~ master 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).

Since: https://github.com/numba/numba/pull/5182

This:
```python
from numba import njit, types
import numpy as np

x = (types.uint64(10),)

@njit
def foo():
    return x[0]

foo()
```
does this
```
    raise LiteralTypingError("{} cannot be used as a literal".format(ty))
numba.core.errors.LiteralTypingError: Failed in nopython mode pipeline (step: nopython frontend)
<class 'numpy.uint64'> cannot be used as a literal
```
it's because `x` is typed as a `UniTuple(uint64 x 1)`, but the actual value of the global is a tuple size 1 containing a `np.uint64` of value 10. This in turn is because `type.uint64(value)` when evaluated by the interpreter instantiates a `np.uint64(value)`.

As original author, any thoughts on fixing this @luk-f-a ? Should `np.?int??` be special cased in the conversion global value typing so that they can be used as literals? Would such a change of a knock-on effect of erasing e.g. the signedness which may be a valuable property?

This bit of code needs looking at I think:
https://github.com/numba/numba/pull/5182/files#diff-30d845b63b04ca21d10c7f123ade6e57R1482-R1485

CC @gmarkall for CUDA RNG problem that hit this.

Discussion:

Patch:
diff --git a/numba/core/typeinfer.py b/numba/core/typeinfer.py
index 9477a43d1..098fdf9c2 100644
--- a/numba/core/typeinfer.py
+++ b/numba/core/typeinfer.py
@@ -1491,9 +1491,11 @@ http://numba.pydata.org/numba-doc/latest/user/troubleshoot.html#my-code-has-an-u
             typ = typ.copy(readonly=True)
 
         if isinstance(typ, types.BaseAnonymousTuple):
-            types_with_literals = (types.Integer, types.UnicodeType)
-            if all(isinstance(ty, types_with_literals) for ty in typ):
-                typ = types.Tuple([types.literal(val) for val in gvar.value])
+            # if it's a tuple of literal types, swap the type for the more
+            # specific literal version
+            literaled = [types.maybe_literal(x) for x in gvar.value]
+            if all(literaled):
+                typ = types.Tuple(literaled)
 
         self.sentry_modified_builtin(inst, gvar)
         # Setting literal_value for globals because they are handled


Test patch:
diff --git a/numba/tests/test_globals.py b/numba/tests/test_globals.py
index 10d0c33cd..1556e8f9d 100644
--- a/numba/tests/test_globals.py
+++ b/numba/tests/test_globals.py
@@ -76,6 +76,7 @@ tup_int = (1, 2)
 tup_str = ('a', 'b')
 tup_mixed = (1, 'a')
 tup_float = (1.2, 3.5)
+tup_npy_ints = (np.uint64(12), np.int8(3))
 
 def global_int_tuple():
     return tup_int[0] + tup_int[1]
@@ -95,6 +96,10 @@ def global_float_tuple():
     return tup_float[0] + tup_float[1]
 
 
+def global_npy_int_tuple():
+    return tup_npy_ints[0] + tup_npy_ints[1]
+
+
 class TestGlobals(unittest.TestCase):
 
     def check_global_ndarray(self, **jitargs):
@@ -209,6 +214,11 @@ class TestGlobals(unittest.TestCase):
         jitfunc = njit(pyfunc)
         self.assertEqual(pyfunc(), jitfunc())
 
+    def test_global_npy_int_tuple(self):
+        pyfunc = global_npy_int_tuple
+        jitfunc = njit(pyfunc)
+        self.assertEqual(pyfunc(), jitfunc())
+
 
 if __name__ == '__main__':
     unittest.main()