How to use dialyzer on linux command line (without mix)?

I’m struggling with dialyzer from linux command line, no mix.

First I have to build PLT but I have no idea what are the needed parameters. I have tried (output edited for readability):

$ dialyzer --build_plt --apps kernel
  Creating PLT /home/jani/.dialyzer_plt ...
Unknown functions:
  atomics:info/1 (erl_erts_errors.erl:68:9)
  beam_lib:chunks/2 (code.erl:872:10)
  beam_lib:md5/1 (code.erl:1082:10)
  binary:decode_unsigned/1 (net_kernel.erl:1754:14)
  binary:match/2 (os.erl:385:10)
[..]
  unicode:latin1_chardata/0 (rpc.erl:1377:16)
 done in 0m9.24s
done (passed successfully)

But it reports huge amount of unknown functions and types. Is that ok?

Anyway the following binary file is created:

$ l ~/.dialyzer_plt 
.rw-rw-r-- 359k jani jani 2023-01-20 11:22 /home/jani/.dialyzer_plt

This is my test code:

defmodule TypeSpecExample do
  @spec add(a :: integer, b :: integer) :: integer
  def add(a, b), do: a + b

  @spec sub(a :: integer, b :: integer) :: integer
  def sub(a, b), do: a - b
end

Compiles fine:

$ elixirc TypeSpecExample.ex 
$ l *TypeSpecExample*
.rwxrwx--- 1,6k root vboxsf 2023-01-20 11:30 Elixir.TypeSpecExample.beam*
.rwxrwx---  190 root vboxsf 2023-01-20 11:13 TypeSpecExample.ex*

When I run dialyzer I get this output telling me nothing but that I don’t know how to use it :frowning:

$ dialyzer Elixir.TypeSpecExample.beam
  Checking whether the PLT /home/jani/.dialyzer_plt is up-to-date... yes
  Proceeding with analysis...=ERROR REPORT==== 20-Jan-2023::11:31:59.637815 ===
Error in process <0.82.0> with exit value:
{undef,
    [{elixir_erl,debug_info,
         [core_v1,'Elixir.TypeSpecExample',
          {elixir_v1,
              #{after_verify => [],attributes => [],compile_opts => [],
                definitions =>
                    [{{sub,2},
                      def,
                      [{line,6}],
                      [{[{line,6}],
                        [{a,[{version,0},{line,6}],nil},
                         {b,[{version,1},{line,6}],nil}],
                        [],
                        {{'.',[{line,6}],[erlang,'-']},
                         [{line,6}],
                         [{a,[{version,0},{line,6}],nil},
                          {b,[{version,1},{line,6}],nil}]}}]},
                     {{add,2},
                      def,
                      [{line,3}],
                      [{[{line,3}],
                        [{a,[{version,0},{line,3}],nil},
                         {b,[{version,1},{line,3}],nil}],
                        [],
                        {{'.',[{line,3}],[erlang,'+']},
                         [{line,3}],
                         [{a,[{version,0},{line,3}],nil},
                          {b,[{version,1},{line,3}],nil}]}}]}],
                deprecated => [],
                file =>
                    <<"/media/sf_src/other/elixir-in-action/TypeSpecExample.ex">>,
                is_behaviour => false,line => 1,
                module => 'Elixir.TypeSpecExample',
                relative_file => <<"TypeSpecExample.ex">>,struct => nil,
                unreachable => []},
              [{attribute,5,spec,
                   {{sub,2},
                    [{type,5,'fun',
                         [{type,5,product,
                              [{ann_type,5,[{var,5,a},{type,5,integer,[]}]},
                               {ann_type,5,[{var,5,b},{type,5,integer,[]}]}]},
                          {type,5,integer,[]}]}]}},
               {attribute,2,spec,
                   {{add,2},
                    [{type,2,'fun',
                         [{type,2,product,
                              [{ann_type,2,[{var,2,a},{type,2,integer,[]}]},
                               {ann_type,2,[{var,2,b},{type,2,integer,[]}]}]},
                          {type,2,integer,[]}]}]}}]},
          [no_copt,to_core,binary,return_errors,no_inline,strict_record_tests,
           strict_record_updates,dialyzer,no_spawn_compiler_process]],
         []},
     {dialyzer_utils,get_core_from_beam,2,
         [{file,"dialyzer_utils.erl"},{line,119}]},
     {dialyzer_analysis_callgraph,compile_byte,5,
         [{file,"dialyzer_analysis_callgraph.erl"},{line,419}]},
     {dialyzer_worker,loop,2,[{file,"dialyzer_worker.erl"},{line,90}]}]}


dialyzer: Analysis failed with error:
{undef,
    [{elixir_erl,debug_info,
         [core_v1,'Elixir.TypeSpecExample',
          {elixir_v1,
              #{after_verify => [],attributes => [],compile_opts => [],
                definitions =>
                    [{{sub,2},
                      def,
                      [{line,6}],
                      [{[{line,6}],
                        [{a,[{version,0},{line,6}],nil},
                         {b,[{version,1},{line,6}],nil}],
                        [],
                        {{'.',[{line,6}],[erlang,'-']},
                         [{line,6}],
                         [{a,[{version,0},{line,6}],nil},
                          {b,[{version,1},{line,6}],nil}]}}]},
                     {{add,2},
                      def,
                      [{line,3}],
                      [{[{line,3}],
                        [{a,[{version,0},{line,3}],nil},
                         {b,[{version,1},{line,3}],nil}],
                        [],
                        {{'.',[{line,3}],[erlang,'+']},
                         [{line,3}],
                         [{a,[{version,0},{line,3}],nil},
                          {b,[{version,1},{line,3}],nil}]}}]}],
                deprecated => [],
                file =>
                    <<"/media/sf_src/other/elixir-in-action/TypeSpecExample.ex">>,
                is_behaviour => false,line => 1,
                module => 'Elixir.TypeSpecExample',
                relative_file => <<"TypeSpecExample.ex">>,struct => nil,
                unreachable => []},
              [{attribute,5,spec,
                   {{sub,2},
                    [{type,5,'fun',
                         [{type,5,product,
                              [{ann_type,5,[{var,5,a},{type,5,integer,[]}]},
                               {ann_type,5,[{var,5,b},{type,5,integer,[]}]}]},
                          {type,5,integer,[]}]}]}},
               {attribute,2,spec,
                   {{add,2},
                    [{type,2,'fun',
                         [{type,2,product,
                              [{ann_type,2,[{var,2,a},{type,2,integer,[]}]},
                               {ann_type,2,[{var,2,b},{type,2,integer,[]}]}]},
                          {type,2,integer,[]}]}]}}]},
          [no_copt,to_core,binary,return_errors,no_inline,strict_record_tests,
           strict_record_updates,dialyzer,no_spawn_compiler_process]],
         []},
     {dialyzer_utils,get_core_from_beam,2,
         [{file,"dialyzer_utils.erl"},{line,119}]},
     {dialyzer_analysis_callgraph,compile_byte,5,
         [{file,"dialyzer_analysis_callgraph.erl"},{line,419}]},
     {dialyzer_worker,loop,2,[{file,"dialyzer_worker.erl"},{line,90}]}]}
Last messages in the log cache:
  Reading files and computing callgraph...

You should not worry about such things. I would recommend to use dialyxir package instead. It contains a mix task, so that with one call everything is done for you. Also if you do not understand something there is a separate mix task to explain specific error. Unfortunately I have no idea about using it in iex. Maybe check it’s documentation.

If this is the reality I guess I’ll have to postpone studying typespecs after I have some idea how to use mix. I’m currently just compiling my Elixir-in-Action code snippets with elixirc (with a help of make) and running code in iex.

Is there a reason to avoid using mix? I believe you can run mix tasks within an iex session, though I’m not able to double check this at the moment.
You can try this: From the root directory of your application run iex -S mix. If you have dialyxir in your dependencies you should then be able to run Mix.Task.run "dialyzer" to see the analysis.

For fun I asked chatGPT:

2 Likes

No, there is no reason to avoid mix - this is just about the learning path. I just thought one could use dialyzer in the similar fashion than I can use elixirc for small code snippets but that seems not to be the case. I have now rescheduled introduction to dialyzer after mix.

I guess this was a XY problem - Wikipedia.

I get the sentiment but hear it from us: mix is very much expected and is the trodden path when working with Elixir. Don’t piss against the wind and you will make your learning much smoother.

Just wanted to follow up that I did test out running dialyzer in iex with mix and it works. Slow on my machine the first time I ran it but it works.