Repository: numba/numba

Issue:
Cannot allow two signatures with `FunctionType`
After finding the case 5 in https://github.com/numba/numba/issues/6972#issuecomment-828302957,

I tried to specify two sigs for one caller, but numba will complain with 
```python
numba.core.errors.TypingError: Failed in nopython mode pipeline (step: nopython frontend)
Unknown attribute 'sum' of type int64

File "~/numba/tests/test_multi_function_type.py", line 33:
def callee_array(c):
    return c.sum()
    ^

During: typing of get attribute at ~/numba/tests/test_multi_function_type.py (33)
```
My test script, on 0.56.3:
```python
import numpy as np
from numba import njit, types, typeof
from numba.types import int64, float64
from numba.tests.support import (
    MemoryLeakMixin, TestCase
)

import os

os.environ['NUMBA_CAPTURED_ERRORS'] = 'new_style'
os.environ['NUMBA_DEBUG_CACHE'] = '1'

nb_array = typeof(np.ones(2))
callee_int_type = types.FunctionType(int64(int64))
sig_int = int64(callee_int_type, int64)
callee_array_type = types.FunctionType(float64(nb_array))
sig_array = float64(callee_array_type, nb_array)

# @njit(sig_int, cache=True)
# @njit(sig_array, cache=True)
@njit([sig_array, sig_int], cache=True)
def caller(callee, a):
    return callee(a)


@njit(cache=True)
def callee_int(b):
    return b


@njit(cache=True)
def callee_array(c):
    return c.sum()


class TestMultiFunctionType(MemoryLeakMixin, TestCase):

    def test_base(self):
        b = 1
        c = np.ones(2)

        print(caller(callee_int, b))
        print(caller(callee_array, c))


if __name__ == "__main__":
    clz = TestMultiFunctionType()
    clz.test_base()

```
If only specify one sig, compilation and cache is fine. But if specify with two sigs, error happens.
Cannot allow two signatures with `FunctionType`
After finding the case 5 in https://github.com/numba/numba/issues/6972#issuecomment-828302957,

I tried to specify two sigs for one caller, but numba will complain with 
```python
numba.core.errors.TypingError: Failed in nopython mode pipeline (step: nopython frontend)
Unknown attribute 'sum' of type int64

File "~/numba/tests/test_multi_function_type.py", line 33:
def callee_array(c):
    return c.sum()
    ^

During: typing of get attribute at ~/numba/tests/test_multi_function_type.py (33)
```
My test script, on 0.56.3:
```python
import numpy as np
from numba import njit, types, typeof
from numba.types import int64, float64
from numba.tests.support import (
    MemoryLeakMixin, TestCase
)

import os

os.environ['NUMBA_CAPTURED_ERRORS'] = 'new_style'
os.environ['NUMBA_DEBUG_CACHE'] = '1'

nb_array = typeof(np.ones(2))
callee_int_type = types.FunctionType(int64(int64))
sig_int = int64(callee_int_type, int64)
callee_array_type = types.FunctionType(float64(nb_array))
sig_array = float64(callee_array_type, nb_array)

# @njit(sig_int, cache=True)
# @njit(sig_array, cache=True)
@njit([sig_array, sig_int], cache=True)
def caller(callee, a):
    return callee(a)


@njit(cache=True)
def callee_int(b):
    return b


@njit(cache=True)
def callee_array(c):
    return c.sum()


class TestMultiFunctionType(MemoryLeakMixin, TestCase):

    def test_base(self):
        b = 1
        c = np.ones(2)

        print(caller(callee_int, b))
        print(caller(callee_array, c))


if __name__ == "__main__":
    clz = TestMultiFunctionType()
    clz.test_base()

```
If only specify one sig, compilation and cache is fine. But if specify with two sigs, error happens.


Discussion:
Thanks for the detailed report. I'm looking into the issue.
Confirmed that this is a problem in dispatcher. When first-class function type test for signature compatibility, there is no handling for the case where an error is raised due to incompatibility. I already have a fix and will submit soon.
Thanks for the detailed report. I'm looking into the issue.
Confirmed that this is a problem in dispatcher. When first-class function type test for signature compatibility, there is no handling for the case where an error is raised due to incompatibility. I already have a fix and will submit soon.

Resolving patch:
diff --git a/numba/core/dispatcher.py b/numba/core/dispatcher.py
--- a/numba/core/dispatcher.py
+++ b/numba/core/dispatcher.py
@@ -975,10 +975,18 @@ def folded(args, kws):
     def get_compile_result(self, sig):
         """Compile (if needed) and return the compilation result with the
         given signature.
+
+        Returns ``CompileResult``.
+        Raises ``NumbaError`` if the signature is incompatible.
         """
         atypes = tuple(sig.args)
         if atypes not in self.overloads:
-            self.compile(atypes)
+            if self._can_compile:
+                # Compiling may raise any NumbaError
+                self.compile(atypes)
+            else:
+                msg = f"{sig} not available and compilation disabled"
+                raise errors.TypingError(msg)
         return self.overloads[atypes]
 
     def recompile(self):
diff --git a/numba/core/types/functions.py b/numba/core/types/functions.py
--- a/numba/core/types/functions.py
+++ b/numba/core/types/functions.py
@@ -578,7 +578,11 @@ def unify(self, context, other):
 
     def can_convert_to(self, typingctx, other):
         if isinstance(other, types.FunctionType):
-            if self.dispatcher.get_compile_result(other.signature):
+            try:
+                self.dispatcher.get_compile_result(other.signature)
+            except errors.NumbaError:
+                return None
+            else:
                 return Conversion.safe
 
 


Test patch:
diff --git a/numba/tests/test_function_type.py b/numba/tests/test_function_type.py
--- a/numba/tests/test_function_type.py
+++ b/numba/tests/test_function_type.py
@@ -1,12 +1,14 @@
 import unittest
 import types as pytypes
 from numba import jit, njit, cfunc, types, int64, float64, float32, errors
-from numba import literal_unroll
+from numba import literal_unroll, typeof
 from numba.core.config import IS_WIN32
 import ctypes
 import warnings
 
-from .support import TestCase
+from .support import TestCase, MemoryLeakMixin
+
+import numpy as np
 
 
 def dump(foo):  # FOR DEBUGGING, TO BE REMOVED
@@ -1244,5 +1246,34 @@ def bar(fcs, ffs):
         self.assertEqual(got, expected)
 
 
+class TestMultiFunctionType(MemoryLeakMixin, TestCase):
+
+    def test_base(self):
+        # The test is adapted from https://github.com/numba/numba/issues/9071
+        nb_array = typeof(np.ones(2))
+        callee_int_type = types.FunctionType(int64(int64))
+        sig_int = int64(callee_int_type, int64)
+        callee_array_type = types.FunctionType(float64(nb_array))
+        sig_array = float64(callee_array_type, nb_array)
+
+        @njit([sig_int, sig_array])
+        def caller(callee, a):
+            return callee(a)
+
+        @njit
+        def callee_int(b):
+            return b
+
+        @njit
+        def callee_array(c):
+            return c.sum()
+
+        b = 1
+        c = np.ones(2)
+
+        self.assertEqual(caller(callee_int, b), b)
+        self.assertEqual(caller(callee_array, c), c.sum())
+
+
 if __name__ == '__main__':
     unittest.main()