jeremyjh / dialyxir

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

Match error when formatting warning #341

Closed rodrigues closed 5 years ago

rodrigues commented 5 years ago

In this fork of stream_data (branch: dialyxir), I added dialyxir to its deps and tried running it, getting this failure instead:

➜ mix dialyzer
Finding suitable PLTs
Checking PLT...
[:elixir, :ex_doc, :ex_unit, :kernel, :mix, :stdlib]
PLT is up to date!
No :ignore_warnings opt specified in mix.exs and default does not exist.

Starting Dialyzer
[
  check_plt: false,
  init_plt: '/Users/rodrigues/code/stream_data/_build/dev/dialyxir_erlang-22.0.4_elixir-1.9.0_deps-dev.plt',
  files_rec: ['/Users/rodrigues/code/stream_data/_build/dev/lib/stream_data/ebin'],
  warnings: [:error_handling, :race_conditions, :unmatched_returns, :underspecs,
   :unknown]
]
** (MatchError) no match of right hand side value: {:error, {1, :erl_parse, ['syntax error before: ', '\'::\'']}}
    dialyzer.erl:626: anonymous fn/1 in :dialyzer.sig/2
    dialyzer.erl:541: :dialyzer.call_or_apply_to_string/6
    dialyzer.erl:322: :dialyzer.message_to_string/2
    dialyzer.erl:297: :dialyzer.format_warning/2
    lib/dialyxir/formatter.ex:106: Dialyxir.Formatter.format_warning/2
    lib/dialyxir/formatter.ex:275: anonymous fn/2 in Dialyxir.Formatter.filter_legacy_warnings/2
    (elixir) lib/enum.ex:3029: Enum.reject_list/2
    (elixir) lib/enum.ex:3032: Enum.reject_list/2

If I run it with --format raw, it works:

➜ mix dialyzer --format raw
Finding suitable PLTs
Checking PLT...
[:elixir, :ex_doc, :ex_unit, :kernel, :mix, :stdlib]
PLT is up to date!
No :ignore_warnings opt specified in mix.exs and default does not exist.

Starting Dialyzer
[
  check_plt: false,
  init_plt: '/Users/rodrigues/code/stream_data/_build/dev/dialyxir_erlang-22.0.4_elixir-1.9.0_deps-dev.plt',
  files_rec: ['/Users/rodrigues/code/stream_data/_build/dev/lib/stream_data/ebin'],
  warnings: [:error_handling, :race_conditions, :unmatched_returns, :underspecs,
   :unknown]
]
done in 0m1.72s
{:warn_contract_types, {'lib/ex_unit_properties.ex', 605}, {:invalid_contract, [ExUnitProperties, :pick, 1, '(atom() | tuple() | \#{\'__struct__\':=\'Elixir.StreamData\', \'generator\':=fun((_,_) -> any()), _=>_}) -> any()']}}
{:warn_contract_supertype, {'lib/stream_data.ex', 252}, {:extra_range, [StreamData, :constant, 1, 'atom() | tuple()', '\'Elixir.StreamData\':t(_) | \#{\'__struct__\':=\'Elixir.StreamData\', \'generator\':=fun((_,_) -> map())}']}}
{:warn_contract_supertype, {'lib/stream_data.ex', 278}, {:extra_range, [StreamData, :map, 2, 'atom() | tuple()', '\'Elixir.StreamData\':t(_) | \#{\'__struct__\':=\'Elixir.StreamData\', \'generator\':=fun((_,_) -> map())}']}}
{:warn_contract_supertype, {'lib/stream_data.ex', 338}, {:extra_range, [StreamData, :bind_filter, 3, 'atom() | tuple()', '\'Elixir.StreamData\':t(_) | \#{\'__struct__\':=\'Elixir.StreamData\', \'generator\':=fun((_,_) -> map())}']}}
{:warn_failing_call, {'lib/stream_data.ex', 344}, {:call, [StreamData, :bind_filter, '(_data@1::any(),fun((_,_) -> any()),_max_consecutive_failures@1::any())', [2], :only_contract, '(any(),fun(),non_neg_integer())', '\'Elixir.StreamData\':t(_) | \#{\'__struct__\':=\'Elixir.StreamData\', \'generator\':=fun((_,_) -> map())}', {true, '(t(a),fun((a) -> {\'cont\',t(b)} | \'skip\'),non_neg_integer()) -> t(b) when a :: term(), b :: term()'}]}}
{:warn_contract_supertype, {'lib/stream_data.ex', 428}, {:extra_range, [StreamData, :bind, 2, 'atom() | tuple()', '\'Elixir.StreamData\':t(_)']}}
{:warn_contract_supertype, {'lib/stream_data.ex', 478}, {:extra_range, [StreamData, :filter, 3, 'atom() | tuple()', '\'Elixir.StreamData\':t(_)']}}
{:warn_contract_supertype, {'lib/stream_data.ex', 507}, {:extra_range, [StreamData, :integer, 1, 'atom() | tuple()', '\'Elixir.StreamData\':t(integer()) | \#{\'__struct__\':=\'Elixir.StreamData\', \'generator\':=fun((_,_) -> map())}']}}
{:warn_contract_supertype, {'lib/stream_data.ex', 562}, {:extra_range, [StreamData, :resize, 2, 'atom() | tuple()', '\'Elixir.StreamData\':t(_) | \#{\'__struct__\':=\'Elixir.StreamData\', \'generator\':=fun((_,_) -> map())}']}}
{:warn_contract_supertype, {'lib/stream_data.ex', 589}, {:extra_range, [StreamData, :sized, 1, 'atom() | tuple()', '\'Elixir.StreamData\':t(_) | \#{\'__struct__\':=\'Elixir.StreamData\', \'generator\':=fun((_,_) -> map())}']}}
{:warn_contract_supertype, {'lib/stream_data.ex', 630}, {:extra_range, [StreamData, :scale, 2, 'atom() | tuple()', '\'Elixir.StreamData\':t(_) | \#{\'__struct__\':=\'Elixir.StreamData\', \'generator\':=fun((_,_) -> map())}']}}
{:warn_contract_supertype, {'lib/stream_data.ex', 656}, {:extra_range, [StreamData, :unshrinkable, 1, 'atom() | tuple()', '\'Elixir.StreamData\':t(_) | \#{\'__struct__\':=\'Elixir.StreamData\', \'generator\':=fun((_,_) -> map())}']}}
{:warn_contract_supertype, {'lib/stream_data.ex', 683}, {:extra_range, [StreamData, :seeded, 2, 'atom() | tuple()', '\'Elixir.StreamData\':t(_) | \#{\'__struct__\':=\'Elixir.StreamData\', \'generator\':=fun((_,_) -> map())}']}}
{:warn_contract_supertype, {'lib/stream_data.ex', 737}, {:extra_range, [StreamData, :frequency, 1, 'atom() | tuple()', '\'Elixir.StreamData\':t(_)']}}
{:warn_contract_supertype, {'lib/stream_data.ex', 769}, {:extra_range, [StreamData, :one_of, 1, 'atom() | tuple()', '\'Elixir.StreamData\':t(_)']}}
{:warn_contract_supertype, {'lib/stream_data.ex', 791}, {:extra_range, [StreamData, :member_of, 1, 'atom() | tuple()', '\'Elixir.StreamData\':t(_)']}}
{:warn_contract_supertype, {'lib/stream_data.ex', 855}, {:extra_range, [StreamData, :list_of, 2, 'atom() | tuple()', '\'Elixir.StreamData\':t([any()]) | \#{\'__struct__\':=\'Elixir.StreamData\', \'generator\':=fun((_,_) -> map())}']}}
{:warn_contract_supertype, {'lib/stream_data.ex', 995}, {:extra_range, [StreamData, :uniq_list_of, 2, 'atom() | tuple()', '\'Elixir.StreamData\':t([any()]) | \#{\'__struct__\':=\'Elixir.StreamData\', \'generator\':=fun((_,_) -> map())}']}}
{:warn_contract_supertype, {'lib/stream_data.ex', 1094}, {:extra_range, [StreamData, :nonempty_improper_list_of, 2, 'atom() | tuple()', '\'Elixir.StreamData\':t(_)']}}
{:warn_contract_supertype, {'lib/stream_data.ex', 1125}, {:extra_range, [StreamData, :maybe_improper_list_of, 2, 'atom() | tuple()', '\'Elixir.StreamData\':t(_)']}}
{:warn_contract_supertype, {'lib/stream_data.ex', 1150}, {:extra_range, [StreamData, :fixed_list, 1, 'atom() | tuple()', '\'Elixir.StreamData\':t([any()]) | \#{\'__struct__\':=\'Elixir.StreamData\', \'generator\':=fun((_,_) -> map())}']}}
{:warn_contract_supertype, {'lib/stream_data.ex', 1178}, {:extra_range, [StreamData, :tuple, 1, 'atom() | tuple()', '\'Elixir.StreamData\':t(tuple()) | \#{\'__struct__\':=\'Elixir.StreamData\', \'generator\':=fun((_,_) -> map())}']}}
{:warn_contract_supertype, {'lib/stream_data.ex', 1208}, {:extra_range, [StreamData, :map_of, 3, 'atom() | tuple()', '\'Elixir.StreamData\':t(_)']}}
{:warn_contract_supertype, {'lib/stream_data.ex', 1241}, {:extra_range, [StreamData, :fixed_map, 1, 'atom() | tuple()', '\'Elixir.StreamData\':t(_)']}}
{:warn_contract_supertype, {'lib/stream_data.ex', 1274}, {:extra_range, [StreamData, :optional_map, 1, 'atom() | tuple()', '\'Elixir.StreamData\':t(map()) | \#{\'__struct__\':=\'Elixir.StreamData\', \'generator\':=fun((_,_) -> map())}']}}
{:warn_contract_supertype, {'lib/stream_data.ex', 1322}, {:extra_range, [StreamData, :keyword_of, 1, 'atom() | tuple()', '\'Elixir.StreamData\':t([{atom(),_}]) | \#{\'__struct__\':=\'Elixir.StreamData\', \'generator\':=fun((_,_) -> map())}']}}
{:warn_contract_supertype, {'lib/stream_data.ex', 1347}, {:extra_range, [StreamData, :mapset_of, 2, 'atom() | tuple()', '\'Elixir.StreamData\':t(_)']}}
{:warn_contract_supertype, {'lib/stream_data.ex', 1369}, {:extra_range, [StreamData, :nonempty, 1, 'atom() | tuple()', '\'Elixir.StreamData\':t(_)']}}
{:warn_contract_supertype, {'lib/stream_data.ex', 1417}, {:extra_range, [StreamData, :tree, 2, 'atom() | tuple()', '\'Elixir.StreamData\':t(_) | \#{\'__struct__\':=\'Elixir.StreamData\', \'generator\':=fun((_,_) -> map())}']}}
{:warn_contract_supertype, {'lib/stream_data.ex', 1465}, {:extra_range, [StreamData, :boolean, 0, 'atom() | tuple()', '\'Elixir.StreamData\':t(boolean()) | \#{\'__struct__\':=\'Elixir.StreamData\', \'generator\':=fun((_,_) -> map())}']}}
{:warn_contract_supertype, {'lib/stream_data.ex', 1487}, {:extra_range, [StreamData, :integer, 0, 'atom() | tuple()', '\'Elixir.StreamData\':t(integer()) | \#{\'__struct__\':=\'Elixir.StreamData\', \'generator\':=fun((_,_) -> map())}']}}
{:warn_contract_supertype, {'lib/stream_data.ex', 1507}, {:extra_range, [StreamData, :positive_integer, 0, 'atom() | tuple()', '\'Elixir.StreamData\':t(pos_integer()) | \#{\'__struct__\':=\'Elixir.StreamData\', \'generator\':=fun((_,_) -> map())}']}}
{:warn_contract_supertype, {'lib/stream_data.ex', 1536}, {:extra_range, [StreamData, :float, 1, 'atom() | tuple()', '\'Elixir.StreamData\':t(_)']}}
{:warn_contract_supertype, {'lib/stream_data.ex', 1612}, {:extra_range, [StreamData, :byte, 0, 'atom() | tuple()', '\'Elixir.StreamData\':t(integer()) | \'Elixir.StreamData\':t(byte())']}}
{:warn_contract_supertype, {'lib/stream_data.ex', 1645}, {:extra_range, [StreamData, :binary, 1, 'atom() | tuple()', '\'Elixir.StreamData\':t(_)']}}
{:warn_contract_supertype, {'lib/stream_data.ex', 1679}, {:extra_range, [StreamData, :bitstring, 1, 'atom() | tuple()', '\'Elixir.StreamData\':t(_)']}}
{:warn_contract_supertype, {'lib/stream_data.ex', 1745}, {:extra_range, [StreamData, :string, 1, 'atom() | tuple()', '\'Elixir.StreamData\':t(_)']}}
{:warn_contract_supertype, {'lib/stream_data.ex', 1873}, {:extra_range, [StreamData, :iolist, 0, 'atom() | tuple()', '\'Elixir.StreamData\':t(_)']}}
{:warn_contract_supertype, {'lib/stream_data.ex', 1898}, {:extra_range, [StreamData, :iodata, 0, 'atom() | tuple()', '\'Elixir.StreamData\':t(_)']}}
{:warn_contract_supertype, {'lib/stream_data.ex', 1936}, {:extra_range, [StreamData, :term, 0, 'atom() | tuple()', '\'Elixir.StreamData\':t(_)']}}
done (warnings were emitted)
asummers commented 5 years ago

Hmmmmm. Seems like it's choking at the Dialyzer call in that stacktrace? But it gives you a warning back in raw? That's really strange to me.

asummers commented 5 years ago

I actually can't reproduce this. What version of Elixir/Erlang are you running?

Running mix dialyzer on that branch yields

lib/ex_unit_properties.ex:605:invalid_contract
The @spec for the function does not match the success typing of the function.

Function:
ExUnitProperties.pick/1

Success typing:
@spec pick(atom() | tuple() | %StreamData{:generator => (_, _ -> any()), _ => _}) :: any()
________________________________________________________________________________
lib/stream_data.ex:252:extra_range
Type specification has too many types.

Function:
StreamData.constant/1

Extra type:
atom() | tuple()

Success typing:
StreamData.t(_) | %StreamData{:generator => (_, _ -> map())}
________________________________________________________________________________
lib/stream_data.ex:278:extra_range
Type specification has too many types.

Function:
StreamData.map/2

Extra type:
atom() | tuple()

Success typing:
StreamData.t(_) | %StreamData{:generator => (_, _ -> map())}
________________________________________________________________________________
lib/stream_data.ex:338:extra_range
Type specification has too many types.

Function:
StreamData.bind_filter/3

Extra type:
atom() | tuple()

Success typing:
StreamData.t(_) | %StreamData{:generator => (_, _ -> map())}
________________________________________________________________________________
lib/stream_data.ex:344:call
The function call will not succeed.

StreamData.bind_filter(_data :: any(), (_, _ -> any()), _max_consecutive_failures :: any())

breaks the contract
(t(97), (97 -> {:cont, t(98)} | :skip), non_neg_integer()) :: t(98)
when a: term(), b: term()
________________________________________________________________________________
lib/stream_data.ex:428:extra_range
Type specification has too many types.

Function:
StreamData.bind/2

Extra type:
atom() | tuple()

Success typing:
StreamData.t(_)
________________________________________________________________________________
lib/stream_data.ex:478:extra_range
Type specification has too many types.

Function:
StreamData.filter/3

Extra type:
atom() | tuple()

Success typing:
StreamData.t(_)
________________________________________________________________________________
lib/stream_data.ex:507:extra_range
Type specification has too many types.

Function:
StreamData.integer/1

Extra type:
atom() | tuple()

Success typing:
StreamData.t(integer()) | %StreamData{:generator => (_, _ -> map())}
________________________________________________________________________________
lib/stream_data.ex:562:extra_range
Type specification has too many types.

Function:
StreamData.resize/2

Extra type:
atom() | tuple()

Success typing:
StreamData.t(_) | %StreamData{:generator => (_, _ -> map())}
________________________________________________________________________________
lib/stream_data.ex:589:extra_range
Type specification has too many types.

Function:
StreamData.sized/1

Extra type:
atom() | tuple()

Success typing:
StreamData.t(_) | %StreamData{:generator => (_, _ -> map())}
________________________________________________________________________________
lib/stream_data.ex:630:extra_range
Type specification has too many types.

Function:
StreamData.scale/2

Extra type:
atom() | tuple()

Success typing:
StreamData.t(_) | %StreamData{:generator => (_, _ -> map())}
________________________________________________________________________________
lib/stream_data.ex:656:extra_range
Type specification has too many types.

Function:
StreamData.unshrinkable/1

Extra type:
atom() | tuple()

Success typing:
StreamData.t(_) | %StreamData{:generator => (_, _ -> map())}
________________________________________________________________________________
lib/stream_data.ex:683:extra_range
Type specification has too many types.

Function:
StreamData.seeded/2

Extra type:
atom() | tuple()

Success typing:
StreamData.t(_) | %StreamData{:generator => (_, _ -> map())}
________________________________________________________________________________
lib/stream_data.ex:737:extra_range
Type specification has too many types.

Function:
StreamData.frequency/1

Extra type:
atom() | tuple()

Success typing:
StreamData.t(_)
________________________________________________________________________________
lib/stream_data.ex:769:extra_range
Type specification has too many types.

Function:
StreamData.one_of/1

Extra type:
atom() | tuple()

Success typing:
StreamData.t(_)
________________________________________________________________________________
lib/stream_data.ex:791:extra_range
Type specification has too many types.

Function:
StreamData.member_of/1

Extra type:
atom() | tuple()

Success typing:
StreamData.t(_)
________________________________________________________________________________
lib/stream_data.ex:855:extra_range
Type specification has too many types.

Function:
StreamData.list_of/2

Extra type:
atom() | tuple()

Success typing:
StreamData.t([any()]) | %StreamData{:generator => (_, _ -> map())}
________________________________________________________________________________
lib/stream_data.ex:995:extra_range
Type specification has too many types.

Function:
StreamData.uniq_list_of/2

Extra type:
atom() | tuple()

Success typing:
StreamData.t([any()]) | %StreamData{:generator => (_, _ -> map())}
________________________________________________________________________________
lib/stream_data.ex:1094:extra_range
Type specification has too many types.

Function:
StreamData.nonempty_improper_list_of/2

Extra type:
atom() | tuple()

Success typing:
StreamData.t(_)
________________________________________________________________________________
lib/stream_data.ex:1125:extra_range
Type specification has too many types.

Function:
StreamData.maybe_improper_list_of/2

Extra type:
atom() | tuple()

Success typing:
StreamData.t(_)
________________________________________________________________________________
lib/stream_data.ex:1150:extra_range
Type specification has too many types.

Function:
StreamData.fixed_list/1

Extra type:
atom() | tuple()

Success typing:
StreamData.t([any()]) | %StreamData{:generator => (_, _ -> map())}
________________________________________________________________________________
lib/stream_data.ex:1178:extra_range
Type specification has too many types.

Function:
StreamData.tuple/1

Extra type:
atom() | tuple()

Success typing:
StreamData.t(tuple()) | %StreamData{:generator => (_, _ -> map())}
________________________________________________________________________________
lib/stream_data.ex:1208:extra_range
Type specification has too many types.

Function:
StreamData.map_of/3

Extra type:
atom() | tuple()

Success typing:
StreamData.t(_)
________________________________________________________________________________
lib/stream_data.ex:1241:extra_range
Type specification has too many types.

Function:
StreamData.fixed_map/1

Extra type:
atom() | tuple()

Success typing:
StreamData.t(_)
________________________________________________________________________________
lib/stream_data.ex:1274:extra_range
Type specification has too many types.

Function:
StreamData.optional_map/1

Extra type:
atom() | tuple()

Success typing:
StreamData.t(map()) | %StreamData{:generator => (_, _ -> map())}
________________________________________________________________________________
lib/stream_data.ex:1322:extra_range
Type specification has too many types.

Function:
StreamData.keyword_of/1

Extra type:
atom() | tuple()

Success typing:
StreamData.t(Keyword.t()) | %StreamData{:generator => (_, _ -> map())}
________________________________________________________________________________
lib/stream_data.ex:1347:extra_range
Type specification has too many types.

Function:
StreamData.mapset_of/2

Extra type:
atom() | tuple()

Success typing:
StreamData.t(_)
________________________________________________________________________________
lib/stream_data.ex:1369:extra_range
Type specification has too many types.

Function:
StreamData.nonempty/1

Extra type:
atom() | tuple()

Success typing:
StreamData.t(_)
________________________________________________________________________________
lib/stream_data.ex:1417:extra_range
Type specification has too many types.

Function:
StreamData.tree/2

Extra type:
atom() | tuple()

Success typing:
StreamData.t(_) | %StreamData{:generator => (_, _ -> map())}
________________________________________________________________________________
lib/stream_data.ex:1465:extra_range
Type specification has too many types.

Function:
StreamData.boolean/0

Extra type:
atom() | tuple()

Success typing:
StreamData.t(boolean()) | %StreamData{:generator => (_, _ -> map())}
________________________________________________________________________________
lib/stream_data.ex:1487:extra_range
Type specification has too many types.

Function:
StreamData.integer/0

Extra type:
atom() | tuple()

Success typing:
StreamData.t(integer()) | %StreamData{:generator => (_, _ -> map())}
________________________________________________________________________________
lib/stream_data.ex:1507:extra_range
Type specification has too many types.

Function:
StreamData.positive_integer/0

Extra type:
atom() | tuple()

Success typing:
StreamData.t(pos_integer()) | %StreamData{:generator => (_, _ -> map())}
________________________________________________________________________________
lib/stream_data.ex:1536:extra_range
Type specification has too many types.

Function:
StreamData.float/1

Extra type:
atom() | tuple()

Success typing:
StreamData.t(_)
________________________________________________________________________________
lib/stream_data.ex:1612:extra_range
Type specification has too many types.

Function:
StreamData.byte/0

Extra type:
atom() | tuple()

Success typing:
StreamData.t(integer()) | StreamData.t(byte())
________________________________________________________________________________
lib/stream_data.ex:1645:extra_range
Type specification has too many types.

Function:
StreamData.binary/1

Extra type:
atom() | tuple()

Success typing:
StreamData.t(_)
________________________________________________________________________________
lib/stream_data.ex:1679:extra_range
Type specification has too many types.

Function:
StreamData.bitstring/1

Extra type:
atom() | tuple()

Success typing:
StreamData.t(_)
________________________________________________________________________________
lib/stream_data.ex:1745:extra_range
Type specification has too many types.

Function:
StreamData.string/1

Extra type:
atom() | tuple()

Success typing:
StreamData.t(_)
________________________________________________________________________________
lib/stream_data.ex:1873:extra_range
Type specification has too many types.

Function:
StreamData.iolist/0

Extra type:
atom() | tuple()

Success typing:
StreamData.t(_)
________________________________________________________________________________
lib/stream_data.ex:1898:extra_range
Type specification has too many types.

Function:
StreamData.iodata/0

Extra type:
atom() | tuple()

Success typing:
StreamData.t(_)
________________________________________________________________________________
lib/stream_data.ex:1936:extra_range
Type specification has too many types.

Function:
StreamData.term/0

Extra type:
atom() | tuple()

Success typing:
StreamData.t(_)
________________________________________________________________________________
done (warnings were emitted)
rodrigues commented 5 years ago

@asummers did you do that with elixir 1.9, otp 22?

Just tried again, mix dialyzer fails like that, and mix dialyzer --format raw works 🤔

skwerlman commented 5 years ago

also hitting this on arch linux: OTP 22, erts 10.4.1, elixir 1.8.2

asummers commented 5 years ago

Seems like an OTP 22 thing then. Will investigate. Works perfectly on 21 for me.

asummers commented 5 years ago

Seems like it's unhappy with this spec:

  @spec bind_filter(t(a), (a -> {:cont, t(b)} | :skip), non_neg_integer()) :: t(b)
        when a: term(),
             b: term()

If the a and b are changed to term() in the spec, it's happy, but still trying to investigate root cause.

asummers commented 5 years ago

This is seemingly fixed in Erlang master. Once they drop a new patch release this should be fixed for you. Nothing I can do on my end for it. I believe it was fixed by this commit:

https://github.com/erlang/otp/commit/dd9a4d6f559cac28fd74dac0ff62d27bfed66e64

rodrigues commented 5 years ago

Yes, just tested now with otp 22.0.5 and it works 👍🏼