Skip to content

Commit

Permalink
BUG: Replace assert with correct error
Browse files Browse the repository at this point in the history
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
  • Loading branch information
seberg authored and charris committed Sep 7, 2022
1 parent fc0d627 commit fb9666f
Show file tree
Hide file tree
Showing 2 changed files with 16 additions and 2 deletions.
9 changes: 7 additions & 2 deletions numpy/core/src/umath/dispatching.c
Expand Up @@ -914,8 +914,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;
}
}

Expand Down
9 changes: 9 additions & 0 deletions numpy/core/tests/test_ufunc.py
Expand Up @@ -492,6 +492,15 @@ def test_partial_signature_mismatch(self, casting):
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.
Expand Down

0 comments on commit fb9666f

Please sign in to comment.