Indicate exclude type when defining type spec

I have a function, and its definition is shown below:

def my_func(%{a: %{b: _}}) do
      "output"
end

def my_func(_) do
      nil
end

when the input of myfunc is nested map with the key a.b, the output will be a string, or the output will be nil.

then I try to add type spec for it like below:

@spec my_func(%{a: %{b: any()}}) :: String.t()
@spec my_func(any()) :: nil
def my_func(%{a: %{b: _}}) do
      "output"
end

def my_func(_) do
      nil
end

But I receive overlapping_contract error after executing mix dialyzer. Now I’m wondering if there is a feature which can indicate the exclude type so I can add type spec like below:

@spec my_func(%{a: %{b: any()}}) :: String.t()
@spec my_func(not(%{a: %{b: any()}})) :: nil
def my_func(%{a: %{b: _}}) do
      "output"
end

def my_func(_) do
      nil
end

And of course if I just declare the input as any():

@spec my_func(any()) :: String.t() | nil
def my_func(%{a: %{b: _}}) do
      "output"
end

def my_func(_) do
      nil
end

I can easily pass the mix dialyzer. But I think the method make the type checking meaningless, because it doesn’t actually check anything, all the types of the input is OK.

There is no such feature.

Also, dialyzer does not attempt to narrow the range of a function according to the given arguments, so even if such a feature existed it would be equivalent to your last example.

1 Like