defmodule Abstract do
@callback foo() :: binary()
defmacro __using__( _) do
quote do
@behavior Abstract
@impl true
def foo() do
raise RuntimeError, "shouldn't have been invoked!"
end
defoverridable Abstract
end
end
end
defmodule SpecificA do
use Abstract
end
defmodule SpecificB do
use Abstract
@impl true
def foo() do
"foo"
end
end
The problem is dialyzer keeps on showing this warning that foo/0 default implementation in SpecificA âhas no local returnâ. Even if I change the callback return value to binary() | no_return(), it still gives the same warning.
Any ideas on how to circumvent the dialyzer warning without providing a dummy implementation of the foo/0 in SpecificA?
What if the foo function has a more serious default implementation? Such as those that exist in âGenServerâ for default callbacks implementations(e.g. handle-*)
If the original @DaAnalystâs questionâs code modified as such:
defmodule Abstract do
@callback foo() :: {:ok, binary()} | {:error, binary()}
# EDIT: Even by marking it as optional, Dialyzer complains
@optional_callbacks foo: 0
defmacro __using__(_) do
quote do
@behaviour Abstract
@impl true
def foo() do
{:ok, "Evrything is good:~"}
end
def bar() do
case foo() do
{:ok, message} -> IO.puts(message)
{:error, message} -> IO.puts(message)
end
end
defoverridable foo: 0
end
end
end
defmodule SpecificA do
use Abstract
end
Dialyzer complains:
ElixirLS Dialyzer: The pattern
{'error', _@2} can never match the type
{'ok', <<_:152>>}
defmodule Abstract do
@callback foo() :: {:ok, binary()} | {:error, binary()}
defmacro __using__(_) do
quote do
@behaviour Abstract
@impl true
def foo() do
case :erlang.phash2(1, 1) do
0 ->
{:ok, "Evrything is good:~"}
1 ->
{:error, "This is not possible to execute"}
end
end
def bar() do
case foo() do
{:ok, message} -> IO.puts(message)
{:error, message} -> IO.puts(message)
end
end
defoverridable foo: 0
end
end
end
defmodule SpecificA do
use Abstract
end