@@ -144,7 +144,7 @@ defmodule Module.Types.Descr do
144144 def args_to_domain ( types ) when is_list ( types ) , do: tuple ( types )
145145
146146 @ doc """
147- Converts the domain to arguments.
147+ Converts the domain to a list of arguments.
148148
149149 The domain is expected to be closed tuples. They may have complex negations
150150 which are then simplified to a union of positive tuple literals only.
@@ -156,27 +156,39 @@ defmodule Module.Types.Descr do
156156
157157 Internally it uses `tuple_reduce/4` with concatenation as the join function
158158 and a transform that is simply the identity.
159+
160+ The list of arguments can be flattened into a broad domain by calling:
161+
162+ |> Enum.zip_with(fn types -> Enum.reduce(types, &union/2) end)
159163 """
160164 def domain_to_args ( descr ) do
161165 case :maps . take ( :dynamic , descr ) do
162166 :error ->
163- { tuple_elim_negations_static ( descr ) , [ ] }
167+ tuple_elim_negations_static ( descr , & Function . identity / 1 )
164168
165169 { dynamic , static } ->
166- { tuple_elim_negations_static ( static ) , tuple_elim_negations_static ( dynamic ) }
170+ tuple_elim_negations_static ( static , & Function . identity / 1 ) ++
171+ tuple_elim_negations_static ( dynamic , fn elems -> Enum . map ( elems , & dynamic / 1 ) end )
167172 end
168173 end
169174
170175 # Call tuple_reduce to build the simple union of tuples that come from each map literal.
171176 # Thus, initial is `[]`, join is concatenation, and the transform of a map literal
172177 # with no negations is just to keep the map literal as is.
173- defp tuple_elim_negations_static ( % { tuple: dnf } = descr ) when map_size ( descr ) == 1 do
178+ defp tuple_elim_negations_static ( % { tuple: dnf } = descr , transform ) when map_size ( descr ) == 1 do
174179 tuple_reduce ( dnf , [ ] , & Kernel . ++ / 2 , fn :closed , elements ->
175- [ elements ]
180+ [ transform . ( elements ) ]
176181 end )
177182 end
178183
179- defp tuple_elim_negations_static ( descr ) when descr == % { } , do: [ ]
184+ defp tuple_elim_negations_static ( descr , _transform ) when descr == % { } , do: [ ]
185+
186+ defp domain_to_flat_args ( domain , arity ) do
187+ case domain_to_args ( domain ) do
188+ [ ] -> List . duplicate ( none ( ) , arity )
189+ args -> Enum . zip_with ( args , fn types -> Enum . reduce ( types , & union / 2 ) end )
190+ end
191+ end
180192
181193 ## Optional
182194
@@ -987,7 +999,12 @@ defmodule Module.Types.Descr do
987999 Applies a function type to a list of argument types.
9881000
9891001 Returns `{:ok, result}` if the application is valid
990- or one `:badarg`, `:badfun`, `{:badarity, arities}` if not.
1002+ or one `{:badarg, to_succeed_domain}`, `:badfun`,
1003+ `{:badarity, arities}` if not.
1004+
1005+ Note the domain returned by `:badarg` is not the strong
1006+ domain, but the domain that must be satisfied for the
1007+ function application to succeed.
9911008
9921009 Handles both static and dynamic function types:
9931010
@@ -1059,11 +1076,11 @@ defmodule Module.Types.Descr do
10591076 fun_normalize_both ( fun_static , fun_dynamic , arity ) do
10601077 cond do
10611078 empty? ( args_domain ) ->
1062- { :badarg , domain }
1079+ { :badarg , domain_to_flat_args ( domain , arity ) }
10631080
10641081 not subtype? ( args_domain , domain ) ->
10651082 if static? or not compatible? ( fun , fun ( arguments , term ( ) ) ) do
1066- { :badarg , domain }
1083+ { :badarg , domain_to_flat_args ( domain , arity ) }
10671084 else
10681085 { :ok , dynamic ( ) }
10691086 end
0 commit comments