Gradualizer icon indicating copy to clipboard operation
Gradualizer copied to clipboard

Make atom() accepted for exhaustiveness checking

Open erszcz opened this issue 2 years ago • 2 comments

The following type cannot be checked for exhaustiveness:

-type complex_t() :: {string, string()}
                   | {list, list(allergen())}
                   | {atom, atom()}
                   | {binary, binary()}
                   | {record, record()}
                   | {map, #{non_empty := true}}
                   | {integer, integer()}
                   | {float, float()}.

The check kicks in when we comment out the atom variant:

-type complex_t() :: {string, string()}
                   | {list, list(allergen())}
                   %| {atom, atom()}
                   | {binary, binary()}
                   | {record, record()}
                   | {map, #{non_empty := true}}
                   | {integer, integer()}
                   | {float, float()}.

This is interesting, since a union of atoms can be checked for exhaustiveness.

erszcz avatar Jun 08 '22 07:06 erszcz

For some context, atom() in general is not refinable - I'm guessing this is the sole reason:

9> Type = fun (T) -> typelib:remove_pos(typelib:parse_type(T)) end.
#Fun<erl_eval.44.40011524>
10> typechecker:refinable(Type("atom()"), []).
false

erszcz avatar Jun 08 '22 07:06 erszcz

For more context, singleton atoms or a union of explicit atoms are accepted in complex types:

-type complex_t() :: {string, string()}
                   | {list, list(allergen())}
                   | {atom, example_atom | another_atom}
                   | {binary, binary()}
                   | {record, record()}
                   | {map, #{non_empty := true}}
                   | {integer, integer()}
                   | {float, float()}.

erszcz avatar Jun 11 '22 19:06 erszcz