Skip to content

Commit 27aadff

Browse files
committed
Tackle empty intersections in map fetch key
1 parent 64a5c17 commit 27aadff

2 files changed

Lines changed: 69 additions & 11 deletions

File tree

lib/elixir/lib/module/types/descr.ex

Lines changed: 13 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -3266,7 +3266,8 @@ defmodule Module.Types.Descr do
32663266
catch
32673267
:open -> {true, term()}
32683268
else
3269-
value -> pop_optional_static(value)
3269+
value ->
3270+
pop_optional_static(value)
32703271
end
32713272

32723273
defp map_split_negative_key(negs, key, value, bdd) do
@@ -3290,7 +3291,7 @@ defmodule Module.Types.Descr do
32903291

32913292
if not found? and neg_tag == :open do
32923293
# In case the map is open, t \ t₁ is always empty,
3293-
# so we just need to deal with the bdd.
3294+
# t ∩ t₁ is always t, so we just need to deal with the bdd.
32943295
Enum.reduce(acc, [], fn {value, bdd}, acc ->
32953296
diff_bdd = map_difference(bdd, neg_bdd)
32963297

@@ -3307,17 +3308,19 @@ defmodule Module.Types.Descr do
33073308
if neg_tag == :closed and map_empty?(map_intersection(bdd, neg_bdd)) do
33083309
[{value, bdd} | acc]
33093310
else
3310-
diff_bdd = map_difference(bdd, neg_bdd)
3311+
intersection_value = intersection(value, neg_value)
33113312

3312-
cond do
3313-
value == neg_value or subtype?(value, neg_value) ->
3314-
if map_empty?(diff_bdd), do: acc, else: [{value, diff_bdd} | acc]
3313+
if empty?(intersection_value) do
3314+
[{value, bdd} | acc]
3315+
else
3316+
diff_bdd = map_difference(bdd, neg_bdd)
33153317

3316-
map_empty?(diff_bdd) ->
3318+
if map_empty?(diff_bdd) do
33173319
prepend_pair_unless_empty_diff(value, neg_value, bdd, acc)
3318-
3319-
true ->
3320-
prepend_pair_unless_empty_diff(value, neg_value, bdd, [{value, diff_bdd} | acc])
3320+
else
3321+
acc = [{intersection_value, diff_bdd} | acc]
3322+
prepend_pair_unless_empty_diff(value, neg_value, bdd, acc)
3323+
end
33213324
end
33223325
end
33233326
end)

lib/elixir/test/elixir/module/types/integration_test.exs

Lines changed: 56 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -928,7 +928,62 @@ defmodule Module.Types.IntegrationTest do
928928
assert_no_warnings(files)
929929
end
930930

931-
test "unions and intersections of open maps" do
931+
test "redundant clause checking of mixed open and closed maps" do
932+
files = %{
933+
"mixed_open_closed_maps.ex" => """
934+
defmodule MixedOpenClosedMaps do
935+
defmodule S1, do: defstruct([:name])
936+
defmodule S2, do: defstruct([:name])
937+
defmodule S3, do: defstruct([:name])
938+
defmodule S4, do: defstruct([:name])
939+
defmodule S5, do: defstruct([:name])
940+
defmodule S6, do: defstruct([:name])
941+
defmodule S7, do: defstruct([:name])
942+
defmodule S8, do: defstruct([:name])
943+
defmodule S9, do: defstruct([:name])
944+
defmodule S10, do: defstruct([:name])
945+
defmodule S11, do: defstruct([:name])
946+
defmodule S12, do: defstruct([:name])
947+
defmodule S13, do: defstruct([:name])
948+
defmodule S14, do: defstruct([:name])
949+
defmodule S15, do: defstruct([:name])
950+
defmodule S16, do: defstruct([:name])
951+
defmodule S17, do: defstruct([:name])
952+
defmodule S18, do: defstruct([:name])
953+
954+
defmodule SValue do
955+
defstruct [:value]
956+
end
957+
958+
def render(%S1{}), do: :ok
959+
def render(%S2{}), do: :ok
960+
def render(%S3{}), do: :ok
961+
def render(%S4{}), do: :ok
962+
def render(%S5{}), do: :ok
963+
def render(%S6{}), do: :ok
964+
def render(%S7{}), do: :ok
965+
def render(%S8{}), do: :ok
966+
def render(%S9{}), do: :ok
967+
def render(%S10{}), do: :ok
968+
def render(%S11{}), do: :ok
969+
def render(%S12{}), do: :ok
970+
def render(%S13{}), do: :ok
971+
def render(%S14{}), do: :ok
972+
def render(%S15{}), do: :ok
973+
def render(%S16{}), do: :ok
974+
def render(%S17{}), do: :ok
975+
def render(%S18{}), do: :ok
976+
# Having the closed map and the struct overlap on a key is important
977+
def render(%SValue{}), do: :ok
978+
def render(%{value: value}), do: value
979+
end
980+
"""
981+
}
982+
983+
assert_no_warnings(files)
984+
end
985+
986+
test "redundant clause checking of open maps with distinct keys" do
932987
files = %{
933988
"large_head.ex" => """
934989
defmodule LargeHead do

0 commit comments

Comments
 (0)