From 3caa8ba9f505afe5abf64feaf5963bbb57728d9e Mon Sep 17 00:00:00 2001 From: Guillaume Duboc Date: Mon, 24 Nov 2025 15:17:40 +0100 Subject: [PATCH 1/3] Unify :empty_list and :list domains in maps --- lib/elixir/lib/module/types/descr.ex | 3 +-- lib/elixir/test/elixir/module/types/descr_test.exs | 12 ++++++++++++ 2 files changed, 13 insertions(+), 2 deletions(-) diff --git a/lib/elixir/lib/module/types/descr.ex b/lib/elixir/lib/module/types/descr.ex index 1eea50dd92..0f89f063cb 100644 --- a/lib/elixir/lib/module/types/descr.ex +++ b/lib/elixir/lib/module/types/descr.ex @@ -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}, @@ -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)), 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)), diff --git a/lib/elixir/test/elixir/module/types/descr_test.exs b/lib/elixir/test/elixir/module/types/descr_test.exs index 8f50b079fe..954d30251e 100644 --- a/lib/elixir/test/elixir/module/types/descr_test.exs +++ b/lib/elixir/test/elixir/module/types/descr_test.exs @@ -1702,6 +1702,18 @@ 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()} end test "map_get with dynamic" do From 3f8881fdff972c2816c494ef21bec74bf3a80dfc Mon Sep 17 00:00:00 2001 From: Guillaume Duboc Date: Mon, 24 Nov 2025 15:58:51 +0100 Subject: [PATCH 2/3] Add test for domain instantiation --- lib/elixir/test/elixir/module/types/descr_test.exs | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/lib/elixir/test/elixir/module/types/descr_test.exs b/lib/elixir/test/elixir/module/types/descr_test.exs index 954d30251e..de202eeeec 100644 --- a/lib/elixir/test/elixir/module/types/descr_test.exs +++ b/lib/elixir/test/elixir/module/types/descr_test.exs @@ -1714,6 +1714,12 @@ defmodule Module.Types.DescrTest do # 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 From 47b58b203274b6ab853efd2e0b252ab45e076954 Mon Sep 17 00:00:00 2001 From: Guillaume Duboc Date: Mon, 24 Nov 2025 16:15:25 +0100 Subject: [PATCH 3/3] Formatting --- .../test/elixir/module/types/descr_test.exs | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/lib/elixir/test/elixir/module/types/descr_test.exs b/lib/elixir/test/elixir/module/types/descr_test.exs index de202eeeec..8ff00ea886 100644 --- a/lib/elixir/test/elixir/module/types/descr_test.exs +++ b/lib/elixir/test/elixir/module/types/descr_test.exs @@ -1710,15 +1710,22 @@ defmodule Module.Types.DescrTest do 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()} + 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()} + 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])}]) + 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, 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