Dialyzer: The Point of No Local Return
June 14, 2015
As I was getting chef-server
up to speed with dialyzer
, I got myself into a
little situation, that I couldn't make heads nor tails of.
If you've run dialyzer
, you've probably seen the dreaded function has no local return
error. The first thing I usually do is look at the following few
errors. If there's something nearby, I'll fix that first. Maybe no local return
will go away.
Of course, sometimes you really want the function to have no return.
Fortunately, dialyzer
provides a type for that: none()
.
In Learn You Some Erlang's
dialyzer chapter,
we're introduced to two most basic types: any()
and none()
. any()
is any
erlang term, so it's not just a clever nickname. none()
is tricky. It means
that no return type is valid and that this function should crash.
So, why are we talking about it?
I had a function that I knew should have no return. Somewhere down it's call
stack, it calls error/1
which crashes things, and I'm cool with that. But
dialyzer
told me there was no local return. I KNOW! I told you it was none()
so we should be fine with that.
After more time than I care to admit, and scrolling through that same Learn You Some Erlang page, I stumbled across this:
no_return(): this is an alias of none()
Well, if it's an alias, it should also break. But, desperate times... And it
worked. Where none()
failed, no_return()
succeeded! Let's look at the code:
%% Dialyzer is ok with this
-spec err(term()) -> none().
err(X) ->
error({error, X}).
%% dialyzer says this spec has no local return
-spec err_bad(term()) -> none().
%% however, this spec is ok
-spec err_bad(term()) -> no_return().
%% So, there is some difference between none() and no_return()
err_bad(X) ->
err(X).
When a function called error/1
directly, none()
was fine; however, when the
function calls a function that calls error/1
, only no_return()
will get the
desired result.
So I emailed Fred about it, which eventually ended with "We should ask Kostis". And as it so happened, I was soon headed to EUC, which Kostis was also attending. I literally had a gist with this code ready to go on my phone, should the opportunity to ask about it arise.
As it turns out, it did! The answer straight from Kostis, is that none()
and
no_return()
should be equivalent. If they're not, it's an issue with the
implementation (read: I found a bug in dialyzer
!), but it doesn't matter,
just always use no_return()
.
So, there you have it. none()
is for chumps. no_return()
4 lyfe.