Repository: numba/numba

Issue:
Array.astype not supported with string literals
<!--

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).

-->

## Array.astype not working with literal strings

Providing a literal string like "float32" doesn't work with array.astype. Here is a reproducer from master:

```python
import numba
import numpy as np

@numba.njit
def ex():
      data = np.arange(1000)
      return data.astype("float32")
  
print(ex())
```
Which produces the output:

```python
Traceback (most recent call last):
  File "test.py", line 9, in <module>
    print(ex())
  File "/Users/nicholasriasanovsky/Documents/bodo/nick-numba/numba/core/dispatcher.py", line 421, in _compile_for_args
    error_rewrite(e, 'typing')
  File "/Users/nicholasriasanovsky/Documents/bodo/nick-numba/numba/core/dispatcher.py", line 360, in error_rewrite
    raise e
  File "/Users/nicholasriasanovsky/Documents/bodo/nick-numba/numba/core/dispatcher.py", line 373, in _compile_for_args
    return_val = self.compile(tuple(argtypes))
  File "/Users/nicholasriasanovsky/Documents/bodo/nick-numba/numba/core/dispatcher.py", line 911, in compile
    cres = self._compiler.compile(args, return_type)
  File "/Users/nicholasriasanovsky/Documents/bodo/nick-numba/numba/core/dispatcher.py", line 84, in compile
    raise retval
  File "/Users/nicholasriasanovsky/Documents/bodo/nick-numba/numba/core/dispatcher.py", line 94, in _compile_cached
    retval = self._compile_core(args, return_type)
  File "/Users/nicholasriasanovsky/Documents/bodo/nick-numba/numba/core/dispatcher.py", line 107, in _compile_core
    cres = compiler.compile_extra(self.targetdescr.typing_context,
  File "/Users/nicholasriasanovsky/Documents/bodo/nick-numba/numba/core/compiler.py", line 675, in compile_extra
    return pipeline.compile_extra(func)
  File "/Users/nicholasriasanovsky/Documents/bodo/nick-numba/numba/core/compiler.py", line 419, in compile_extra
    return self._compile_bytecode()
  File "/Users/nicholasriasanovsky/Documents/bodo/nick-numba/numba/core/compiler.py", line 483, in _compile_bytecode
    return self._compile_core()
  File "/Users/nicholasriasanovsky/Documents/bodo/nick-numba/numba/core/compiler.py", line 462, in _compile_core
    raise e
  File "/Users/nicholasriasanovsky/Documents/bodo/nick-numba/numba/core/compiler.py", line 453, in _compile_core
    pm.run(self.state)
  File "/Users/nicholasriasanovsky/Documents/bodo/nick-numba/numba/core/compiler_machinery.py", line 343, in run
    raise patched_exception
  File "/Users/nicholasriasanovsky/Documents/bodo/nick-numba/numba/core/compiler_machinery.py", line 334, in run
    self._runPass(idx, pass_inst, state)
  File "/Users/nicholasriasanovsky/Documents/bodo/nick-numba/numba/core/compiler_lock.py", line 35, in _acquire_compile_lock
    return func(*args, **kwargs)
  File "/Users/nicholasriasanovsky/Documents/bodo/nick-numba/numba/core/compiler_machinery.py", line 289, in _runPass
    mutated |= check(pss.run_pass, internal_state)
  File "/Users/nicholasriasanovsky/Documents/bodo/nick-numba/numba/core/compiler_machinery.py", line 262, in check
    mangled = func(compiler_state)
  File "/Users/nicholasriasanovsky/Documents/bodo/nick-numba/numba/core/typed_passes.py", line 105, in run_pass
    typemap, return_type, calltypes, errs = type_inference_stage(
  File "/Users/nicholasriasanovsky/Documents/bodo/nick-numba/numba/core/typed_passes.py", line 83, in type_inference_stage
    errs = infer.propagate(raise_errors=raise_errors)
  File "/Users/nicholasriasanovsky/Documents/bodo/nick-numba/numba/core/typeinfer.py", line 1074, in propagate
    raise errors[0]
numba.core.errors.TypingError: Failed in nopython mode pipeline (step: nopython frontend)
Invalid use of BoundFunction(array.astype for array(int64, 1d, C)) with parameters (Literal[str](float32))

During: resolving callee type: BoundFunction(array.astype for array(int64, 1d, C))
During: typing of call at test.py (7)


File "test.py", line 7:
def ex():
    <source elided>
    data = np.arange(1000)
    return data.astype("float32")
```

<!--

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!

-->



Discussion:

Resolving patch:
diff --git a/numba/core/typing/arraydecl.py b/numba/core/typing/arraydecl.py
--- a/numba/core/typing/arraydecl.py
+++ b/numba/core/typing/arraydecl.py
@@ -9,7 +9,7 @@
 # import time side effect: array operations requires typing support of sequence
 # defined in collections: e.g. array.shape[i]
 from numba.core.typing import collections
-from numba.core.errors import TypingError
+from numba.core.errors import RequireLiteralValue, TypingError
 
 Indexing = namedtuple("Indexing", ("index", "result", "advanced"))
 
@@ -448,6 +448,9 @@ def resolve_astype(self, ary, args, kws):
         from .npydecl import parse_dtype
         assert not kws
         dtype, = args
+        if isinstance(dtype, types.UnicodeType):
+            raise RequireLiteralValue(("array.astype if dtype is a string it "
+                                       "must be constant"))
         dtype = parse_dtype(dtype)
         if dtype is None:
             return
diff --git a/numba/np/arrayobj.py b/numba/np/arrayobj.py
--- a/numba/np/arrayobj.py
+++ b/numba/np/arrayobj.py
@@ -4146,6 +4146,7 @@ def array_ascontiguousarray(context, builder, sig, args):
 
 
 @lower_builtin("array.astype", types.Array, types.DTypeSpec)
+@lower_builtin("array.astype", types.Array, types.StringLiteral)
 def array_astype(context, builder, sig, args):
     arytype = sig.args[0]
     ary = make_array(arytype)(context, builder, value=args[0])


Test patch:
diff --git a/numba/tests/test_array_methods.py b/numba/tests/test_array_methods.py
--- a/numba/tests/test_array_methods.py
+++ b/numba/tests/test_array_methods.py
@@ -471,6 +471,7 @@ def check(arr, dtype):
         check(arr, np.int32)
         check(arr, np.float32)
         check(arr, np.complex128)
+        check(arr, "float32")
 
         # F-contiguous
         arr = np.arange(24, dtype=np.int8).reshape((3, 8)).T
@@ -491,6 +492,15 @@ def check(arr, dtype):
             check(arr, dt)
         self.assertIn('cannot convert from int32 to Record',
                       str(raises.exception))
+        # Check non-Literal string raises
+        unicode_val = "float32"
+        with self.assertTypingError() as raises:
+            @jit(nopython=True)
+            def foo(dtype):
+                np.array([1]).astype(dtype)
+            foo(unicode_val)
+        self.assertIn('array.astype if dtype is a string it must be constant',
+                      str(raises.exception))
 
     def check_np_frombuffer(self, pyfunc):
         def run(buf):