Dialyxir can't detect error of anonymous function while Erlang can

Recently I found that Elixir’s typespec can’t detect type mismatch of anonymous/captured functions.

For demonstration purpose, say I have things like:

@spec mmap([number], (number -> number)) :: [number]
def mmap([], _), do: []
def mmap([head | tail], f), do: [ f.(head) | mmap(tail, f)]

def run do
  mmap([1, 2, 3, 4, 5], &Integer.to_charlist/1) # This is always wrong since it returns a list of charlist instead of list of number
end

But dialixir let the code pass:

...
[:elixir, :kernel, :logger, :stdlib]
PLT is up to date!
No :ignore_warnings opt specified in mix.exs and default does not exist.

Starting Dialyzer
[
  check_plt: false,
  init_plt: '/Users/tai/Projects/sandbox/fun_thu/type_example/_build/dev/dialyxir_erlang-21.1.1_elixir-1.7.4_deps-dev.plt',
  files_rec: ['/Users/tai/Projects/sandbox/fun_thu/type_example/_build/dev/lib/type_example/ebin'],
  warnings: [:unknown]
]
Total errors: 0, Skipped: 0
done in 0m1.02s
done (passed successfully)

I tried to replace the &Integer.to_charlist/1 to an anonymous function, or a local function with typespec, but still no luck.

Expect behavior

When in Erlang, if I got something similar:

-spec mmap([number()], fun((number()) -> number())) -> [number()].
mmap([], _) -> [];
mmap([Head | Tail], F) ->
  [F(Head) | mmap(Tail, F)].

run() ->
  mmap([1, 2, 3, 4, 5], fun(I) -> integer_to_list(I) end).

Dialyzer reports an error:

tp.erl:4: Invalid type specification for function tp:mmap/2. The success typing is ([1 | 2 | 3 | 4 | 5],fun((_) -> string())) -> [string()]
 done in 0m0.13s

Environment

Eralng 21.1.1
Elixir 1.7.4-otp-21
macOS 10.14.1

Question(s)

I’m wondering if I like to dig into the issue and make Elixir/dialyxir works in this situation, where should I start? As for my understanding, Erlang’s dialyzer analyzes the beam binary by default, not the source code. So is this because Elixir didn’t provide some information that dialyzer need, or it’s dialyxir’s own issue? Thanks for any advice or hint! :heart:

3 Likes

I would first check if the default settings for dialyzer used by dialyxir and dialyzer CLI itself are the same. Do you get the same results if you have the erlang module in the mix project and analyse it with dialyxir?

2 Likes

Thanks for great suggestion! I just put the erlang module in the mix project. And dialyxir report a type error in erlang correctly. Guess I’ll first try to look into dialyxir first.

I upload my experiment here: https://github.com/taiansu/dia_fpos, if anyone like to try out.

2 Likes