summaryrefslogtreecommitdiff
path: root/numpy
diff options
context:
space:
mode:
authorSebastian Berg <sebastian@sipsolutions.net>2022-08-05 10:11:08 +0530
committerSebastian Berg <sebastian@sipsolutions.net>2022-08-05 10:28:28 +0530
commite3bcb6a7e54239ee83e0f9ca80cf71dd8f35bec9 (patch)
treed0adbdebfce79eabce70568d551d9da47c4c1dc3 /numpy
parentf4f7595e99fffffe15effdaefe12cb7ef686ec6f (diff)
downloadnumpy-e3bcb6a7e54239ee83e0f9ca80cf71dd8f35bec9.tar.gz
BUG: Replace assert with correct error
If we cache a promoted version of the loop, that promoted can mismatch the correct one. This ends up being rejected later in the legacy paths (should be the only path currently used), but we should reject it here (or in principle we could reject it after cache lookup, but we are fixing up the operation DTypes here anyway, so we are looking at the signature). A call sequence reproducing this directly is: np.add(1, 2, signature=(bool, int, None)) # should fail np.add(True, 2) # A promoted loop np.add(1, 2, signature=(bool, int, None)) # should still fail Not that the errors differ, because the first one comes from the old type resolution code and is currently less precise
Diffstat (limited to 'numpy')
-rw-r--r--numpy/core/src/umath/dispatching.c9
-rw-r--r--numpy/core/tests/test_ufunc.py9
2 files changed, 16 insertions, 2 deletions
diff --git a/numpy/core/src/umath/dispatching.c b/numpy/core/src/umath/dispatching.c
index 5aecdd1fc..79de6c3c8 100644
--- a/numpy/core/src/umath/dispatching.c
+++ b/numpy/core/src/umath/dispatching.c
@@ -1016,8 +1016,13 @@ promote_and_get_ufuncimpl(PyUFuncObject *ufunc,
signature[i] = (PyArray_DTypeMeta *)PyTuple_GET_ITEM(all_dtypes, i);
Py_INCREF(signature[i]);
}
- else {
- assert((PyObject *)signature[i] == PyTuple_GET_ITEM(all_dtypes, i));
+ else if ((PyObject *)signature[i] != PyTuple_GET_ITEM(all_dtypes, i)) {
+ /*
+ * If signature is forced the cache may contain an incompatible
+ * loop found via promotion (signature not enforced). Reject it.
+ */
+ raise_no_loop_found_error(ufunc, (PyObject **)op_dtypes);
+ return NULL;
}
}
diff --git a/numpy/core/tests/test_ufunc.py b/numpy/core/tests/test_ufunc.py
index e4b1ceee3..ce30e63db 100644
--- a/numpy/core/tests/test_ufunc.py
+++ b/numpy/core/tests/test_ufunc.py
@@ -492,6 +492,15 @@ class TestUfunc:
with pytest.raises(TypeError):
np.ldexp(1., np.uint64(3), signature=(None, None, "d"))
+ def test_partial_signature_mismatch_with_cache(self):
+ with pytest.raises(TypeError):
+ np.add(np.float16(1), np.uint64(2), sig=("e", "d", None))
+ # Ensure e,d->None is in the dispatching cache (double loop)
+ np.add(np.float16(1), np.float64(2))
+ # The error must still be raised:
+ with pytest.raises(TypeError):
+ np.add(np.float16(1), np.uint64(2), sig=("e", "d", None))
+
def test_use_output_signature_for_all_arguments(self):
# Test that providing only `dtype=` or `signature=(None, None, dtype)`
# is sufficient if falling back to a homogeneous signature works.