Credence.Pattern.RedundantListGuard (credence v0.7.0)

Copy Markdown

Detects is_list/1 guards on a cons-pattern tail variable ([head | tail] when is_list(tail)) that are redundant under the proper_lists promise.

Why this matters

The pattern `[headtail]` destructures a cons cell, but it does not
guarantee tail is a list: it also matches improper lists like `[12]`,

where tail is a non-list. So is_list(tail) is doing real work — it filters those out. The guard is only redundant when no improper list can reach the clause, i.e. when the caller promises proper lists.

This rule therefore declares the proper_lists assumption and runs only while that switch is on (the default). Under :strict it does not fire, because removing the guard would change behaviour on [1 | 2] (the guarded clause rejects it and falls through; the unguarded clause matches it).

Flagged patterns

PatternFix
def f([h | t]) when is_list(t)def f([h | t])
def f([h | t]) when is_list(t) and is_atom(h)def f([h | t]) when is_atom(h)
def f([_ | a], [_ | b]) when is_list(a) and …Remove each redundant is_list call

Bad

def max_subarray_sum([first | rest]) when is_list(rest) do
  rest
end

def merge([h1 | t1], [h2 | t2]) when is_list(t1) and is_list(t2) do
  {t1, t2}
end

Good

def max_subarray_sum([first | rest]) do
  rest
end

def merge([h1 | t1], [h2 | t2]) do
  {t1, t2}
end