def impl_numba_typeref_ctor(cls, *args): """Defines lowering for ``List()`` and ``List(iterable)``. This defines the lowering logic to instantiate either an empty typed-list or a typed-list initialised with values from a single iterable argument. Parameters ---------- cls : TypeRef Expecting a TypeRef of a precise ListType. args: tuple A tuple that contains a single iterable (optional) Returns ------- impl : function An implementation suitable for lowering the constructor call. See also: `redirect_type_ctor` in numba/cpython/bulitins.py """ list_ty = cls.instance_type if not isinstance(list_ty, types.ListType): return # reject # Ensure the list is precisely typed. if not list_ty.is_precise(): msg = "expecting a precise ListType but got {}".format(list_ty) raise LoweringError(msg) item_type = types.TypeRef(list_ty.item_type) if args: # special case 0d Numpy arrays if isinstance(args[0], types.Array) and args[0].ndim == 0: def impl(cls, *args): # Instatiate an empty list and populate it with the single # value from the array. r = List.empty_list(item_type) r.append(args[0].item()) return r else: def impl(cls, *args): # Instatiate an empty list and populate it with values from the # iterable. r = List.empty_list(item_type) for i in args[0]: r.append(i) return r else: def impl(cls, *args): # Simply call .empty_list with the item type from *cls* return List.empty_list(item_type) return impl
def scale_timedelta(context, builder, val, srcty, destty): """ Scale the timedelta64 *val* from *srcty* to *destty* (both numba.types.NPTimedelta instances) """ factor = npdatetime_helpers.get_timedelta_conversion_factor( srcty.unit, destty.unit) if factor is None: # This can happen when using explicit output in a ufunc. msg = f"cannot convert timedelta64 from {srcty.unit} to {destty.unit}" raise LoweringError(msg) return scale_by_constant(builder, val, factor)
def cast_LiteralStrKeyDict_LiteralStrKeyDict(context, builder, fromty, toty, val): # should have been picked up by typing for (k1, v1), (k2, v2) in zip(fromty.literal_value.items(), toty.literal_value.items()): # these checks are just guards, typing should have picked up any # problems if k1 != k2: # keys must be same msg = "LiteralDictionary keys are not the same {} != {}" raise LoweringError(msg.format(k1, k2)) # values must be same ty if context.typing_context.unify_pairs(v1, v2) is None: msg = "LiteralDictionary values cannot by unified, have {} and {}" raise LoweringError(msg.format(v1, v2)) else: fromty = types.Tuple(fromty.types) toty = types.Tuple(toty.types) olditems = cgutils.unpack_tuple(builder, val, len(fromty)) items = [context.cast(builder, v, f, t) for v, f, t in zip(olditems, fromty, toty)] return context.make_tuple(builder, toty, items)
def convert_datetime_for_arith(builder, dt_val, src_unit, dest_unit): """ Convert datetime *dt_val* from *src_unit* to *dest_unit*. """ # First partial conversion to days or weeks, if necessary. dt_val, dt_unit = reduce_datetime_for_unit(builder, dt_val, src_unit, dest_unit) # Then multiply by the remaining constant factor. dt_factor = npdatetime_helpers.get_timedelta_conversion_factor( dt_unit, dest_unit) if dt_factor is None: # This can happen when using explicit output in a ufunc. raise LoweringError("cannot convert datetime64 from %r to %r" % (src_unit, dest_unit)) return scale_by_constant(builder, dt_val, dt_factor)
def lower_call(self, resty, expr): signature = self.fndesc.calltypes[expr] self.debug_print("# lower_call: expr = {0}".format(expr)) if isinstance(signature.return_type, types.Phantom): return self.context.get_dummy_value() if isinstance(expr.func, ir.Intrinsic): fnty = expr.func.name else: fnty = self.typeof(expr.func.name) if isinstance(fnty, types.ObjModeDispatcher): res = self._lower_call_ObjModeDispatcher(fnty, expr, signature) elif isinstance(fnty, types.ExternalFunction): res = self._lower_call_ExternalFunction(fnty, expr, signature) elif isinstance(fnty, types.ExternalFunctionPointer): res = self._lower_call_ExternalFunctionPointer( fnty, expr, signature) elif isinstance(fnty, types.RecursiveCall): res = self._lower_call_RecursiveCall(fnty, expr, signature) else: res = self._lower_call_normal(fnty, expr, signature) # If lowering the call returned None, interpret that as returning dummy # value if the return type of the function is void, otherwise there is # a problem if res is None: if signature.return_type == types.void: res = self.context.get_dummy_value() else: raise LoweringError( msg="non-void function returns None from implementation", loc=self.loc) return self.context.cast(self.builder, res, signature.return_type, resty)
def generic_is(context, builder, sig, args): """ Default implementation for `x is y` """ lhs_type, rhs_type = sig.args # the lhs and rhs have the same type if lhs_type == rhs_type: # mutable types if lhs_type.mutable: msg = 'no default `is` implementation' raise LoweringError(msg) # immutable types else: # fallbacks to `==` try: eq_impl = context.get_function(operator.eq, sig) except NotImplementedError: # no `==` implemented for this type return cgutils.false_bit else: return eq_impl(builder, args) else: return cgutils.false_bit
def lower_expr(self, expr): if expr.op == 'binop': return self.lower_binop(expr, expr.fn, inplace=False) elif expr.op == 'inplace_binop': return self.lower_binop(expr, expr.fn, inplace=True) elif expr.op == 'unary': value = self.loadvar(expr.value.name) if expr.fn == operator.neg: res = self.pyapi.number_negative(value) elif expr.fn == operator.pos: res = self.pyapi.number_positive(value) elif expr.fn == operator.not_: res = self.pyapi.object_not(value) self.check_int_status(res) res = self.pyapi.bool_from_bool(res) elif expr.fn == operator.invert: res = self.pyapi.number_invert(value) else: raise NotImplementedError(expr) self.check_error(res) return res elif expr.op == 'call': argvals = [self.loadvar(a.name) for a in expr.args] fn = self.loadvar(expr.func.name) args = self.pyapi.tuple_pack(argvals) if expr.vararg: # Expand *args new_args = self.pyapi.number_add( args, self.loadvar(expr.vararg.name)) self.decref(args) args = new_args if not expr.kws: # No named arguments ret = self.pyapi.call(fn, args, None) else: # Named arguments keyvalues = [(k, self.loadvar(v.name)) for k, v in expr.kws] kws = self.pyapi.dict_pack(keyvalues) ret = self.pyapi.call(fn, args, kws) self.decref(kws) self.decref(args) self.check_error(ret) return ret elif expr.op == 'getattr': obj = self.loadvar(expr.value.name) res = self.pyapi.object_getattr(obj, self._freeze_string(expr.attr)) self.check_error(res) return res elif expr.op == 'build_tuple': items = [self.loadvar(it.name) for it in expr.items] res = self.pyapi.tuple_pack(items) self.check_error(res) return res elif expr.op == 'build_list': items = [self.loadvar(it.name) for it in expr.items] res = self.pyapi.list_pack(items) self.check_error(res) return res elif expr.op == 'build_map': res = self.pyapi.dict_new(expr.size) self.check_error(res) for k, v in expr.items: key = self.loadvar(k.name) value = self.loadvar(v.name) ok = self.pyapi.dict_setitem(res, key, value) self.check_int_status(ok) return res elif expr.op == 'build_set': items = [self.loadvar(it.name) for it in expr.items] res = self.pyapi.set_new() self.check_error(res) for it in items: ok = self.pyapi.set_add(res, it) self.check_int_status(ok) return res elif expr.op == 'getiter': obj = self.loadvar(expr.value.name) res = self.pyapi.object_getiter(obj) self.check_error(res) return res elif expr.op == 'iternext': iterobj = self.loadvar(expr.value.name) item = self.pyapi.iter_next(iterobj) is_valid = cgutils.is_not_null(self.builder, item) pair = self.pyapi.tuple_new(2) with self.builder.if_else(is_valid) as (then, otherwise): with then: self.pyapi.tuple_setitem(pair, 0, item) with otherwise: self.check_occurred() # Make the tuple valid by inserting None as dummy # iteration "result" (it will be ignored). self.pyapi.tuple_setitem(pair, 0, self.pyapi.make_none()) self.pyapi.tuple_setitem(pair, 1, self.pyapi.bool_from_bool(is_valid)) return pair elif expr.op == 'pair_first': pair = self.loadvar(expr.value.name) first = self.pyapi.tuple_getitem(pair, 0) self.incref(first) return first elif expr.op == 'pair_second': pair = self.loadvar(expr.value.name) second = self.pyapi.tuple_getitem(pair, 1) self.incref(second) return second elif expr.op == 'exhaust_iter': iterobj = self.loadvar(expr.value.name) tup = self.pyapi.sequence_tuple(iterobj) self.check_error(tup) # Check tuple size is as expected tup_size = self.pyapi.tuple_size(tup) expected_size = self.context.get_constant(types.intp, expr.count) has_wrong_size = self.builder.icmp(lc.ICMP_NE, tup_size, expected_size) with cgutils.if_unlikely(self.builder, has_wrong_size): self.return_exception(ValueError) return tup elif expr.op == 'getitem': value = self.loadvar(expr.value.name) index = self.loadvar(expr.index.name) res = self.pyapi.object_getitem(value, index) self.check_error(res) return res elif expr.op == 'static_getitem': value = self.loadvar(expr.value.name) index = self.context.get_constant(types.intp, expr.index) indexobj = self.pyapi.long_from_ssize_t(index) self.check_error(indexobj) res = self.pyapi.object_getitem(value, indexobj) self.decref(indexobj) self.check_error(res) return res elif expr.op == 'getslice': target = self.loadvar(expr.target.name) start = self.loadvar(expr.start.name) stop = self.loadvar(expr.stop.name) slicefn = self.get_builtin_obj("slice") sliceobj = self.pyapi.call_function_objargs(slicefn, (start, stop)) self.decref(slicefn) self.check_error(sliceobj) res = self.pyapi.object_getitem(target, sliceobj) self.check_error(res) return res elif expr.op == 'cast': val = self.loadvar(expr.value.name) self.incref(val) return val elif expr.op == 'phi': raise LoweringError("PHI not stripped") elif expr.op == 'null': # Make null value return cgutils.get_null_value(self.pyapi.pyobj) else: raise NotImplementedError(expr)
def lower_expr(self, resty, expr): if expr.op == 'binop': return self.lower_binop(resty, expr, expr.fn) elif expr.op == 'inplace_binop': lty = self.typeof(expr.lhs.name) if lty.mutable: return self.lower_binop(resty, expr, expr.fn) else: # inplace operators on non-mutable types reuse the same # definition as the corresponding copying operators.) return self.lower_binop(resty, expr, expr.immutable_fn) elif expr.op == 'unary': val = self.loadvar(expr.value.name) typ = self.typeof(expr.value.name) func_ty = self.context.typing_context.resolve_value_type(expr.fn) # Get function signature = self.fndesc.calltypes[expr] impl = self.context.get_function(func_ty, signature) # Convert argument to match val = self.context.cast(self.builder, val, typ, signature.args[0]) res = impl(self.builder, [val]) res = self.context.cast(self.builder, res, signature.return_type, resty) return res elif expr.op == 'call': res = self.lower_call(resty, expr) return res elif expr.op == 'pair_first': val = self.loadvar(expr.value.name) ty = self.typeof(expr.value.name) res = self.context.pair_first(self.builder, val, ty) self.incref(resty, res) return res elif expr.op == 'pair_second': val = self.loadvar(expr.value.name) ty = self.typeof(expr.value.name) res = self.context.pair_second(self.builder, val, ty) self.incref(resty, res) return res elif expr.op in ('getiter', 'iternext'): val = self.loadvar(expr.value.name) ty = self.typeof(expr.value.name) signature = self.fndesc.calltypes[expr] impl = self.context.get_function(expr.op, signature) [fty] = signature.args castval = self.context.cast(self.builder, val, ty, fty) res = impl(self.builder, (castval, )) res = self.context.cast(self.builder, res, signature.return_type, resty) return res elif expr.op == 'exhaust_iter': val = self.loadvar(expr.value.name) ty = self.typeof(expr.value.name) # Unpack optional if isinstance(ty, types.Optional): val = self.context.cast(self.builder, val, ty, ty.type) ty = ty.type # If we have a tuple, we needn't do anything # (and we can't iterate over the heterogeneous ones). if isinstance(ty, types.BaseTuple): assert ty == resty self.incref(ty, val) return val itemty = ty.iterator_type.yield_type tup = self.context.get_constant_undef(resty) pairty = types.Pair(itemty, types.boolean) getiter_sig = typing.signature(ty.iterator_type, ty) getiter_impl = self.context.get_function('getiter', getiter_sig) iternext_sig = typing.signature(pairty, ty.iterator_type) iternext_impl = self.context.get_function('iternext', iternext_sig) iterobj = getiter_impl(self.builder, (val, )) # We call iternext() as many times as desired (`expr.count`). for i in range(expr.count): pair = iternext_impl(self.builder, (iterobj, )) is_valid = self.context.pair_second(self.builder, pair, pairty) with cgutils.if_unlikely(self.builder, self.builder.not_(is_valid)): self.return_exception(ValueError, loc=self.loc) item = self.context.pair_first(self.builder, pair, pairty) tup = self.builder.insert_value(tup, item, i) # Call iternext() once more to check that the iterator # is exhausted. pair = iternext_impl(self.builder, (iterobj, )) is_valid = self.context.pair_second(self.builder, pair, pairty) with cgutils.if_unlikely(self.builder, is_valid): self.return_exception(ValueError, loc=self.loc) self.decref(ty.iterator_type, iterobj) return tup elif expr.op == "getattr": val = self.loadvar(expr.value.name) ty = self.typeof(expr.value.name) if isinstance(resty, types.BoundFunction): # if we are getting out a method, assume we have typed this # properly and just build a bound function object casted = self.context.cast(self.builder, val, ty, resty.this) res = self.context.get_bound_function(self.builder, casted, resty.this) self.incref(resty, res) return res else: impl = self.context.get_getattr(ty, expr.attr) attrty = self.context.typing_context.resolve_getattr( ty, expr.attr) if impl is None: # ignore the attribute return self.context.get_dummy_value() else: res = impl(self.context, self.builder, ty, val, expr.attr) # Cast the attribute type to the expected output type res = self.context.cast(self.builder, res, attrty, resty) return res elif expr.op == "static_getitem": signature = typing.signature( resty, self.typeof(expr.value.name), _lit_or_omitted(expr.index), ) try: # Both get_function() and the returned implementation can # raise NotImplementedError if the types aren't supported impl = self.context.get_function("static_getitem", signature) return impl(self.builder, (self.loadvar(expr.value.name), expr.index)) except NotImplementedError: if expr.index_var is None: raise # Fall back on the generic getitem() implementation # for this type. signature = self.fndesc.calltypes[expr] return self.lower_getitem(resty, expr, expr.value, expr.index_var, signature) elif expr.op == "typed_getitem": signature = typing.signature( resty, self.typeof(expr.value.name), self.typeof(expr.index.name), ) impl = self.context.get_function("typed_getitem", signature) return impl( self.builder, (self.loadvar(expr.value.name), self.loadvar(expr.index.name))) elif expr.op == "getitem": signature = self.fndesc.calltypes[expr] return self.lower_getitem(resty, expr, expr.value, expr.index, signature) elif expr.op == "build_tuple": itemvals = [self.loadvar(i.name) for i in expr.items] itemtys = [self.typeof(i.name) for i in expr.items] castvals = [ self.context.cast(self.builder, val, fromty, toty) for val, toty, fromty in zip(itemvals, resty, itemtys) ] tup = self.context.make_tuple(self.builder, resty, castvals) self.incref(resty, tup) return tup elif expr.op == "build_list": itemvals = [self.loadvar(i.name) for i in expr.items] itemtys = [self.typeof(i.name) for i in expr.items] castvals = [ self.context.cast(self.builder, val, fromty, resty.dtype) for val, fromty in zip(itemvals, itemtys) ] return self.context.build_list(self.builder, resty, castvals) elif expr.op == "build_set": # Insert in reverse order, as Python does items = expr.items[::-1] itemvals = [self.loadvar(i.name) for i in items] itemtys = [self.typeof(i.name) for i in items] castvals = [ self.context.cast(self.builder, val, fromty, resty.dtype) for val, fromty in zip(itemvals, itemtys) ] return self.context.build_set(self.builder, resty, castvals) elif expr.op == "build_map": items = expr.items keys, values = [], [] key_types, value_types = [], [] for k, v in items: key = self.loadvar(k.name) keytype = self.typeof(k.name) val = self.loadvar(v.name) valtype = self.typeof(v.name) keys.append(key) values.append(val) key_types.append(keytype) value_types.append(valtype) return self.context.build_map(self.builder, resty, list(zip(key_types, value_types)), list(zip(keys, values))) elif expr.op == "cast": val = self.loadvar(expr.value.name) ty = self.typeof(expr.value.name) castval = self.context.cast(self.builder, val, ty, resty) self.incref(resty, castval) return castval elif expr.op == "phi": raise LoweringError("PHI not stripped") elif expr.op in self.context.special_ops: res = self.context.special_ops[expr.op](self, expr) return res raise NotImplementedError(expr)