|
| 1 | +# Dialyzer warning suppressions. Every entry is a false positive driven |
| 2 | +# by a dialyzer limitation documented below, not a correctness issue. |
| 3 | +# Use `{file, warning_type[, line]}` tuples; add a comment per cluster. |
| 4 | + |
| 5 | +[ |
| 6 | + # --------------------------------------------------------------- |
| 7 | + # Emily.Backend — Nx.Backend callback type mismatches |
| 8 | + # --------------------------------------------------------------- |
| 9 | + # |
| 10 | + # `wrap/3` (lib/emily/backend.ex:71) returns `%T{out | data: %B{...}}`, |
| 11 | + # which dialyzer's map-update analysis infers as a partial map |
| 12 | + # (`%Nx.Tensor{data, type, _ => _}`) — the unchanged `:shape`, |
| 13 | + # `:names`, `:vectorized_axes` keys drop out of the inferred type |
| 14 | + # because dialyzer doesn't propagate struct field types across map |
| 15 | + # updates. Nx.Backend's callback specs require the full |
| 16 | + # `Nx.Tensor.t()` record, so dialyzer reports a "nothing in common" |
| 17 | + # mismatch for every `@impl`'d callback (≈115 warnings). |
| 18 | + # |
| 19 | + # The code IS correct — we genuinely return complete `%Nx.Tensor{}` |
| 20 | + # structs — so suppressing the category wholesale is the right call. |
| 21 | + # Attempts to coax dialyzer (guards, explicit struct reconstruction, |
| 22 | + # narrower `@type tensor`) fix the shape/names tracking but introduce |
| 23 | + # their own quirks. Revisit if dialyzer's map-update analysis improves |
| 24 | + # (pre-Erlang 28 this was worse). |
| 25 | + {"lib/emily/backend.ex", :callback_type_mismatch}, |
| 26 | + {"lib/emily/backend.ex", :callback_arg_type_mismatch}, |
| 27 | + # Same root cause — `wrap/3`'s success typing ends up wider than the |
| 28 | + # declared `@spec wrap(ref(), tensor(), reference()) :: tensor()`. |
| 29 | + {"lib/emily/backend.ex", :invalid_contract, 71}, |
| 30 | + |
| 31 | + # --------------------------------------------------------------- |
| 32 | + # Emily.Fast — `Nx.Defn.Expr.optional/3` untyped return |
| 33 | + # --------------------------------------------------------------- |
| 34 | + # |
| 35 | + # `Nx.Defn.Expr.optional/3` has no `@spec` (see |
| 36 | + # `deps/nx/lib/nx/defn/expr.ex`). Dialyzer infers its return as |
| 37 | + # `tuple() | %{data: %Nx.Defn.Expr{…}, _ => _}` — the tuple branch |
| 38 | + # only fires when the fallback fun itself returns a tuple, which ours |
| 39 | + # don't. At runtime every one of these returns a proper |
| 40 | + # `Nx.Tensor.t()`, matching the declared `@spec`. Suppress the contract |
| 41 | + # check until Nx specs `optional/3`. |
| 42 | + {"lib/emily/fast.ex", :invalid_contract}, |
| 43 | + |
| 44 | + # --------------------------------------------------------------- |
| 45 | + # Emily.Quantization / Emily.QuantizedWeight — tensor construction |
| 46 | + # --------------------------------------------------------------- |
| 47 | + # |
| 48 | + # `quantized_matmul/2`, `from_dense/2`, and `to_dense/1` build a |
| 49 | + # fresh `%T{data: %B{ref: …}, shape: …, type: …, names: …}` from |
| 50 | + # NIF-returned refs. Dialyzer infers the resulting tensor's `:type` |
| 51 | + # as `{atom(), non_neg_integer()}` — `Native.dtype/1`'s declared |
| 52 | + # return — which doesn't overlap with `Nx.Tensor.t()`'s |
| 53 | + # `Nx.Type.t()` specific union. The NIF does return a valid |
| 54 | + # `Nx.Type.t()` tuple; the width is a declaration limitation in |
| 55 | + # the stub module. |
| 56 | + {"lib/emily/quantization.ex", :invalid_contract, 67}, |
| 57 | + {"lib/emily/quantized_weight.ex", :invalid_contract, 78}, |
| 58 | + {"lib/emily/quantized_weight.ex", :invalid_contract, 112} |
| 59 | +] |
0 commit comments