Elixir: Protocols make Dialyzer unhappy for built-in datatypes without implementation

Created on 25 May 2018  路  6Comments  路  Source: elixir-lang/elixir

This issue is created after discussion at https://elixirforum.com/t/dialyzer-listed-not-implemented-protocols-as-unknown-functions/2099

Environment

  • Elixir & Erlang/OTP versions (elixir --version):
    Erlang/OTP 20 [erts-9.3.1] [source] [64-bit] [smp:4:4] [ds:4:4:10] [async-threads:10] [hipe] [kernel-poll:false] [dtrace]

    Elixir 1.6.5 (compiled with OTP 20)
  • Operating system:
    MacOS High Sierra 10.13.4

Current behavior

I'm defining a protocol and a couple of implementations like this:

    defprotocol Template.Consumes.BaseViewProvider do
      @fallback_to_any true
      def retrieve(template_id)
    end

    defimpl Template.Consumes.BaseViewProvider, for: Any do
      def retrieve(_) do
        "Not implemented!"
      end
    end

    defimpl Template.Consumes.BaseViewProvider, for: Atom do
      defdelegate retrieve(template_id), to: Template.Consumes.BaseViewProvider.Any
    end

Also, I have {:dialyxir, "~> 0.5", only: [:dev], runtime: false} in my deps.

When running $ mix dialyse, I get:

done in 0m1.19s
:0: Unknown function 'Elixir.Template.Consumes.BaseViewProvider.BitString':'__impl__'/1
:0: Unknown function 'Elixir.Template.Consumes.BaseViewProvider.Float':'__impl__'/1
:0: Unknown function 'Elixir.Template.Consumes.BaseViewProvider.Function':'__impl__'/1
:0: Unknown function 'Elixir.Template.Consumes.BaseViewProvider.Integer':'__impl__'/1
:0: Unknown function 'Elixir.Template.Consumes.BaseViewProvider.List':'__impl__'/1
:0: Unknown function 'Elixir.Template.Consumes.BaseViewProvider.Map':'__impl__'/1
:0: Unknown function 'Elixir.Template.Consumes.BaseViewProvider.PID':'__impl__'/1
:0: Unknown function 'Elixir.Template.Consumes.BaseViewProvider.Port':'__impl__'/1
:0: Unknown function 'Elixir.Template.Consumes.BaseViewProvider.Reference':'__impl__'/1
:0: Unknown function 'Elixir.Template.Consumes.BaseViewProvider.Tuple':'__impl__'/1
done (warnings were emitted)

This behavior is present both with and without consolidate_protocols: false in mix.exs's def project.

Expected behavior

It is expected, that when @fallback_to_any true, then it passes Dialyzer checks.

I believe, that it could be possible if defprotocol macro generated delegates to .Any for all built-in data types, for which there is no implementation.

Elixir Intermediate

Most helpful comment

@im-tollu I took the liberty to report this here https://github.com/jeremyjh/dialyxir/issues/221

Please feel free to add/correct my issue there in case I missed something.

All 6 comments

@im-tollu Can you please push a small project to GitHub? Your description is already great but an existing project will make our lives even easier. :) Thank you!

@josevalim Sure, here it is: UnhappyDialyzer. And thank you!

@josevalim fyi Earmark is affected too in case that helps

So this is a "bug" in dialyxir because they are not considering the consolidation path when invoking dialyzer.

I changed dialyxir to consider consolidated protocols by changing this function:

https://github.com/jeremyjh/dialyxir/blob/master/lib/dialyxir/project.ex#L179-L183

to:

  defp default_paths() do
    [Mix.Project.consolidation_path()] ++ reduce_umbrella_children([], fn(paths) ->
      [Mix.Project.compile_path | paths]
    end)
  end

However, it fails with:

:dialyzer.run error: Analysis failed with error:
Duplicate modules: [["/Users/jose/OSS/unhappy_dialyzer/_build/dev/lib/unhappy_dialyzer/consolidated/Elixir.UnhappyDialyzer.beam",
                     "/Users/jose/OSS/unhappy_dialyzer/_build/dev/lib/unhappy_dialyzer/ebin/Elixir.UnhappyDialyzer.beam"]]
Last messages in the log cache:
  Reading files and computing callgraph...

Which makes sense. Once I deleted the project beam file, everything passed.

However, dialyxir cannot simply delete the beam files. One option is that it could copy all .beam files to one directory, making sure that the consolidation files override any previous copy, and then give that path to dialyzer.

@im-tollu can you please report this bug on dialyxir? We will be glad to answer any questions. Thank you!

@im-tollu I took the liberty to report this here https://github.com/jeremyjh/dialyxir/issues/221

Please feel free to add/correct my issue there in case I missed something.

Was this page helpful?
0 / 5 - 0 ratings