@@ -839,6 +839,9 @@ defmodule Module.Types.Descr do
839839 defp print_as_negated_bdd ( bdd_leaf ( _ , _ ) , _top ) , do: 0
840840 defp print_as_negated_bdd ( bdd , top ) , do: if ( negated_bdd? ( bdd , top ) , do: 1 , else: - 100 )
841841
842+ defp negated_bdd? ( { top , bdd , :bdd_bot , :bdd_bot } , top ) ,
843+ do: negated_bdd? ( bdd , top )
844+
842845 defp negated_bdd? ( { _ , :bdd_bot , :bdd_bot , bdd } , top ) ,
843846 do: bdd in [ :bdd_top , top ] or negated_bdd? ( bdd , top )
844847
@@ -3090,17 +3093,24 @@ defmodule Module.Types.Descr do
30903093 #
30913094 # Outside of this particular scenario, the `a_int` optimization has been useful,
30923095 # but we haven't measured benefits for `a_union`.
3093- defp map_leaf_difference ( bdd_leaf ( tag , fields ) , bdd_leaf ( :open , [ { key , v2 } ] ) , :none ) do
3096+ defp map_leaf_difference ( bdd_leaf ( tag , fields ) , bdd_leaf ( :open , [ { key , v2 } ] ) , type ) do
30943097 { found? , v1 } =
30953098 case fields_find ( key , fields ) do
30963099 { :ok , value } -> { true , value }
30973100 :error -> { false , map_key_tag_to_type ( tag ) }
30983101 end
30993102
3100- if tag == :closed and not found? and not is_optional_static ( v2 ) do
3101- :disjoint
3102- else
3103- map_leaf_one_key_difference ( tag , fields , key , v1 , v2 , :none )
3103+ cond do
3104+ tag == :closed and not found? and not is_optional_static ( v2 ) ->
3105+ :disjoint
3106+
3107+ tag == :open and not found? ->
3108+ # In case the left-side is open, we will only be adding new keys
3109+ # to the open map, which makes future eliminations harder.
3110+ :none
3111+
3112+ true ->
3113+ map_leaf_one_key_difference ( tag , fields , key , v1 , v2 , type )
31043114 end
31053115 end
31063116
@@ -3709,8 +3719,11 @@ defmodule Module.Types.Descr do
37093719 { required_keys , optional_keys , maybe_negated_set , required_domains , optional_domains } =
37103720 split_keys
37113721
3722+ optional_keys =
3723+ ( ( map_keys_from_negated_set ( maybe_negated_set , bdd ) -- optional_keys ) -- required_keys ) ++
3724+ optional_keys
3725+
37123726 dnf = map_bdd_to_dnf_with_empty ( bdd )
3713- bdd = map_update_put_negated ( bdd , maybe_negated_set , type_fun )
37143727
37153728 { found? , value , domains , errors } =
37163729 if force? and not return_type? do
@@ -3874,29 +3887,6 @@ defmodule Module.Types.Descr do
38743887 end
38753888 end
38763889
3877- # For keys with `not :foo`, we generate an approximation
3878- # by adding the type to all keys, except `:foo`.
3879- defp map_update_put_negated ( bdd , nil , _type_fun ) , do: bdd
3880-
3881- defp map_update_put_negated ( bdd , negated , type_fun ) do
3882- bdd_map ( bdd , fn { tag , fields } ->
3883- fields =
3884- fields_map (
3885- fn key , value ->
3886- if :sets . is_element ( key , negated ) do
3887- value
3888- else
3889- { optional? , call_value } = pop_optional_static ( value )
3890- union ( value , type_fun . ( optional? , call_value ) )
3891- end
3892- end ,
3893- fields
3894- )
3895-
3896- { tag , fields }
3897- end )
3898- end
3899-
39003890 defp map_update_merge_atom_key ( bdd , dnf ) do
39013891 { _seen , acc } =
39023892 bdd_reduce ( bdd , { % { } , none ( ) } , fn { _tag , fields } , seen_acc ->
@@ -4079,8 +4069,11 @@ defmodule Module.Types.Descr do
40794069 { required_keys , optional_keys , maybe_negated_set , required_domains , optional_domains } =
40804070 split_keys
40814071
4072+ optional_keys =
4073+ ( ( map_keys_from_negated_set ( maybe_negated_set , bdd ) -- optional_keys ) -- required_keys ) ++
4074+ optional_keys
4075+
40824076 type_fun = fn _ , _ -> type end
4083- bdd = map_update_put_negated ( bdd , maybe_negated_set , type_fun )
40844077
40854078 descr =
40864079 case required_domains ++ optional_domains do
@@ -4171,7 +4164,7 @@ defmodule Module.Types.Descr do
41714164 acc = none ( )
41724165 acc = map_get_keys ( dnf , required_keys , acc )
41734166 acc = map_get_keys ( dnf , optional_keys , acc )
4174- acc = map_get_keys ( dnf , map_materialize_negated_set ( maybe_negated_set , bdd ) , acc )
4167+ acc = map_get_keys ( dnf , map_keys_from_negated_set ( maybe_negated_set , bdd ) , acc )
41754168 acc = Enum . reduce ( required_domains , acc , & map_get_domain_no_optional ( dnf , & 1 , & 2 ) )
41764169 acc = Enum . reduce ( optional_domains , acc , & map_get_domain_no_optional ( dnf , & 1 , & 2 ) )
41774170 remove_optional ( acc )
@@ -4206,9 +4199,9 @@ defmodule Module.Types.Descr do
42064199 end )
42074200 end
42084201
4209- defp map_materialize_negated_set ( nil , _bdd ) , do: [ ]
4202+ defp map_keys_from_negated_set ( nil , _bdd ) , do: [ ]
42104203
4211- defp map_materialize_negated_set ( set , bdd ) do
4204+ defp map_keys_from_negated_set ( set , bdd ) do
42124205 bdd
42134206 |> bdd_reduce ( % { } , fn { _ , fields } , acc ->
42144207 fields_fold ( fields , acc , fn atom , _ , acc ->
@@ -5901,7 +5894,7 @@ defmodule Module.Types.Descr do
59015894 # and the union of said keys, returning a_union and a_diff:
59025895 #
59035896 # ((a1 and C1) or U1 or (not a1 and D1)) and not a2
5904- # (a_diff and C1) or (U1 and not a2) or (not a1 and not a2 and D1)
5897+ # (a_diff and C1) or (U1 and not a2) or (not a_union and D1)
59055898 #
59065899 defp bdd_difference ( { a1 , c1 , u1 , d1 } = bdd1 , bdd_leaf ( _ , _ ) = bdd2 , leaf_compare )
59075900 when is_tuple ( bdd2 ) do
0 commit comments