@@ -2870,6 +2870,12 @@ defmodule Module.Types.Descr do
28702870 end
28712871 end
28722872
2873+ defp map_union ( bdd_leaf ( :open , fields ) = leaf , _ ) when is_fields_empty ( fields ) ,
2874+ do: leaf
2875+
2876+ defp map_union ( _ , bdd_leaf ( :open , fields ) = leaf ) when is_fields_empty ( fields ) ,
2877+ do: leaf
2878+
28732879 defp map_union ( bdd_leaf ( tag1 , fields1 ) , bdd_leaf ( tag2 , fields2 ) ) do
28742880 case maybe_optimize_map_union ( tag1 , fields1 , tag2 , fields2 ) do
28752881 { tag , fields } -> bdd_leaf ( tag , fields )
@@ -3043,6 +3049,9 @@ defmodule Module.Types.Descr do
30433049 defp map_difference ( _ , bdd_leaf ( :open , [ ] ) ) ,
30443050 do: :bdd_bot
30453051
3052+ defp map_difference ( bdd_leaf ( :open , [ ] ) , { _ , _ , _ , _ } = bdd2 ) ,
3053+ do: bdd_negation ( bdd2 )
3054+
30463055 defp map_difference ( bdd1 , bdd2 ) ,
30473056 do: bdd_difference ( bdd1 , bdd2 , & map_leaf_difference / 3 )
30483057
@@ -4961,10 +4970,10 @@ defmodule Module.Types.Descr do
49614970 end
49624971 end
49634972
4964- defp tuple_difference ( bdd_leaf ( :open , [ ] ) , bdd_leaf ( :open , [ ] ) ) ,
4973+ defp tuple_difference ( _ , bdd_leaf ( :open , [ ] ) ) ,
49654974 do: :bdd_bot
49664975
4967- defp tuple_difference ( bdd_leaf ( :open , [ ] ) , bdd2 ) ,
4976+ defp tuple_difference ( bdd_leaf ( :open , [ ] ) , { _ , _ , _ , _ } = bdd2 ) ,
49684977 do: bdd_negation ( bdd2 )
49694978
49704979 defp tuple_difference ( bdd1 , bdd2 ) ,
@@ -5163,6 +5172,12 @@ defmodule Module.Types.Descr do
51635172 end )
51645173 end
51655174
5175+ defp tuple_union ( bdd_leaf ( :open , fields ) = leaf , _ ) when is_fields_empty ( fields ) ,
5176+ do: leaf
5177+
5178+ defp tuple_union ( _ , bdd_leaf ( :open , fields ) = leaf ) when is_fields_empty ( fields ) ,
5179+ do: leaf
5180+
51665181 defp tuple_union (
51675182 bdd_leaf ( tag1 , elements1 ) = tuple1 ,
51685183 bdd_leaf ( tag2 , elements2 ) = tuple2
@@ -5845,8 +5860,8 @@ defmodule Module.Types.Descr do
58455860 defp bdd_difference_union ( i , u1 , u2 ) ,
58465861 do: bdd_difference ( i , bdd_union ( u1 , u2 ) )
58475862
5848- # We avoid unions because they are lazy and we prune
5849- # intersections more actively .
5863+ # We avoid bdd_negation(bdd_union(u1, u2)) because the negation
5864+ # would spread the unions across constrained and dual parts anyway .
58505865 defp bdd_negation_union ( u1 , u2 ) do
58515866 bdd_intersection ( bdd_negation ( u1 ) , bdd_negation ( u2 ) )
58525867 end
@@ -6049,109 +6064,70 @@ defmodule Module.Types.Descr do
60496064
60506065 # Intersections are great because they allow us to cut down
60516066 # the number of nodes in the tree. So whenever we have a leaf,
6052- # we actually propagate it throughout the whole tree, cutting
6053- # down nodes.
6054- defguardp is_not_open ( leaf ) when elem ( leaf , 0 ) != :open
6055-
6067+ # we propagate it throughout the whole tree, cutting down nodes.
60566068 defp bdd_intersection ( bdd_leaf ( _ , _ ) = leaf1 , bdd_leaf ( _ , _ ) = leaf2 , leaf_intersection ) do
60576069 leaf_intersection . ( leaf1 , leaf2 )
60586070 end
60596071
6060- defp bdd_intersection ( bdd_leaf ( _ , _ ) = leaf , bdd , leaf_intersection ) when is_not_open ( leaf ) do
6061- bdd_leaf_intersection ( leaf , bdd , leaf_intersection )
6072+ defp bdd_intersection ( bdd , bdd_leaf ( tag , _ ) = leaf , leaf_intersection ) when tag != :open do
6073+ bdd_non_open_leaf_intersection ( leaf , bdd , leaf_intersection )
60626074 end
60636075
6064- defp bdd_intersection ( bdd , bdd_leaf ( _ , _ ) = leaf , leaf_intersection ) when is_not_open ( leaf ) do
6065- bdd_leaf_intersection ( leaf , bdd , leaf_intersection )
6076+ defp bdd_intersection ( bdd_leaf ( tag , _ ) = leaf , bdd , leaf_intersection ) when tag != :open do
6077+ bdd_non_open_leaf_intersection ( leaf , bdd , leaf_intersection )
60666078 end
60676079
6068- # Take two BDDs, B1 = {a1, C1, U2, D2} and B2.
6069- #
6070- # When C1 = :bdd_top, we have:
6080+ defp bdd_intersection ( bdd1 , bdd2 , _leaf_intersection ) do
6081+ bdd_intersection ( bdd1 , bdd2 )
6082+ end
6083+
6084+ # Take two BDDs, B1 = {a1, C1, U1, D1} and B2 = a2.
60716085 #
6072- # ((a1 and C1) or U2 or (not a1 and D2)) and B2
6073- # (a1 and B2) or (B2 and U2) or (B2 and not a1 and D2)
6086+ # We have:
60746087 #
6075- # When C1 = :bdd_bot, we have:
6088+ # ((a1 and C1) or U1 or (not a1 and D1)) and a2
6089+ # (a1 and a2 and C1) or (a2 and U1) or (a2 and not a1 and D1)
60766090 #
6077- # (U2 or (not a1 and D2)) and B2
6078- # (B2 and U2) or (B2 and not a1 and D2)
6079- defp bdd_intersection ( { leaf , :bdd_top , u , d } , bdd , leaf_intersection ) when is_not_open ( leaf ) do
6080- bdd_leaf_intersection ( leaf , bdd , leaf_intersection )
6081- |> bdd_union ( bdd_intersection ( u , bdd , leaf_intersection ) )
6082- |> case do
6083- result when d == :bdd_bot -> result
6084- result -> bdd_union ( result , bdd_intersection ( bdd , { leaf , :bdd_bot , :bdd_bot , d } ) )
6085- end
6091+ # When C1 = :bdd_top, (a1 and a2) or (a2 and U2) or (a2 and not a1 and D2)
6092+ # When C2 = :bdd_bot, (a2 and U2) or (a2 and not a1 and D2)
6093+ defp bdd_non_open_leaf_intersection ( leaf1 , bdd_leaf ( _ , _ ) = leaf2 , leaf_intersection ) do
6094+ leaf_intersection . ( leaf1 , leaf2 )
60866095 end
60876096
6088- defp bdd_intersection ( bdd , { leaf , :bdd_top , u , d } , leaf_intersection ) when is_not_open ( leaf ) do
6089- bdd_leaf_intersection ( leaf , bdd , leaf_intersection )
6090- |> bdd_union ( bdd_intersection ( u , bdd , leaf_intersection ) )
6097+ defp bdd_non_open_leaf_intersection ( leaf , { a , :bdd_top , u , d } , leaf_intersection ) do
6098+ leaf_intersection . ( a , leaf )
6099+ |> bdd_union ( bdd_non_open_leaf_intersection ( leaf , u , leaf_intersection ) )
60916100 |> case do
6092- result when d == :bdd_bot -> result
6093- result -> bdd_union ( result , bdd_intersection ( bdd , { leaf , :bdd_bot , :bdd_bot , d } ) )
6094- end
6095- end
6101+ result when d == :bdd_bot ->
6102+ result
60966103
6097- defp bdd_intersection ( { leaf , :bdd_bot , u , d } , bdd , leaf_intersection ) when is_not_open ( leaf ) do
6098- case bdd_intersection ( u , bdd , leaf_intersection ) do
6099- result when d == :bdd_bot -> result
6100- result -> bdd_union ( result , bdd_intersection ( bdd , { leaf , :bdd_bot , :bdd_bot , d } ) )
6104+ result ->
6105+ leaf
6106+ |> bdd_non_open_leaf_intersection ( d , leaf_intersection )
6107+ |> bdd_difference ( a )
6108+ |> bdd_union ( result )
61016109 end
61026110 end
61036111
6104- defp bdd_intersection ( bdd , { leaf , :bdd_bot , u , d } , leaf_intersection ) when is_not_open ( leaf ) do
6105- case bdd_intersection ( u , bdd , leaf_intersection ) do
6106- result when d == :bdd_bot -> result
6107- result -> bdd_union ( result , bdd_intersection ( bdd , { leaf , :bdd_bot , :bdd_bot , d } ) )
6112+ defp bdd_non_open_leaf_intersection ( leaf , { a , :bdd_bot , u , d } , leaf_intersection ) do
6113+ case bdd_non_open_leaf_intersection ( leaf , u , leaf_intersection ) do
6114+ result when d == :bdd_bot ->
6115+ result
6116+
6117+ result ->
6118+ leaf
6119+ |> bdd_non_open_leaf_intersection ( d , leaf_intersection )
6120+ |> bdd_difference ( a )
6121+ |> bdd_union ( result )
61086122 end
61096123 end
61106124
6111- defp bdd_intersection ( bdd1 , bdd2 , _leaf_intersection ) do
6125+ defp bdd_non_open_leaf_intersection ( bdd1 , bdd2 , _leaf_intersection ) do
61126126 bdd_intersection ( bdd1 , bdd2 )
61136127 end
61146128
6115- defp bdd_leaf_intersection ( leaf , bdd , intersection ) do
6116- case bdd do
6117- :bdd_top ->
6118- leaf
6119-
6120- :bdd_bot ->
6121- :bdd_bot
6122-
6123- bdd_leaf ( _ , _ ) ->
6124- intersection . ( leaf , bdd )
6125-
6126- { bdd_leaf ( :open , _ ) , _ , _ , _ } ->
6127- bdd_intersection ( leaf , bdd )
6128-
6129- { lit , c , u , _ } when lit == leaf ->
6130- case bdd_union ( c , u ) do
6131- :bdd_bot -> :bdd_bot
6132- cu -> { lit , cu , :bdd_bot , :bdd_bot }
6133- end
6134-
6135- { lit , c , u , d } ->
6136- rest =
6137- bdd_union (
6138- bdd_leaf_intersection ( leaf , u , intersection ) ,
6139- bdd_difference ( bdd_leaf_intersection ( leaf , d , intersection ) , lit )
6140- )
6141-
6142- if c == :bdd_bot do
6143- rest
6144- else
6145- case intersection . ( leaf , lit ) do
6146- :bdd_bot -> rest
6147- new_leaf -> bdd_union ( bdd_leaf_intersection ( new_leaf , c , intersection ) , rest )
6148- end
6149- end
6150- end
6151- end
6152-
6153- # {lit, c, u, d} = (lit and c) or u or (not lit and d), so
6154- # its negation is ((lit and not c) or (not lit and not d)) and not u.
6129+ # {lit, c, u, d} = (lit and c) or u or (not lit and d),
6130+ # so its negation is ((lit and not c) or (not lit and not d)) and not u.
61556131 def bdd_negation ( :bdd_top ) , do: :bdd_bot
61566132 def bdd_negation ( :bdd_bot ) , do: :bdd_top
61576133 def bdd_negation ( { _ , _ } = pair ) , do: { pair , :bdd_bot , :bdd_bot , :bdd_top }
0 commit comments