This issue is created after discussion at https://elixirforum.com/t/dialyzer-listed-not-implemented-protocols-as-unknown-functions/2099
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)
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.
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.
@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.
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.