Skip to content

Commit 6ce5044

Browse files
committed
Optimize leaf intersections in differences
1 parent 5f60c39 commit 6ce5044

1 file changed

Lines changed: 54 additions & 39 deletions

File tree

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

Lines changed: 54 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -1983,22 +1983,19 @@ defmodule Module.Types.Descr do
19831983

19841984
defp list_intersection(bdd1, bdd2) do
19851985
cond do
1986-
list_top?(bdd1) and is_tuple(bdd2) ->
1987-
bdd2
1988-
1989-
list_top?(bdd2) and is_tuple(bdd1) ->
1990-
bdd1
1986+
list_top?(bdd1) and is_tuple(bdd2) -> bdd2
1987+
list_top?(bdd2) and is_tuple(bdd1) -> bdd1
1988+
true -> bdd_intersection(bdd1, bdd2, &list_leaf_intersection/2)
1989+
end
1990+
end
19911991

1992-
true ->
1993-
bdd_intersection(bdd1, bdd2, fn bdd_leaf(list1, last1), bdd_leaf(list2, last2) ->
1994-
try do
1995-
list = non_empty_intersection!(list1, list2)
1996-
last = non_empty_intersection!(last1, last2)
1997-
bdd_leaf(list, last)
1998-
catch
1999-
:empty -> :bdd_bot
2000-
end
2001-
end)
1992+
defp list_leaf_intersection(bdd_leaf(list1, last1), bdd_leaf(list2, last2)) do
1993+
try do
1994+
list = non_empty_intersection!(list1, list2)
1995+
last = non_empty_intersection!(last1, last2)
1996+
bdd_leaf(list, last)
1997+
catch
1998+
:empty -> :bdd_bot
20021999
end
20032000
end
20042001

@@ -2026,7 +2023,7 @@ defmodule Module.Types.Descr do
20262023
end
20272024
end
20282025

2029-
defp list_difference(bdd1, bdd2), do: bdd_difference(bdd1, bdd2)
2026+
defp list_difference(bdd1, bdd2), do: bdd_difference(bdd1, bdd2, &list_leaf_intersection/2)
20302027

20312028
defp list_empty?(@non_empty_list_top), do: false
20322029

@@ -2599,21 +2596,18 @@ defmodule Module.Types.Descr do
25992596

26002597
defp map_intersection(bdd1, bdd2) do
26012598
cond do
2602-
map_top?(bdd1) and is_tuple(bdd2) ->
2603-
bdd2
2604-
2605-
map_top?(bdd2) and is_tuple(bdd1) ->
2606-
bdd1
2599+
map_top?(bdd1) and is_tuple(bdd2) -> bdd2
2600+
map_top?(bdd2) and is_tuple(bdd1) -> bdd1
2601+
true -> bdd_intersection(bdd1, bdd2, &map_leaf_intersection/2)
2602+
end
2603+
end
26072604

2608-
true ->
2609-
bdd_intersection(bdd1, bdd2, fn bdd_leaf(tag1, fields1), bdd_leaf(tag2, fields2) ->
2610-
try do
2611-
{tag, fields} = map_literal_intersection(tag1, fields1, tag2, fields2)
2612-
bdd_leaf(tag, fields)
2613-
catch
2614-
:empty -> :bdd_bot
2615-
end
2616-
end)
2605+
defp map_leaf_intersection(bdd_leaf(tag1, fields1), bdd_leaf(tag2, fields2)) do
2606+
try do
2607+
{tag, fields} = map_literal_intersection(tag1, fields1, tag2, fields2)
2608+
bdd_leaf(tag, fields)
2609+
catch
2610+
:empty -> :bdd_bot
26172611
end
26182612
end
26192613

@@ -2636,12 +2630,12 @@ defmodule Module.Types.Descr do
26362630
bdd_leaf(tag, Map.update!(fields, diff_key, &difference(&1, neg_fields[diff_key])))
26372631

26382632
_ ->
2639-
bdd_difference(map1, map2)
2633+
bdd_difference(map1, map2, &map_leaf_intersection/2)
26402634
end
26412635
end
26422636
end
26432637

2644-
defp map_difference(bdd1, bdd2), do: bdd_difference(bdd1, bdd2)
2638+
defp map_difference(bdd1, bdd2), do: bdd_difference(bdd1, bdd2, &map_leaf_intersection/2)
26452639

26462640
# Intersects two map literals; throws if their intersection is empty.
26472641
# Both open: the result is open.
@@ -4089,12 +4083,14 @@ defmodule Module.Types.Descr do
40894083
defp tuple_new(tag, elements), do: bdd_leaf(tag, elements)
40904084

40914085
defp tuple_intersection(bdd1, bdd2) do
4092-
bdd_intersection(bdd1, bdd2, fn bdd_leaf(tag1, elements1), bdd_leaf(tag2, elements2) ->
4093-
case tuple_literal_intersection(tag1, elements1, tag2, elements2) do
4094-
{tag, elements} -> bdd_leaf(tag, elements)
4095-
:empty -> :bdd_bot
4096-
end
4097-
end)
4086+
bdd_intersection(bdd1, bdd2, &tuple_leaf_intersection/2)
4087+
end
4088+
4089+
defp tuple_leaf_intersection(bdd_leaf(tag1, elements1), bdd_leaf(tag2, elements2)) do
4090+
case tuple_literal_intersection(tag1, elements1, tag2, elements2) do
4091+
{tag, elements} -> bdd_leaf(tag, elements)
4092+
:empty -> :bdd_bot
4093+
end
40984094
end
40994095

41004096
defp tuple_literal_intersection(:open, [], tag, elements), do: {tag, elements}
@@ -4135,7 +4131,7 @@ defmodule Module.Types.Descr do
41354131
end
41364132
end
41374133

4138-
defp tuple_difference(bdd1, bdd2), do: bdd_difference(bdd1, bdd2)
4134+
defp tuple_difference(bdd1, bdd2), do: bdd_difference(bdd1, bdd2, &tuple_leaf_intersection/2)
41394135

41404136
defp non_empty_tuple_literals_intersection(tuples) do
41414137
try do
@@ -4911,6 +4907,25 @@ defmodule Module.Types.Descr do
49114907
defp bdd_difference_union(i, u1, u2),
49124908
do: bdd_difference(i, bdd_union(u1, u2))
49134909

4910+
# Optimize differences when D2 != :bottom
4911+
# to use the same optimization as bdd_leaf_intersection.
4912+
#
4913+
# (B1) and not (B2)
4914+
# (B1) and not (B2_no_D2 or (not a2 and D2))
4915+
# (B1) and (not B2_no_D2 and (a2 or not D2))
4916+
# (B1) and (a2 or not D2) and not B2_no_D2
4917+
# ((B1 and a2) or (B1 and not D2)) and not B2_no_D2
4918+
#
4919+
defp bdd_difference(bdd, {leaf, c, u, d}, leaf_intersection) when d != :bdd_bottom do
4920+
bdd_leaf_intersection(leaf, bdd, leaf_intersection)
4921+
|> bdd_union(bdd_difference(bdd, d, leaf_intersection))
4922+
|> bdd_difference({leaf, c, u, :bdd_bot})
4923+
end
4924+
4925+
defp bdd_difference(bdd1, bdd2, _leaf_intersection) do
4926+
bdd_difference(bdd1, bdd2)
4927+
end
4928+
49144929
def bdd_intersection(bdd1, bdd2) do
49154930
case {bdd1, bdd2} do
49164931
{:bdd_top, bdd} ->

0 commit comments

Comments
 (0)