Repository: numba/numba

Issue:
NotImplementedError. Problem in Numba's internals.
I got a non implemented error trying to compile some function with numpy matrices. A minimal (not) working example reads:
```
import numpy as np
import numba

# Pauli matrices
sigmas = [
    np.matrix([[1, 0],[0, 1]]),
    np.matrix([[0, 1],[1, 0]]),
    np.matrix([[0, -1j],[1j, 0]]),
    np.matrix([[1, 0],[0,-1]]),
]

# Nambu x spin space
ts = [[np.kron(t, s) for s in sigmas] for t in sigmas]

@numba.njit
def T_matrix (phi):
    return ts[0][0]*np.cos(phi)  - 1j*ts[3][3]*np.sin(phi)

T_matrix(0.3)
```

and here the full error log
```
---------------------------------------------------------------------------
NotImplementedError                       Traceback (most recent call last)
~/Miscelania/anaconda3/lib/python3.6/site-packages/numba/targets/base.py in get_constant_generic(self, builder, ty, val)
    498         try:
--> 499             impl = self._get_constants.find((ty,))
    500             return impl(self, builder, ty, val)

~/Miscelania/anaconda3/lib/python3.6/site-packages/numba/targets/base.py in find(self, sig)
     49         if out is None:
---> 50             out = self._find(sig)
     51             self._cache[sig] = out

~/Miscelania/anaconda3/lib/python3.6/site-packages/numba/targets/base.py in _find(self, sig)
     58         else:
---> 59             raise NotImplementedError(self, sig)
     60 

NotImplementedError: (<numba.targets.base.OverloadSelector object at 0x7ff2ff01e7f0>, (reflected list(reflected list(array(int64, 2d, C))),))

During handling of the above exception, another exception occurred:

NotImplementedError                       Traceback (most recent call last)
~/Miscelania/anaconda3/lib/python3.6/site-packages/numba/errors.py in new_error_context(fmt_, *args, **kwargs)
    626     try:
--> 627         yield
    628     except NumbaError as e:

~/Miscelania/anaconda3/lib/python3.6/site-packages/numba/lowering.py in lower_block(self, block)
    257                                    loc=self.loc, errcls_=defaulterrcls):
--> 258                 self.lower_inst(inst)
    259 

~/Miscelania/anaconda3/lib/python3.6/site-packages/numba/lowering.py in lower_inst(self, inst)
    300             ty = self.typeof(inst.target.name)
--> 301             val = self.lower_assign(ty, inst)
    302             self.storevar(val, inst.target.name)

~/Miscelania/anaconda3/lib/python3.6/site-packages/numba/lowering.py in lower_assign(self, ty, inst)
    448             res = self.context.get_constant_generic(self.builder, ty,
--> 449                                                     value.value)
    450             self.incref(ty, res)

~/Miscelania/anaconda3/lib/python3.6/site-packages/numba/targets/base.py in get_constant_generic(self, builder, ty, val)
    501         except NotImplementedError:
--> 502             raise NotImplementedError("Cannot lower constant of type '%s'" % (ty,))
    503 

NotImplementedError: Cannot lower constant of type 'reflected list(reflected list(array(int64, 2d, C)))'

During handling of the above exception, another exception occurred:

LoweringError                             Traceback (most recent call last)
<ipython-input-8-a8e8627a1b30> in <module>
----> 1 T_matrix(0)

~/Miscelania/anaconda3/lib/python3.6/site-packages/numba/dispatcher.py in _compile_for_args(self, *args, **kws)
    367                     e.patch_message(''.join(e.args) + help_msg)
    368             # ignore the FULL_TRACEBACKS config, this needs reporting!
--> 369             raise e
    370 
    371     def inspect_llvm(self, signature=None):

~/Miscelania/anaconda3/lib/python3.6/site-packages/numba/dispatcher.py in _compile_for_args(self, *args, **kws)
    324                 argtypes.append(self.typeof_pyval(a))
    325         try:
--> 326             return self.compile(tuple(argtypes))
    327         except errors.TypingError as e:
    328             # Intercept typing error that may be due to an argument

~/Miscelania/anaconda3/lib/python3.6/site-packages/numba/compiler_lock.py in _acquire_compile_lock(*args, **kwargs)
     30         def _acquire_compile_lock(*args, **kwargs):
     31             with self:
---> 32                 return func(*args, **kwargs)
     33         return _acquire_compile_lock
     34 

~/Miscelania/anaconda3/lib/python3.6/site-packages/numba/dispatcher.py in compile(self, sig)
    656 
    657             self._cache_misses[sig] += 1
--> 658             cres = self._compiler.compile(args, return_type)
    659             self.add_overload(cres)
    660             self._cache.save_overload(sig, cres)

~/Miscelania/anaconda3/lib/python3.6/site-packages/numba/dispatcher.py in compile(self, args, return_type)
     80                                       args=args, return_type=return_type,
     81                                       flags=flags, locals=self.locals,
---> 82                                       pipeline_class=self.pipeline_class)
     83         # Check typing error if object mode is used
     84         if cres.typing_error is not None and not flags.enable_pyobject:

~/Miscelania/anaconda3/lib/python3.6/site-packages/numba/compiler.py in compile_extra(typingctx, targetctx, func, args, return_type, flags, locals, library, pipeline_class)
    939     pipeline = pipeline_class(typingctx, targetctx, library,
    940                               args, return_type, flags, locals)
--> 941     return pipeline.compile_extra(func)
    942 
    943 

~/Miscelania/anaconda3/lib/python3.6/site-packages/numba/compiler.py in compile_extra(self, func)
    370         self.lifted = ()
    371         self.lifted_from = None
--> 372         return self._compile_bytecode()
    373 
    374     def compile_ir(self, func_ir, lifted=(), lifted_from=None):

~/Miscelania/anaconda3/lib/python3.6/site-packages/numba/compiler.py in _compile_bytecode(self)
    870         """
    871         assert self.func_ir is None
--> 872         return self._compile_core()
    873 
    874     def _compile_ir(self):

~/Miscelania/anaconda3/lib/python3.6/site-packages/numba/compiler.py in _compile_core(self)
    857         self.define_pipelines(pm)
    858         pm.finalize()
--> 859         res = pm.run(self.status)
    860         if res is not None:
    861             # Early pipeline completion

~/Miscelania/anaconda3/lib/python3.6/site-packages/numba/compiler_lock.py in _acquire_compile_lock(*args, **kwargs)
     30         def _acquire_compile_lock(*args, **kwargs):
     31             with self:
---> 32                 return func(*args, **kwargs)
     33         return _acquire_compile_lock
     34 

~/Miscelania/anaconda3/lib/python3.6/site-packages/numba/compiler.py in run(self, status)
    251                     # No more fallback pipelines?
    252                     if is_final_pipeline:
--> 253                         raise patched_exception
    254                     # Go to next fallback pipeline
    255                     else:

~/Miscelania/anaconda3/lib/python3.6/site-packages/numba/compiler.py in run(self, status)
    242                 try:
    243                     event(stage_name)
--> 244                     stage()
    245                 except _EarlyPipelineCompletion as e:
    246                     return e.result

~/Miscelania/anaconda3/lib/python3.6/site-packages/numba/compiler.py in stage_nopython_backend(self)
    729         """
    730         lowerfn = self.backend_nopython_mode
--> 731         self._backend(lowerfn, objectmode=False)
    732 
    733     def stage_compile_interp_mode(self):

~/Miscelania/anaconda3/lib/python3.6/site-packages/numba/compiler.py in _backend(self, lowerfn, objectmode)
    679             self.library.enable_object_caching()
    680 
--> 681         lowered = lowerfn()
    682         signature = typing.signature(self.return_type, *self.args)
    683         self.cr = compile_result(

~/Miscelania/anaconda3/lib/python3.6/site-packages/numba/compiler.py in backend_nopython_mode(self)
    666                 self.calltypes,
    667                 self.flags,
--> 668                 self.metadata)
    669 
    670     def _backend(self, lowerfn, objectmode):

~/Miscelania/anaconda3/lib/python3.6/site-packages/numba/compiler.py in native_lowering_stage(targetctx, library, interp, typemap, restype, calltypes, flags, metadata)
   1061         lower = lowering.Lower(targetctx, library, fndesc, interp,
   1062                                metadata=metadata)
-> 1063         lower.lower()
   1064         if not flags.no_cpython_wrapper:
   1065             lower.create_cpython_wrapper(flags.release_gil)

~/Miscelania/anaconda3/lib/python3.6/site-packages/numba/lowering.py in lower(self)
    175         if self.generator_info is None:
    176             self.genlower = None
--> 177             self.lower_normal_function(self.fndesc)
    178         else:
    179             self.genlower = self.GeneratorLower(self)

~/Miscelania/anaconda3/lib/python3.6/site-packages/numba/lowering.py in lower_normal_function(self, fndesc)
    216         # Init argument values
    217         self.extract_function_arguments()
--> 218         entry_block_tail = self.lower_function_body()
    219 
    220         # Close tail of entry block

~/Miscelania/anaconda3/lib/python3.6/site-packages/numba/lowering.py in lower_function_body(self)
    241             bb = self.blkmap[offset]
    242             self.builder.position_at_end(bb)
--> 243             self.lower_block(block)
    244 
    245         self.post_lower()

~/Miscelania/anaconda3/lib/python3.6/site-packages/numba/lowering.py in lower_block(self, block)
    256             with new_error_context('lowering "{inst}" at {loc}', inst=inst,
    257                                    loc=self.loc, errcls_=defaulterrcls):
--> 258                 self.lower_inst(inst)
    259 
    260     def create_cpython_wrapper(self, release_gil=False):

~/Miscelania/anaconda3/lib/python3.6/contextlib.py in __exit__(self, type, value, traceback)
     97                 value = type()
     98             try:
---> 99                 self.gen.throw(type, value, traceback)
    100             except StopIteration as exc:
    101                 # Suppress StopIteration *unless* it's the same exception that

~/Miscelania/anaconda3/lib/python3.6/site-packages/numba/errors.py in new_error_context(fmt_, *args, **kwargs)
    633         from numba import config
    634         tb = sys.exc_info()[2] if config.FULL_TRACEBACKS else None
--> 635         six.reraise(type(newerr), newerr, tb)
    636 
    637 

~/Miscelania/anaconda3/lib/python3.6/site-packages/numba/six.py in reraise(tp, value, tb)
    657         if value.__traceback__ is not tb:
    658             raise value.with_traceback(tb)
--> 659         raise value
    660 
    661 else:

LoweringError: Failed in nopython mode pipeline (step: nopython mode backend)
Cannot lower constant of type 'reflected list(reflected list(array(int64, 2d, C)))'

File "<ipython-input-6-c8c5dfd066cc>", line 17:
def T_matrix (phi):
    return ts[0][0]*np.cos(phi)  - 1j*ts[3][3]*np.sin(phi)
    ^

[1] During: lowering "$0.1 = global(ts: [[matrix([[1, 0, 0, 0],
        [0, 1, 0, 0],
        [0, 0, 1, 0],
        [0, 0, 0, 1]]), matrix([[0, 1, 0, 0],
        [1, 0, 0, 0],
        [0, 0, 0, 1],
        [0, 0, 1, 0]]), matrix([[0.+0.j, 0.-1.j, 0.+0.j, 0.-0.j],
        [0.+1.j, 0.+0.j, 0.+0.j, 0.+0.j],
        [0.+0.j, 0.-0.j, 0.+0.j, 0.-1.j],
        [0.+0.j, 0.+0.j, 0.+1.j, 0.+0.j]]), matrix([[ 1,  0,  0,  0],
        [ 0, -1,  0,  0],
        [ 0,  0,  1,  0],
        [ 0,  0,  0, -1]])], [matrix([[0, 0, 1, 0],
        [0, 0, 0, 1],
        [1, 0, 0, 0],
        [0, 1, 0, 0]]), matrix([[0, 0, 0, 1],
        [0, 0, 1, 0],
        [0, 1, 0, 0],
        [1, 0, 0, 0]]), matrix([[0.+0.j, 0.-0.j, 0.+0.j, 0.-1.j],
        [0.+0.j, 0.+0.j, 0.+1.j, 0.+0.j],
        [0.+0.j, 0.-1.j, 0.+0.j, 0.-0.j],
        [0.+1.j, 0.+0.j, 0.+0.j, 0.+0.j]]), matrix([[ 0,  0,  1,  0],
        [ 0,  0,  0, -1],
        [ 1,  0,  0,  0],
        [ 0, -1,  0,  0]])], [matrix([[0.+0.j, 0.+0.j, 0.-1.j, 0.-0.j],
        [0.+0.j, 0.+0.j, 0.-0.j, 0.-1.j],
        [0.+1.j, 0.+0.j, 0.+0.j, 0.+0.j],
        [0.+0.j, 0.+1.j, 0.+0.j, 0.+0.j]]), matrix([[0.+0.j, 0.+0.j, 0.-0.j, 0.-1.j],
        [0.+0.j, 0.+0.j, 0.-1.j, 0.-0.j],
        [0.+0.j, 0.+1.j, 0.+0.j, 0.+0.j],
        [0.+1.j, 0.+0.j, 0.+0.j, 0.+0.j]]), matrix([[ 0.+0.j,  0.-0.j,  0.-0.j, -1.+0.j],
        [ 0.+0.j,  0.+0.j,  1.-0.j,  0.-0.j],
        [ 0.+0.j,  1.-0.j,  0.+0.j,  0.-0.j],
        [-1.+0.j,  0.+0.j,  0.+0.j,  0.+0.j]]), matrix([[ 0.+0.j,  0.+0.j,  0.-1.j,  0.-0.j],
        [ 0.+0.j, -0.+0.j,  0.-0.j,  0.+1.j],
        [ 0.+1.j,  0.+0.j,  0.+0.j,  0.+0.j],
        [ 0.+0.j, -0.-1.j,  0.+0.j, -0.+0.j]])], [matrix([[ 1,  0,  0,  0],
        [ 0,  1,  0,  0],
        [ 0,  0, -1,  0],
        [ 0,  0,  0, -1]]), matrix([[ 0,  1,  0,  0],
        [ 1,  0,  0,  0],
        [ 0,  0,  0, -1],
        [ 0,  0, -1,  0]]), matrix([[ 0.+0.j,  0.-1.j,  0.+0.j,  0.-0.j],
        [ 0.+1.j,  0.+0.j,  0.+0.j,  0.+0.j],
        [ 0.+0.j,  0.-0.j, -0.+0.j,  0.+1.j],
        [ 0.+0.j,  0.+0.j, -0.-1.j, -0.+0.j]]), matrix([[ 1,  0,  0,  0],
        [ 0, -1,  0,  0],
        [ 0,  0, -1,  0],
        [ 0,  0,  0,  1]])]])" at <ipython-input-6-c8c5dfd066cc> (17)
-------------------------------------------------------------------------------
This should not have happened, a problem has occurred in Numba's internals.

Please report the error message and traceback, along with a minimal reproducer
at: https://github.com/numba/numba/issues/new

If more help is needed please feel free to speak to the Numba core developers
directly at: https://gitter.im/numba/numba

Thanks in advance for your help in improving Numba!
```

Thank you in advance!


Discussion:
Thanks for the report. This error is caused by the (unsupported) use of a global reflected list, Numba 0.44 spots this and reports the following:

```
numba.errors.TypingError: Failed in nopython mode pipeline (step: ensure IR is legal prior to lowering)
Writing to a reflected list(reflected list(array(int64, 2d, C))) defined in globals is not supported as globals are considered compile-time constants.

File "issue4143.py", line 17:
def T_matrix (phi):
    return ts[0][0]*np.cos(phi)  - 1j*ts[3][3]*np.sin(phi)
```
probably need to update that message to read `Accessing a reflected list`... but the gist is the same.


Resolving patch:
diff --git a/numba/ir_utils.py b/numba/ir_utils.py
--- a/numba/ir_utils.py
+++ b/numba/ir_utils.py
@@ -1918,12 +1918,13 @@ def raise_on_unsupported_feature(func_ir, typemap):
             # checks for globals that are also reflected
             if isinstance(stmt.value, ir.Global):
                 ty = typemap[stmt.target.name]
-                msg = ("Writing to a %s defined in globals is not "
-                        "supported as globals are considered compile-time "
-                        "constants.")
+                msg = ("The use of a %s type, assigned to variable '%s' in "
+                       "globals, is not supported as globals are considered "
+                       "compile-time constants and there is no known way to "
+                       "compile a %s type as a constant.")
                 if (getattr(ty, 'reflected', False) or
                     isinstance(ty, types.DictType)):
-                    raise TypingError(msg % ty, loc=stmt.loc)
+                    raise TypingError(msg % (ty, stmt.value.name, ty), loc=stmt.loc)
 
     # There is more than one call to function gdb/gdb_init
     if len(gdb_calls) > 1:


Test patch:
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
@@ -133,7 +133,7 @@ def check_write_to_globals(self, func):
         with self.assertRaises(errors.TypingError) as raises:
             func()
 
-        expected = ["Writing to a", "defined in globals is not supported"]
+        expected = ["The use of a", "in globals, is not supported as globals"]
         for ex in expected:
             self.assertIn(ex, str(raises.exception))