Repository: numba/numba

Issue:
Give better error when there are incompatible return types
numba in `nopython` mode fails expected fails on functions which can possibly return two different types of result, but the error message given is hard to understand and if possible we should which tell the programmer exactly why his/her code cannot be compiled in the `nopython` mode. Here is the  example code and error message I got:

``` python
In [3]: @numba.jit(nopython=True)
   ...: def example(x):
   ...:     if x > 0:
   ...:         return "Hello"
   ...:     else:
   ...:         return 1
   ...:     

In [4]: example(2)
---------------------------------------------------------------------------
LoweringError                             Traceback (most recent call last)
<ipython-input-4-390f115c7a56> in <module>()
----> 1 example(2)

/home/hargup/anaconda/lib/python2.7/site-packages/numba/dispatcher.pyc in _compile_for_args(self, *args, **kws)
    163         assert not kws
    164         sig = tuple([self.typeof_pyval(a) for a in args])
--> 165         return self.compile(sig)
    166 
    167     def inspect_llvm(self, signature=None):

/home/hargup/anaconda/lib/python2.7/site-packages/numba/dispatcher.pyc in compile(self, sig)
    301                                           self.py_func,
    302                                           args=args, return_type=return_type,
--> 303                                           flags=flags, locals=self.locals)
    304 
    305             # Check typing error if object mode is used

/home/hargup/anaconda/lib/python2.7/site-packages/numba/compiler.pyc in compile_extra(typingctx, targetctx, func, args, return_type, flags, locals, library)
    592     pipeline = Pipeline(typingctx, targetctx, library,
    593                         args, return_type, flags, locals)
--> 594     return pipeline.compile_extra(func)
    595 
    596 

/home/hargup/anaconda/lib/python2.7/site-packages/numba/compiler.pyc in compile_extra(self, func)
    315                 raise e
    316 
--> 317         return self.compile_bytecode(bc, func_attr=self.func_attr)
    318 
    319     def compile_bytecode(self, bc, lifted=(), lifted_from=None,

/home/hargup/anaconda/lib/python2.7/site-packages/numba/compiler.pyc in compile_bytecode(self, bc, lifted, lifted_from, func_attr)
    324         self.lifted_from = lifted_from
    325         self.func_attr = func_attr
--> 326         return self._compile_bytecode()
    327 
    328     def compile_internal(self, bc, func_attr=DEFAULT_FUNCTION_ATTRIBUTES):

/home/hargup/anaconda/lib/python2.7/site-packages/numba/compiler.pyc in _compile_bytecode(self)
    579 
    580         pm.finalize()
--> 581         return pm.run(self.status)
    582 
    583 

/home/hargup/anaconda/lib/python2.7/site-packages/numba/compiler.pyc in run(self, status)
    207                     # No more fallback pipelines?
    208                     if is_final_pipeline:
--> 209                         raise patched_exception
    210                     # Go to next fallback pipeline
    211                     else:

LoweringError: Caused By:
Traceback (most recent call last):
  File "/home/hargup/anaconda/lib/python2.7/site-packages/numba/compiler.py", line 201, in run
    res = stage()
  File "/home/hargup/anaconda/lib/python2.7/site-packages/numba/compiler.py", line 537, in stage_nopython_backend
    return self._backend(lowerfn, objectmode=False)
  File "/home/hargup/anaconda/lib/python2.7/site-packages/numba/compiler.py", line 492, in _backend
    lowered = lowerfn()
  File "/home/hargup/anaconda/lib/python2.7/site-packages/numba/compiler.py", line 483, in backend_nopython_mode
    self.flags)
  File "/home/hargup/anaconda/lib/python2.7/site-packages/numba/compiler.py", line 728, in native_lowering_stage
    lower.lower()
  File "/home/hargup/anaconda/lib/python2.7/site-packages/numba/lowering.py", line 99, in lower
    self.lower_normal_function(self.fndesc)
  File "/home/hargup/anaconda/lib/python2.7/site-packages/numba/lowering.py", line 131, in lower_normal_function
    entry_block_tail = self.lower_function_body()
  File "/home/hargup/anaconda/lib/python2.7/site-packages/numba/lowering.py", line 157, in lower_function_body
    self.lower_block(block)
  File "/home/hargup/anaconda/lib/python2.7/site-packages/numba/lowering.py", line 175, in lower_block
    raise LoweringError(msg, inst.loc)
LoweringError: Internal error:
NotImplementedError: ('cast', <llvmlite.ir.instructions.LoadInstr object at 0x7f0807c859d0>, str, pyobject)
File "<ipython-input-3-b1eef8320bc7>", line 4

Failed at nopython (nopython mode backend)
Internal error:
NotImplementedError: ('cast', <llvmlite.ir.instructions.LoadInstr object at 0x7f0807c859d0>, str, pyobject)
File "<ipython-input-3-b1eef8320bc7>", line 4
```



Discussion:
I'm surprised type inference succeeds on this piece of code. 


Resolving patch:
diff --git a/numba/typeinfer.py b/numba/typeinfer.py
--- a/numba/typeinfer.py
+++ b/numba/typeinfer.py
@@ -485,7 +485,12 @@ def get_return_type(self, typemap):
                 rettypes.add(typemap[term.value.name])
 
         if rettypes:
-            return self.context.unify_types(*rettypes)
+            unified = self.context.unify_types(*rettypes)
+            if unified is types.pyobject:
+                raise TypingError("Can't unify return type from the "
+                                  "following types: %s"
+                                  % ", ".join(sorted(map(str, rettypes))))
+            return unified
         else:
             return types.none
 


Test patch:
diff --git a/numba/tests/test_typingerror.py b/numba/tests/test_typingerror.py
--- a/numba/tests/test_typingerror.py
+++ b/numba/tests/test_typingerror.py
@@ -9,19 +9,24 @@
 def what():
     pass
 
-
 def foo():
     return what()
 
-
 def bar(x):
     return x.a
 
 def issue_868(a):
     return a.shape * 2
 
+def impossible_return_type(x):
+    if x > 0:
+        return ()
+    else:
+        return 1j
+
 
 class TestTypingError(unittest.TestCase):
+
     def test_unknown_function(self):
         try:
             compile_isolated(foo, ())
@@ -51,6 +56,12 @@ def test_issue_868(self):
         else:
             self.fail('Should raise error')
 
+    def test_return_type_unification(self):
+        with self.assertRaises(TypingError) as raises:
+            compile_isolated(impossible_return_type, (types.int32,))
+        self.assertIn("Can't unify return type from the following types: (), complex128",
+                      str(raises.exception))
+
 
 if __name__ == '__main__':
     unittest.main()