@@ -3118,75 +3118,117 @@ defmodule Module.Types.Descr do
31183118 end
31193119
31203120 defp process_tuples_values ( dnf ) do
3121- Enum . reduce ( dnf , none ( ) , fn { tag , elements , negs } , acc ->
3122- union ( tuple_values ( tag , elements , negs ) , acc )
3121+ tuple_reduce ( dnf , none ( ) , & union / 2 , fn tag , elements ->
3122+ cond do
3123+ Enum . any? ( elements , & empty? / 1 ) -> none ( )
3124+ tag == :open -> term ( )
3125+ tag == :closed -> Enum . reduce ( elements , none ( ) , & union / 2 )
3126+ end
31233127 end )
31243128 end
31253129
3126- defp tuple_values ( tag , elements , [ ] ) do
3127- cond do
3128- Enum . any? ( elements , & empty? / 1 ) -> none ( )
3129- tag == :open -> term ( )
3130- tag == :closed -> Enum . reduce ( elements , none ( ) , & union / 2 )
3131- end
3130+ defp tuple_reduce ( dnf , initial , join , transform ) do
3131+ Enum . reduce ( dnf , initial , fn { tag , elements , negs } , acc ->
3132+ join . ( acc , tuple_reduce ( tag , elements , negs , initial , join , transform ) )
3133+ end )
31323134 end
31333135
3134- defp tuple_values ( _tag , _elements , [ { :open , [ ] } | _ ] ) , do: none ( )
3136+ defp tuple_reduce ( tag , elements , [ ] , _init , _join , transform ) , do: transform . ( tag , elements )
3137+ defp tuple_reduce ( _tag , _elements , [ { :open , [ ] } | _ ] , initial , _join , _transform ) , do: initial
31353138
3136- defp tuple_values ( tag , elements , [ { neg_tag , neg_elements } | negs ] ) do
3139+ defp tuple_reduce ( tag , elements , [ { neg_tag , neg_elements } | negs ] , initial , join , transform ) do
31373140 n = length ( elements )
31383141 m = length ( neg_elements )
31393142
31403143 if ( tag == :closed and n < m ) or ( neg_tag == :closed and n > m ) do
3141- tuple_values ( tag , elements , negs )
3144+ tuple_reduce ( tag , elements , negs , initial , join , transform )
31423145 else
31433146 # Those two functions eliminate the negations, transforming into
31443147 # a union of tuples to compute their values.
3145- values_elements ( [ ] , tag , elements , neg_elements , negs )
3146- |> union ( values_size ( n , m , tag , elements , neg_tag , negs ) )
3148+ elim_content ( [ ] , tag , elements , neg_elements , negs , initial , join , transform )
3149+ |> join . ( elim_size ( n , m , tag , elements , neg_tag , negs , initial , join , transform ) )
31473150 end
31483151 end
31493152
3153+ # Eliminates negations according to tuple content.
31503154 # This means that there are no more neg_elements to subtract -- end the recursion.
3151- defp values_elements ( _acc , _tag , _elements , [ ] , _ ) , do: none ( )
3155+ defp elim_content ( _acc , _tag , _elements , [ ] , _ , initial , _join , _transform ) , do: initial
31523156
3153- # Eliminates negations according to tuple content.
31543157 # Subtracts each element of a negative tuple to build a new tuple with the difference.
31553158 # Example: {number(), atom()} and not {float(), :foo} contains types {integer(), :foo}
31563159 # as well as {float(), atom() and not :foo}
31573160 # Same process as tuple_elements_empty?
3158- defp values_elements ( acc , tag , elements , [ neg_type | neg_elements ] , negs ) do
3161+ defp elim_content ( acc , tag , elements , [ neg_type | neg_elements ] , negs , init , join , transform ) do
31593162 { ty , elements } = List . pop_at ( elements , 0 , term ( ) )
31603163 diff = difference ( ty , neg_type )
31613164
31623165 if empty? ( diff ) do
3163- none ( )
3166+ init
31643167 else
3165- tuple_values ( tag , Enum . reverse ( acc , [ diff | elements ] ) , negs )
3168+ tuple_reduce ( tag , Enum . reverse ( acc , [ diff | elements ] ) , negs , init , join , transform )
31663169 end
3167- |> union ( values_elements ( [ ty | acc ] , tag , elements , neg_elements , negs ) )
3170+ |> join . ( elim_content ( [ ty | acc ] , tag , elements , neg_elements , negs , init , join , transform ) )
31683171 end
31693172
31703173 # Eliminates negations according to size
31713174 # Example: {integer(), ...} and not {term(), term(), ...} contains {integer()}
3172- defp values_size ( n , m , tag , elements , neg_tag , negs ) do
3173- if tag == :closed do
3174- none ( )
3175- else
3176- n .. ( m - 1 ) // 1
3177- |> Enum . reduce ( none ( ) , fn i , acc ->
3178- tuple_values ( :closed , tuple_fill ( elements , i ) , negs ) |> union ( acc )
3179- end )
3180- |> union (
3181- if neg_tag == :open do
3182- none ( )
3183- else
3184- tuple_values ( tag , tuple_fill ( elements , m + 1 ) , negs )
3185- end
3186- )
3175+ defp elim_size ( _ , _ , :closed , _ , _ , _ , initial , _join , _transfo ) , do: initial
3176+
3177+ defp elim_size ( n , m , tag , elements , neg_tag , negs , initial , join , transform ) do
3178+ n .. ( m - 1 ) // 1
3179+ |> Enum . reduce ( initial , fn i , acc ->
3180+ tuple_reduce ( :closed , tuple_fill ( elements , i ) , negs , initial , join , transform )
3181+ |> join . ( acc )
3182+ end )
3183+ |> join . (
3184+ if neg_tag == :open do
3185+ initial
3186+ else
3187+ tuple_reduce ( tag , tuple_fill ( elements , m + 1 ) , negs , initial , join , transform )
3188+ end
3189+ )
3190+ end
3191+
3192+ @ doc """
3193+ Converts a tuple type to a simple union by eliminating negations.
3194+
3195+ Takes a tuple type with complex negations and simplifies it to a union of
3196+ positive tuple literals only.
3197+
3198+ For static tuple types: eliminates all negations from the DNF representation.
3199+ For gradual tuple types: processes both dynamic and static components separately,
3200+ then combines them.
3201+
3202+ Uses `tuple_reduce/4` with concatenation as the join function and a transform
3203+ that is simply the identity.
3204+
3205+ Returns the descriptor unchanged for non-tuple types, or a descriptor with
3206+ simplified tuple DNF containing only positive literals. If simplification
3207+ results in an empty tuple list, removes the `:tuple` key entirely.
3208+ """
3209+ def tuple_elim_negations ( descr ) do
3210+ case :maps . take ( :dynamic , descr ) do
3211+ :error ->
3212+ tuple_elim_negations_static ( descr )
3213+
3214+ { dynamic , static } ->
3215+ tuple_elim_negations_static ( static )
3216+ |> union ( dynamic ( tuple_elim_negations_static ( dynamic ) ) )
31873217 end
31883218 end
31893219
3220+ # Call tuple_reduce to build the simple union of tuples that come from each map literal.
3221+ # Thus, initial is `[]`, join is concatenation, and the transform of a map literal
3222+ # with no negations is just to keep the map literal as is.
3223+ defp tuple_elim_negations_static ( % { tuple: dnf } = descr ) do
3224+ case tuple_reduce ( dnf , [ ] , & Kernel . ++ / 2 , fn tag , elements -> [ { tag , elements , [ ] } ] end ) do
3225+ [ ] -> Map . delete ( descr , :tuple )
3226+ new_dnf -> % { descr | tuple: new_dnf }
3227+ end
3228+ end
3229+
3230+ defp tuple_elim_negations_static ( descr ) , do: descr
3231+
31903232 defp tuple_pop_index ( tag , elements , index ) do
31913233 case List . pop_at ( elements , index ) do
31923234 { nil , _ } -> { tag_to_type ( tag ) , % { tuple: [ { tag , elements , [ ] } ] } }
0 commit comments