Skip to content

Commit 1b8618d

Browse files
committed
Remove duplicate for map_difference
1 parent d7bdea5 commit 1b8618d

File tree

1 file changed

+41
-15
lines changed

1 file changed

+41
-15
lines changed

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

Lines changed: 41 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -2370,6 +2370,8 @@ defmodule Module.Types.Descr do
23702370
if subtype?(v2, v1), do: :right_subtype_of_left
23712371
end
23722372

2373+
defp map_intersection(dnf, dnf), do: dnf
2374+
23732375
# Given two unions of maps, intersects each pair of maps.
23742376
defp map_intersection(dnf1, dnf2) do
23752377
for {tag1, pos1, negs1} <- dnf1,
@@ -2378,15 +2380,17 @@ defmodule Module.Types.Descr do
23782380
acc ->
23792381
try do
23802382
{tag, fields} = map_literal_intersection(tag1, pos1, tag2, pos2)
2381-
entry = {tag, fields, negs1 ++ negs2}
2383+
negs = negs1 ++ (negs2 -- negs1)
2384+
entry = {tag, fields, negs}
23822385

23832386
# Imagine a, b, c, where a is closed and b and c are open with
23842387
# no keys in common. The result in both cases will be a and we
23852388
# want to avoid adding duplicates, especially as intersection
23862389
# is a cartesian product.
2387-
case :lists.member(entry, acc) do
2388-
true -> acc
2389-
false -> [entry | acc]
2390+
cond do
2391+
:lists.member({tag, fields}, negs) -> acc
2392+
:lists.member(entry, acc) -> acc
2393+
true -> [entry | acc]
23902394
end
23912395
catch
23922396
:empty -> acc
@@ -2454,33 +2458,55 @@ defmodule Module.Types.Descr do
24542458
if empty?(type), do: throw(:empty), else: type
24552459
end
24562460

2457-
defp map_difference(_, dnf) when dnf == @map_top do
2458-
0
2459-
end
2461+
defp map_difference(_, dnf) when dnf == @map_top, do: 0
2462+
defp map_difference(dnf, dnf), do: 0
24602463

24612464
defp map_difference(dnf1, dnf2) do
24622465
Enum.reduce(dnf2, dnf1, fn
2463-
# Optimization: we are removing an open map with one field.
2464-
{:open, fields2, []}, dnf1 when map_size(fields2) == 1 ->
2465-
Enum.reduce(dnf1, [], fn {tag1, fields1, negs1}, acc ->
2466+
{:open, fields2, []}, current_dnf when map_size(fields2) == 1 ->
2467+
# Optimization: we are removing an open map with one field.
2468+
Enum.reduce(current_dnf, [], fn {tag1, fields1, negs1}, acc ->
24662469
{key, value, _rest} = :maps.next(:maps.iterator(fields2))
24672470
t_diff = difference(Map.get(fields1, key, tag_to_type(tag1)), value)
24682471

24692472
if empty?(t_diff) do
24702473
acc
24712474
else
2472-
[{tag1, Map.put(fields1, key, t_diff), negs1} | acc]
2475+
{tag, pos} = {tag1, Map.put(fields1, key, t_diff)}
2476+
entry = {tag, pos, negs1}
2477+
2478+
cond do
2479+
:lists.member({tag, pos}, negs1) -> acc
2480+
:lists.member(entry, acc) -> acc
2481+
true -> [entry | acc]
2482+
end
24732483
end
24742484
end)
24752485

2476-
{tag2, fields2, negs2}, dnf1 ->
2477-
Enum.reduce(dnf1, [], fn {tag1, fields1, negs1}, acc ->
2478-
acc = [{tag1, fields1, [{tag2, fields2} | negs1]} | acc]
2486+
{tag2, fields2, negs2}, current_dnf ->
2487+
Enum.reduce(current_dnf, [], fn {tag1, fields1, negs1}, acc ->
2488+
negs =
2489+
if :lists.member({tag2, fields2}, negs1), do: negs1, else: [{tag2, fields2} | negs1]
2490+
2491+
entry = {tag1, fields1, negs}
2492+
2493+
acc =
2494+
cond do
2495+
:lists.member({tag1, fields1}, negs) -> acc
2496+
:lists.member(entry, acc) -> acc
2497+
true -> [entry | acc]
2498+
end
24792499

24802500
Enum.reduce(negs2, acc, fn {neg_tag2, neg_fields2}, acc ->
24812501
try do
24822502
{tag, fields} = map_literal_intersection(tag1, fields1, neg_tag2, neg_fields2)
2483-
[{tag, fields, negs1} | acc]
2503+
entry = {tag, fields, negs1}
2504+
2505+
cond do
2506+
:lists.member({tag, fields}, negs1) -> acc
2507+
:lists.member(entry, acc) -> acc
2508+
true -> [entry | acc]
2509+
end
24842510
catch
24852511
:empty -> acc
24862512
end

0 commit comments

Comments
 (0)