Credence.Pattern.NoLiteralListTypespec (credence v0.7.0)

Copy Markdown

Correctness rule: Detects a multi-element literal list used as an @spec return type — e.g. [pos_integer(), pos_integer()]. This is not valid Elixir: in a typespec [type] means "a list of type", and a list with two or more comma-separated element types raises Kernel.TypespecError at compile time. LLMs translating fixed-size return values from other languages (a Python tuple, say) emit this shape.

The fix converts the literal list to a tuple, the idiomatic way to express a fixed-size heterogeneous type. A @spec has no runtime effect and the original does not compile, so the rewrite only ever touches already-broken specs.

Scope (deliberately narrow)

Only fires when every element is a plain type call (pos_integer(), atom(), String.t(), list(integer()), …). It does not touch:

  • keyword-list types ([ok: integer(), error: atom()]) — those are valid;
  • non-empty list types ([type, ...]) — also valid;
  • literal-atom lists ([:ok, :error]) — ambiguous (likely a :ok | :error union, not a tuple), so left for a human;

  • single-element list types ([type]) — valid.

Bad

@spec foo(integer()) :: [pos_integer(), pos_integer()]

Good

@spec foo(integer()) :: {pos_integer(), pos_integer()}