Warning of contract with dialyzer

Environment

  • Elixir & Erlang/OTP versions : elixir --1.8

  • Which version of Dialyxir are you using? 1.0.0-rc.6

Current behavior

When i run this code -

def withdraw(account_id, value) when is_binary(account_id) and is_binary(value) do
    with {:ok, _} <- AccountState.account_exist(account_id),
         {:ok, value_in_integer} <-
           Currency.amount_do(:store, value, AccountState.show(account_id).currency),
         {:ok, _} <- FinHelper.funds(account_id, value_in_integer) do
      {:ok,
       AccountState.withdraw(
         account_id,
         value_in_integer
       )}
    end
  end

this is the stacktrace

lib/financial_system/financial_operations.ex:83:call
The function call will not succeed.

FinancialSystem.AccountState.withdraw(_account_id :: binary(), _value_in_integer :: binary())

will never return since the success typing is:
(binary(), pos_integer()) ::
  atom()
  | %FinancialSystem.Account{
      :account_id => integer(),
      :currency => binary(),
      :name => binary(),
      :value => binary()
    }

and the contract is
(String.t(), pos_integer()) :: FinancialSystem.Account.t() | no_return()
________________________________________________________________________________
lib/financial_system/financial_operations.ex:113:pattern_match
The pattern can never match the type.

Pattern:
{:ok, _withdraw_result}

Type:

  {:error,
   :account_dont_exist
   | :currency_is_not_valid
   | :do_not_have_funds
   | :invalid_account_id_type
   | :invalid_arguments_type
   | :invalid_currency_type
   | :invalid_operation_type
   | :invalid_value_less_than_0
   | :invalid_value_type}

Expected behavior

When i use the function Currency.amount_do out of the with statement, the dialyzer dont show warnings:

  def withdraw(account_id, value) when is_binary(account_id) and is_binary(value) do
    with {:ok, _} <- AccountState.account_exist(account_id),
         {:ok, value_in_integer} <-
           Currency.amount_do(:store, value, AccountState.show(account_id).currency),
         {:ok, _} <- FinHelper.funds(account_id, value_in_integer) do
{:ok, test} =  Currency.amount_do (:store, value, AccountState.show(account_id).currency)
      {:ok,
       AccountState.withdraw(
         account_id,
         test
       )}
    end
  end

This is like if the variable value_in_integer is not a integer but a String.

If you can/want test the code, he is here: git@github.com:yashin5/financial_system.git
This function is in lib/financial_system/financial_operations.ex:77 .

the code is with unit tests and are working.

Thank you guys :slight_smile:

Just as a test, can you convert your with to a set of nested cases? I know that with plays a little odd with dialyzer at times and just want to make sure that it’s not the issue.

1 Like

Resolved, I find that has a invalid spec that as injeting a invalid type. Thank you all :slight_smile:

2 Likes