“Dialyzer is usually never wrong”, but I can't figure out how my @spec is incorrect
I have some code that is failing dialyzer and I cannot understand why. No matter what I put into the @spec at the top of the function, calls to that function return a puzzling dialyzer error. Here is a simplification of the function. As far as I can tell, I have spec'd the function correctly.
@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 fakebal(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
My issue is that every call across the codebase to this function is failing if I expect to get anything other than {:ok, balances}:
user_balances =
case balances(uuid) do
{:ok, user_balances} -> user_balances
_ -> # Dialyzer error here
end
Dialyzer warns that The variable _ can never match since previous clauses completely covered the type {'ok',[map()]}. I read this to mean that any call to balances will always return {:ok, balances}, but that can't be true as the case statement for HTTPoison.get is the last thing evaluated in the function, and it appears to have only three possible results:
{:ok, list}{:internal_server_error, String.t(), String.t()}
{:internal_server_error, map | list, String.t()}.
I understand that I am likely missing something very obvious but I can't figure out what it is. Any help would be greatly appreciated. Thank You!
elixir dialyzer
add a comment |
I have some code that is failing dialyzer and I cannot understand why. No matter what I put into the @spec at the top of the function, calls to that function return a puzzling dialyzer error. Here is a simplification of the function. As far as I can tell, I have spec'd the function correctly.
@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 fakebal(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
My issue is that every call across the codebase to this function is failing if I expect to get anything other than {:ok, balances}:
user_balances =
case balances(uuid) do
{:ok, user_balances} -> user_balances
_ -> # Dialyzer error here
end
Dialyzer warns that The variable _ can never match since previous clauses completely covered the type {'ok',[map()]}. I read this to mean that any call to balances will always return {:ok, balances}, but that can't be true as the case statement for HTTPoison.get is the last thing evaluated in the function, and it appears to have only three possible results:
{:ok, list}{:internal_server_error, String.t(), String.t()}
{:internal_server_error, map | list, String.t()}.
I understand that I am likely missing something very obvious but I can't figure out what it is. Any help would be greatly appreciated. Thank You!
elixir dialyzer
1
Do you get the same Dialyzer error if you comment out the calls toNotifier.notify?
– legoscia
Nov 14 '18 at 14:32
@legoscia oddly no I don't. If I go and check that error there's a dialyzer error in that function as well (which I have a PR out for an open source library to fix). So is that the issue? Dialyzer can't analyze the other 2 paths, thus the{:ok, balances}branch is the only one it's aware of?
– localshred
Nov 14 '18 at 15:01
1
Exactly. Since Dialyzer thinks thatNotifier.notifyalways crashes, it concludes that your function can never actually return:internal_server_error.
– legoscia
Nov 14 '18 at 15:23
add a comment |
I have some code that is failing dialyzer and I cannot understand why. No matter what I put into the @spec at the top of the function, calls to that function return a puzzling dialyzer error. Here is a simplification of the function. As far as I can tell, I have spec'd the function correctly.
@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 fakebal(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
My issue is that every call across the codebase to this function is failing if I expect to get anything other than {:ok, balances}:
user_balances =
case balances(uuid) do
{:ok, user_balances} -> user_balances
_ -> # Dialyzer error here
end
Dialyzer warns that The variable _ can never match since previous clauses completely covered the type {'ok',[map()]}. I read this to mean that any call to balances will always return {:ok, balances}, but that can't be true as the case statement for HTTPoison.get is the last thing evaluated in the function, and it appears to have only three possible results:
{:ok, list}{:internal_server_error, String.t(), String.t()}
{:internal_server_error, map | list, String.t()}.
I understand that I am likely missing something very obvious but I can't figure out what it is. Any help would be greatly appreciated. Thank You!
elixir dialyzer
I have some code that is failing dialyzer and I cannot understand why. No matter what I put into the @spec at the top of the function, calls to that function return a puzzling dialyzer error. Here is a simplification of the function. As far as I can tell, I have spec'd the function correctly.
@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 fakebal(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
My issue is that every call across the codebase to this function is failing if I expect to get anything other than {:ok, balances}:
user_balances =
case balances(uuid) do
{:ok, user_balances} -> user_balances
_ -> # Dialyzer error here
end
Dialyzer warns that The variable _ can never match since previous clauses completely covered the type {'ok',[map()]}. I read this to mean that any call to balances will always return {:ok, balances}, but that can't be true as the case statement for HTTPoison.get is the last thing evaluated in the function, and it appears to have only three possible results:
{:ok, list}{:internal_server_error, String.t(), String.t()}
{:internal_server_error, map | list, String.t()}.
I understand that I am likely missing something very obvious but I can't figure out what it is. Any help would be greatly appreciated. Thank You!
elixir dialyzer
elixir dialyzer
edited Nov 15 '18 at 12:49
Justin Wood
7,08822037
7,08822037
asked Nov 14 '18 at 14:24
localshredlocalshred
1,89111529
1,89111529
1
Do you get the same Dialyzer error if you comment out the calls toNotifier.notify?
– legoscia
Nov 14 '18 at 14:32
@legoscia oddly no I don't. If I go and check that error there's a dialyzer error in that function as well (which I have a PR out for an open source library to fix). So is that the issue? Dialyzer can't analyze the other 2 paths, thus the{:ok, balances}branch is the only one it's aware of?
– localshred
Nov 14 '18 at 15:01
1
Exactly. Since Dialyzer thinks thatNotifier.notifyalways crashes, it concludes that your function can never actually return:internal_server_error.
– legoscia
Nov 14 '18 at 15:23
add a comment |
1
Do you get the same Dialyzer error if you comment out the calls toNotifier.notify?
– legoscia
Nov 14 '18 at 14:32
@legoscia oddly no I don't. If I go and check that error there's a dialyzer error in that function as well (which I have a PR out for an open source library to fix). So is that the issue? Dialyzer can't analyze the other 2 paths, thus the{:ok, balances}branch is the only one it's aware of?
– localshred
Nov 14 '18 at 15:01
1
Exactly. Since Dialyzer thinks thatNotifier.notifyalways crashes, it concludes that your function can never actually return:internal_server_error.
– legoscia
Nov 14 '18 at 15:23
1
1
Do you get the same Dialyzer error if you comment out the calls to
Notifier.notify?– legoscia
Nov 14 '18 at 14:32
Do you get the same Dialyzer error if you comment out the calls to
Notifier.notify?– legoscia
Nov 14 '18 at 14:32
@legoscia oddly no I don't. If I go and check that error there's a dialyzer error in that function as well (which I have a PR out for an open source library to fix). So is that the issue? Dialyzer can't analyze the other 2 paths, thus the
{:ok, balances} branch is the only one it's aware of?– localshred
Nov 14 '18 at 15:01
@legoscia oddly no I don't. If I go and check that error there's a dialyzer error in that function as well (which I have a PR out for an open source library to fix). So is that the issue? Dialyzer can't analyze the other 2 paths, thus the
{:ok, balances} branch is the only one it's aware of?– localshred
Nov 14 '18 at 15:01
1
1
Exactly. Since Dialyzer thinks that
Notifier.notify always crashes, it concludes that your function can never actually return :internal_server_error.– legoscia
Nov 14 '18 at 15:23
Exactly. Since Dialyzer thinks that
Notifier.notify always crashes, it concludes that your function can never actually return :internal_server_error.– legoscia
Nov 14 '18 at 15:23
add a comment |
1 Answer
1
active
oldest
votes
Thanks to @legoscia's comment, I investigated the call to Notifier.notify, and sure enough there is a dialyzer warning in that function as well (I have PR out to an open source project to fix the spec that is causing the notify function to fail dialyzer). If I modify the notify function such that no warning occurs, sure enough the calls to balances no longer produce dialyzer warnings.
tl;dr If dialyzer gives you a warning about a function that doesn't appear to be incorrectly specified, start going through the function calls within your function to find a downstream dialyzer error.
Accept your own answer if this solved your problem.
– Paweł Obrok
Nov 14 '18 at 15:44
1
SO won't let me for a few days, I'll do so then.
– localshred
Nov 14 '18 at 16:03
add a comment |
Your Answer
StackExchange.ifUsing("editor", function () {
StackExchange.using("externalEditor", function () {
StackExchange.using("snippets", function () {
StackExchange.snippets.init();
});
});
}, "code-snippets");
StackExchange.ready(function() {
var channelOptions = {
tags: "".split(" "),
id: "1"
};
initTagRenderer("".split(" "), "".split(" "), channelOptions);
StackExchange.using("externalEditor", function() {
// Have to fire editor after snippets, if snippets enabled
if (StackExchange.settings.snippets.snippetsEnabled) {
StackExchange.using("snippets", function() {
createEditor();
});
}
else {
createEditor();
}
});
function createEditor() {
StackExchange.prepareEditor({
heartbeatType: 'answer',
autoActivateHeartbeat: false,
convertImagesToLinks: true,
noModals: true,
showLowRepImageUploadWarning: true,
reputationToPostImages: 10,
bindNavPrevention: true,
postfix: "",
imageUploader: {
brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
allowUrls: true
},
onDemand: true,
discardSelector: ".discard-answer"
,immediatelyShowMarkdownHelp:true
});
}
});
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53302431%2fdialyzer-is-usually-never-wrong-but-i-cant-figure-out-how-my-spec-is-incorr%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
1 Answer
1
active
oldest
votes
1 Answer
1
active
oldest
votes
active
oldest
votes
active
oldest
votes
Thanks to @legoscia's comment, I investigated the call to Notifier.notify, and sure enough there is a dialyzer warning in that function as well (I have PR out to an open source project to fix the spec that is causing the notify function to fail dialyzer). If I modify the notify function such that no warning occurs, sure enough the calls to balances no longer produce dialyzer warnings.
tl;dr If dialyzer gives you a warning about a function that doesn't appear to be incorrectly specified, start going through the function calls within your function to find a downstream dialyzer error.
Accept your own answer if this solved your problem.
– Paweł Obrok
Nov 14 '18 at 15:44
1
SO won't let me for a few days, I'll do so then.
– localshred
Nov 14 '18 at 16:03
add a comment |
Thanks to @legoscia's comment, I investigated the call to Notifier.notify, and sure enough there is a dialyzer warning in that function as well (I have PR out to an open source project to fix the spec that is causing the notify function to fail dialyzer). If I modify the notify function such that no warning occurs, sure enough the calls to balances no longer produce dialyzer warnings.
tl;dr If dialyzer gives you a warning about a function that doesn't appear to be incorrectly specified, start going through the function calls within your function to find a downstream dialyzer error.
Accept your own answer if this solved your problem.
– Paweł Obrok
Nov 14 '18 at 15:44
1
SO won't let me for a few days, I'll do so then.
– localshred
Nov 14 '18 at 16:03
add a comment |
Thanks to @legoscia's comment, I investigated the call to Notifier.notify, and sure enough there is a dialyzer warning in that function as well (I have PR out to an open source project to fix the spec that is causing the notify function to fail dialyzer). If I modify the notify function such that no warning occurs, sure enough the calls to balances no longer produce dialyzer warnings.
tl;dr If dialyzer gives you a warning about a function that doesn't appear to be incorrectly specified, start going through the function calls within your function to find a downstream dialyzer error.
Thanks to @legoscia's comment, I investigated the call to Notifier.notify, and sure enough there is a dialyzer warning in that function as well (I have PR out to an open source project to fix the spec that is causing the notify function to fail dialyzer). If I modify the notify function such that no warning occurs, sure enough the calls to balances no longer produce dialyzer warnings.
tl;dr If dialyzer gives you a warning about a function that doesn't appear to be incorrectly specified, start going through the function calls within your function to find a downstream dialyzer error.
answered Nov 14 '18 at 15:10
localshredlocalshred
1,89111529
1,89111529
Accept your own answer if this solved your problem.
– Paweł Obrok
Nov 14 '18 at 15:44
1
SO won't let me for a few days, I'll do so then.
– localshred
Nov 14 '18 at 16:03
add a comment |
Accept your own answer if this solved your problem.
– Paweł Obrok
Nov 14 '18 at 15:44
1
SO won't let me for a few days, I'll do so then.
– localshred
Nov 14 '18 at 16:03
Accept your own answer if this solved your problem.
– Paweł Obrok
Nov 14 '18 at 15:44
Accept your own answer if this solved your problem.
– Paweł Obrok
Nov 14 '18 at 15:44
1
1
SO won't let me for a few days, I'll do so then.
– localshred
Nov 14 '18 at 16:03
SO won't let me for a few days, I'll do so then.
– localshred
Nov 14 '18 at 16:03
add a comment |
Thanks for contributing an answer to Stack Overflow!
- Please be sure to answer the question. Provide details and share your research!
But avoid …
- Asking for help, clarification, or responding to other answers.
- Making statements based on opinion; back them up with references or personal experience.
To learn more, see our tips on writing great answers.
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53302431%2fdialyzer-is-usually-never-wrong-but-i-cant-figure-out-how-my-spec-is-incorr%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
1
Do you get the same Dialyzer error if you comment out the calls to
Notifier.notify?– legoscia
Nov 14 '18 at 14:32
@legoscia oddly no I don't. If I go and check that error there's a dialyzer error in that function as well (which I have a PR out for an open source library to fix). So is that the issue? Dialyzer can't analyze the other 2 paths, thus the
{:ok, balances}branch is the only one it's aware of?– localshred
Nov 14 '18 at 15:01
1
Exactly. Since Dialyzer thinks that
Notifier.notifyalways crashes, it concludes that your function can never actually return:internal_server_error.– legoscia
Nov 14 '18 at 15:23