From dialyzer
Analyzes and fixes Dialyzer warnings, type specs, and discrepancies in Erlang/Elixir code with patterns for unions, opaque types, and success typing.
npx claudepluginhub thebushidocollective/han --plugin dialyzerThis skill cannot use any tools. It operates in read-only mode without the ability to modify files or execute commands.
Understanding and fixing Dialyzer warnings in Erlang and Elixir code.
Guides Dialyzer setup for Erlang/Elixir static analysis, including mix.exs config, PLTs, flags, ignore warnings, best practices, and GitHub Actions integration.
Identifies and refactors Elixir anti-patterns like excessive comments, complex `with` else clauses, and complex variable extractions. Use for reviewing code smells, refactoring, and improving quality.
Identifies and refactors Elixir anti-patterns like excessive comments, complex `with` else clauses, and complex clause extractions. Use for code reviews, refactoring smells, and quality improvements.
Share bugs, ideas, or general feedback.
Understanding and fixing Dialyzer warnings in Erlang and Elixir code.
@spec add(integer(), integer()) :: integer()
def add(a, b), do: a + b
@spec get_user(pos_integer()) :: {:ok, User.t()} | {:error, atom()}
def get_user(id) do
# implementation
end
@type user :: %{
id: pos_integer(),
name: String.t(),
email: String.t(),
role: :admin | :user | :guest
}
@spec process_users([user()]) :: {:ok, [user()]} | {:error, String.t()}
@spec map_values(map(), (any() -> any())) :: map()
@spec filter_list([t], (t -> boolean())) :: [t] when t: any()
# Warning: pattern match is not exhaustive
case value do
:ok -> :success
# Missing :error case
end
# Fixed
case value do
:ok -> :success
:error -> :failure
_ -> :unknown
end
# Warning: function has no local return
def always_raises do
raise "error"
end
# Fixed with spec
@spec always_raises :: no_return()
def always_raises do
raise "error"
end
# Warning: unmatched return
def process do
{:error, "failed"} # Return value not used
:ok
end
# Fixed
def process do
case do_something() do
{:error, reason} -> handle_error(reason)
:ok -> :ok
end
end
# Warning: unknown function
SomeModule.undefined_function()
# Fixed: ensure function exists or handle dynamically
if Code.ensure_loaded?(SomeModule) and
function_exported?(SomeModule, :function_name, 1) do
SomeModule.function_name(arg)
end
@type result :: :ok | {:ok, any()} | {:error, String.t()}
@spec handle_result(result()) :: any()
def handle_result(:ok), do: nil
def handle_result({:ok, value}), do: value
def handle_result({:error, msg}), do: Logger.error(msg)
@opaque internal_state :: %{data: map(), timestamp: integer()}
@spec new() :: internal_state()
def new, do: %{data: %{}, timestamp: System.system_time()}
@spec process_conn(Plug.Conn.t()) :: Plug.Conn.t()
@spec format_date(Date.t()) :: String.t()
Dialyzer uses success typing:
# Dialyzer infers: integer() -> integer()
def double(x), do: x * 2
# More specific spec
@spec double(pos_integer()) :: pos_integer()
def double(x) when x > 0, do: x * 2
any()mix dialyzer --format dialyzer
mix dialyzer --explain
mix dialyzer lib/my_module.ex