jeremyjh / dialyxir

Mix tasks to simplify use of Dialyzer in Elixir projects.
Apache License 2.0
1.71k stars 142 forks source link

Failing to run `mix dialyzer` inside child project #289

Open mguimas opened 5 years ago

mguimas commented 5 years ago

Environment

$ elixir --version
Erlang/OTP 21 [erts-10.2.3] [source] [64-bit] [smp:4:4] [ds:4:4:10] [async-threads:1] [hipe]

Elixir 1.8.1 (compiled with Erlang/OTP 21)

In both the umbrella and child projects I have:

$ cat mix.exs | grep dialyxir
      {:dialyxir, "~> 0.5.1", only: [:dev, :test]}

In the single mix.lock file shared by all projects in the umbrella I have:

$ cat mix.lock | grep dialyxir
  "dialyxir": {:hex, :dialyxir, "0.5.1", "b331b091720fd93e878137add264bac4f644e1ddae07a70bf7062c7862c4b952", [:mix], [], "hexpm"},

Current behavior

$ mix help
...
mix dialyzer           # Runs dialyzer with default or project-defined flags.
...

$ mix help dialyzer

                                  mix dialyzer

This task compiles the mix project, creates a PLT with dependencies if needed
and runs dialyzer. Much of its behavior can be managed in configuration as
described below.
...

$ mix dialyzer
In an Umbrella child and no PLT found - building that first.
** (Mix) The task "dialyzer" could not be found
** (Protocol.UndefinedError) protocol String.Chars not implemented for %IO.Stream{device: :standard_io, line_or_bytes: :line, raw: false}
    (elixir) lib/string/chars.ex:3: String.Chars.impl_for!/1
    (elixir) lib/string/chars.ex:22: String.Chars.to_string/1
    lib/mix/tasks/dialyzer.ex:179: Mix.Tasks.Dialyzer.build_parent_plt/0
    lib/mix/tasks/dialyzer.ex:113: Mix.Tasks.Dialyzer.no_check?/1
    lib/mix/tasks/dialyzer.ex:101: Mix.Tasks.Dialyzer.run/1
    (mix) lib/mix/task.ex:331: Mix.Task.run_task/3
    (mix) lib/mix/cli.ex:79: Mix.CLI.run_task/2

It is also strange to get the message ** (Mix) The task "dialyzer" could not be found after showing the help for the dialyzer task.

Expected behavior

The expected behavior is for the mix dialyzer command to build the PLT and run Dialyzer as expected.

asummers commented 5 years ago

Interesting. So I've only ever run Dialyzer from the top level in an umbrella or in a non-umbrella'd app. Does the child application list Dialyzer as one of its dependencies in its mix.exs?

mguimas commented 5 years ago

Yes it lists. In the past I have run Dialyzer from child projects and it worked.

asummers commented 5 years ago

I'm assuming this isn't a public project. That would be too easy =). There have been SUBSTANTIAL bug fixes and improvements since 0.5.1 so can you try bumping to 1.0.0-rc4?

mguimas commented 5 years ago

Ok, I am going to try 1.0.0-rc4. I'll come back here as soon as possible.

mguimas commented 5 years ago

I upgraded to 1.0.0-rc.4, and got the same error when running mix dialyzer from the child project's directory.

Running mix dialyzer at the umbrella root dir works, then running mix dialyzer at the child project's directory works too.

So the problem is running mix dialyzer from the child project when there is no PLT.

asummers commented 5 years ago

I totally buy that theory. Sounds like the regenerate PLT code just needs to be more robust to being run from child applications. Thanks for the report!

jeremyjh commented 5 years ago

It looks like its a new issue on Elixir 1.8. It works for me on 1.7.3 but I get the same error on 1.8. This code is a garbage fire, it is shelling another process to build the PLT at the parent level because of load order issues for recursive app children. But I'm guessing something in the shell environment defaults has changed.

asummers commented 5 years ago

I audibly laughed in public when I read :wastebasket: :fire: haha. Was unexpected.

That code could definitely use some love, and I'm curious what changed upstream.