I apologize for not reducing this to a simpler test case, but I can’t seem to reproduce this in any other situation. Note the create
function is autogenerated based on a specification, hence the verbosity.
I have the following code (spanning a few files, but consolidated here):
#in Kurento.Client
@spec invoke(client(), any) :: {:error, map} | {:ok, nil | maybe_improper_list | map}
@doc false
def invoke(client, request) do
name = via(client)
GenServer.call(name, {:call, request})
end
#In Kurento.Remote.MediaPipeline
@type t :: %{client: Kurento.Client.client(), id: String.t()}
@spec create(any) :: {:error, Kurento.CallError.t()} | {:ok, Kurento.Remote.MediaPipeline.t()}
def create(client) do
constructor_params = %{}
params = %{type: "MediaPipeline", constructorParams: constructor_params, properties: %{}}
request = Kurento.RPCRequest.create("create", params)
result = Kurento.Client.invoke(client, request)
case(result) do
{:ok, value} ->
{:ok, Kurento.Remote.MediaPipeline.from_param(client, value["value"])}
{:error, err} ->
{:error, Kurento.CallError.from_map(err)}
end
end
def test(client) do
{:ok, pipe} = create(client)
pipe
end
Dialyzer does not like the {:ok, pipe} = create(client)
line complaining:
lib/gen/remote/media_pipeline.ex:34:pattern_match
The pattern can never match the type.
Pattern:
{:ok, _pipe}
Type:
{:error, %Kurento.CallError{:code => integer(), :message => binary()}}
Basically insisting create will always return an error (it doesn’t).
What’s weird is if I remove the spec line @spec create(any) :: {:error, Kurento.CallError.t()} | {:ok, Kurento.Remote.MediaPipeline.t()}
Dialyzer is happy with that code, and Visual Studio Code is immediately suggesting I add it back (I assume inferred from Dialyzer).
Another oddball is if I add a new branch to the case (note that nil
is impossible in this particular scenario, which is why the auto-generated code doesn’t have it):
{:ok, nil} ->
:ok
The error becomes:
The pattern can never match the type.
Pattern:
{:ok, _pipe}
Type:
:ok | {:error, %Kurento.CallError{:code => integer(), :message => binary()}}
It seems (as long as the spec on create
is in place) Dialyzer believes hitting the {:ok, value}
branch is impossible. I tried to make it clear it was by adding the spec on `Kurento.Client.invoke, but I can’t seem to convince it.
If I remove the spec however, it infers the same spec, and is happy with it.
Does anyone have advice?