How can I get Dialyzer to accept a call to a function that intentionally throws?

204 views Asked by At

I have a function that intentionally throws when its first argument is the atom throw.

A simplified version of this code is:

-module(sample).

-export([main/1, throw_or_ok/1]).

main(_Args) ->
    throw_or_ok(throw).


throw_or_ok(Action) ->
    case Action of
        throw -> throw("throwing");
        ok -> ok
    end.

Dialyzer errors on the call to throw_or_ok:

sample.erl:7: The call sample:throw_or_ok
         ('throw') will never return since it differs in the 1st argument from the success typing arguments:
         ('ok')

Adding specs doesn't help, the error message is the same:

-module(sample).

-export([main/1, throw_or_ok/1]).

-spec main(_) -> no_return().
main(_Args) ->
    throw_or_ok(throw).

-spec throw_or_ok(throw) -> no_return(); (ok) -> ok.
throw_or_ok(Action) ->
    case Action of
        throw -> throw("throwing");
        ok -> ok
    end.

How can I get Dialyzer to accept calls to throw_or_ok/1 that are guaranteed to throw?

2

There are 2 answers

0
aronisstav On

Unfortunately there is currently no clean way to mark this as acceptable for Dialyzer via specs.

Perhaps you can use an ignore warning annotation, however.

0
vkatsuba On

Looks like if will put throw it will never return, if will put ok the pattern will never match with throw. See topic with similar issue. The logic of main/1 need to change, eg:

main(Args) ->
    MaybeOk = case Args of
        0 -> throw;
        _ -> ok
    end,
    throw_or_ok(MaybeOk).

OR

main(_Args) ->
    throw_or_ok(_Args).