New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Help! Why doesn't dialyzer like this spec? :( #159

Merged
merged 2 commits into from Oct 29, 2017

Conversation

Projects
None yet
1 participant
@PragTob
Owner

PragTob commented Oct 29, 2017

The following line was originally in #153 and we dropped the type spec cause we couldn't get it to work. It would fail on all Erlang versions that aren't 18.3.

Basically it is the following (the only place where the offending function is called):

  @spec extended_statistics([Scenario.t], unit_per_statistic, integer)
    :: [String.t]
  defp extended_statistics(scenarios, units, label_width) do
    Enum.map(scenarios, fn(scenario) ->
      format_scenario_extended(scenario, units, label_width)
    end)
  end
  
  # problem seems to be Scenario.t, pattern match on Scenario omitted for brevity
  @spec format_scenario_extended(Scenario.t, unit_per_statistic, integer)
    :: String.t
  defp format_scenario_extended(%Scenario{}, %{run_time: run_time_unit}, label_width) do
    "~*s~*ts~*ts~*ts~*ts\n"
    |> :io_lib.format([lots_of_options])
    |> to_string
  end

We get the following error:

lib/benchee/formatters/console.ex:173: Invalid type specification for function 'Elixir.Benchee.Formatters.Console':format_scenario_extended/3. The success typing is (#{'__struct__':='Elixir.Benchee.Benchmark.Scenario', 'job_name':=_, 'run_time_statistics':=#{'__struct__':='Elixir.Benchee.Statistics', 'maximum':=number(), 'minimum':=number(), 'mode':=[number()], 'sample_size':=_, _=>_}, _=>_},#{'ips':=#{'__struct__':='Elixir.Benchee.Conversion.Unit', 'label':=binary(), 'long':=binary(), 'magnitude':=non_neg_integer(), 'name':=atom()}, 'run_time':=#{'__struct__':='Elixir.Benchee.Conversion.Unit', 'label':=binary(), 'long':=binary(), 'magnitude':=non_neg_integer(), 'name':=atom()}},integer()) -> binary(

The problem seems to be with dialyzers interpretation what Scenario.t is. If it is exchanged against any or map dialyzer instead complains about underspecs:

lib/benchee/formatters/console.ex:173: Type specification 'Elixir.Benchee.Formatters.Console':format_scenario_extended(map(),unit_per_statistic(),integer()) -> 'Elixir.String':t() is a supertype of the success typing: 'Elixir.Benchee.Formatters.Console':format_scenario_extended(#{'__struct__':='Elixir.Benchee.Benchmark.Scenario', 'job_name':=_, 'run_time_statistics':=#{'__struct__':='Elixir.Benchee.Statistics', 'maximum':=number(), 'minimum':=number(), 'mode':=[number()], 'sample_size':=_, _=>_}, _=>_},#{'ips':=#{'__struct__':='Elixir.Benchee.Conversion.Unit', 'label':=binary(), 'long':=binary(), 'magnitude':=non_neg_integer(), 'name':=atom()}, 'run_time':=#{'__struct__':='Elixir.Benchee.Conversion.Unit', 'label':=binary(), 'long':=binary(), 'magnitude':=non_neg_integer(), 'name':=atom()}},integer()) -> binary()

One of the weirdest things about this is that we have virtually the same structure elsewhere in the same file and it works just fine:

  @spec scenario_reports([Scenario.t], unit_per_statistic, integer)
    :: [String.t]
  defp scenario_reports(scenarios, units, label_width) do
    Enum.map(scenarios, fn(scenario) ->
      format_scenario(scenario, units, label_width)
    end)
  end

  # pattern match on scenario omitted for brevity
  @spec format_scenario(Scenario.t, unit_per_statistic, integer) :: String.t
  defp format_scenario(%Scenario{},
                       %{run_time: run_time_unit,
                         ips:      ips_unit,
                       }, label_width) do
    "~*s~*ts~*ts~*ts~*ts~*ts\n"
    |> :io_lib.format([options])
    |> to_string
  end

So umm help - help is rewarded with gratefulness and cute bunny pictures. Bonus points if you can lay out how to debug something like this :)

img_20171028_173235

@PragTob

This comment has been minimized.

Owner

PragTob commented Oct 29, 2017

@PragTob PragTob merged commit f6d7fff into master Oct 29, 2017

3 checks passed

continuous-integration/travis-ci/pr The Travis CI build passed
Details
continuous-integration/travis-ci/push The Travis CI build passed
Details
coverage/coveralls Coverage remained the same at 94.344%
Details

@PragTob PragTob deleted the dialyzer-weirdness branch Oct 29, 2017

@PragTob

This comment has been minimized.

Owner

PragTob commented Oct 29, 2017

🎉

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment