@@ -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