«Диализатор обычно никогда не ошибается», но я не могу понять, как мой @spec неверен - PullRequest
0 голосов
/ 14 ноября 2018

У меня есть код, который не работает на диализаторе, и я не могу понять, почему. Независимо от того, что я положил в @spec в верхней части функции, вызовы этой функции возвращают загадочную ошибку диализатора. Вот упрощение функции. Насколько я могу судить, я правильно определил функцию.

@spec balances(uuid :: String.t(), retries :: non_neg_integer) ::
        {:ok, list()}
        | {:internal_server_error, String.t(), String.t()}
        | {:internal_server_error, map | list, String.t()}
def balances(uuid, retries \\ 0) do
  url = "/url/for/balances" |> process_url

  case HTTPoison.get(
         url,
         [, {"Content-Type", "application/json"}],
         []
       ) do
    {:ok, %HTTPoison.Response{status_code: 200, body: body}} ->
      response = Poison.decode!(body, as: %{"message" => [%Currency{}]})

      cond response["message"] do
        length(bal) > 0 ->
          {:ok, bal}

        retries >= 1 ->
          {:ok, []}

        true ->
          init(uuid)
          balances(uuid, retries + 1)
      end

    {:error, %HTTPoison.Error{reason: reason}} ->
      Notifier.notify(url, reason, Helpers.line_info(__ENV__))
      {:internal_server_error, reason, url}

    {_, %HTTPoison.Response{body: body} = res} ->
      response = Poison.decode!(body)
      Notifier.notify(url, response, Helpers.line_info(__ENV__))

      {:internal_server_error, response, url}
  end
end

Моя проблема заключается в том, что каждый вызов через кодовую базу этой функции не выполняется, если я ожидаю получить что-либо кроме {:ok, balances}:

  user_balances =
    case balances(uuid) do
      {:ok, user_balances} -> user_balances
      _ -> [] # Dialyzer error here
    end

Диализатор предупреждает, что The variable _ can never match since previous clauses completely covered the type {'ok',[map()]}. Я прочитал это, чтобы означать, что любой вызов весов всегда будет возвращать {:ok, balances}, но это не может быть правдой, так как оператор case для HTTPoison.get - это последнее, что оценивается в функции, и, похоже, он имеет только три возможных результата :

  • {:ok, list}
  • {:internal_server_error, String.t(), String.t()}
  • {:internal_server_error, map | list, String.t()}.

Я понимаю, что, скорее всего, мне не хватает чего-то очень очевидного, но я не могу понять, что это такое. Любая помощь будет принята с благодарностью. Спасибо!

1 Ответ

0 голосов
/ 14 ноября 2018

Благодаря комментарию @ legoscia я исследовал вызов Notifier.notify, и, конечно же, в этой функции также есть предупреждение о диализаторе (у меня есть PR для проекта с открытым исходным кодом, чтобы исправить спецификацию, которая вызывает уведомлениефункция сбоя диализатора).Если я изменю функцию уведомления таким образом, чтобы предупреждение не появлялось, достаточно, чтобы вызовы balances больше не выдавали предупреждения диализатора.

tl; dr Если диализатор выдает предупреждение о функции, которая не отображаетсябыть неправильно заданным, начните выполнять вызовы функций в вашей функции, чтобы найти ошибку нижестоящего диализатора.

...