Type and spec - Dialyzer not detecting error

defmodule Lima do

  @type unit_quantity_t :: 0..1000
  @type unit_quantity_error :: {:error, String.t()}
  @type unit_quantity_success :: {:ok, unit_quantity_t()}
  @type unit_quantity_result :: unit_quantity_success() | unit_quantity_error()

  @spec create_unit_quantity_error(s) :: r when s: String.t, r: unit_quantity_error()
  defp create_unit_quantity_error(msg),
    do: {:error, msg}
  @spec create_unit_quantity_success(n) :: r when n: unit_quantity_t(), r: unit_quantity_success()
  defp create_unit_quantity_success(qty),
    do: {:okidoki, qty}

 @spec create_unit_quantity(n) :: r when n: integer(), r: unit_quantity_result()
 def create_unit_quantity(qty) when is_integer(qty) do
   cond do
     qty < 0     ->
       create_unit_quantity_error("unit_quantity can not be negative")
     qty > 1_000 ->
       create_unit_quantity_error("unit_quantity can not be more than 1000")
     true        ->
       create_unit_quantity_success(qty)
    end
  end

end

.

$ mix dialyzer
...
Compiling 1 file (.ex)
Checking PLT...
[:compiler, :elixir, :kernel, :logger, :stdlib]
PLT is up to date!
Starting Dialyzer
dialyzer args: [check_plt: false,
 init_plt: '/Users/wheatley/sbox/elx/trial/lima/_build/dev/dialyxir_erlang-19.3_elixir-1.4.4_deps-dev.plt',
 files_rec: ['/Users/wheatley/sbox/elx/trial/lima/_build/dev/lib/lima/ebin'],
 warnings: [:unknown]]
done in 0m1.34s
lib/lima.ex:11: Invalid type specification for function 'Elixir.Lima':create_unit_quantity_success/1. The success typing is (integer()) -> {'okidoki',integer()}
done (warnings were emitted)
$

Alternately

defmodule Lima do

  @type result_error_t :: {:error, String.t()}
  @type result_success_t(t) :: {:ok, t}
  @type result_t(t) :: result_success_t(t) | result_error_t()

  @type unit_quantity_t :: 0..1000

  @spec unit_quantity_error(s) :: r when s: String.t, r: result_error_t()
  defp unit_quantity_error(msg),
    do: {:error, msg}

  @spec unit_quantity_success(v) :: r when v: unit_quantity_t(), r: result_success_t(unit_quantity_t())
  defp unit_quantity_success(qty),
    do: {:ok, qty}

  @spec create_unit_quantity(n) :: r when n: integer(), r: result_t(unit_quantity_t())
  def create_unit_quantity(qty) when is_integer(qty) do
    cond do
      qty < 0     ->
        unit_quantity_error("unit_quantity can not be negative")
      qty > 1_000 ->
        unit_quantity_error("unit_quantity can not be more than 1000")
      true        ->
        unit_quantity_success(qty)
    end
  end

end
4 Likes