Credence.Pattern.NoCaseTupleGuardDispatch (credence v0.7.0)

Copy Markdown

Detects case on a tuple of variables where every clause's pattern is the same tuple of the same variables — all dispatch is via guards. This is a cond in disguise.

Bad

case {e1, e2} do
  {e1, e2} when e1 < e2 -> advance_left(rest1, list2)
  {e1, e2} when e1 > e2 -> advance_right(list1, rest2)
  {e1, e2} -> advance_both(rest1, rest2)
end

Good

cond do
  e1 < e2 -> advance_left(rest1, list2)
  e1 > e2 -> advance_right(list1, rest2)
  true -> advance_both(rest1, rest2)
end

Auto-fix

Unwraps the tuple, extracts guards, and rewrites as cond. A trailing _ wildcard (or a final guardless tuple clause) is converted to true.

Safety — why this is narrowed

Moving a when guard into a cond condition is not generally behaviour-preserving:

  • Guards swallow errors: when hd(a) > 0 treats a raised error as a failed clause, but the same expression as a cond condition propagates the error. So we only fire when every guard is built from operators that can never raise — the boolean connectives (and/or/not) over the total comparison operators (==, !=, ===, !==, <, >, <=, >=) whose operands are bare variables or literals. Term comparison is total, so these are bit-identical in a guard and in an expression, and they always yield a real boolean (so guard-truth and cond-truthiness agree).
  • A guard-only case with no catch-all raises CaseClauseError, while the corresponding cond raises CondClauseError. So we only fire when the final clause is a guardless catch-all (_ or the full tuple), making both constructs total over the same inputs.