Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 1 addition & 2 deletions lib/elixir/lib/module/types/descr.ex
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,6 @@ defmodule Module.Types.Descr do

@domain_key_types [
{:domain_key, :binary},
{:domain_key, :empty_list},
{:domain_key, :integer},
{:domain_key, :float},
{:domain_key, :pid},
Expand Down Expand Up @@ -3031,7 +3030,7 @@ defmodule Module.Types.Descr do
defp bitmap_to_domain_keys(bitmap) do
[
if((bitmap &&& @bit_binary) != 0, do: domain_key(:binary)),
if((bitmap &&& @bit_empty_list) != 0, do: domain_key(:empty_list)),
if((bitmap &&& @bit_empty_list) != 0, do: domain_key(:list)),
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Now we can include :list twice. I think we need to handle that a bit upstream. :S

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I believe this gets handled gracefully thanks to

  # TODO: Double check if we indeed want the union here
  # when we start using domain types from Elixir itself
  defp map_put_domain(domain, key, value) do
    Map.update(domain, key, if_set(value), &union(&1, value))
  end

So when we instantiate say, empty_list() to integer() and non_empty_list() to atom() from Elixir, this will be split into two pairs of bindings passed to the constructor closed_map or open_map, with twice the same key domain_key(:list). Then, the map will have :list bound to integer() or atom(). I just added a test for that. A typing test would be nice too perhaps.

if((bitmap &&& @bit_integer) != 0, do: domain_key(:integer)),
if((bitmap &&& @bit_float) != 0, do: domain_key(:float)),
if((bitmap &&& @bit_pid) != 0, do: domain_key(:pid)),
Expand Down
25 changes: 25 additions & 0 deletions lib/elixir/test/elixir/module/types/descr_test.exs
Original file line number Diff line number Diff line change
Expand Up @@ -1702,6 +1702,31 @@ defmodule Module.Types.DescrTest do
t2 = closed_map([{domain_key(:tuple), float()}])
t3 = union(t1, t2)
assert map_get(t3, tuple()) == {:ok, number() |> nil_or_type()}

# Verify that empty_list() bitmap type maps to :list domain (not :empty_list domain)
map_with_list_domain = closed_map([{domain_key(:list), atom([:empty])}])

# empty_list() should access the :list domain
assert map_get(map_with_list_domain, empty_list()) == {:ok, atom([:empty]) |> nil_or_type()}

# non_empty_list() should also access the :list domain
assert map_get(map_with_list_domain, non_empty_list(integer())) ==
{:ok, atom([:empty]) |> nil_or_type()}

# list() should also access the :list domain
assert map_get(map_with_list_domain, list(integer())) ==
{:ok, atom([:empty]) |> nil_or_type()}

# If I create a map and instantiate both empty_list() and non_empty_list(integer()), it should return the union of the two types
map =
closed_map([{domain_key(:list), atom([:empty])}, {domain_key(:list), atom([:non_empty])}])

assert map_get(map, empty_list()) == {:ok, atom([:empty, :non_empty]) |> nil_or_type()}

assert map_get(map, non_empty_list(integer())) ==
{:ok, atom([:empty, :non_empty]) |> nil_or_type()}

assert map_get(map, list(integer())) == {:ok, atom([:empty, :non_empty]) |> nil_or_type()}
end

test "map_get with dynamic" do
Expand Down