jeremyjh / dialyxir

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

The guard clause can never succeed (with `ExUnit` `assert`) #455

Closed thbar closed 2 years ago

thbar commented 2 years ago

Precheck

Environment

Erlang/OTP 24 [erts-12.2.1] [source] [64-bit] [smp:16:16] [ds:16:16:10] [async-threads:1] [jit]

Elixir 1.13.3 (compiled with Erlang/OTP 24)
cat mix.lock | grep dialyxir
  "dialyxir": {:hex, :dialyxir, "1.1.0", "c5aab0d6e71e5522e77beff7ba9e08f8e02bad90dfbeffae60eaf0cb47e29488", [:mix], [{:erlex, ">= 0.2.6", [hex: :erlex, repo: "hexpm", optional: false]}], "hexpm", "07ea8e49c45f15264ebe6d5b93799d4dd56a44036cf42d0ad9c960bc266c0b9a"},

Current behavior

This code:

https://github.com/etalab/transport-site/blob/2c34dcd6d18a0d354b4697bec80a5136d7454303/apps/transport/test/support/s3_test_utils.ex#L14-L20

Leads to this warning:

test/support/s3_test_utils.ex:14:guard_fail
The guard clause:

when _ :: %{:http_method => :get, :path => <<_::8>>, :service => :s3, _ => _} === false

can never succeed.

Expected behavior

I was expecting it would work, even after looking a bit closer at how exunit handles matches (https://github.com/elixir-lang/elixir/blob/feb9884a3e7196aac6c8ba2132cb41515adb1c5e/lib/ex_unit/lib/ex_unit/assertions.ex#L84-L99), and switching from require ExUnit.Assertions to import ExUnit.Assertions.

I wonder if my understanding is incorrect, or if this is a trouble in the dialyzer run, not very sure yet, but I thought it would be worth opening to discuss this here.

jeremyjh commented 2 years ago

My intuition is that it's unhappy that the expression passed to assert can never evaluate to nil or false, because instead of a comparison you are passing a non-refutable pattern match. So instead of nil/false you will get an exception, and the guard clause in the expanded macro will indeed never be used.

This isn't really a question about dialyxir since its a question about the results of the analysis which isn't done in this project; but for it to be an OTP issue you'd have to reproduce it in valid Erlang. The best place to ask for help is the Elixir forum. You might have a tough time getting good results dialyzing tests just because almost no one does it, so idiomatic expressions may yield warnings that you can't solve.