Skip to content

Commit 2a0cf28

Browse files
committed
Reject integer/complex output on explicit jit_backend="js"
The explicit JS path bypassed the output-dtype check, so an integer/complex output kernel would silently compute in float64 instead of failing. Raise a clear ValueError up front (matching the documented "explicit js raises on gaps" contract); integer inputs with a floating output still use JS. Keeps integer output entirely on miniexpr. Add a test and update the coverage plan.
1 parent 2308af3 commit 2a0cf28

3 files changed

Lines changed: 21 additions & 1 deletion

File tree

plans/dsl-js-coverage.md

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -71,7 +71,9 @@ except Exception:
7171
```
7272

7373
With an **explicit** `jit_backend="js"`, the same gaps instead **raise** rather than fall
74-
back (the user asked for JS specifically, so we don't second-guess them).
74+
back (the user asked for JS specifically, so we don't second-guess them). This includes a
75+
non-floating *output* dtype: `_maybe_js_backend` raises a clear `ValueError` up front rather
76+
than letting the float64 bridge silently compute integer/complex output (see below).
7577

7678
The JS backend today covers *float64/float32 element-wise scalar kernels* using arithmetic,
7779
`where`, comparisons, `if/elif/else`, `range` loops, and whitelisted math functions.

src/blosc2/lazyexpr.py

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1510,6 +1510,14 @@ def _maybe_js_backend(expression, jit, jit_backend, reduce_args, operands, kwarg
15101510
if jit_backend == "js":
15111511
if reduce_args:
15121512
raise ValueError('jit_backend="js" does not support reductions')
1513+
out_dtype = kwargs.get("dtype")
1514+
if out_dtype is not None and not np.issubdtype(np.dtype(out_dtype), np.floating):
1515+
# The JS bridge computes in float64 and cannot reproduce integer/complex output
1516+
# semantics (division/overflow/truncation); keep those on miniexpr.
1517+
raise ValueError(
1518+
'jit_backend="js" requires a floating-point output dtype '
1519+
f"(got {np.dtype(out_dtype)}); drop jit_backend to use miniexpr"
1520+
)
15131521
return _as_js_udf(expression, shape), None, None
15141522
prefer_js = (
15151523
jit is not False # jit=True/None prefer the best JIT (js); only jit=False forces interpreter

tests/ndarray/test_dsl_js.py

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -306,3 +306,13 @@ def test_explicit_js_off_wasm_raises():
306306
assert not blosc2.IS_WASM # this test runs on a native build
307307
with pytest.raises(RuntimeError, match="WebAssembly"):
308308
lx._maybe_js_backend(_add, None, "js", {}, {}, {})
309+
310+
311+
def test_explicit_js_integer_output_raises():
312+
# Integer/complex output is left to miniexpr; explicit jit_backend="js" must reject it
313+
# (the float64 bridge can't reproduce integer semantics) rather than silently compute.
314+
af = blosc2.asarray(np.ones((4, 4), dtype=np.float64))
315+
with pytest.raises(ValueError, match="floating-point output"):
316+
lx._maybe_js_backend(_add, None, "js", {}, {"a": af, "b": af}, {"dtype": np.int64})
317+
with pytest.raises(ValueError, match="floating-point output"):
318+
lx._maybe_js_backend(_add, None, "js", {}, {"a": af, "b": af}, {"dtype": np.complex128})

0 commit comments

Comments
 (0)