Repository: numba/numba

Issue:
Unable to create set from unicode containing numba.typed.List
```python
from numba import njit
from numba.typed import List


@njit
def foo(l):
    return set(l)


print(foo(List((1,2,3))))
print(foo(List(("a","b","c"))))
```


Discussion:
```
💥 zsh» python foo047.py                                                                                                                                                              :(
{1, 2, 3}
Traceback (most recent call last):
  File "/Users/vhaenel/git/numba/numba/core/typeinfer.py", line 149, in propagate
    constraint(typeinfer)
  File "/Users/vhaenel/git/numba/numba/core/typeinfer.py", line 487, in __call__
    self.resolve(typeinfer, typevars, fnty)
  File "/Users/vhaenel/git/numba/numba/core/typeinfer.py", line 507, in resolve
    sig = typeinfer.resolve_call(fnty, pos_args, kw_args)
  File "/Users/vhaenel/git/numba/numba/core/typeinfer.py", line 1451, in resolve_call
    return self.context.resolve_function_type(fnty, pos_args, kw_args)
  File "/Users/vhaenel/git/numba/numba/core/typing/context.py", line 214, in resolve_function_type
    raise last_exception
  File "/Users/vhaenel/git/numba/numba/core/typing/context.py", line 197, in resolve_function_type
    res = self._resolve_user_function_type(func, args, kws)
  File "/Users/vhaenel/git/numba/numba/core/typing/context.py", line 249, in _resolve_user_function_type
    return func.get_call_type(self, args, kws)
  File "/Users/vhaenel/git/numba/numba/core/types/functions.py", line 148, in get_call_type
    failures.raise_error()
  File "/Users/vhaenel/git/numba/numba/core/types/functions.py", line 77, in raise_error
    raise errors.TypingError(self.format())
numba.core.errors.TypingError: Invalid use of Function(<class 'set'>) with argument(s) of type(s): (ListType[unicode_type])
 * 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(<class 'set'>)
[2] During: typing of call at foo047.py (7)


The above exception was the direct cause of the following exception:

Traceback (most recent call last):
  File "foo047.py", line 11, in <module>
    print(foo(List(("a","b","c"))))
  File "/Users/vhaenel/git/numba/numba/core/dispatcher.py", line 401, in _compile_for_args
    error_rewrite(e, 'typing')
  File "/Users/vhaenel/git/numba/numba/core/dispatcher.py", line 342, in error_rewrite
    raise e
  File "/Users/vhaenel/git/numba/numba/core/dispatcher.py", line 353, in _compile_for_args
    return self.compile(tuple(argtypes))
  File "/Users/vhaenel/git/numba/numba/core/compiler_lock.py", line 32, in _acquire_compile_lock
    return func(*args, **kwargs)
  File "/Users/vhaenel/git/numba/numba/core/dispatcher.py", line 794, in compile
    cres = self._compiler.compile(args, return_type)
  File "/Users/vhaenel/git/numba/numba/core/dispatcher.py", line 81, in compile
    raise retval
  File "/Users/vhaenel/git/numba/numba/core/dispatcher.py", line 91, in _compile_cached
    retval = self._compile_core(args, return_type)
  File "/Users/vhaenel/git/numba/numba/core/dispatcher.py", line 104, in _compile_core
    cres = compiler.compile_extra(self.targetdescr.typing_context,
  File "/Users/vhaenel/git/numba/numba/core/compiler.py", line 568, in compile_extra
    return pipeline.compile_extra(func)
  File "/Users/vhaenel/git/numba/numba/core/compiler.py", line 339, in compile_extra
    return self._compile_bytecode()
  File "/Users/vhaenel/git/numba/numba/core/compiler.py", line 401, in _compile_bytecode
    return self._compile_core()
  File "/Users/vhaenel/git/numba/numba/core/compiler.py", line 381, in _compile_core
    raise e
  File "/Users/vhaenel/git/numba/numba/core/compiler.py", line 372, in _compile_core
    pm.run(self.state)
  File "/Users/vhaenel/git/numba/numba/core/compiler_machinery.py", line 341, in run
    raise patched_exception
  File "/Users/vhaenel/git/numba/numba/core/compiler_machinery.py", line 332, in run
    self._runPass(idx, pass_inst, state)
  File "/Users/vhaenel/git/numba/numba/core/compiler_lock.py", line 32, in _acquire_compile_lock
    return func(*args, **kwargs)
  File "/Users/vhaenel/git/numba/numba/core/compiler_machinery.py", line 291, in _runPass
    mutated |= check(pss.run_pass, internal_state)
  File "/Users/vhaenel/git/numba/numba/core/compiler_machinery.py", line 264, in check
    mangled = func(compiler_state)
  File "/Users/vhaenel/git/numba/numba/core/typed_passes.py", line 92, in run_pass
    typemap, return_type, calltypes = type_inference_stage(
  File "/Users/vhaenel/git/numba/numba/core/typed_passes.py", line 70, in type_inference_stage
    infer.propagate(raise_errors=raise_errors)
  File "/Users/vhaenel/git/numba/numba/core/typeinfer.py", line 986, in propagate
    raise errors[0]
numba.core.errors.TypingError: Failed in nopython mode pipeline (step: nopython frontend)
Invalid use of Function(<class 'set'>) with argument(s) of type(s): (ListType[unicode_type])
 * 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(<class 'set'>)
[2] During: typing of call at foo047.py (7)


File "foo047.py", line 7:
def foo(l):
    return set(l)
```
This is because, for reasons of probably it just being overlooked, `types.UnicodeType` doesn't inherit from `types.Hashable`.

Resolving patch:
diff --git a/numba/core/types/misc.py b/numba/core/types/misc.py
--- a/numba/core/types/misc.py
+++ b/numba/core/types/misc.py
@@ -1,4 +1,4 @@
-from numba.core.types.abstract import Callable, Literal, Type
+from numba.core.types.abstract import Callable, Literal, Type, Hashable
 from numba.core.types.common import (Dummy, IterableType, Opaque,
                                      SimpleIteratorType)
 from numba.core.typeconv import Conversion
@@ -498,7 +498,7 @@ def get_call_type(self, context, args, kws):
         return typing.signature(self, *posargs)
 
 
-class UnicodeType(IterableType):
+class UnicodeType(IterableType, Hashable):
 
     def __init__(self, name):
         super(UnicodeType, self).__init__(name)
diff --git a/numba/cpython/setobj.py b/numba/cpython/setobj.py
--- a/numba/cpython/setobj.py
+++ b/numba/cpython/setobj.py
@@ -198,8 +198,15 @@ def _lookup(self, item, h, for_insert=False):
 
         mask = self.mask
         dtype = self._ty.dtype
-        eqfn = context.get_function(operator.eq,
-                                    typing.signature(types.boolean, dtype, dtype))
+        tyctx = context.typing_context
+        fnty = tyctx.resolve_value_type(operator.eq)
+        sig = fnty.get_call_type(tyctx, (dtype, dtype), {})
+        for arg in sig.args:
+            if context.data_model_manager[arg].contains_nrt_meminfo():
+                msg = ("Use of reference counted items in 'set()' is "
+                       "unsupported, offending type is: '{}'.")
+                raise ValueError(msg.format(arg))
+        eqfn = context.get_function(fnty, sig)
 
         one = ir.Constant(intp_t, 1)
         five = ir.Constant(intp_t, 5)


Test patch:
diff --git a/numba/tests/test_sets.py b/numba/tests/test_sets.py
--- a/numba/tests/test_sets.py
+++ b/numba/tests/test_sets.py
@@ -9,7 +9,7 @@
 
 import numpy as np
 
-from numba.core.compiler import compile_isolated, Flags
+from numba.core.compiler import compile_isolated, Flags, errors
 from numba import jit
 from numba.core import types
 import unittest
@@ -399,7 +399,7 @@ def test_update(self):
         b = self.duplicates_array(50)
         c = self.sparse_array(50)
         check(a, b, c)
-    
+
     def test_bool(self):
         pyfunc = bool_usecase
         check = self.unordered_checker(pyfunc)
@@ -426,6 +426,19 @@ def test_remove_error(self):
         with self.assertRaises(KeyError) as raises:
             cfunc((1, 2, 3), (5, ))
 
+    def test_refcounted_types_forbidden(self):
+        # References are leaked on exception
+        self.disable_leak_check()
+
+        pyfunc = constructor_usecase
+        cfunc = jit(nopython=True)(pyfunc)
+        with self.assertRaises(errors.LoweringError) as raises:
+            cfunc("abc")
+
+        excstr = str(raises.exception)
+        self.assertIn("Use of reference counted items in 'set()'", excstr)
+        self.assertIn("offending type is: 'unicode_type'", excstr)
+
     def test_discard(self):
         pyfunc = discard_usecase
         check = self.unordered_checker(pyfunc)
diff --git a/numba/tests/test_unicode.py b/numba/tests/test_unicode.py
--- a/numba/tests/test_unicode.py
+++ b/numba/tests/test_unicode.py
@@ -9,6 +9,7 @@
 from numba.core.errors import TypingError
 from numba.cpython.unicode import _MAX_UNICODE
 from numba.core.types.functions import _header_lead
+from numba.extending import overload
 
 
 _py37_or_later = utils.PYVERSION >= (3, 7)
@@ -2515,6 +2516,27 @@ def test_chr_invalid(self):
             cfunc('abc')
         self.assertIn(_header_lead, str(raises.exception))
 
+    def test_unicode_type_mro(self):
+        # see issue #5635
+        def bar(x):
+            return True
+
+        @overload(bar)
+        def ol_bar(x):
+            ok = False
+            if isinstance(x, types.UnicodeType):
+                if isinstance(x, types.Hashable):
+                    ok = True
+            return lambda x: ok
+
+        @njit
+        def foo(strinst):
+            return bar(strinst)
+
+        inst = "abc"
+        self.assertEqual(foo.py_func(inst), foo(inst))
+        self.assertIn(types.Hashable, types.unicode_type.__class__.__mro__)
+
 
 if __name__ == '__main__':
     unittest.main()