def typer(ptr, shape, dtype=types.none): if ptr is types.voidptr: ptr_dtype = None elif isinstance(ptr, types.CPointer): ptr_dtype = ptr.dtype else: raise NumbaTypeError( "%s(): pointer argument expected, got '%s'" % (func_name, ptr)) if dtype is types.none: if ptr_dtype is None: raise NumbaTypeError( "%s(): explicit dtype required for void* argument" % (func_name, )) dtype = ptr_dtype elif isinstance(dtype, types.DTypeSpec): dtype = dtype.dtype if ptr_dtype is not None and dtype != ptr_dtype: raise NumbaTypeError( "%s(): mismatching dtype '%s' for pointer type '%s'" % (func_name, dtype, ptr)) else: raise NumbaTypeError("%s(): invalid dtype spec '%s'" % (func_name, dtype)) ndim = parse_shape(shape) if ndim is None: raise NumbaTypeError("%s(): invalid shape '%s'" % (func_name, shape)) return types.Array(dtype, ndim, self.layout)
def _homogeneous_dims(context, func_name, arrays): ndim = arrays[0].ndim for a in arrays: if a.ndim != ndim: msg = ( f"{func_name}(): all the input arrays must have same number " "of dimensions") raise NumbaTypeError(msg) return ndim
def dummy_to_float(x): if isinstance(x, self.DummyType): def codegen(x): return float(x.value) return codegen else: raise NumbaTypeError('cannot type float({})'.format(x))
def generic(self, args, kws): assert not kws ary, idx, val = args if not isinstance(ary, types.Buffer): return if not ary.mutable: msg = f"Cannot modify readonly array of type: {ary}" raise NumbaTypeError(msg) out = get_array_index_type(ary, idx) if out is None: return idx = out.index res = out.result # res is the result type of the access ary[idx] if isinstance(res, types.Array): # Indexing produces an array if isinstance(val, types.Array): if not self.context.can_convert(val.dtype, res.dtype): # DType conversion not possible return else: res = val elif isinstance(val, types.Sequence): if (res.ndim == 1 and self.context.can_convert(val.dtype, res.dtype)): # Allow assignment of sequence to 1d array res = val else: # NOTE: sequence-to-array broadcasting is unsupported return else: # Allow scalar broadcasting if self.context.can_convert(val, res.dtype): res = res.dtype else: # Incompatible scalar type return elif not isinstance(val, types.Array): # Single item assignment if not self.context.can_convert(val, res): # if the array dtype is not yet defined if not res.is_precise(): # set the array type to use the dtype of value (RHS) newary = ary.copy(dtype=val) return signature(types.none, newary, idx, res) else: return res = val elif (isinstance(val, types.Array) and val.ndim == 0 and self.context.can_convert(val.dtype, res)): # val is an array(T, 0d, O), where T is the type of res, O is order res = val else: return return signature(types.none, ary, idx, res)
def __init__(self, dtype, ndim, layout, readonly=False, name=None): from .misc import unliteral if isinstance(dtype, Buffer): msg = ( "The dtype of a Buffer type cannot itself be a Buffer type, " "this is unsupported behaviour." "\nThe dtype requested for the unsupported Buffer was: {}.") raise NumbaTypeError(msg.format(dtype)) if layout not in self.LAYOUTS: raise NumbaValueError("Invalid layout '%s'" % layout) self.dtype = unliteral(dtype) self.ndim = ndim self.layout = layout if readonly: self.mutable = False if name is None: type_name = self.__class__.__name__.lower() if readonly: type_name = "readonly %s" % type_name name = "%s(%s, %sd, %s)" % (type_name, dtype, ndim, layout) super(Buffer, self).__init__(name)
def ol_isinstance(var, typs): def true_impl(var, typs): return True def false_impl(var, typs): return False var_ty = as_numba_type(var) if isinstance(var_ty, types.Optional): msg = f'isinstance cannot handle optional types. Found: "{var_ty}"' raise NumbaTypeError(msg) # NOTE: The current implementation of `isinstance` restricts the type of the # instance variable to types that are well known and in common use. The # danger of unrestricted tyoe comparison is that a "default" of `False` is # required and this means that if there is a bug in the logic of the # comparison tree `isinstance` returns False! It's therefore safer to just # reject the compilation as untypable! supported_var_ty = (types.Number, types.Bytes, types.RangeType, types.DictType, types.LiteralStrKeyDict, types.List, types.ListType, types.Tuple, types.UniTuple, types.Set, types.Function, types.ClassType, types.UnicodeType, types.ClassInstanceType, types.NoneType, types.Array) if not isinstance(var_ty, supported_var_ty): msg = f'isinstance() does not support variables of type "{var_ty}".' raise NumbaTypeError(msg) # Warn about the experimental nature of this feature. msg = "Use of isinstance() detected. This is an experimental feature." warnings.warn(msg, category=NumbaExperimentalFeatureWarning) t_typs = typs # Check the types that the var can be an instance of, it'll be a scalar, # a unituple or a tuple. if isinstance(t_typs, types.UniTuple): # corner case - all types in isinstance are the same t_typs = (t_typs.key[0]) if not isinstance(t_typs, types.Tuple): t_typs = (t_typs, ) for typ in t_typs: if isinstance(typ, types.Function): key = typ.key[0] # functions like int(..), float(..), str(..) elif isinstance(typ, types.ClassType): key = typ # jitclasses else: key = typ.key # corner cases for bytes, range, ... # avoid registering those types on `as_numba_type` types_not_registered = { bytes: types.Bytes, range: types.RangeType, dict: (types.DictType, types.LiteralStrKeyDict), list: types.List, tuple: types.BaseTuple, set: types.Set, } if key in types_not_registered: if isinstance(var_ty, types_not_registered[key]): return true_impl continue if isinstance(typ, types.TypeRef): # Use of Numba type classes is in general not supported as they do # not work when the jit is disabled. if key not in (types.ListType, types.DictType): msg = ("Numba type classes (except numba.typed.* container " "types) are not supported.") raise NumbaTypeError(msg) # Case for TypeRef (i.e. isinstance(var, typed.List)) # var_ty == ListType[int64] (instance) # typ == types.ListType (class) return true_impl if type(var_ty) is key else false_impl else: numba_typ = as_numba_type(key) if var_ty == numba_typ: return true_impl elif isinstance(numba_typ, types.ClassType) and \ isinstance(var_ty, types.ClassInstanceType) and \ var_ty.key == numba_typ.instance_type.key: # check for jitclasses return true_impl elif isinstance(numba_typ, types.Container) and \ numba_typ.key[0] == types.undefined: # check for containers (list, tuple, set, ...) if isinstance(var_ty, numba_typ.__class__) or \ (isinstance(var_ty, types.BaseTuple) and \ isinstance(numba_typ, types.BaseTuple)): return true_impl return false_impl
def generic(self, args, kws): # First, strip optional types, ufunc loops are typed on concrete types args = [x.type if isinstance(x, types.Optional) else x for x in args] ufunc = self.ufunc base_types, explicit_outputs, ndims, layout = self._handle_inputs( ufunc, args, kws) ufunc_loop = ufunc_find_matching_loop(ufunc, base_types) if ufunc_loop is None: raise TypingError("can't resolve ufunc {0} for types {1}".format( ufunc.__name__, args)) # check if all the types involved in the ufunc loop are supported in this mode if not supported_ufunc_loop(ufunc, ufunc_loop): msg = "ufunc '{0}' using the loop '{1}' not supported in this mode" raise TypingError( msg=msg.format(ufunc.__name__, ufunc_loop.ufunc_sig)) # if there is any explicit output type, check that it is valid explicit_outputs_np = [as_dtype(tp.dtype) for tp in explicit_outputs] # Numpy will happily use unsafe conversions (although it will actually warn) if not all( np.can_cast(fromty, toty, 'unsafe') for (fromty, toty ) in zip(ufunc_loop.numpy_outputs, explicit_outputs_np)): msg = "ufunc '{0}' can't cast result to explicit result type" raise TypingError(msg=msg.format(ufunc.__name__)) # A valid loop was found that is compatible. The result of type inference should # be based on the explicit output types, and when not available with the type given # by the selected NumPy loop out = list(explicit_outputs) implicit_output_count = ufunc.nout - len(explicit_outputs) if implicit_output_count > 0: # XXX this is sometimes wrong for datetime64 and timedelta64, # as ufunc_find_matching_loop() doesn't do any type inference ret_tys = ufunc_loop.outputs[-implicit_output_count:] if ndims > 0: assert layout is not None # If either of the types involved in the ufunc operation have a # __array_ufunc__ method then invoke the first such one to # determine the output type of the ufunc. array_ufunc_type = None for a in args: if hasattr(a, "__array_ufunc__"): array_ufunc_type = a break output_type = types.Array if array_ufunc_type is not None: output_type = array_ufunc_type.__array_ufunc__( ufunc, "__call__", *args, **kws) if output_type is NotImplemented: msg = (f"unsupported use of ufunc {ufunc} on " f"{array_ufunc_type}") # raise TypeError here because # NumpyRulesArrayOperator.generic is capturing # TypingError raise NumbaTypeError(msg) elif not issubclass(output_type, types.Array): msg = (f"ufunc {ufunc} on {array_ufunc_type}" f"cannot return non-array {output_type}") # raise TypeError here because # NumpyRulesArrayOperator.generic is capturing # TypingError raise TypeError(msg) ret_tys = [ output_type(dtype=ret_ty, ndim=ndims, layout=layout) for ret_ty in ret_tys ] ret_tys = [ resolve_output_type(self.context, args, ret_ty) for ret_ty in ret_tys ] out.extend(ret_tys) return _ufunc_loop_sig(out, args)
def get_array_index_type(ary, idx): """ Returns None or a tuple-3 for the types of the input array, index, and resulting type of ``array[index]``. Note: This is shared logic for ndarray getitem and setitem. """ if not isinstance(ary, types.Buffer): return ndim = ary.ndim left_indices = [] right_indices = [] ellipsis_met = False advanced = False has_integer = False if not isinstance(idx, types.BaseTuple): idx = [idx] # Walk indices for ty in idx: if ty is types.ellipsis: if ellipsis_met: raise NumbaTypeError("only one ellipsis allowed in array index " "(got %s)" % (idx,)) ellipsis_met = True elif isinstance(ty, types.SliceType): pass elif isinstance(ty, types.Integer): # Normalize integer index ty = types.intp if ty.signed else types.uintp # Integer indexing removes the given dimension ndim -= 1 has_integer = True elif (isinstance(ty, types.Array) and ty.ndim == 0 and isinstance(ty.dtype, types.Integer)): # 0-d array used as integer index ndim -= 1 has_integer = True elif (isinstance(ty, types.Array) and ty.ndim == 1 and isinstance(ty.dtype, (types.Integer, types.Boolean))): if advanced or has_integer: # We don't support the complicated combination of # advanced indices (and integers are considered part # of them by Numpy). msg = "only one advanced index supported" raise NumbaNotImplementedError(msg) advanced = True else: raise NumbaTypeError("unsupported array index type %s in %s" % (ty, idx)) (right_indices if ellipsis_met else left_indices).append(ty) # Only Numpy arrays support advanced indexing if advanced and not isinstance(ary, types.Array): return # Check indices and result dimensionality all_indices = left_indices + right_indices if ellipsis_met: assert right_indices[0] is types.ellipsis del right_indices[0] n_indices = len(all_indices) - ellipsis_met if n_indices > ary.ndim: raise NumbaTypeError("cannot index %s with %d indices: %s" % (ary, n_indices, idx)) if n_indices == ary.ndim and ndim == 0 and not ellipsis_met: # Full integer indexing => scalar result # (note if ellipsis is present, a 0-d view is returned instead) res = ary.dtype elif advanced: # Result is a copy res = ary.copy(ndim=ndim, layout='C', readonly=False) else: # Result is a view if ary.slice_is_copy: # Avoid view semantics when the original type creates a copy # when slicing. return # Infer layout layout = ary.layout def keeps_contiguity(ty, is_innermost): # A slice can only keep an array contiguous if it is the # innermost index and it is not strided return (ty is types.ellipsis or isinstance(ty, types.Integer) or (is_innermost and isinstance(ty, types.SliceType) and not ty.has_step)) def check_contiguity(outer_indices): """ Whether indexing with the given indices (from outer to inner in physical layout order) can keep an array contiguous. """ for ty in outer_indices[:-1]: if not keeps_contiguity(ty, False): return False if outer_indices and not keeps_contiguity(outer_indices[-1], True): return False return True if layout == 'C': # Integer indexing on the left keeps the array C-contiguous if n_indices == ary.ndim: # If all indices are there, ellipsis's place is indifferent left_indices = left_indices + right_indices right_indices = [] if right_indices: layout = 'A' elif not check_contiguity(left_indices): layout = 'A' elif layout == 'F': # Integer indexing on the right keeps the array F-contiguous if n_indices == ary.ndim: # If all indices are there, ellipsis's place is indifferent right_indices = left_indices + right_indices left_indices = [] if left_indices: layout = 'A' elif not check_contiguity(right_indices[::-1]): layout = 'A' if ndim == 0: # Implicitly convert to a scalar if the output ndim==0 res = ary.dtype else: res = ary.copy(ndim=ndim, layout=layout) # Re-wrap indices if isinstance(idx, types.BaseTuple): idx = types.BaseTuple.from_types(all_indices) else: idx, = all_indices return Indexing(idx, res, advanced)