Repository: numba/numba

Issue:
[Question]List comprehension compile failed
Hi all please help me .
fast_chi2_distance function compile ok not using List comprehension. but fast_find_angle compile failed. Some one can tell me what i'm doing wrong ? I'm using python3 in windows
thanks !

[source](https://gist.github.com/hoangtocdo90/0a8a646d04ea8a223f36b80381c5e327)


Discussion:
Thanks for the report. This is a bit puzzling, though I've seen something similar before. This is a reproducer:
```python
from numba import jit

@jit
def foo():
    x1 = [i for i in range(0, 4)]
    dist_0 = sum([1,2,3])

foo()
```
either statement by itself works fine, but together they produce an error. I think this is something to do with the interaction between the closure inlining pass and object mode fallback. The closure inlining will work for the list comprehension, but `njit` compilation will fail due to the use of `sum` and cause a fallback to object mode. Object mode seems to not like closures (the inlining pass is not part of the pipeline). Reproducer:

```python
from numba import jit

@jit(forceobj=True)
def foo():
    x1 = [i for i in range(0, 4)]

foo()
```

adding the inling pass to object mode after the `stage_objectmode_frontend` fixes both. I'll try and put a fix in for this in the next release.


Resolving patch:
diff --git a/numba/compiler.py b/numba/compiler.py
--- a/numba/compiler.py
+++ b/numba/compiler.py
@@ -247,7 +247,8 @@ def run(self, status):
                 except _EarlyPipelineCompletion as e:
                     return e.result
                 except BaseException as e:
-                    msg = "Failed at %s (%s)" % (pipeline_name, stage_name)
+                    msg = "Failed in %s mode pipeline (step: %s)" % \
+                        (pipeline_name, stage_name)
                     patched_exception = self._patch_error(msg, e)
                     # No more fallback pipelines?
                     if is_final_pipeline:
@@ -775,6 +776,8 @@ def define_objectmode_pipeline(self, pm, name='object'):
         self.add_preprocessing_stage(pm)
         pm.add_stage(self.stage_objectmode_frontend,
                      "object mode frontend")
+        pm.add_stage(self.stage_inline_pass,
+                     "inline calls to locally defined closures")
         pm.add_stage(self.stage_annotate_type, "annotate type")
         pm.add_stage(self.stage_ir_legalization,
                      "ensure IR is legal prior to lowering")


Test patch:
diff --git a/numba/tests/test_comprehension.py b/numba/tests/test_comprehension.py
--- a/numba/tests/test_comprehension.py
+++ b/numba/tests/test_comprehension.py
@@ -1,6 +1,7 @@
 from __future__ import print_function
 
 import numba.unittest_support as unittest
+from .support import TestCase
 
 import sys
 
@@ -25,7 +26,7 @@ def comp_list(n):
     return s
 
 
-class TestListComprehension(unittest.TestCase):
+class TestListComprehension(TestCase):
 
     @tag('important')
     def test_comp_list(self):
@@ -107,7 +108,6 @@ def inner(x):
                 return [y + l[0] for y in x]
             return inner(l)
 
-        # expected fail, nested mem managed object
         def list11(x):
             """ Test scalar array construction in list comprehension """
             l = [np.array(z) for z in x]
@@ -227,6 +227,19 @@ def list24(x):
             msg = "Cannot unify reflected list(int%d) and int%d" % (bits, bits)
             self.assertIn(msg, str(raises.exception))
 
+    def test_objmode_inlining(self):
+        def objmode_func(y):
+            z = object()
+            inlined = [x for x in y]
+            return inlined
+
+        cfunc = jit(forceobj=True)(objmode_func)
+        t = [1, 2, 3]
+        expected = objmode_func(t)
+        got = cfunc(t)
+        self.assertPreciseEqual(expected, got)
+
+
 class TestArrayComprehension(unittest.TestCase):
 
     def check(self, pyfunc, *args, **kwargs):
diff --git a/numba/tests/test_errorhandling.py b/numba/tests/test_errorhandling.py
--- a/numba/tests/test_errorhandling.py
+++ b/numba/tests/test_errorhandling.py
@@ -25,32 +25,6 @@ def func(x):
             expected = self.expected_msg % "<lambda>"
             self.assertIn(expected, str(raises.exception))
 
-    def test_unsupported_make_function_listcomp(self):
-        try:
-            @jit
-            def func(x):
-                a = [i for i in x]
-                return undefined_global  # force error
-
-            with self.assertRaises(errors.UnsupportedError) as raises:
-                func([1])
-
-            expected = self.expected_msg % "<listcomp>"
-            self.assertIn(expected, str(raises.exception))
-        except NameError: #py27 cannot handle the undefined global
-            self.assertTrue(utils.PY2)
-
-    def test_unsupported_make_function_dictcomp(self):
-        @jit
-        def func():
-            return {i:0 for i in range(1)}
-
-        with self.assertRaises(errors.UnsupportedError) as raises:
-            func()
-
-        expected = self.expected_msg % "<dictcomp>"
-        self.assertIn(expected, str(raises.exception))
-
     def test_unsupported_make_function_return_inner_func(self):
         def func(x):
             """ return the closure """