@@ -2143,9 +2143,31 @@ defmodule Module.Types.Descr do
21432143 #
21442144 # none() types can be given and, while stored, it means the list type is empty.
21452145 defp list_descr ( list_type , last_type , empty? ) do
2146- { list_dynamic? , list_type } = list_pop_dynamic ( list_type )
2147- { last_dynamic? , last_type } = list_pop_dynamic ( last_type )
2146+ { dynamic_list_type , static_list_type } = pop_dynamic ( list_type )
2147+ { dynamic_last_type , static_last_type } = pop_dynamic ( last_type )
2148+ dynamic? = dynamic_list_type != static_list_type or dynamic_last_type != static_last_type
2149+ static_possible? = not empty? ( static_list_type ) and not empty? ( static_last_type )
21482150
2151+ dynamic_descr = list_descr_build ( dynamic_list_type , dynamic_last_type , empty? )
2152+
2153+ cond do
2154+ empty? ( dynamic_descr ) ->
2155+ % { }
2156+
2157+ dynamic? ->
2158+ if not static_possible? do
2159+ % { dynamic: dynamic_descr }
2160+ else
2161+ static_descr = list_descr_build ( static_list_type , static_last_type , empty? )
2162+ Map . put ( static_descr , :dynamic , dynamic_descr )
2163+ end
2164+
2165+ true ->
2166+ dynamic_descr
2167+ end
2168+ end
2169+
2170+ defp list_descr_build ( list_type , last_type , empty? ) do
21492171 list_part =
21502172 if last_type == :term do
21512173 list_new ( :term , :term )
@@ -2176,13 +2198,7 @@ defmodule Module.Types.Descr do
21762198 end
21772199 end
21782200
2179- list_descr =
2180- if empty? , do: % { list: list_part , bitmap: @ bit_empty_list } , else: % { list: list_part }
2181-
2182- case list_dynamic? or last_dynamic? do
2183- true -> % { dynamic: list_descr }
2184- false -> list_descr
2185- end
2201+ if empty? , do: % { list: list_part , bitmap: @ bit_empty_list } , else: % { list: list_part }
21862202 end
21872203
21882204 defp list_new ( list_type , last_type ) , do: bdd_leaf_new ( list_type , last_type )
@@ -2231,15 +2247,6 @@ defmodule Module.Types.Descr do
22312247 end )
22322248 end
22332249
2234- defp list_pop_dynamic ( :term ) , do: { false , :term }
2235-
2236- defp list_pop_dynamic ( descr ) do
2237- case :maps . take ( :dynamic , descr ) do
2238- :error -> { false , descr }
2239- { dynamic , _ } -> { true , dynamic }
2240- end
2241- end
2242-
22432250 defp list_tail_unfold ( :term ) , do: @ not_non_empty_list
22442251 defp list_tail_unfold ( other ) , do: Map . delete ( other , :list )
22452252
@@ -2784,8 +2791,29 @@ defmodule Module.Types.Descr do
27842791 defp domain_key_to_descr ( :list ) , do: @ list_top
27852792
27862793 defp map_descr ( tag , pairs ) do
2787- { fields , domains , dynamic? } = map_descr_pairs ( pairs , [ ] , @ fields_new , false )
2794+ { fields , domains , dynamic_fields , dynamic_domains , dynamic? , static_possible? } =
2795+ map_descr_pairs ( pairs , [ ] , @ fields_new , [ ] , @ fields_new , false , true )
2796+
2797+ dynamic_descr = map_descr_build ( tag , dynamic_fields , dynamic_domains )
2798+
2799+ cond do
2800+ empty? ( dynamic_descr ) ->
2801+ % { }
2802+
2803+ dynamic? ->
2804+ if not static_possible? do
2805+ % { dynamic: dynamic_descr }
2806+ else
2807+ static_descr = map_descr_build ( tag , fields , domains )
2808+ Map . put ( static_descr , :dynamic , dynamic_descr )
2809+ end
2810+
2811+ true ->
2812+ dynamic_descr
2813+ end
2814+ end
27882815
2816+ defp map_descr_build ( tag , fields , domains ) do
27892817 map_new =
27902818 if not is_fields_empty ( domains ) do
27912819 domains =
@@ -2801,10 +2829,7 @@ defmodule Module.Types.Descr do
28012829 map_new ( tag , fields )
28022830 end
28032831
2804- case dynamic? do
2805- true -> % { dynamic: % { map: map_new } }
2806- false -> % { map: map_new }
2807- end
2832+ % { map: map_new }
28082833 end
28092834
28102835 defp map_put_domain ( domain , domain_keys , value ) when is_list ( domain_keys ) do
@@ -2825,28 +2850,89 @@ defmodule Module.Types.Descr do
28252850
28262851 defp map_put_domain ( domain , [ ] , _initial , _value ) , do: domain
28272852
2828- defp map_descr_pairs ( [ { key , :term } | rest ] , fields , domain , dynamic? ) do
2853+ defp map_descr_pairs (
2854+ [ { key , :term } | rest ] ,
2855+ fields ,
2856+ domain ,
2857+ dynamic_fields ,
2858+ dynamic_domain ,
2859+ dynamic? ,
2860+ static_possible?
2861+ ) do
28292862 case is_atom ( key ) do
2830- true -> map_descr_pairs ( rest , [ { key , :term } | fields ] , domain , dynamic? )
2831- false -> map_descr_pairs ( rest , fields , map_put_domain ( domain , key , :term ) , dynamic? )
2863+ true ->
2864+ map_descr_pairs (
2865+ rest ,
2866+ [ { key , :term } | fields ] ,
2867+ domain ,
2868+ [ { key , :term } | dynamic_fields ] ,
2869+ dynamic_domain ,
2870+ dynamic? ,
2871+ static_possible?
2872+ )
2873+
2874+ false ->
2875+ map_descr_pairs (
2876+ rest ,
2877+ fields ,
2878+ map_put_domain ( domain , key , :term ) ,
2879+ dynamic_fields ,
2880+ map_put_domain ( dynamic_domain , key , :term ) ,
2881+ dynamic? ,
2882+ static_possible?
2883+ )
28322884 end
28332885 end
28342886
2835- defp map_descr_pairs ( [ { key , value } | rest ] , fields , domain , dynamic? ) do
2836- { value , dynamic? } =
2837- case :maps . take ( :dynamic , value ) do
2838- :error -> { value , dynamic? }
2839- { dynamic , _static } -> { dynamic , true }
2840- end
2887+ defp map_descr_pairs (
2888+ [ { key , value } | rest ] ,
2889+ fields ,
2890+ domain ,
2891+ dynamic_fields ,
2892+ dynamic_domain ,
2893+ dynamic? ,
2894+ static_possible?
2895+ ) do
2896+ { dynamic_value , static_value } = pop_dynamic ( value )
2897+ dynamic? = dynamic? or dynamic_value != static_value
2898+ static_possible? = static_possible? and not empty? ( static_value )
28412899
28422900 case is_atom ( key ) do
2843- true -> map_descr_pairs ( rest , [ { key , value } | fields ] , domain , dynamic? )
2844- false -> map_descr_pairs ( rest , fields , map_put_domain ( domain , key , value ) , dynamic? )
2901+ true ->
2902+ map_descr_pairs (
2903+ rest ,
2904+ [ { key , static_value } | fields ] ,
2905+ domain ,
2906+ [ { key , dynamic_value } | dynamic_fields ] ,
2907+ dynamic_domain ,
2908+ dynamic? ,
2909+ static_possible?
2910+ )
2911+
2912+ false ->
2913+ map_descr_pairs (
2914+ rest ,
2915+ fields ,
2916+ map_put_domain ( domain , key , static_value ) ,
2917+ dynamic_fields ,
2918+ map_put_domain ( dynamic_domain , key , dynamic_value ) ,
2919+ dynamic? ,
2920+ static_possible?
2921+ )
28452922 end
28462923 end
28472924
2848- defp map_descr_pairs ( [ ] , fields , domain , dynamic? ) do
2849- { fields_from_reverse_list ( fields ) , domain , dynamic? }
2925+ defp map_descr_pairs (
2926+ [ ] ,
2927+ fields ,
2928+ domain ,
2929+ dynamic_fields ,
2930+ dynamic_domain ,
2931+ dynamic? ,
2932+ static_possible?
2933+ ) do
2934+ { fields_from_reverse_list ( fields ) , domain , fields_from_reverse_list ( dynamic_fields ) ,
2935+ dynamic_domain , dynamic? , static_possible? }
28502936 end
28512937
28522938 # Gets the default type associated to atom keys in a map.
@@ -4895,46 +4981,47 @@ defmodule Module.Types.Descr do
48954981 # - {atom(), boolean(), ...} is encoded as {:open, [atom(), boolean()]}
48964982
48974983 defp tuple_descr ( tag , fields ) do
4898- case tuple_descr ( fields , [ ] , false ) do
4899- :empty -> % { }
4900- { fields , true } -> % { dynamic: % { tuple: tuple_new ( tag , Enum . reverse ( fields ) ) } }
4901- { _ , false } -> % { tuple: tuple_new ( tag , fields ) }
4984+ case tuple_descr ( fields , [ ] , [ ] , false , true ) do
4985+ :empty ->
4986+ % { }
4987+
4988+ { static_fields , dynamic_fields , true , static_possible? } ->
4989+ dynamic_descr = % { tuple: tuple_new ( tag , :lists . reverse ( dynamic_fields ) ) }
4990+
4991+ if not static_possible? do
4992+ % { dynamic: dynamic_descr }
4993+ else
4994+ static_descr = % { tuple: tuple_new ( tag , :lists . reverse ( static_fields ) ) }
4995+ Map . put ( static_descr , :dynamic , dynamic_descr )
4996+ end
4997+
4998+ { fields , _dynamic_fields , false , _static_possible? } ->
4999+ % { tuple: tuple_new ( tag , :lists . reverse ( fields ) ) }
49025000 end
49035001 end
49045002
4905- defp tuple_descr ( [ :term | rest ] , acc , dynamic? ) do
4906- tuple_descr ( rest , [ :term | acc ] , dynamic? )
5003+ defp tuple_descr ( [ :term | rest ] , acc , dynamic_acc , dynamic? , static_possible ?) do
5004+ tuple_descr ( rest , [ :term | acc ] , [ :term | dynamic_acc ] , dynamic? , static_possible ?)
49075005 end
49085006
4909- defp tuple_descr ( [ value | rest ] , acc , dynamic? ) do
4910- # Check if the static part is empty
4911- static_empty? =
4912- case value do
4913- # Has dynamic component, check static separately
4914- % { dynamic: _ } -> false
4915- _ -> empty? ( value )
4916- end
5007+ defp tuple_descr ( [ value | rest ] , acc , dynamic_acc , dynamic? , static_possible? ) do
5008+ { dynamic_value , static_value } = pop_dynamic ( value )
49175009
4918- if static_empty? do
5010+ if empty? ( dynamic_value ) do
49195011 :empty
49205012 else
4921- case :maps . take ( :dynamic , value ) do
4922- :error ->
4923- tuple_descr ( rest , [ value | acc ] , dynamic? )
4924-
4925- { dynamic , _static } ->
4926- # Check if dynamic component is empty
4927- if empty? ( dynamic ) do
4928- :empty
4929- else
4930- tuple_descr ( rest , [ dynamic | acc ] , true )
4931- end
4932- end
5013+ tuple_descr (
5014+ rest ,
5015+ [ static_value | acc ] ,
5016+ [ dynamic_value | dynamic_acc ] ,
5017+ dynamic? or dynamic_value != static_value ,
5018+ static_possible? and not empty? ( static_value )
5019+ )
49335020 end
49345021 end
49355022
4936- defp tuple_descr ( [ ] , acc , dynamic? ) do
4937- { acc , dynamic? }
5023+ defp tuple_descr ( [ ] , acc , dynamic_acc , dynamic? , static_possible ?) do
5024+ { acc , dynamic_acc , dynamic? , static_possible ?}
49385025 end
49395026
49405027 defp tuple_new ( tag , elements ) , do: bdd_leaf_new ( tag , elements )
0 commit comments