Repository: numba/numba

Issue:
np.asarray sometimes doesn't work on List
```python
Python 3.7.6 (default, Jan  8 2020, 13:42:34)
[Clang 4.0.1 (tags/RELEASE_401/final)] :: Anaconda, Inc. on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> import numpy as np
>>> from numba import njit
>>> from numba.typed import List
>>> @njit
... def lt(a, b):
...   return np.asarray(a) <= np.asarray(b)
...
>>> l1 = List()
>>> l1.append(4)
>>> l1.append(2)
>>> l1.append(1)
>>>
>>> l2 = List()
>>> l2.append(2)
>>> l2.append(2)
>>> l2.append(2)
>>>
>>> print(lt(l1, l2))
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/Users/hameerabbasi/miniconda3/envs/sparse/lib/python3.7/site-packages/numba/dispatcher.py", line 401, in _compile_for_args
    error_rewrite(e, 'typing')
  File "/Users/hameerabbasi/miniconda3/envs/sparse/lib/python3.7/site-packages/numba/dispatcher.py", line 344, in error_rewrite
    reraise(type(e), e, None)
  File "/Users/hameerabbasi/miniconda3/envs/sparse/lib/python3.7/site-packages/numba/six.py", line 668, in reraise
    raise value.with_traceback(tb)
numba.errors.TypingError: Failed in nopython mode pipeline (step: nopython frontend)
Invalid use of Function(<function asarray at 0x7f8df02a0440>) with argument(s) of type(s): (ListType[int64])
 * parameterized
In definition 0:
    All templates rejected with literals.
In definition 1:
    All templates rejected without literals.
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 asarray at 0x7f8df02a0440>)
[2] During: typing of call at <stdin> (3)


File "<stdin>", line 3:
<source missing, REPL/exec in use?>

>>> import numba
>>> numba.__version__
'0.48.0'
```


Discussion:
Smaller reproducer:

```python
Python 3.7.6 (default, Jan  8 2020, 13:42:34)
[Clang 4.0.1 (tags/RELEASE_401/final)] :: Anaconda, Inc. on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> import numpy as np
>>> import numba as nb
>>>
>>> @nb.njit
... def to_array(x):
...     return np.asarray(x)
...
>>> l = nb.typed.List()
>>> l.append(5)
>>> to_array(l)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/Users/hameerabbasi/miniconda3/envs/sparse/lib/python3.7/site-packages/numba/dispatcher.py", line 401, in _compile_for_args
    error_rewrite(e, 'typing')
  File "/Users/hameerabbasi/miniconda3/envs/sparse/lib/python3.7/site-packages/numba/dispatcher.py", line 344, in error_rewrite
    reraise(type(e), e, None)
  File "/Users/hameerabbasi/miniconda3/envs/sparse/lib/python3.7/site-packages/numba/six.py", line 668, in reraise
    raise value.with_traceback(tb)
numba.errors.TypingError: Failed in nopython mode pipeline (step: nopython frontend)
Invalid use of Function(<function asarray at 0x7fb330038440>) with argument(s) of type(s): (ListType[int64])
 * parameterized
In definition 0:
    All templates rejected with literals.
In definition 1:
    All templates rejected without literals.
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 asarray at 0x7fb330038440>)
[2] During: typing of call at <stdin> (3)


File "<stdin>", line 3:
<source missing, REPL/exec in use?>
```
Should be possible to implement.
Thanks for filing the issue! @hameerabbasi 
I will try to implement this.
Great, thanks @rohitsanj 
@rohitsanj The use of Numba's extension API `@overload` decorator is strongly recommended for this task. A guide to using `@overload` is [here](http://numba.pydata.org/numba-doc/dev/extending/overloading-guide.html?highlight=overload) and API documentation is [here](http://numba.pydata.org/numba-doc/latest/extending/high-level.html#implementing-functions).
As a new contributor, some instructions for getting set up for development are [here](http://numba.pydata.org/numba-doc/latest/developer/contributing.html#getting-set-up) and are a great place to start.

It may be useful to take a look at examples of pull requests adding support for a NumPy function that have already been done if guidance is needed... here's a couple:

* `np.roll`: https://github.com/numba/numba/pull/3563/files
* `np.roots`: https://github.com/numba/numba/pull/2135/files
Thanks for the links! 😄 @stuartarchibald 

Resolving patch:
diff --git a/numba/np/arraymath.py b/numba/np/arraymath.py
--- a/numba/np/arraymath.py
+++ b/numba/np/arraymath.py
@@ -3877,6 +3877,20 @@ def impl(a, dtype=None):
 
         def impl(a, dtype=None):
             return np.array(a, ty)
+    elif isinstance(a, types.containers.ListType):
+        if not isinstance(a.dtype, (types.Number, types.Boolean)):
+            raise TypingError(
+                "asarray support for List is limited "
+                "to Boolean and Number types")
+
+        target_dtype = a.dtype if is_nonelike(dtype) else dtype
+
+        def impl(a, dtype=None):
+            l = len(a)
+            ret = np.empty(l, dtype=target_dtype)
+            for i, v in enumerate(a):
+                ret[i] = v
+            return ret
 
     return impl
 
diff --git a/numba/np/numpy_support.py b/numba/np/numpy_support.py
--- a/numba/np/numpy_support.py
+++ b/numba/np/numpy_support.py
@@ -599,5 +599,8 @@ def type_can_asarray(arr):
     """ Returns True if the type of 'arr' is supported by the Numba `np.asarray`
     implementation, False otherwise.
     """
-    ok = (types.Array, types.Sequence, types.Tuple, types.Number, types.Boolean)
+
+    ok = (types.Array, types.Sequence, types.Tuple,
+          types.Number, types.Boolean, types.containers.ListType)
+
     return isinstance(arr, ok)


Test patch:
diff --git a/numba/tests/test_np_functions.py b/numba/tests/test_np_functions.py
--- a/numba/tests/test_np_functions.py
+++ b/numba/tests/test_np_functions.py
@@ -10,6 +10,7 @@
 from numba.core.compiler import Flags
 from numba import jit, njit, typeof
 from numba.core import types
+from numba.typed import List, Dict
 from numba.np.numpy_support import numpy_version
 from numba.core.errors import TypingError
 from numba.core.config import IS_WIN32, IS_32BITS
@@ -2911,6 +2912,17 @@ def input_variations():
             yield np.arange(12).reshape(3, 4)
             yield np.arange(12).reshape(3, 4).T
 
+            # Test cases for `numba.typed.List`
+            def make_list(values):
+                a = List()
+                for i in values:
+                    a.append(i)
+                return a
+            yield make_list((1, 2, 3))
+            yield make_list((1.0, 2.0, 3.0))
+            yield make_list((1j, 2j, 3j))
+            yield make_list((True, False, True))
+
         # used to check that if the input is already an array and the dtype is
         # the same as that of the input/omitted then the array itself is
         # returned.
@@ -2950,6 +2962,48 @@ def check_pass_through(jitted, expect_same, params):
                 else:
                     check_pass_through(cfunc, True, params)
 
+    def test_asarray_rejects_List_with_illegal_dtype(self):
+        self.disable_leak_check()
+        cfunc = jit(nopython=True)(asarray)
+
+        def test_reject(alist):
+            with self.assertRaises(TypingError) as e:
+                cfunc(alist)
+            self.assertIn(
+                "asarray support for List is limited "
+                "to Boolean and Number types",
+                str(e.exception))
+
+        def make_none_typed_list():
+            l = List()
+            l.append(None)
+            return l
+
+        def make_nested_list():
+            l = List()
+            m = List()
+            m.append(1)
+            l.append(m)
+            return l
+
+        def make_nested_list_with_dict():
+            l = List()
+            d = Dict()
+            d[1] = "a"
+            l.append(d)
+            return l
+
+        def make_unicode_list():
+            l = List()
+            for i in ("a", "bc", "def"):
+                l.append(i)
+            return l
+
+        test_reject(make_none_typed_list())
+        test_reject(make_nested_list())
+        test_reject(make_nested_list_with_dict())
+        test_reject(make_unicode_list())
+
     def test_repeat(self):
         # np.repeat(a, repeats)
         np_pyfunc = np_repeat