@@ -303,12 +303,11 @@ defmodule Module.Types.Descr do
303303 end
304304 end
305305
306- defp remove_optional_static ( descr ) do
307- case descr do
308- % { optional: _ } -> Map . delete ( descr , :optional )
309- descr -> descr
310- end
311- end
306+ defp optional_static? ( % { optional: _ } ) , do: true
307+ defp optional_static? ( _ ) , do: false
308+
309+ defp remove_optional_static ( % { } = descr ) , do: Map . delete ( descr , :optional )
310+ defp remove_optional_static ( descr ) , do: descr
312311
313312 defp optional_to_term ( descr ) do
314313 case descr do
@@ -2730,7 +2729,7 @@ defmodule Module.Types.Descr do
27302729 { tag , fields , negs } , acc ->
27312730 { fst , snd } = map_pop_key ( tag , fields , key )
27322731
2733- case map_split_negative ( negs , key ) do
2732+ case map_split_negative_key ( negs , key ) do
27342733 :empty ->
27352734 acc
27362735
@@ -2772,59 +2771,53 @@ defmodule Module.Types.Descr do
27722771
27732772 defp map_put_key_static ( descr , _key , _type ) , do: descr
27742773
2775- @ doc """
2776- Removes a key from a map type and return its type.
2777-
2778- ## Algorithm
2779-
2780- 1. Split the map type based on the presence of the key.
2781- 2. Take the second part of the split, which represents the union of all
2782- record types where the key has been explicitly removed.
2783- 3. Intersect this with an open record type where the key is explicitly absent.
2784- This step eliminates the key from open record types where it was implicitly present.
2785- """
2786- # TODO: This should not be exposed
2787- def map_take_key ( descr , key ) do
2788- map_take_key ( descr , key , none ( ) , & intersection_static ( & 1 , open_map ( [ { key , not_set ( ) } ] ) ) )
2789- end
2790-
2791- # If initial is nil, note we don't compute the value
2774+ # Removes a key from a map type and return its type.
2775+ #
2776+ # ## Algorithm
2777+ #
2778+ # 1. Split the map type based on the presence of the key.
2779+ # 2. Take the second part of the split, which represents the union of all
2780+ # record types where the key has been explicitly removed.
2781+ # 3. Intersect this with an open record type where the key is explicitly absent.
2782+ # This step eliminates the key from open record types where it was implicitly present.
2783+ #
2784+ # Note: if initial is nil, it means the value is not required.
2785+ # So we don't compute it for performance.
27922786 defp map_take_key ( :term , _key , _initial , _updater ) , do: :badmap
27932787
27942788 defp map_take_key ( descr , key , initial , updater ) when is_atom ( key ) do
27952789 case :maps . take ( :dynamic , descr ) do
27962790 :error ->
27972791 if descr_key? ( descr , :map ) and map_only? ( descr ) do
2798- { optional? , taken , result } =
2799- map_take_key_static ( descr , key , initial )
2792+ { taken , result } = map_take_key_static ( descr , key , initial )
28002793
2801- cond do
2802- taken == nil -> { nil , updater . ( result ) }
2803- optional? or empty? ( taken ) -> :badkey
2804- true -> { taken , updater . ( result ) }
2794+ if taken == nil do
2795+ { nil , updater . ( result ) }
2796+ else
2797+ { optional? , taken } = pop_optional_static ( taken )
2798+ if optional? or empty? ( taken ) , do: :badkey , else: { taken , updater . ( result ) }
28052799 end
28062800 else
28072801 :badmap
28082802 end
28092803
28102804 { dynamic , static } ->
28112805 if descr_key? ( dynamic , :map ) and map_only? ( static ) do
2812- { _ , dynamic_taken , dynamic_result } = map_take_key_static ( dynamic , key , initial )
2813-
2814- { static_optional? , static_taken , static_result } =
2815- map_take_key_static ( static , key , initial )
2816-
2806+ { dynamic_taken , dynamic_result } = map_take_key_static ( dynamic , key , initial )
2807+ { static_taken , static_result } = map_take_key_static ( static , key , initial )
28172808 result = union ( dynamic ( updater . ( dynamic_result ) ) , updater . ( static_result ) )
28182809
2819- cond do
2820- static_taken == nil and dynamic_taken == nil ->
2821- { nil , result }
2810+ if static_taken == nil and dynamic_taken == nil do
2811+ { nil , result }
2812+ else
2813+ { static_optional? , static_taken } = pop_optional_static ( static_taken )
2814+ { _dynamic_optional? , dynamic_taken } = pop_optional_static ( dynamic_taken )
28222815
2823- static_optional? or empty? ( dynamic_taken ) ->
2816+ if static_optional? or empty? ( dynamic_taken ) do
28242817 :badkey
2825-
2826- true ->
2818+ else
28272819 { union ( dynamic ( dynamic_taken ) , static_taken ) , result }
2820+ end
28282821 end
28292822 else
28302823 :badmap
@@ -2840,11 +2833,11 @@ defmodule Module.Types.Descr do
28402833
28412834 # If there is no map part to this static type, there is nothing to delete.
28422835 defp map_take_key_static ( % { } , _key , initial ) do
2843- { false , initial , none ( ) }
2836+ { initial , none ( ) }
28442837 end
28452838
28462839 defp map_take_key_static ( :term , _key , initial ) do
2847- { true , maybe_union ( initial , fn -> term ( ) end ) , open_map ( ) }
2840+ { maybe_union ( initial , fn -> term ( ) end ) , open_map ( ) }
28482841 end
28492842
28502843 defp map_dnf_take_key_static ( dnf , key , initial ) do
@@ -2858,7 +2851,7 @@ defmodule Module.Types.Descr do
28582851 { tag , fields , negs } , { value , map } ->
28592852 { fst , snd } = map_pop_key ( tag , fields , key )
28602853
2861- case map_split_negative ( negs , key ) do
2854+ case map_split_negative_key ( negs , key ) do
28622855 :empty ->
28632856 { value , map }
28642857
@@ -2870,13 +2863,7 @@ defmodule Module.Types.Descr do
28702863 end
28712864 end )
28722865
2873- if value == nil do
2874- # The boolean is unused when value is nil
2875- { true , value , descr }
2876- else
2877- { optional? , value } = pop_optional_static ( value )
2878- { optional? , value , descr }
2879- end
2866+ { value , descr }
28802867 end
28812868
28822869 @ doc """
@@ -2902,14 +2889,15 @@ defmodule Module.Types.Descr do
29022889 case :maps . take ( :dynamic , descr ) do
29032890 :error ->
29042891 if descr_key? ( descr , :map ) and map_only? ( descr ) do
2905- with { present? , _maybe_optional_value , descr } <-
2906- map_update_static ( descr , split_keys , type , fn optional? , value ->
2907- optional? or empty? ( value )
2892+ with { :ok , { _type , descr } } <-
2893+ map_update_static ( descr , split_keys , type , fn type ->
2894+ { optional? , type } = pop_optional_static ( type )
2895+ optional? or empty? ( type )
29082896 end ) do
2909- if present? do
2910- { :ok , descr }
2911- else
2897+ if descr == none ( ) do
29122898 { :baddomain , key_descr }
2899+ else
2900+ { :ok , descr }
29132901 end
29142902 end
29152903 else
@@ -2918,14 +2906,14 @@ defmodule Module.Types.Descr do
29182906
29192907 { dynamic , static } ->
29202908 if descr_key? ( dynamic , :map ) and map_only? ( static ) do
2921- with { static_present? , _maybe_optional_static_value , static_descr } <-
2922- map_update_static ( static , split_keys , type , fn optional? , _ -> optional? end ) ,
2923- { dynamic_present? , _maybe_optional_dynamic_value , dynamic_descr } <-
2924- map_update_static ( dynamic , split_keys , type , fn _ , value -> empty? ( value ) end ) do
2925- if static_present? or dynamic_present? do
2926- { :ok , union ( static_descr , dynamic ( dynamic_descr ) ) }
2927- else
2909+ with { :ok , { _static_value , static_descr } } <-
2910+ map_update_static ( static , split_keys , type , & optional_static? / 1 ) ,
2911+ { :ok , { _dynamic_value , dynamic_descr } } <-
2912+ map_update_static ( dynamic , split_keys , type , & empty_or_optional? / 1 ) do
2913+ if dynamic_descr == none ( ) do
29282914 { :baddomain , key_descr }
2915+ else
2916+ { :ok , union ( static_descr , dynamic ( dynamic_descr ) ) }
29292917 end
29302918 end
29312919 else
@@ -2962,9 +2950,9 @@ defmodule Module.Types.Descr do
29622950 # initial return type. `map_update_static_keys` will then union into the
29632951 # computed type below, using the original bdd/dnf, not the one with updated domains.
29642952 descr = map_update_put_domains ( bdd , required_domains ++ optional_domains , type )
2965- { true , value , descr }
2953+ { value , descr }
29662954 else
2967- { false , value , none ( ) }
2955+ { value , none ( ) }
29682956 end
29692957
29702958 map_update_static_keys ( dnf , required_keys , optional_keys , type , missing_fun , acc )
@@ -2975,7 +2963,7 @@ defmodule Module.Types.Descr do
29752963 end
29762964
29772965 defp map_update_static ( % { } , _split_keys , _type , _missing_fun ) do
2978- { false , none ( ) , none ( ) }
2966+ { :ok , { none ( ) , none ( ) } }
29792967 end
29802968
29812969 defp map_update_static ( :term , split_keys , type , missing_fun ) do
@@ -2985,28 +2973,39 @@ defmodule Module.Types.Descr do
29852973 { required_keys , optional_keys , _maybe_negated_set , required_domains , optional_domains } =
29862974 split_keys
29872975
2988- dnf = map_bdd_to_dnf ( @ map_top )
2989- acc = { required_domains != [ ] or optional_domains != [ ] , term ( ) , open_map ( ) }
2990- map_update_static_keys ( dnf , required_keys , optional_keys , type , missing_fun , acc )
2976+ if required_domains != [ ] or optional_domains != [ ] do
2977+ { :ok , { term ( ) , open_map ( ) } }
2978+ else
2979+ acc = { none ( ) , none ( ) }
2980+ dnf = map_bdd_to_dnf ( @ map_top )
2981+ map_update_static_keys ( dnf , required_keys , optional_keys , type , missing_fun , acc )
2982+ end
29912983 end
29922984
29932985 defp map_update_static_keys ( dnf , required , optional , type , missing_fun , acc ) do
29942986 acc = map_update_keys ( dnf , required , type , :required , missing_fun , acc )
29952987 acc = map_update_keys ( dnf , optional , type , :optional , missing_fun , acc )
2996- acc
2988+ { :ok , acc }
29972989 catch
29982990 { :badkey , key } -> { :badkey , key }
29992991 end
30002992
30012993 defp map_update_keys ( dnf , keys , type , required_or_optional , missing_fun , acc ) do
3002- Enum . reduce ( keys , acc , fn key , { present? , acc_value , acc_descr } ->
3003- { optional? , value , descr } = map_dnf_take_key_static ( dnf , key , none ( ) )
3004- missing? = missing_fun . ( optional? , value )
3005-
3006- required_or_optional == :required and missing? and throw ( { :badkey , key } )
3007- acc_value = union ( value , acc_value )
3008- acc_descr = union ( map_put_key_static ( descr , key , type ) , acc_descr )
3009- { present? or not missing? , acc_value , acc_descr }
2994+ Enum . reduce ( keys , acc , fn key , { acc_value , acc_descr } ->
2995+ { value , descr } = map_dnf_take_key_static ( dnf , key , none ( ) )
2996+
2997+ cond do
2998+ not missing_fun . ( value ) ->
2999+ acc_value = union ( value , acc_value )
3000+ acc_descr = union ( map_put_key_static ( descr , key , type ) , acc_descr )
3001+ { acc_value , acc_descr }
3002+
3003+ required_or_optional == :required ->
3004+ throw ( { :badkey , key } )
3005+
3006+ true ->
3007+ { acc_value , acc_descr }
3008+ end
30103009 end )
30113010 end
30123011
@@ -3454,11 +3453,11 @@ defmodule Module.Types.Descr do
34543453 end
34553454 end
34563455
3457- # Atom case
3456+ # Open/close key
34583457 defp map_pop_domain ( tag , fields , _domain_key ) ,
34593458 do: { map_key_tag_to_type ( tag ) , % { map: map_new ( tag , fields ) } }
34603459
3461- defp map_split_negative ( negs , key ) do
3460+ defp map_split_negative_key ( negs , key ) do
34623461 Enum . reduce_while ( negs , [ ] , fn
34633462 # A negation with an open map means the whole thing is empty.
34643463 { :open , fields } , _acc when map_size ( fields ) == 0 -> { :halt , :empty }
0 commit comments