@@ -63,6 +63,11 @@ defmodule Module.Types.Descr do
6363 @ not_non_empty_list Map . delete ( @ term , :list )
6464 @ not_list Map . replace! ( @ not_non_empty_list , :bitmap , @ bit_top - @ bit_empty_list )
6565
66+ @ not_set % { optional: 1 }
67+ @ term_or_optional Map . put ( @ term , :optional , 1 )
68+ @ term_or_dynamic_optional Map . put ( @ term , :dynamic , % { optional: 1 } )
69+ @ not_atom_or_optional Map . delete ( @ term_or_optional , :atom )
70+
6671 @ empty_intersection [ 0 , @ none ]
6772 @ empty_difference [ 0 , [ ] ]
6873
@@ -88,12 +93,11 @@ defmodule Module.Types.Descr do
8893
8994 def closed_map ( pairs ) do
9095 { regular_pairs , domain_pairs } = split_domain_key_pairs ( pairs )
91- # Validate domain keys and make their types optional
9296 domain_pairs = validate_domain_keys ( domain_pairs )
9397
9498 if domain_pairs == [ ] ,
9599 do: map_descr ( :closed , regular_pairs ) ,
96- else: map_descr ( :closed , regular_pairs , domain_pairs )
100+ else: map_descr ( domain_pairs , regular_pairs )
97101 end
98102
99103 def empty_list ( ) , do: % { bitmap: @ bit_empty_list }
@@ -104,26 +108,20 @@ defmodule Module.Types.Descr do
104108 def non_empty_list ( type , tail \\ @ empty_list ) , do: list_descr ( type , tail , false )
105109
106110 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 )
107113
108- @ doc "A map (closed or open is the same) with a default type %{term() => default}"
109- def map_with_default ( default ) do
110- map_descr (
111- :closed ,
112- [ ] ,
113- Enum . map ( @ domain_key_types , fn key_type ->
114- { domain_key ( key_type ) , if_set ( default ) }
115- end )
116- )
117- end
118-
119- def open_map ( pairs ) do
114+ defp open_map ( pairs , default , force? ) do
120115 { regular_pairs , domain_pairs } = split_domain_key_pairs ( pairs )
121- # Validate domain keys and make their types optional
122116 domain_pairs = validate_domain_keys ( domain_pairs )
123117
124- if domain_pairs == [ ] ,
125- do: map_descr ( :open , regular_pairs ) ,
126- else: map_descr ( :open , regular_pairs , domain_pairs )
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 )
127125 end
128126
129127 def open_tuple ( elements , _fallback \\ term ( ) ) , do: tuple_descr ( :open , elements )
@@ -289,16 +287,11 @@ defmodule Module.Types.Descr do
289287 # is equivalent to `%{:foo => integer() or not_set()}`.
290288 #
291289 # `not_set()` has no meaning outside of map types.
292-
293- @ not_set % { optional: 1 }
294- @ term_or_optional Map . put ( @ term , :optional , 1 )
295- @ term_or_dynamic_optional Map . put ( @ term , :dynamic , % { optional: 1 } )
296- @ not_atom_or_optional Map . delete ( @ term_or_optional , :atom )
297-
298290 def not_set ( ) , do: @ not_set
291+
299292 def if_set ( :term ) , do: term_or_optional ( )
300- # actually, if type contains a :dynamic part, :optional gets added there because
301- # the dynamic
293+
294+ # If type contains a : dynamic part, :optional gets added there.
302295 def if_set ( type ) do
303296 case type do
304297 % { dynamic: dyn } -> Map . put ( % { type | dynamic: Map . put ( dyn , :optional , 1 ) } , :optional , 1 )
@@ -2245,7 +2238,7 @@ defmodule Module.Types.Descr do
22452238 # The type %{..., atom() => integer()} represents maps with atom keys bound to integers,
22462239 # and other keys bound to any type, represented by {{:closed, %{atom: integer()}}, %{}, []}.
22472240
2248- defp map_descr ( tag , fields ) do
2241+ defp map_descr ( tag , fields ) when is_atom ( tag ) do
22492242 case map_descr_pairs ( fields , [ ] , false ) do
22502243 { fields , true } ->
22512244 % { dynamic: % { map: map_new ( tag , fields |> Enum . reverse ( ) |> :maps . from_list ( ) ) } }
@@ -2255,17 +2248,17 @@ defmodule Module.Types.Descr do
22552248 end
22562249 end
22572250
2258- def map_descr ( tag , fields , domains ) do
2251+ defp map_descr ( domains , fields ) do
22592252 { fields , fields_dynamic? } = map_descr_pairs ( fields , [ ] , false )
22602253 { domains , domains_dynamic? } = map_descr_pairs ( domains , [ ] , false )
22612254
22622255 fields_map = :maps . from_list ( if fields_dynamic? , do: Enum . reverse ( fields ) , else: fields )
22632256 domains_map = :maps . from_list ( if domains_dynamic? , do: Enum . reverse ( domains ) , else: domains )
22642257
22652258 if fields_dynamic? or domains_dynamic? do
2266- % { dynamic: % { map: map_new ( tag , fields_map , domains_map ) } }
2259+ % { dynamic: % { map: map_new ( :closed , fields_map , domains_map ) } }
22672260 else
2268- % { map: map_new ( tag , fields_map , domains_map ) }
2261+ % { map: map_new ( :closed , fields_map , domains_map ) }
22692262 end
22702263 end
22712264
0 commit comments