@@ -285,7 +285,7 @@ defmodule Module.Types.Descr do
285285 end
286286
287287 defp unwrap_domain_tuple ( % { tuple: bdd } = descr , transform ) when map_size ( descr ) == 1 do
288- tuple_bdd_to_dnf ( bdd ) |> Enum . map ( transform )
288+ tuple_bdd_to_dnf_no_negations ( bdd ) |> Enum . map ( transform )
289289 end
290290
291291 defp unwrap_domain_tuple ( descr , _transform ) when descr == % { } , do: [ ]
@@ -679,15 +679,15 @@ defmodule Module.Types.Descr do
679679 defp each_singleton? ( :atom , atoms ) , do: match? ( { :union , set } when map_size ( set ) == 1 , atoms )
680680
681681 defp each_singleton? ( :tuple , bdd ) do
682- case tuple_bdd_to_dnf ( bdd ) do
682+ case tuple_bdd_to_dnf_no_negations ( bdd ) do
683683 [ ] -> :empty
684684 [ { :closed , entries } ] -> Enum . all? ( entries , & static_singleton? / 1 )
685685 _ -> false
686686 end
687687 end
688688
689689 defp each_singleton? ( :map , bdd ) do
690- case map_bdd_to_dnf_no_negations ( bdd ) do
690+ case map_bdd_to_dnf_remove_empty ( bdd ) do
691691 [ ] ->
692692 :empty
693693
@@ -3172,7 +3172,7 @@ defmodule Module.Types.Descr do
31723172 if empty? ( type ) , do: throw ( :empty ) , else: type
31733173 end
31743174
3175- defp map_bdd_to_dnf_no_negations ( bdd ) do
3175+ defp map_bdd_to_dnf_remove_empty ( bdd ) do
31763176 bdd_to_dnf ( bdd )
31773177 |> Enum . reduce ( [ ] , fn { pos , negs } , acc ->
31783178 case non_empty_map_literals_intersection ( pos ) do
@@ -3189,7 +3189,7 @@ defmodule Module.Types.Descr do
31893189 end )
31903190 end
31913191
3192- defp map_bdd_to_dnf_with_negations ( bdd ) do
3192+ defp map_bdd_to_dnf_with_empty ( bdd ) do
31933193 bdd_to_dnf ( bdd )
31943194 |> Enum . reduce ( [ ] , fn { pos , negs } , acc ->
31953195 case non_empty_map_literals_intersection ( pos ) do
@@ -3257,7 +3257,7 @@ defmodule Module.Types.Descr do
32573257 end
32583258
32593259 defp map_fetch_key_static ( % { map: bdd } , key ) do
3260- bdd |> map_bdd_to_dnf_with_negations ( ) |> map_dnf_fetch_static ( key )
3260+ bdd |> map_bdd_to_dnf_with_empty ( ) |> map_dnf_fetch_static ( key )
32613261 end
32623262
32633263 defp map_fetch_key_static ( % { } , _key ) , do: { false , none ( ) }
@@ -3395,7 +3395,7 @@ defmodule Module.Types.Descr do
33953395 end
33963396
33973397 defp map_to_list_static ( % { map: bdd } , fun ) do
3398- case map_bdd_to_dnf_no_negations ( bdd ) do
3398+ case map_bdd_to_dnf_remove_empty ( bdd ) do
33993399 [ ] ->
34003400 :badmap
34013401
@@ -3590,7 +3590,7 @@ defmodule Module.Types.Descr do
35903590 { required_keys , optional_keys , maybe_negated_set , required_domains , optional_domains } =
35913591 split_keys
35923592
3593- dnf = map_bdd_to_dnf_with_negations ( bdd )
3593+ dnf = map_bdd_to_dnf_with_empty ( bdd )
35943594 bdd = map_update_put_negated ( bdd , maybe_negated_set , type_fun )
35953595
35963596 { found? , value , domains , errors } =
@@ -3658,7 +3658,7 @@ defmodule Module.Types.Descr do
36583658 { term ( ) , open_map ( ) , [ ] , true }
36593659 else
36603660 acc = { none ( ) , none ( ) , [ ] , false }
3661- dnf = map_bdd_to_dnf_with_negations ( @ map_top )
3661+ dnf = map_bdd_to_dnf_with_empty ( @ map_top )
36623662 map_update_keys_static ( dnf , required_keys , optional_keys , type_fun , force? , static? , acc )
36633663 end
36643664 end
@@ -3969,7 +3969,7 @@ defmodule Module.Types.Descr do
39693969 domains -> map_update_put_domains ( bdd , domains , type_fun )
39703970 end
39713971
3972- dnf = map_bdd_to_dnf_with_negations ( bdd )
3972+ dnf = map_bdd_to_dnf_with_empty ( bdd )
39733973 map_put_keys_static ( dnf , required_keys ++ optional_keys , type , descr )
39743974 end
39753975
@@ -3987,7 +3987,7 @@ defmodule Module.Types.Descr do
39873987 if required_domains != [ ] or optional_domains != [ ] do
39883988 open_map ( )
39893989 else
3990- dnf = map_bdd_to_dnf_with_negations ( @ map_top )
3990+ dnf = map_bdd_to_dnf_with_empty ( @ map_top )
39913991 map_put_keys_static ( dnf , required_keys ++ optional_keys , type , none ( ) )
39923992 end
39933993 end
@@ -4047,7 +4047,7 @@ defmodule Module.Types.Descr do
40474047 { required_keys , optional_keys , maybe_negated_set , required_domains , optional_domains } =
40484048 split_keys
40494049
4050- dnf = map_bdd_to_dnf_with_negations ( bdd )
4050+ dnf = map_bdd_to_dnf_with_empty ( bdd )
40514051
40524052 acc = none ( )
40534053 acc = map_get_keys ( dnf , required_keys , acc )
@@ -4552,7 +4552,7 @@ defmodule Module.Types.Descr do
45524552
45534553 defp map_to_quoted ( bdd , opts ) do
45544554 bdd
4555- |> map_bdd_to_dnf_with_negations ( )
4555+ |> map_bdd_to_dnf_with_empty ( )
45564556 |> Enum . flat_map ( fn { tag , fields , negs } ->
45574557 map_eliminate_while_negs_decrease ( tag , fields , negs )
45584558 end )
@@ -5192,25 +5192,43 @@ defmodule Module.Types.Descr do
51925192 end
51935193
51945194 defp tuple_to_quoted ( bdd , opts ) do
5195- tuple_bdd_to_dnf ( bdd )
5195+ tuple_bdd_to_dnf_with_negations ( bdd )
51965196 |> tuple_fusion ( )
51975197 |> Enum . map ( & tuple_literal_to_quoted ( & 1 , opts ) )
51985198 end
51995199
52005200 # Transforms a bdd into a union of tuples with no negations.
5201- # Note: it is important to compose the results with tuple_dnf_union/2 to avoid duplicates
5202- defp tuple_bdd_to_dnf ( bdd ) do
5201+ # Note: it is important to compose the results with
5202+ # tuple_dnf_union/2 to avoid duplicates
5203+ defp tuple_bdd_to_dnf_no_negations ( bdd ) do
52035204 bdd_to_dnf ( bdd )
5204- |> Enum . reduce ( [ ] , fn { positive_tuples , negative_tuples } , acc ->
5205- case non_empty_tuple_literals_intersection ( positive_tuples ) do
5205+ |> Enum . reduce ( [ ] , fn { pos , negs } , acc ->
5206+ case non_empty_tuple_literals_intersection ( pos ) do
5207+ :empty ->
5208+ acc
5209+
5210+ { tag , elements } ->
5211+ if tuple_line_empty? ( tag , elements , negs ) do
5212+ acc
5213+ else
5214+ tuple_eliminate_negations ( tag , elements , negs ) |> tuple_dnf_union ( acc )
5215+ end
5216+ end
5217+ end )
5218+ end
5219+
5220+ defp tuple_bdd_to_dnf_with_negations ( bdd ) do
5221+ bdd_to_dnf ( bdd )
5222+ |> Enum . reduce ( [ ] , fn { pos , negs } , acc ->
5223+ case non_empty_tuple_literals_intersection ( pos ) do
52065224 :empty ->
52075225 acc
52085226
52095227 { tag , elements } ->
5210- if tuple_line_empty? ( tag , elements , negative_tuples ) do
5228+ if tuple_line_empty? ( tag , elements , negs ) do
52115229 acc
52125230 else
5213- tuple_eliminate_negations ( tag , elements , negative_tuples ) |> tuple_dnf_union ( acc )
5231+ [ { tag , elements , negs } | acc ]
52145232 end
52155233 end
52165234 end )
@@ -5219,20 +5237,32 @@ defmodule Module.Types.Descr do
52195237 # Given a union of tuples, fuses the tuple unions when possible,
52205238 # e.g. {integer(), atom()} or {float(), atom()} into {number(), atom()}
52215239 # The negations of two fused tuples are just concatenated.
5222- defp tuple_fusion ( dnf_no_negations ) do
5223- # Steps:
5224- # 1. Consider tuples without negations apart from those with
5225- # 2. Group tuples by size and tag
5226- # 3. Try fusions for each group until no fusion is found
5227- # 4. Merge the groups back into a dnf
5228- dnf_no_negations
5229- |> Enum . group_by ( fn { tag , elems } -> { tag , length ( elems ) } end )
5230- |> Enum . flat_map ( fn { _ , tuples } -> tuple_non_negated_fuse ( tuples ) end )
5231- end
5232-
5233- defp tuple_non_negated_fuse ( tuples ) do
5234- Enum . reduce ( tuples , [ ] , fn tuple , acc ->
5235- tuple_fuse_with_first_fusible ( tuple , acc )
5240+ #
5241+ # Steps:
5242+ # 1. Consider tuples without negations apart from those with
5243+ # 2. Group tuples by size and tag
5244+ # 3. Try fusions for each group until no fusion is found
5245+ # 4. Merge the groups back into a dnf
5246+ defp tuple_fusion ( dnf ) do
5247+ { with_negs , without_negs } =
5248+ Enum . reduce ( dnf , { [ ] , % { } } , fn
5249+ { tag , elements , [ ] } , { with , without } ->
5250+ key = { tag , length ( elements ) }
5251+ value = { tag , elements }
5252+ { with , Map . update ( without , key , [ value ] , & [ value | & 1 ] ) }
5253+
5254+ triplet , { with , without } ->
5255+ { [ triplet | with ] , without }
5256+ end )
5257+
5258+ Enum . reduce ( without_negs , with_negs , fn { _ , tuples } , with_negs ->
5259+ tuples
5260+ |> Enum . reduce ( [ ] , fn tuple , acc ->
5261+ tuple_fuse_with_first_fusible ( tuple , acc )
5262+ end )
5263+ |> Enum . reduce ( with_negs , fn { tag , elements } , with_negs ->
5264+ [ { tag , elements , [ ] } | with_negs ]
5265+ end )
52365266 end )
52375267 end
52385268
@@ -5247,9 +5277,17 @@ defmodule Module.Types.Descr do
52475277 end
52485278 end
52495279
5250- defp tuple_literal_to_quoted ( { :closed , [ ] } , _opts ) , do: { :{} , [ ] , [ ] }
5280+ defp tuple_literal_to_quoted ( { :closed , [ ] , [ ] } , _opts ) , do: { :{} , [ ] , [ ] }
5281+
5282+ defp tuple_literal_to_quoted ( { tag , elements , negs } , opts ) do
5283+ pos = tuple_fields_to_quoted ( tag , elements , opts )
5284+
5285+ Enum . reduce ( negs , pos , fn { tag , elements } , acc ->
5286+ { :and , [ ] , [ acc , { :not , [ ] , [ tuple_fields_to_quoted ( tag , elements , opts ) ] } ] }
5287+ end )
5288+ end
52515289
5252- defp tuple_literal_to_quoted ( { tag , elements } , opts ) do
5290+ defp tuple_fields_to_quoted ( tag , elements , opts ) do
52535291 case tag do
52545292 :closed -> { :{} , [ ] , Enum . map ( elements , & to_quoted ( & 1 , opts ) ) }
52555293 :open -> { :{} , [ ] , Enum . map ( elements , & to_quoted ( & 1 , opts ) ) ++ [ { :... , [ ] , nil } ] }
@@ -5359,7 +5397,7 @@ defmodule Module.Types.Descr do
53595397 end
53605398
53615399 defp tuple_get ( bdd , index ) do
5362- tuple_bdd_to_dnf ( bdd )
5400+ tuple_bdd_to_dnf_no_negations ( bdd )
53635401 |> Enum . reduce ( none ( ) , fn
53645402 { tag , elements } , acc -> Enum . at ( elements , index , tuple_tag_to_type ( tag ) ) |> union ( acc )
53655403 end )
@@ -5390,7 +5428,7 @@ defmodule Module.Types.Descr do
53905428 end
53915429
53925430 defp process_tuples_values ( bdd ) do
5393- tuple_bdd_to_dnf ( bdd )
5431+ tuple_bdd_to_dnf_no_negations ( bdd )
53945432 |> Enum . reduce ( none ( ) , fn { tag , elements } , acc ->
53955433 cond do
53965434 Enum . any? ( elements , & empty? / 1 ) -> none ( )
@@ -5528,7 +5566,7 @@ defmodule Module.Types.Descr do
55285566 defp tuple_of_size_at_least_static? ( descr , index ) do
55295567 case descr do
55305568 % { tuple: bdd } ->
5531- tuple_bdd_to_dnf ( bdd )
5569+ tuple_bdd_to_dnf_no_negations ( bdd )
55325570 |> Enum . all? ( fn { _ , elements } -> length ( elements ) >= index end )
55335571
55345572 % { } ->
0 commit comments