Why does removing this default argument get rid of the dialyzer error?

If I have a function defined as:

defmodule Test
  def win(scene \\ %{}, args \\ %{}) do
     # some stuff
    Map.put(%{a: 1}, :body, :2) #return a map with some keys/values

And then I run dialyzer, I get:

The call:
Test.win(%{}, %{})

will never return since it differs in arguments with
positions 1st from the success typing arguments:

(%{:win_body => _, _ => _}, map())

Changing the function to the below by removing the default map arg for the scene variable results in no dialyzer issue anymore. Why is this?

  def win(scene, args \\ %{}) do
     # some stuff

It’s baffling because there are no typespecs referenced anywhere in this module. There are no typespecs associated with any of the function code inside win.

When I do call these functions in the test code, I do pass a map to “scene” that is populated with keys and values. My guess is that dialyzer infers that it’s a non-empty map and that’s why it’s complaining even though there are no specified typespecs.

You must show # some stuff. I think somewhere there you access :win_body key from scene.


Oh thanks @sztosz, that is the case. I do something like scene.win_body inside of win, so then it seems you’re saying dialyzer automatically “infers” this since there’s no typespec describing the passing of the key win_body via the scene map?


Dialyzer deduces that your default argument %{} will result in a crash when you try to access its key :win_body. That is why the success typing has the key mentioned.