-
Notifications
You must be signed in to change notification settings - Fork 13
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
match? pattern seems to not affect the type #98
Comments
Hi, @LostKobrakai! Thanks for the report, that's appreciated. Both |
# match?([_a], list)
case list do
[_a] -> true
_ -> false
end |
Ok, here's some research. This Elixir: @spec g(list(integer())) :: integer()
def g(list) do
cond do
[] == list ->
0
match?([_|_], list) ->
list |> hd()
true ->
Enum.max(list)
end
end Compiles to this Erlang: -spec g([integer()]) -> integer().
g(_list@1) ->
case [] == _list@1 of
true -> 0;
false ->
case case _list@1 of
[_ | _] -> true;
_ -> false
end
of
true -> erlang:hd(_list@1);
false ->
case true of
true -> 'Elixir.Enum':max(_list@1);
false -> erlang:error(cond_clause)
end
end
end. Which means we would have to come up with a custom rule to refine the type of the Elixir The best we could do now is a manual type assertion, like this: @spec g(list(integer())) :: integer()
def g(list) do
cond do
[] == list ->
0
match?([_|_], list) ->
list |> assert_type(nonempty_list(integer())) |> hd()
true ->
Enum.max(list)
end
end Annotations and assertions are supported by Gradualizer, so we're good with that. There are some hurdles on the Elixir level, though:
These lead to the following code: @spec g(list(integer())) :: integer()
def g(list) do
cond do
[] == list ->
0
match?([_|_], list) ->
list |> assert_type(BuiltinType.nonempty_list_(BuiltinType.integer_())) |> hd()
true ->
Enum.max(list)
end
end Which results in the following warning:
The returned warning seems to be caused by a bug in Thanks again for the report, @LostKobrakai. A lot of food for thought, but we should be able to pull it off with a manual annotation in the short term and therefore pave the way for a builtin rule in the long run. |
@LostKobrakai Could you check if #101 works for you with an explicit type annotation like this: @spec g(list(integer())) :: integer()
def g(list) do
cond do
[] == list ->
0
match?([_|_], list) ->
list |> assert_type(nonempty_list(integer())) |> hd()
true ->
Enum.max(list)
end
end If it does, then we're halfway there, i.e. there's no automatic type refinement yet, but at least we can let the typechecker know about the refined type ourselves. |
Just saw I need |
Thanks for the confirmation, @LostKobrakai! I'm reclassifying this as an enhancement, as automagic refinement would be nice, but now it's at least possible to solve the problem with an explicit annotation. |
I'm not sure where the issue comes from or if it's supposed to be covered, but neither
match?
nor a normal function pattern matching on the list holding one item will make the type be refined tononempty_list
.The text was updated successfully, but these errors were encountered: