title: Dialyzer emits Type specification is a subtype of the success typing for multiple functions with same name
body: <p>I have the following two functions and I am receiving this dialyzer warning on them: </p>
  
  <pre><code>"Type specification 'Elixir.MyModule':calculate(arg1::'Elixir.String':t(),arg2::'Elixir.CustomType':t(),arg3::'Elixir.String':t()) -&gt; 'ok' | 'error'; calculate(arg1::'Elixir.String':t(),arg2::'Elixir.CustomType':t(),arg3::maybe_improper_list()) -&gt; 'ok' | 'error' is a subtype of the success typing: 'Elixir.MyModule':calculate(binary(),#{'__struct__':='Elixir.CustomType', _=&gt;_},binary() | maybe_improper_list()) -&gt; 'error' | 'ok'"
  </code></pre>
  
  <p>Here are the functions:</p>
  
  <pre><code>@spec calculate(arg1 :: String.t, arg2 :: CustomType.t, arg3 :: String.t)
  def calculate(arg1, %CustomType{} = arg2, arg3) when is_binary(arg1) and is_binary(arg3) do
    calculate(arg1, arg2, [arg3])
  end
  
  @spec calculate(arg1 :: String.t, arg2 :: CustomType.t, arg3 :: maybe_improper_list())
  def calculate(arg1, %CustomType{prop1: val, prop2: val2}, arg3) when is_binary(arg1) and is_integer(val2) and is_binary(val) and is_list(arg3) do
  ...
  end
  </code></pre>
  
  <p>I don't understand why I am getting this warning. I thought this is the correct way to write functions with different argument types in Elixir but given Dialyzer keeps emitting warnings, I am beginning to wonder if I am writing this code incorrectly?</p>
  
  <hr>
  
  <pre><code>defmodule CustomType do
    @type t :: %CustomType{
      prop1: String.t(),
      prop2: integer(),
      prop3: String.t(),
      prop4: boolean(),
      ...
    }
  end
  </code></pre>
  
  <hr>
  
  <p>These are the dialyzer flags I am running with:</p>
  
  <pre><code>dialyzer: [
    flags: ~w[underspecs overspecs race_conditions error_handling unmatched_returns]a
  ]
  </code></pre>
  
  <hr>
  
  <p>Repro Sample:</p>
  
  <pre><code>defmodule MyCustomType do
      @type t :: %MyCustomType{
          prop1: String.t(),
          prop2: integer(),
          prop3: String.t()
      }
  
      defstruct [:prop1, :prop2, :prop3]
  end
  
  defmodule MyModule do
      @spec calculate(String.t, 
                      MyCustomType.t, 
                      String.t) 
      :: :ok
      def calculate(arg1, %MyCustomType{} = arg2, arg3) when is_binary(arg1) and is_binary(arg3) do
          calculate(arg1, arg2, [arg3])
      end
  
      @spec calculate(String.t, 
                      MyCustomType.t, 
                      maybe_improper_list) 
      :: :ok
      def calculate(arg1, %MyCustomType{prop1: val, prop2: val2}, arg3) when is_binary(arg1) and is_list(arg3) and is_binary(val) and is_integer(val2) do
          :ok
      end
  end
  </code></pre>
  
  <p>Here are the warnings I am getting:</p>
  
  <pre><code>      Type specification 'Elixir.MyModule':calculate
            ('Elixir.String':t(),
            'Elixir.MyCustomType':t(),
            'Elixir.String':t()) -&gt;
               'ok';
           ('Elixir.String':t(),
            'Elixir.MyCustomType':t(),
            maybe_improper_list()) -&gt;
               'ok' is a subtype of the success typing: 'Elixir.MyModule':calculate
            (binary(),
            #{'__struct__' := 'Elixir.MyCustomType',
              'prop1' := binary(),
              'prop2' := integer(),
              _ =&gt; _},
            binary() | maybe_improper_list()) -&gt;
               'ok'
  </code></pre>