Claude-skill-registry dialyzer-analysis
Use when analyzing and fixing Dialyzer warnings and type discrepancies in Erlang/Elixir code.
install
source · Clone the upstream repo
git clone https://github.com/majiayu000/claude-skill-registry
Claude Code · Install into ~/.claude/skills/
T=$(mktemp -d) && git clone --depth=1 https://github.com/majiayu000/claude-skill-registry "$T" && mkdir -p ~/.claude/skills && cp -r "$T/skills/data/dialyzer-analysis" ~/.claude/skills/majiayu000-claude-skill-registry-dialyzer-analysis && rm -rf "$T"
manifest:
skills/data/dialyzer-analysis/SKILL.mdsource content
Dialyzer Analysis
Understanding and fixing Dialyzer warnings in Erlang and Elixir code.
Type Specifications
Basic Specs
@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
Complex Types
@type user :: %{ id: pos_integer(), name: String.t(), email: String.t(), role: :admin | :user | :guest } @spec process_users([user()]) :: {:ok, [user()]} | {:error, String.t()}
Generic Types
@spec map_values(map(), (any() -> any())) :: map() @spec filter_list([t], (t -> boolean())) :: [t] when t: any()
Common Warnings
Pattern Match Coverage
# 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
No Return
# 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
Unmatched Returns
# 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
Unknown Functions
# 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 Analysis Patterns
Union Types
@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 Types
@opaque internal_state :: %{data: map(), timestamp: integer()} @spec new() :: internal_state() def new, do: %{data: %{}, timestamp: System.system_time()}
Remote Types
@spec process_conn(Plug.Conn.t()) :: Plug.Conn.t() @spec format_date(Date.t()) :: String.t()
Success Typing
Dialyzer uses success typing:
- Approximates what a function can succeed with
- Different from traditional type systems
- May miss some errors, but no false positives (in theory)
Example
# 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
Best Practices
- Start with Core Modules: Add specs to public APIs first
- Use Strict Types: Prefer specific types over
any() - Document Assumptions: Use specs to document expected behavior
- Test Specs: Ensure specs match actual behavior
- Iterative Fixing: Fix warnings incrementally
Debugging Tips
Verbose Output
mix dialyzer --format dialyzer
Explain Warnings
mix dialyzer --explain
Check Specific Files
mix dialyzer lib/my_module.ex