Repository: numba/numba

Issue:
No error for jit(nopython=True, forceobj=True)
- [ x] I am using the latest released version of Numba (most recent is visible in
 the change log (https://github.com/numba/numba/blob/master/CHANGE_LOG).
- [ x] I have included below a minimal working reproducer (if you are unsure how
 to write one see http://matthewrocklin.com/blog/work/2018/02/28/minimal-bug-reports).

When using the `jit` decorator with both `nopython=True` and `forceobj=True` no error is reported, despite these flags probably being mutually exclusive.
```python
import numba

@numba.jit(nopython=True, forceobj=True)
def f():
    pass

f()
```
The prior example runs without complaints. If the `njit` decorator is used instead, appropriate warnings are thrown.


Discussion:
Thanks for the report. From https://gitter.im/numba/numba?at=5eafceefb6dd230697a45990. Think this will just permit the objmode pipeline to run.
@stuartarchibald I just noticed that `njit` throws warnings that it will ignore `nopython` and `forceobj` but `forceobj` is actually passed on to `jit`. In combination with the behaviour above, that means that `njit(forceobj=True)` actually compiles in object mode (this might be convenient for in some cases, but somewhat contradicts the idea of njit). 

Do you think it would be appropriate to eliminate `forceobj` if it is passed to `njit`, and add a check to `jit` that raises an error if both options are passed as True?

If yes, then I am happy to use this as pull request training :)

Resolving patch:
diff --git a/numba/core/decorators.py b/numba/core/decorators.py
--- a/numba/core/decorators.py
+++ b/numba/core/decorators.py
@@ -143,6 +143,8 @@ def bar(x, y):
         raise DeprecationError(_msg_deprecated_signature_arg.format('argtypes'))
     if 'restype' in options:
         raise DeprecationError(_msg_deprecated_signature_arg.format('restype'))
+    if options.get('nopython', False) and options.get('forceobj', False):
+        raise ValueError("Only one of 'nopython' or 'forceobj' can be True.")
 
     options['boundscheck'] = boundscheck
 
@@ -232,6 +234,7 @@ def njit(*args, **kws):
         warnings.warn('nopython is set for njit and is ignored', RuntimeWarning)
     if 'forceobj' in kws:
         warnings.warn('forceobj is set for njit and is ignored', RuntimeWarning)
+        del kws['forceobj']
     kws.update({'nopython': True})
     return jit(*args, **kws)
 


Test patch:
diff --git a/numba/tests/test_api.py b/numba/tests/test_api.py
--- a/numba/tests/test_api.py
+++ b/numba/tests/test_api.py
@@ -1,4 +1,7 @@
+import warnings
+
 import numba
+from numba import jit, njit
 
 from numba.tests.support import TestCase
 import unittest
@@ -28,5 +31,60 @@ def test_numba_module(self):
         numba.__version__  # not in __all__
 
 
+class TestJitDecorator(TestCase):
+    """
+    Test the jit and njit decorators
+    """
+    def test_jit_nopython_forceobj(self):
+        with self.assertRaises(ValueError) as cm:
+            jit(nopython=True, forceobj=True)
+        self.assertIn(
+            "Only one of 'nopython' or 'forceobj' can be True.",
+            str(cm.exception)
+        )
+
+        def py_func(x):
+            return x
+
+        jit_func = jit(nopython=True)(py_func)
+        jit_func(1)
+        # Check length of nopython_signatures to check
+        # which mode the function was compiled in
+        self.assertEqual(len(jit_func.nopython_signatures), 1)
+
+        jit_func = jit(forceobj=True)(py_func)
+        jit_func(1)
+        self.assertEqual(len(jit_func.nopython_signatures), 0)
+
+    def test_njit_nopython_forceobj(self):
+        with warnings.catch_warnings(record=True) as w:
+            warnings.simplefilter('always', RuntimeWarning)
+            njit(forceobj=True)
+        self.assertEqual(len(w), 1)
+        self.assertIn(
+            'forceobj is set for njit and is ignored', str(w[0].message)
+        )
+
+        with warnings.catch_warnings(record=True) as w:
+            warnings.simplefilter('always', RuntimeWarning)
+            njit(nopython=True)
+        self.assertEqual(len(w), 1)
+        self.assertIn(
+            'nopython is set for njit and is ignored', str(w[0].message)
+        )
+
+        def py_func(x):
+            return x
+
+        jit_func = njit(nopython=True)(py_func)
+        jit_func(1)
+        self.assertEqual(len(jit_func.nopython_signatures), 1)
+
+        jit_func = njit(forceobj=True)(py_func)
+        jit_func(1)
+        # Since forceobj is ignored this has to compile in nopython mode
+        self.assertEqual(len(jit_func.nopython_signatures), 1)
+
+
 if __name__ == '__main__':
     unittest.main()