Repository: numba/numba

Issue:
Getting `raise LoweringError(msg, inst.loc) LoweringError: Internal error: AssertionError: ('i1', 'i8')`
Hi all,

Could you explain what this error means? In particular, is it a "numba error" or is it due to some mistake I've made?

Kind regards,
bmer



Discussion:
Is there any more backtrace besides that?

```

  File "A:\anaconda\lib\site-packages\numba\lowering.py", line 183, in lower_function_body
    self.lower_block(block)
  File "A:\anaconda\lib\site-packages\numba\lowering.py", line 201, in lower_block
    raise LoweringError(msg, inst.loc)
LoweringError: Internal error:
AssertionError: ('i1', 'i8')
File "line_segment_intersection_test4.py", line 153

Failed at nopython (nopython mode backend)
Internal error:
AssertionError: ('i1', 'i8')
File "line_segment_intersection_test4.py", line 153
--%<-----------------------------------------------------------------

File "line_segment_intersection_test4.py", line 175]
```

Line 153: 

```

if check_if_line_segments_intersect(a, b, polygon_coords[vi], polygon_coords[(vi + 1)%num_vertices]):
    return True

```

Line 175:

```
if check_if_line_segment_goes_through_polygon(coords_a, coords_b, this_poly_coords):
    return True
```

I figured this one out -- it was an error on my part. I had a function which would return a boolean if one if-statement branch was taken, and would return nothing if the other was taken. I am guessing this confused numba as to what type the function had

Hmm, our error should be clearer on this.


Resolving patch:
diff --git a/numba/targets/callconv.py b/numba/targets/callconv.py
--- a/numba/targets/callconv.py
+++ b/numba/targets/callconv.py
@@ -55,23 +55,29 @@ def __init__(self, context):
 
     def return_optional_value(self, builder, retty, valty, value):
         if valty == types.none:
+            # Value is none
             self.return_native_none(builder)
 
         elif retty == valty:
+            # Value is an optional, need a runtime switch
             optcls = self.context.make_optional(retty)
             optval = optcls(self.context, builder, value=value)
 
             validbit = cgutils.as_bool_bit(builder, optval.valid)
             with builder.if_then(validbit):
-                self.return_value(builder, optval.data)
+                retval = self.context.get_return_value(builder, retty.type,
+                                                       optval.data)
+                self.return_value(builder, retval)
 
             self.return_native_none(builder)
 
         elif not isinstance(valty, types.Optional):
+            # Value is not an optional, need a cast
             if valty != retty.type:
                 value = self.context.cast(builder, value, fromty=valty,
                                           toty=retty.type)
-            self.return_value(builder, value)
+            retval = self.context.get_return_value(builder, retty.type, value)
+            self.return_value(builder, retval)
 
         else:
             raise NotImplementedError("returning {0} for {1}".format(valty,


Test patch:
diff --git a/numba/tests/test_optional.py b/numba/tests/test_optional.py
--- a/numba/tests/test_optional.py
+++ b/numba/tests/test_optional.py
@@ -1,11 +1,14 @@
 from __future__ import print_function, absolute_import
 
+import itertools
+
 import numpy
 
 import numba.unittest_support as unittest
 from numba.compiler import compile_isolated, Flags
 from numba import types, typeof, njit
 from numba import lowering
+from .support import TestCase
 
 
 def return_double_or_none(x):
@@ -23,6 +26,22 @@ def return_different_statement(x):
         return 1.2
 
 
+def return_bool_optional_or_none(x, y):
+    if y:
+        z = False
+    else:
+        z = None
+    if x == 2:
+        # A boolean
+        return True
+    elif x == 1:
+        # A runtime optional
+        return z
+    else:
+        # None
+        return None
+
+
 def is_this_a_none(x):
     if x:
         val_or_none = None
@@ -52,14 +71,15 @@ def a_is_not_b(a, b):
     return a is not b
 
 
-class TestOptional(unittest.TestCase):
+class TestOptional(TestCase):
+
     def test_return_double_or_none(self):
         pyfunc = return_double_or_none
         cres = compile_isolated(pyfunc, [types.boolean])
         cfunc = cres.entry_point
 
         for v in [True, False]:
-            self.assertEqual(pyfunc(v), cfunc(v))
+            self.assertPreciseEqual(pyfunc(v), cfunc(v))
 
     def test_return_different_statement(self):
         pyfunc = return_different_statement
@@ -67,7 +87,15 @@ def test_return_different_statement(self):
         cfunc = cres.entry_point
 
         for v in [True, False]:
-            self.assertEqual(pyfunc(v), cfunc(v))
+            self.assertPreciseEqual(pyfunc(v), cfunc(v))
+
+    def test_return_bool_optional_or_none(self):
+        pyfunc = return_bool_optional_or_none
+        cres = compile_isolated(pyfunc, [types.int32, types.int32])
+        cfunc = cres.entry_point
+
+        for x, y in itertools.product((0, 1, 2), (0, 1)):
+            self.assertPreciseEqual(pyfunc(x, y), cfunc(x, y))
 
     def test_is_this_a_none(self):
         pyfunc = is_this_a_none
@@ -75,7 +103,7 @@ def test_is_this_a_none(self):
         cfunc = cres.entry_point
 
         for v in [-1, 0, 1, 2]:
-            self.assertEqual(pyfunc(v), cfunc(v))
+            self.assertPreciseEqual(pyfunc(v), cfunc(v))
 
     def test_is_this_a_none_objmode(self):
         pyfunc = is_this_a_none
@@ -85,7 +113,7 @@ def test_is_this_a_none_objmode(self):
         cfunc = cres.entry_point
         self.assertTrue(cres.objectmode)
         for v in [-1, 0, 1, 2]:
-            self.assertEqual(pyfunc(v), cfunc(v))
+            self.assertPreciseEqual(pyfunc(v), cfunc(v))
 
     def test_a_is_b_intp(self):
         pyfunc = a_is_b