@@ -29,18 +29,18 @@ defmodule Module.Types.Descr do
2929 defmacrop domain_key ( key ) , do: { :domain_key , key }
3030
3131 @ domain_key_types [
32- : binary,
33- : empty_list,
34- : integer,
35- : float,
36- : pid,
37- : port,
38- : reference,
39- : fun,
40- : atom,
41- : tuple,
42- : map,
43- : list
32+ { :domain_key , : binary} ,
33+ { :domain_key , : empty_list} ,
34+ { :domain_key , : integer} ,
35+ { :domain_key , : float} ,
36+ { :domain_key , : pid} ,
37+ { :domain_key , : port} ,
38+ { :domain_key , : reference} ,
39+ { :domain_key , : fun} ,
40+ { :domain_key , : atom} ,
41+ { :domain_key , : tuple} ,
42+ { :domain_key , : map} ,
43+ { :domain_key , : list}
4444 ]
4545
4646 @ fun_top :fun_top
@@ -90,40 +90,16 @@ defmodule Module.Types.Descr do
9090 def atom ( as ) , do: % { atom: atom_new ( as ) }
9191 def atom ( ) , do: % { atom: @ atom_top }
9292 def binary ( ) , do: % { bitmap: @ bit_binary }
93-
94- def closed_map ( pairs ) do
95- { regular_pairs , domain_pairs } = split_domain_key_pairs ( pairs )
96- domain_pairs = validate_domain_keys ( domain_pairs )
97-
98- if domain_pairs == [ ] ,
99- do: map_descr ( :closed , regular_pairs ) ,
100- else: map_descr ( domain_pairs , regular_pairs )
101- end
102-
93+ def closed_map ( pairs ) , do: map_descr ( :closed , pairs , @ term_or_optional , false )
10394 def empty_list ( ) , do: % { bitmap: @ bit_empty_list }
10495 def empty_map ( ) , do: % { map: @ map_empty }
10596 def integer ( ) , do: % { bitmap: @ bit_integer }
10697 def float ( ) , do: % { bitmap: @ bit_float }
10798 def list ( type ) , do: list_descr ( type , @ empty_list , true )
10899 def non_empty_list ( type , tail \\ @ empty_list ) , do: list_descr ( type , tail , false )
109-
110100 def open_map ( ) , do: % { map: @ map_top }
111- def open_map ( pairs ) , do: open_map ( pairs , @ term_or_optional , false )
112- def open_map ( pairs , default ) , do: open_map ( pairs , if_set ( default ) , true )
113-
114- defp open_map ( pairs , default , force? ) do
115- { regular_pairs , domain_pairs } = split_domain_key_pairs ( pairs )
116- domain_pairs = validate_domain_keys ( domain_pairs )
117-
118- if domain_pairs != [ ] or force? ,
119- do:
120- Map . new ( @ domain_key_types , fn key_type -> { domain_key ( key_type ) , default } end )
121- |> Map . merge ( Map . new ( domain_pairs ) )
122- |> Map . to_list ( )
123- |> map_descr ( regular_pairs ) ,
124- else: map_descr ( :open , regular_pairs )
125- end
126-
101+ def open_map ( pairs ) , do: map_descr ( :open , pairs , @ term_or_optional , false )
102+ def open_map ( pairs , default ) , do: map_descr ( :open , pairs , if_set ( default ) , true )
127103 def open_tuple ( elements , _fallback \\ term ( ) ) , do: tuple_descr ( :open , elements )
128104 def pid ( ) , do: % { bitmap: @ bit_pid }
129105 def port ( ) , do: % { bitmap: @ bit_port }
@@ -2238,43 +2214,56 @@ defmodule Module.Types.Descr do
22382214 # The type %{..., atom() => integer()} represents maps with atom keys bound to integers,
22392215 # and other keys bound to any type, represented by {{:closed, %{atom: integer()}}, %{}, []}.
22402216
2241- defp map_descr ( tag , fields ) when is_atom ( tag ) do
2242- case map_descr_pairs ( fields , [ ] , false ) do
2243- { fields , true } ->
2244- % { dynamic: % { map: map_new ( tag , fields |> Enum . reverse ( ) |> :maps . from_list ( ) ) } }
2217+ defp map_descr ( tag , pairs , default , force? ) do
2218+ { fields , domains , dynamic? } = map_descr_pairs ( pairs , [ ] , % { } , false )
22452219
2246- { _ , false } ->
2247- % { map: map_new ( tag , :maps . from_list ( fields ) ) }
2220+ map_new =
2221+ if domains != % { } or force? do
2222+ domains =
2223+ if tag == :open do
2224+ Enum . reduce ( @ domain_key_types , domains , & Map . put_new ( & 2 , & 1 , default ) )
2225+ else
2226+ domains
2227+ end
2228+
2229+ map_new ( { tag , domains } , fields )
2230+ else
2231+ map_new ( tag , fields )
2232+ end
2233+
2234+ case dynamic? do
2235+ true -> % { dynamic: % { map: map_new } }
2236+ false -> % { map: map_new }
22482237 end
22492238 end
22502239
2251- defp map_descr ( domains , fields ) do
2252- { fields , fields_dynamic? } = map_descr_pairs ( fields , [ ] , false )
2253- { domains , domains_dynamic? } = map_descr_pairs ( domains , [ ] , false )
2254-
2255- fields_map = :maps . from_list ( if fields_dynamic? , do: Enum . reverse ( fields ) , else: fields )
2256- domains_map = :maps . from_list ( if domains_dynamic? , do: Enum . reverse ( domains ) , else: domains )
2240+ # TOD: Double check if we indeed want the union here
2241+ defp map_put_domain ( domain , key , value ) do
2242+ Map . update ( domain , key , if_set ( value ) , & union ( & 1 , value ) )
2243+ end
22572244
2258- if fields_dynamic? or domains_dynamic? do
2259- % { dynamic: % { map: map_new ( :closed , fields_map , domains_map ) } }
2260- else
2261- % { map: map_new ( :closed , fields_map , domains_map ) }
2245+ defp map_descr_pairs ( [ { key , :term } | rest ] , fields , domain , dynamic? ) do
2246+ case is_atom ( key ) do
2247+ true -> map_descr_pairs ( rest , [ { key , :term } | fields ] , domain , dynamic? )
2248+ false -> map_descr_pairs ( rest , fields , map_put_domain ( domain , key , :term ) , dynamic? )
22622249 end
22632250 end
22642251
2265- defp map_descr_pairs ( [ { key , :term } | rest ] , acc , dynamic? ) do
2266- map_descr_pairs ( rest , [ { key , :term } | acc ] , dynamic? )
2267- end
2252+ defp map_descr_pairs ( [ { key , value } | rest ] , fields , domain , dynamic? ) do
2253+ { value , dynamic? } =
2254+ case :maps . take ( :dynamic , value ) do
2255+ :error -> { value , dynamic? }
2256+ { dynamic , _static } -> { dynamic , true }
2257+ end
22682258
2269- defp map_descr_pairs ( [ { key , value } | rest ] , acc , dynamic? ) do
2270- case :maps . take ( :dynamic , value ) do
2271- :error -> map_descr_pairs ( rest , [ { key , value } | acc ] , dynamic? )
2272- { dynamic , _static } -> map_descr_pairs ( rest , [ { key , dynamic } | acc ] , true )
2259+ case is_atom ( key ) do
2260+ true -> map_descr_pairs ( rest , [ { key , value } | fields ] , domain , dynamic? )
2261+ false -> map_descr_pairs ( rest , fields , map_put_domain ( domain , key , value ) , dynamic? )
22732262 end
22742263 end
22752264
2276- defp map_descr_pairs ( [ ] , acc , dynamic? ) do
2277- { acc , dynamic? }
2265+ defp map_descr_pairs ( [ ] , fields , domain , dynamic? ) do
2266+ { fields |> Enum . reverse ( ) |> :maps . from_list ( ) , domain , dynamic? }
22782267 end
22792268
22802269 # TODO: Rename this to tuple_tag_to_type
@@ -2289,40 +2278,10 @@ defmodule Module.Types.Descr do
22892278 defp map_key_tag_to_type ( { :open , domain } ) ,
22902279 do: Map . get ( domain , domain_key ( :atom ) , term_or_optional ( ) )
22912280
2292- # Helpers for domain key validation
2293- # TODO: Merge this and the next clause into one
2294- defp split_domain_key_pairs ( pairs ) do
2295- Enum . split_with ( pairs , fn
2296- { domain_key ( _ ) , _ } -> false
2297- _ -> true
2298- end )
2299- end
2300-
2301- defp validate_domain_keys ( pairs ) do
2302- # Check if domain keys are valid and don't overlap
2303- domains = Enum . map ( pairs , fn { domain_key ( domain ) , _ } -> domain end )
2304-
2305- if length ( domains ) != length ( Enum . uniq ( domains ) ) do
2306- raise ArgumentError , "Domain key types should not overlap"
2307- end
2308-
2309- # Check that all domain keys are valid
2310- invalid_domains = Enum . reject ( domains , & ( & 1 in @ domain_key_types ) )
2311-
2312- if invalid_domains != [ ] do
2313- raise ArgumentError ,
2314- "Invalid domain key types: #{ inspect ( invalid_domains ) } . " <>
2315- "Valid types are: #{ inspect ( @ domain_key_types ) } "
2316- end
2317-
2318- Enum . map ( pairs , fn { key , type } -> { key , if_set ( type ) } end )
2319- end
2320-
23212281 defguardp is_optional_static ( map )
23222282 when is_map ( map ) and is_map_key ( map , :optional )
23232283
23242284 defp map_new ( tag , fields = % { } ) , do: [ { tag , fields , [ ] } ]
2325- defp map_new ( tag , fields = % { } , domains = % { } ) , do: [ { { tag , domains } , fields , [ ] } ]
23262285
23272286 defp map_only? ( descr ) , do: empty? ( Map . delete ( descr , :map ) )
23282287
@@ -2534,15 +2493,15 @@ defmodule Module.Types.Descr do
25342493 new_domains =
25352494 for domain_key <- @ domain_key_types , reduce: % { } do
25362495 acc_domains ->
2537- type1 = Map . get ( domains1 , domain_key ( domain_key ) , default1 )
2538- type2 = Map . get ( domains2 , domain_key ( domain_key ) , default2 )
2496+ type1 = Map . get ( domains1 , domain_key , default1 )
2497+ type2 = Map . get ( domains2 , domain_key , default2 )
25392498
25402499 inter = intersection ( type1 , type2 )
25412500
25422501 if empty? ( inter ) do
25432502 acc_domains
25442503 else
2545- Map . put ( acc_domains , domain_key ( domain_key ) , inter )
2504+ Map . put ( acc_domains , domain_key , inter )
25462505 end
25472506 end
25482507
@@ -2781,8 +2740,8 @@ defmodule Module.Types.Descr do
27812740 { :atom , atom_key } , acc ->
27822741 map_refresh_atom ( acc , atom_key , type )
27832742
2784- key , acc ->
2785- map_refresh_domain ( acc , key , type )
2743+ domain_key , acc ->
2744+ map_refresh_domain ( acc , domain_key , type )
27862745 end )
27872746
27882747 { :ok , new_descr }
@@ -2861,27 +2820,27 @@ defmodule Module.Types.Descr do
28612820 considered_keys
28622821 |> :sets . to_list ( )
28632822 |> Enum . reduce ( descr , fn key , acc -> map_refresh_key ( acc , key , type ) end )
2864- |> map_refresh_domain ( :atom , type )
2823+ |> map_refresh_domain ( domain_key ( :atom ) , type )
28652824 end
28662825 end
28672826
2868- def map_refresh_tag ( tag , domain , type ) do
2827+ def map_refresh_tag ( tag , domain_key , type ) do
28692828 case tag do
28702829 :open ->
28712830 :open
28722831
28732832 :closed ->
2874- { :closed , % { domain_key ( domain ) => if_set ( type ) } }
2833+ { :closed , % { domain_key => if_set ( type ) } }
28752834
28762835 { :open , domains } ->
2877- if Map . has_key? ( domains , domain_key ( domain ) ) do
2878- { :open , Map . update! ( domains , domain_key ( domain ) , & union ( & 1 , type ) ) }
2836+ if Map . has_key? ( domains , domain_key ) do
2837+ { :open , Map . update! ( domains , domain_key , & union ( & 1 , type ) ) }
28792838 else
28802839 { :open , domains }
28812840 end
28822841
28832842 { :closed , domains } ->
2884- { :closed , Map . update ( domains , domain_key ( domain ) , if_set ( type ) , & union ( & 1 , type ) ) }
2843+ { :closed , Map . update ( domains , domain_key , if_set ( type ) , & union ( & 1 , type ) ) }
28852844 end
28862845 end
28872846
@@ -3007,21 +2966,22 @@ defmodule Module.Types.Descr do
30072966 cond do
30082967 type_kind == :atom -> [ { :atom , type } | acc ]
30092968 type_kind == :bitmap -> bitmap_to_domain_keys ( type ) ++ acc
3010- not empty? ( % { type_kind => type } ) -> [ type_kind | acc ]
2969+ not empty? ( % { type_kind => type } ) -> [ domain_key ( type_kind ) | acc ]
30112970 true -> acc
30122971 end
30132972 end
30142973 end
30152974
2975+ # TODO: Optimize this
30162976 defp bitmap_to_domain_keys ( bitmap ) do
30172977 [
3018- if ( ( bitmap &&& @ bit_binary ) != 0 , do: :binary ) ,
3019- if ( ( bitmap &&& @ bit_empty_list ) != 0 , do: :empty_list ) ,
3020- if ( ( bitmap &&& @ bit_integer ) != 0 , do: :integer ) ,
3021- if ( ( bitmap &&& @ bit_float ) != 0 , do: :float ) ,
3022- if ( ( bitmap &&& @ bit_pid ) != 0 , do: :pid ) ,
3023- if ( ( bitmap &&& @ bit_port ) != 0 , do: :port ) ,
3024- if ( ( bitmap &&& @ bit_reference ) != 0 , do: :reference )
2978+ if ( ( bitmap &&& @ bit_binary ) != 0 , do: domain_key ( :binary ) ) ,
2979+ if ( ( bitmap &&& @ bit_empty_list ) != 0 , do: domain_key ( :empty_list ) ) ,
2980+ if ( ( bitmap &&& @ bit_integer ) != 0 , do: domain_key ( :integer ) ) ,
2981+ if ( ( bitmap &&& @ bit_float ) != 0 , do: domain_key ( :float ) ) ,
2982+ if ( ( bitmap &&& @ bit_pid ) != 0 , do: domain_key ( :pid ) ) ,
2983+ if ( ( bitmap &&& @ bit_port ) != 0 , do: domain_key ( :port ) ) ,
2984+ if ( ( bitmap &&& @ bit_reference ) != 0 , do: domain_key ( :reference ) )
30252985 ]
30262986 |> Enum . reject ( & is_nil / 1 )
30272987 end
@@ -3042,7 +3002,7 @@ defmodule Module.Types.Descr do
30423002
30433003 key_type , acc ->
30443004 # Note: we could stop if we reach term()_or_optional()
3045- Map . get ( domains , domain_key ( key_type ) , map_key_tag_to_type ( tag ) ) |> union ( acc )
3005+ Map . get ( domains , key_type , map_key_tag_to_type ( tag ) ) |> union ( acc )
30463006 end )
30473007 end
30483008
@@ -3053,8 +3013,8 @@ defmodule Module.Types.Descr do
30533013 { :atom , atom_type } , acc ->
30543014 map_get_atom ( dnf , atom_type ) |> union ( acc )
30553015
3056- key_type , acc ->
3057- map_get_domain ( dnf , key_type ) |> union ( acc )
3016+ domain_key , acc ->
3017+ map_get_domain ( dnf , domain_key ) |> union ( acc )
30583018 end )
30593019 end
30603020
@@ -3107,7 +3067,7 @@ defmodule Module.Types.Descr do
31073067 union ( type , acc )
31083068 end
31093069 end )
3110- |> union ( map_get_domain ( dnf , :atom ) )
3070+ |> union ( map_get_domain ( dnf , domain_key ( :atom ) ) )
31113071 end
31123072 end
31133073
@@ -3127,24 +3087,24 @@ defmodule Module.Types.Descr do
31273087 end
31283088
31293089 # Take a map dnf and return the union of types for the given key domain.
3130- def map_get_domain ( dnf , key_domain ) when is_atom ( key_domain ) do
3090+ def map_get_domain ( dnf , domain_key ( _ ) = domain_key ) do
31313091 dnf
31323092 |> Enum . reduce ( none ( ) , fn
31333093 { tag , _fields , [ ] } , acc when is_atom ( tag ) ->
31343094 map_key_tag_to_type ( tag ) |> union ( acc )
31353095
31363096 # Optimization: if there are no negatives and domains exists, return its value
3137- { { _tag , % { domain_key ( ^ key_domain ) => value } } , _fields , [ ] } , acc ->
3097+ { { _tag , % { ^ domain_key => value } } , _fields , [ ] } , acc ->
31383098 value |> union ( acc )
31393099
31403100 # Optimization: if there are no negatives and the key does not exist, return the default type.
31413101 { { tag , % { } } , _fields , [ ] } , acc ->
31423102 map_key_tag_to_type ( tag ) |> union ( acc )
31433103
31443104 { tag , fields , negs } , acc ->
3145- { fst , snd } = map_pop_domain ( tag , fields , key_domain )
3105+ { fst , snd } = map_pop_domain ( tag , fields , domain_key )
31463106
3147- case map_split_negative_domain ( negs , key_domain ) do
3107+ case map_split_negative_domain ( negs , domain_key ) do
31483108 :empty ->
31493109 acc
31503110
@@ -3374,12 +3334,12 @@ defmodule Module.Types.Descr do
33743334 # Negative must contain all domain key types
33753335 negative_check =
33763336 Enum . all? ( @ domain_key_types , fn domain_key ->
3377- domain_key_present = Map . has_key? ( neg_domains , domain_key ( domain_key ) )
3378- pos_has_key = Map . has_key? ( pos_domains , domain_key ( domain_key ) )
3337+ domain_key_present = Map . has_key? ( neg_domains , domain_key )
3338+ pos_has_key = Map . has_key? ( pos_domains , domain_key )
33793339
33803340 domain_key_present &&
33813341 ( pos_has_key ||
3382- subtype? ( term_or_optional ( ) , Map . get ( neg_domains , domain_key ( domain_key ) ) ) )
3342+ subtype? ( term_or_optional ( ) , Map . get ( neg_domains , domain_key ) ) )
33833343 end )
33843344
33853345 positive_check && negative_check
@@ -3404,7 +3364,7 @@ defmodule Module.Types.Descr do
34043364 { :open , { :closed , neg_domains } } ->
34053365 # The domains must include all possible domain key types, and they must be at least term_or_optional()
34063366 Enum . all? ( @ domain_key_types , fn domain_key ->
3407- case Map . get ( neg_domains , domain_key ( domain_key ) ) do
3367+ case Map . get ( neg_domains , domain_key ) do
34083368 # Not all domain keys are present
34093369 nil -> false
34103370 type -> subtype? ( term_or_optional ( ) , type )
@@ -3422,7 +3382,7 @@ defmodule Module.Types.Descr do
34223382 { { :open , pos_domains } , :closed } ->
34233383 # The pos_domains must include all possible domain key types, and they must be subtypes of not_set()
34243384 Enum . all? ( @ domain_key_types , fn domain_key ->
3425- case Map . get ( pos_domains , domain_key ( domain_key ) ) do
3385+ case Map . get ( pos_domains , domain_key ) do
34263386 # Not all domain keys are present
34273387 nil -> false
34283388 type -> subtype? ( type , not_set ( ) )
@@ -3442,9 +3402,9 @@ defmodule Module.Types.Descr do
34423402 # returns {if_set(integer()), %{integer() => if_set(binary())}}
34433403 # If the domain is not present, use the tag to type as default.
34443404 defp map_pop_domain ( { tag , domains } , fields , domain_key ) do
3445- case :maps . take ( domain_key ( domain_key ) , domains ) do
3446- { value , domains } -> { value , % { map: map_new ( tag , fields , domains ) } }
3447- :error -> { map_key_tag_to_type ( tag ) , % { map: map_new ( tag , fields , domains ) } }
3405+ case :maps . take ( domain_key , domains ) do
3406+ { value , domains } -> { value , % { map: map_new ( { tag , domains } , fields ) } }
3407+ :error -> { map_key_tag_to_type ( tag ) , % { map: map_new ( { tag , domains } , fields ) } }
34483408 end
34493409 end
34503410
0 commit comments