Why does dialyzer overlook this spec miss-match?

Why is it that dialyzer doesn’t pick up on (obvious) miss-matches between @spec and implementation:

@spec example(Ecto.Changeset.t()) :: MySchema.t()
def example(changeset) do
    Repo.update(changeset)
end

I would expect it to complain since Repo.update is specced with {:ok, Ecto.Schema.t()} | {:error, Ecto.Changeset.t()} as it’s return value.

That is because the default implementation does not define the spec.

You can define it in your Repo module, and Dialyzer will complain.

defmodule Repo do
  use Ecto.Repo,
    otp_app: :your_app_name,
    adapter: Ecto.Adapters.Postgres

  @spec update(changeset :: Ecto.Changeset.t(), opts :: Keyword.t()) ::
          {:ok, Ecto.Schema.t()} | {:error, Ecto.Changeset.t()}
end

I guess you could submit a patch to Ecto fixing this.

2 Likes