Skip to content

Fix Elixir 1.20 type-checker warnings#2

Merged
simoncocking merged 1 commit into
mainfrom
fix/elixir-1.20-warnings
Jun 16, 2026
Merged

Fix Elixir 1.20 type-checker warnings#2
simoncocking merged 1 commit into
mainfrom
fix/elixir-1.20-warnings

Conversation

@simoncocking

@simoncocking simoncocking commented Jun 16, 2026

Copy link
Copy Markdown
Contributor

Summary

Elixir 1.20's new type checker surfaces two warnings in consuming applications. Both are fixed here with no behaviour change.

1. Redundant clause in generated struct channel/2

The use Amplified.PubSub macro generated:

def channel(%module{id: id}, ns) do ... end
def channel(_subject, _ns), do: nil

Each impl is for: a single struct, so the checker sees %module{id: id} as covering every value of that struct and flags the nil fallback as redundant — one warning per consuming module (100+ in parasol).

Fixed by collapsing to a single clause that checks for :id via Map.has_key?/2. A plain function call is opaque to the checker, so the nil branch stays reachable. Behaviour is identical: structs with an :id (including nil, which derives "thing:") get a channel; structs without one return nil.

Note: an is_map_key/2 guard does not work — the checker narrows guards too and re-flags the fallback. It must be a plain call.

2. Deprecated default argument in the protocol

Amplified.PubSub.Protocol declared def channel(subject, namespace \\ nil). Default args in defprotocol are deprecated in 1.20 ("protocols can only define functions without implementation"). Split into explicit channel/1 and channel/2; the Tuple impl gains a channel/1 head.

Testing

  • mix compile --force --all-warnings is clean.
  • All 66 tests pass.
  • Verified against parasol: build goes from 9 of these warnings to 0.

Two warnings surfaced in consuming applications under Elixir 1.20's new
type checker:

- The generated struct `channel/2` paired a `%module{id: id}` clause with
  a `nil` fallback. Because each impl is `for:` a single struct, the
  checker sees the struct clause as covering every value and flags the
  fallback as redundant. Replaced with a single clause that checks for the
  `:id` field via `Map.has_key?/2` — a plain call is opaque to the checker,
  so the `nil` branch stays reachable. Behaviour is unchanged (structs with
  an `:id`, including `nil`, derive a channel; others return `nil`). An
  `is_map_key/2` guard does NOT work here: the checker narrows guards too.

- `Amplified.PubSub.Protocol.channel/2` used a deprecated default argument
  (`namespace \\ nil`) in the protocol definition. Split into explicit
  `channel/1` and `channel/2` declarations; the `Tuple` impl gains a
  `channel/1` head to satisfy the new arity.

No behaviour change; all tests pass.
@simoncocking
simoncocking merged commit dcc5c36 into main Jun 16, 2026
1 check passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant