@@ -2311,6 +2311,19 @@ defmodule Module.Types.Descr do
23112311 acc
23122312 end
23132313
2314+ defp domain_key_to_descr ( domain_key ( :atom ) ) , do: atom ( )
2315+ defp domain_key_to_descr ( domain_key ( :binary ) ) , do: binary ( )
2316+ defp domain_key_to_descr ( domain_key ( :empty_list ) ) , do: empty_list ( )
2317+ defp domain_key_to_descr ( domain_key ( :integer ) ) , do: integer ( )
2318+ defp domain_key_to_descr ( domain_key ( :float ) ) , do: float ( )
2319+ defp domain_key_to_descr ( domain_key ( :pid ) ) , do: pid ( )
2320+ defp domain_key_to_descr ( domain_key ( :port ) ) , do: port ( )
2321+ defp domain_key_to_descr ( domain_key ( :reference ) ) , do: reference ( )
2322+ defp domain_key_to_descr ( domain_key ( :fun ) ) , do: fun ( )
2323+ defp domain_key_to_descr ( domain_key ( :tuple ) ) , do: tuple ( )
2324+ defp domain_key_to_descr ( domain_key ( :map ) ) , do: open_map ( )
2325+ defp domain_key_to_descr ( domain_key ( :list ) ) , do: non_empty_list ( term ( ) , term ( ) )
2326+
23142327 defp map_descr ( tag , pairs , default , force_domains? ) do
23152328 { fields , domains , dynamic? } = map_descr_pairs ( pairs , [ ] , % { } , false )
23162329
@@ -2921,148 +2934,184 @@ defmodule Module.Types.Descr do
29212934 end
29222935 end
29232936
2924- # def map_update(:term, key_descr, _type), do: :badmap
2925-
2926- # def map_update(descr, key_descr, :term),
2927- # do: map_update_shared(descr, key_descr, :term)
2928-
2929- # def map_update(descr, key_descr, type) do
2930- # case :maps.take(:dynamic, type) do
2931- # :error -> map_update_shared(descr, key_descr, type)
2932- # {dynamic, _static} -> map_update_shared(dynamic(descr), key_descr, dynamic)
2933- # end
2934- # end
2935-
2936- # defp map_update_shared(descr, key_descr, type) do
2937- # key_descr = upper_bound(key_descr)
2938-
2939- # case :maps.take(:dynamic, descr) do
2940- # :error ->
2941- # if descr_key?(descr, :map) and map_only?(descr) do
2942- # case map_existing_domains(descr, domain_keys) do
2943- # [] -> :badkey
2944- # domain_keys -> {:ok, map_update_domains(descr, domain_keys, type)}
2945- # end
2946- # else
2947- # :badmap
2948- # end
2949-
2950- # {dynamic, static} ->
2951- # if descr_key?(dynamic, :map) and map_only?(static) do
2952- # case map_existing_domains(dynamic, domain_keys) do
2953- # [] ->
2954- # :badkey
2955-
2956- # domain_keys ->
2957- # {:ok,
2958- # union(
2959- # dynamic(map_update_domains(dynamic, domain_keys, type)),
2960- # map_update_domains(static, domain_keys, type)
2961- # )}
2962- # end
2963- # else
2964- # :badmap
2965- # end
2966- # end
2967- # end
2968-
2969- # defp map_update_static(%{map: bdd}, key_descr, type) do
2970- # dnf = map_bdd_to_dnf(bdd)
2971- # {keys, key_descr} = map_split_keys(key_descr, bdd)
2972- # {optional, value, descr} = map_update_keys(dnf, keys, type)
2973-
2974- # key_descr
2975- # |> to_domain_keys()
2976- # |> Enum.reduce({optional, value, descr}, fn domain_key, acc ->
2977- # map_update_domain(dnf, domain_key) |> union(acc)
2978- # end)
2979- # end
2980-
2981- # defp map_update_static(%{}, _key_descr, _type) do
2982- # # No optional keys, no returned value, none is returned
2983- # {none(), none(), none()}
2984- # end
2985-
2986- # defp map_update_static(:term, key_descr, _type) do
2987- # # The whole key_descr is optional, returned value is term, open map is returned
2988- # {key_descr, term(), open_map()}
2989- # end
2990-
2991- # defp map_update_keys(dnf, keys, type) do
2992- # Enum.reduce(keys, {none(), none(), none()}, fn atom, {optional, value, acc} ->
2993- # {optional?, value, descr} = map_dnf_take_static(dnf, atom, value)
2994- # optional = if optional?, do: union(optional, atom([atom])), else: optional
2995- # descr = union(map_put_key_static(descr, atom, type), acc)
2996- # {optional, value, descr}
2997- # end)
2998- # end
2999-
3000- # defp map_update_atom_negation(%{atom: {:negation, atoms}} = descr, type) do
3001- # # 1) Fetch all the possible keys in the bdd
3002- # # 2) Get them all, except the ones in neg_atoms
3003- # all_fields = map_merge_all_fields(dnf)
3004- # acc = map_get_domain(dnf, domain_key(:atom))
3005-
3006- # for {atom, _} <- all_fields, not :sets.is_element(atom, atoms), reduce: acc do
3007- # acc ->
3008- # {static_optional?, type} = map_dnf_fetch_static(dnf, atom)
3009-
3010- # if static_optional? do
3011- # union(type, acc) |> nil_or_type() |> if_set()
3012- # else
3013- # union(type, acc)
3014- # end
3015- # end
3016- # end
3017-
3018- defp map_existing_domains ( % { map: bdd } , domain_keys ) do
3019- dnf = map_bdd_to_dnf ( bdd )
2937+ @ doc """
2938+ TODO
2939+ """
2940+ def map_update ( :term , _key_descr , _type ) , do: :badmap
30202941
3021- Enum . filter ( domain_keys , fn domain_key ->
3022- Enum . any? ( dnf , fn
3023- { :open , _fields , [ ] } ->
3024- true
2942+ def map_update ( descr , key_descr , :term ) ,
2943+ do: map_update_shared ( descr , key_descr , :term )
30252944
3026- { :closed , _fields , [ ] } ->
3027- false
2945+ def map_update ( descr , key_descr , type ) do
2946+ case :maps . take ( :dynamic , type ) do
2947+ :error -> map_update_shared ( descr , key_descr , type )
2948+ { dynamic , _static } -> map_update_shared ( dynamic ( descr ) , key_descr , dynamic )
2949+ end
2950+ end
2951+
2952+ defp map_update_shared ( descr , key_descr , type ) do
2953+ split_keys = map_split_keys_and_domains ( key_descr )
30282954
3029- { domains , _fields , [ ] } ->
3030- case domains do
3031- % { ^ domain_key => type } -> not empty_or_optional? ( type )
3032- % { } -> false
2955+ case :maps . take ( :dynamic , descr ) do
2956+ :error ->
2957+ if descr_key? ( descr , :map ) and map_only? ( descr ) do
2958+ { present? , _value , descr } =
2959+ map_update_static ( descr , split_keys , type , fn optional? , value ->
2960+ optional? or empty? ( value )
2961+ end )
2962+
2963+ if present? do
2964+ { :ok , descr }
2965+ else
2966+ { :badomain , key_descr }
30332967 end
2968+ else
2969+ :badmap
2970+ end
30342971
3035- { tag_or_domains , fields , negs } ->
3036- { fst , snd } = map_pop_domain ( tag_or_domains , fields , domain_key )
2972+ { dynamic , static } ->
2973+ if descr_key? ( dynamic , :map ) and map_only? ( static ) do
2974+ { static_present? , _value , static_descr } =
2975+ map_update_static ( descr , split_keys , type , fn optional? , _ -> optional? end )
30372976
3038- case map_split_negative_domain ( negs , domain_key ) do
3039- :empty ->
3040- false
2977+ { dynamic_present? , _value , dynamic_descr } =
2978+ map_update_static ( descr , split_keys , type , fn _ , value -> empty? ( value ) end )
30412979
3042- negative ->
3043- type =
2980+ if static_present? or dynamic_present? do
2981+ { :ok , union ( static_descr , dynamic ( dynamic_descr ) ) }
2982+ else
2983+ { :badomain , key_descr }
2984+ end
2985+ else
2986+ :badmap
2987+ end
2988+ end
2989+ end
2990+
2991+ defp map_update_static ( % { map: bdd } , split_keys , type , missing_fun ) do
2992+ { required_keys , optional_keys , maybe_negated_set , required_domains , optional_domains } =
2993+ split_keys
2994+
2995+ non_negated = map_materialize_negated_set ( maybe_negated_set , bdd )
2996+ dnf = map_bdd_to_dnf ( bdd )
2997+
2998+ case map_update_get_domains ( dnf , required_domains , none ( ) ) do
2999+ { required_domains , [ ] , value } ->
3000+ # Optional domains can miss
3001+ { optional_domains , _ , value } = map_update_get_domains ( dnf , optional_domains , value )
3002+
3003+ # If any of required or optional domains are satisfied, we are already good
3004+ present? = required_domains != [ ] or optional_domains != [ ]
3005+
3006+ # Now compute the initial return type. Note that map_update_static_keys works
3007+ # on the original bdd/dnf, not the one with updated domains
3008+ descr = map_update_put_domains ( bdd , required_domains ++ optional_domains , type )
3009+
3010+ map_update_static_keys (
3011+ dnf ,
3012+ required_keys ,
3013+ optional_keys ,
3014+ non_negated ,
3015+ type ,
3016+ missing_fun ,
3017+ { present? , value , descr }
3018+ )
3019+
3020+ { _ , [ missing_domain | _ ] , _ } ->
3021+ { :baddomain , domain_key_to_descr ( missing_domain ) }
3022+ end
3023+ end
3024+
3025+ defp map_update_static ( % { } , _split_keys , _type , _missing_fun ) do
3026+ { false , none ( ) , none ( ) }
3027+ end
3028+
3029+ defp map_update_static ( :term , split_keys , type , missing_fun ) do
3030+ # Since it is an open map, we don't need to check the domains...
3031+ { required_keys , optional_keys , maybe_negated_set , required_domains , optional_domains } =
3032+ split_keys
3033+
3034+ non_negated = :sets . to_list ( maybe_negated_set )
3035+ dnf = map_bdd_to_dnf ( @ map_top )
3036+ acc = { required_domains != [ ] or optional_domains != [ ] , term ( ) , open_map ( ) }
3037+ map_update_static_keys ( dnf , required_keys , optional_keys , non_negated , type , missing_fun , acc )
3038+ end
3039+
3040+ defp map_update_static_keys ( dnf , required , optional , non_negated , type , missing_fun , acc ) do
3041+ acc = map_update_keys ( dnf , required , type , :required , missing_fun , acc )
3042+ acc = map_update_keys ( dnf , optional , type , :optional , missing_fun , acc )
3043+ acc = map_update_keys ( dnf , non_negated , type , :optional , missing_fun , acc )
3044+ acc
3045+ catch
3046+ { :badkey , key } -> { :badkey , key }
3047+ end
3048+
3049+ defp map_update_keys ( dnf , keys , type , required_or_optional , missing_fun , acc ) do
3050+ Enum . reduce ( keys , acc , fn key , { present? , acc_value , acc_descr } ->
3051+ { optional? , value , descr } = map_dnf_take_static ( dnf , key , none ( ) )
3052+ value = union ( value , acc_value )
3053+ descr = union ( map_put_key_static ( descr , key , type ) , acc_descr )
3054+
3055+ missing? = missing_fun . ( optional? , value )
3056+ required_or_optional == :required and missing? and throw ( { :badkey , key } )
3057+ { present? or not missing? , value , descr }
3058+ end )
3059+ end
3060+
3061+ defp map_update_get_domains ( dnf , domain_keys , acc ) do
3062+ Enum . reduce ( domain_keys , { [ ] , [ ] , acc } , fn domain_key , { valid , invalid , acc } ->
3063+ value =
3064+ Enum . reduce ( dnf , none ( ) , fn
3065+ { :open , _fields , [ ] } , _acc ->
3066+ term ( )
3067+
3068+ { :closed , _fields , [ ] } , acc ->
3069+ acc
3070+
3071+ { domains , _fields , [ ] } , acc ->
3072+ case domains do
3073+ % { ^ domain_key => type } -> union ( remove_optional_static ( type ) , acc )
3074+ % { } -> acc
3075+ end
3076+
3077+ { tag_or_domains , fields , negs } , acc ->
3078+ { fst , snd } = map_pop_domain ( tag_or_domains , fields , domain_key )
3079+
3080+ case map_split_negative_domain ( negs , domain_key ) do
3081+ :empty ->
3082+ acc
3083+
3084+ negative ->
30443085 negative
30453086 |> pair_make_disjoint ( )
30463087 |> pair_eliminate_negations_fst ( fst , snd )
3088+ |> remove_optional_static ( )
3089+ |> union ( acc )
3090+ end
3091+ end )
30473092
3048- not empty_or_optional? ( type )
3049- end
3050- end )
3093+ if empty? ( value ) do
3094+ { valid , [ domain_key | invalid ] , acc }
3095+ else
3096+ { [ domain_key | valid ] , invalid , union ( acc , value ) }
3097+ end
30513098 end )
30523099 end
30533100
3054- defp map_update_domains ( % { map: bdd } , domain_keys , type ) do
3101+ defp map_update_put_domains ( bdd , domain_keys , type ) do
30553102 # For negations, we count on the idea that a negation will not remove any
30563103 # type from a domain unless it completely cancels out the type.
30573104 # So for any non-empty map bdd, we just update the domain with the new type,
30583105 # as well as its negations to keep them accurate.
30593106 % {
30603107 map:
3061- bdd_map ( bdd , fn { tag , fields } -> { map_update_domain ( tag , domain_keys , type ) , fields } end )
3108+ bdd_map ( bdd , fn { tag , fields } ->
3109+ { map_update_put_domain ( tag , domain_keys , type ) , fields }
3110+ end )
30623111 }
30633112 end
30643113
3065- defp map_update_domain ( tag_or_domains , domain_keys , type ) do
3114+ defp map_update_put_domain ( tag_or_domains , domain_keys , type ) do
30663115 case tag_or_domains do
30673116 :open ->
30683117 :open
@@ -3122,7 +3171,7 @@ defmodule Module.Types.Descr do
31223171 def map_get ( :term , _key_descr ) , do: :badmap
31233172
31243173 def map_get ( % { } = descr , key_descr ) do
3125- split_keys = map_split_keys ( key_descr )
3174+ split_keys = map_split_keys_and_domains ( key_descr )
31263175
31273176 case :maps . take ( :dynamic , descr ) do
31283177 :error ->
@@ -3162,11 +3211,11 @@ defmodule Module.Types.Descr do
31623211 defp nil_or_type ( type ) , do: union ( type , atom ( [ nil ] ) )
31633212
31643213 defp map_get_static ( % { map: bdd } , split_keys ) do
3165- dnf = map_bdd_to_dnf ( bdd )
3166-
31673214 { required_keys , optional_keys , maybe_negated_set , required_domains , optional_domains } =
31683215 split_keys
31693216
3217+ dnf = map_bdd_to_dnf ( bdd )
3218+
31703219 acc = none ( )
31713220 acc = map_get_keys ( dnf , required_keys , acc )
31723221 acc = map_get_keys ( dnf , optional_keys , acc )
@@ -3232,7 +3281,7 @@ defmodule Module.Types.Descr do
32323281 end
32333282
32343283 # Compute which keys are optional, which ones are required, as well as domain keys
3235- defp map_split_keys ( % { dynamic: dynamic } = static ) do
3284+ defp map_split_keys_and_domains ( % { dynamic: dynamic } = static ) do
32363285 { required_keys , optional_keys , maybe_negated_set } =
32373286 case { static , dynamic } do
32383287 { % { atom: { :union , static_union } } , % { atom: { :union , dynamic_union } } } ->
@@ -3264,20 +3313,20 @@ defmodule Module.Types.Descr do
32643313 { [ ] , [ ] , nil }
32653314 end
32663315
3267- required_domain = to_domain_keys ( Map . delete ( static , :dynamic ) )
3268- optional_domain = to_domain_keys ( dynamic ) -- required_domain
3269- { required_keys , optional_keys , maybe_negated_set , required_domain , optional_domain }
3316+ required_domains = to_domain_keys ( Map . delete ( static , :dynamic ) )
3317+ optional_domains = to_domain_keys ( dynamic ) -- required_domains
3318+ { required_keys , optional_keys , maybe_negated_set , required_domains , optional_domains }
32703319 end
32713320
3272- defp map_split_keys ( % { atom: { :union , atoms } } = key_descr ) do
3321+ defp map_split_keys_and_domains ( % { atom: { :union , atoms } } = key_descr ) do
32733322 { :sets . to_list ( atoms ) , [ ] , nil , to_domain_keys ( key_descr ) , [ ] }
32743323 end
32753324
3276- defp map_split_keys ( % { atom: { :negation , atoms } } = key_descr ) do
3325+ defp map_split_keys_and_domains ( % { atom: { :negation , atoms } } = key_descr ) do
32773326 { [ ] , [ ] , atoms , to_domain_keys ( key_descr ) , [ ] }
32783327 end
32793328
3280- defp map_split_keys ( key_descr ) do
3329+ defp map_split_keys_and_domains ( key_descr ) do
32813330 { [ ] , [ ] , nil , to_domain_keys ( key_descr ) , [ ] }
32823331 end
32833332
0 commit comments