@@ -2143,9 +2143,27 @@ 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? = gradual? ( list_type ) or gradual? ( last_type )
2147+ { dynamic_list_type , static_list_type } = pop_dynamic ( list_type )
2148+ { dynamic_last_type , static_last_type } = pop_dynamic ( last_type )
2149+ dynamic_descr = list_descr_static ( dynamic_list_type , dynamic_last_type , empty? )
2150+ # Just a syntactic check, to avoid a recursive empty? call
2151+ static_empty? = static_list_type == @ none or static_last_type == @ none
21482152
2153+ cond do
2154+ not dynamic? ->
2155+ dynamic_descr
2156+
2157+ static_empty? ->
2158+ % { dynamic: dynamic_descr }
2159+
2160+ true ->
2161+ list_descr_static ( static_list_type , static_last_type , empty? )
2162+ |> Map . put ( :dynamic , dynamic_descr )
2163+ end
2164+ end
2165+
2166+ defp list_descr_static ( list_type , last_type , empty? ) do
21492167 list_part =
21502168 if last_type == :term do
21512169 list_new ( :term , :term )
@@ -2176,13 +2194,7 @@ defmodule Module.Types.Descr do
21762194 end
21772195 end
21782196
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
2197+ if empty? , do: % { list: list_part , bitmap: @ bit_empty_list } , else: % { list: list_part }
21862198 end
21872199
21882200 defp list_new ( list_type , last_type ) , do: bdd_leaf_new ( list_type , last_type )
@@ -2231,15 +2243,6 @@ defmodule Module.Types.Descr do
22312243 end )
22322244 end
22332245
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-
22432246 defp list_tail_unfold ( :term ) , do: @ not_non_empty_list
22442247 defp list_tail_unfold ( other ) , do: Map . delete ( other , :list )
22452248
@@ -2784,8 +2787,19 @@ defmodule Module.Types.Descr do
27842787 defp domain_key_to_descr ( :list ) , do: @ list_top
27852788
27862789 defp map_descr ( tag , pairs ) do
2787- { fields , domains , dynamic? } = map_descr_pairs ( pairs , [ ] , @ fields_new , false )
2790+ { fields , domains , dynamic_fields , dynamic_domains , dynamic? , static_empty? } =
2791+ map_descr_pairs ( pairs )
2792+
2793+ dynamic_descr = map_descr_static ( tag , dynamic_fields , dynamic_domains )
2794+
2795+ cond do
2796+ not dynamic? -> dynamic_descr
2797+ static_empty? -> % { dynamic: dynamic_descr }
2798+ true -> Map . put ( map_descr_static ( tag , fields , domains ) , :dynamic , dynamic_descr )
2799+ end
2800+ end
27882801
2802+ defp map_descr_static ( tag , fields , domains ) do
27892803 map_new =
27902804 if not is_fields_empty ( domains ) do
27912805 domains =
@@ -2801,10 +2815,7 @@ defmodule Module.Types.Descr do
28012815 map_new ( tag , fields )
28022816 end
28032817
2804- case dynamic? do
2805- true -> % { dynamic: % { map: map_new } }
2806- false -> % { map: map_new }
2807- end
2818+ % { map: map_new }
28082819 end
28092820
28102821 defp map_put_domain ( domain , domain_keys , value ) when is_list ( domain_keys ) do
@@ -2825,30 +2836,34 @@ defmodule Module.Types.Descr do
28252836
28262837 defp map_put_domain ( domain , [ ] , _initial , _value ) , do: domain
28272838
2828- defp map_descr_pairs ( [ { key , :term } | rest ] , fields , domain , dynamic? ) do
2829- 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? )
2832- end
2839+ defp map_descr_pairs ( pairs ) do
2840+ { fields , domains , dynamic_fields , dynamic_domains , dynamic? , static_possible? } =
2841+ Enum . reduce ( pairs , { [ ] , @ fields_new , [ ] , @ fields_new , false , false } , fn { key , value } , acc ->
2842+ map_descr_pair ( key , value , acc )
2843+ end )
2844+
2845+ { fields_from_reverse_list ( fields ) , domains , fields_from_reverse_list ( dynamic_fields ) ,
2846+ dynamic_domains , dynamic? , static_possible? }
28332847 end
28342848
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
2849+ defp map_descr_pair (
2850+ key ,
2851+ value ,
2852+ { fields , domains , dynamic_fields , dynamic_domains , dynamic? , static_empty? }
2853+ ) do
2854+ { dynamic_value , static_value } = pop_dynamic ( value )
2855+ dynamic? = dynamic? or gradual? ( value )
2856+ static_empty? = static_empty? or static_value == @ none
28412857
2842- 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? )
2858+ if is_atom ( key ) do
2859+ { [ { key , static_value } | fields ] , domains , [ { key , dynamic_value } | dynamic_fields ] ,
2860+ dynamic_domains , dynamic? , static_empty? }
2861+ else
2862+ { fields , map_put_domain ( domains , key , static_value ) , dynamic_fields ,
2863+ map_put_domain ( dynamic_domains , key , dynamic_value ) , dynamic? , static_empty? }
28452864 end
28462865 end
28472866
2848- defp map_descr_pairs ( [ ] , fields , domain , dynamic? ) do
2849- { fields_from_reverse_list ( fields ) , domain , dynamic? }
2850- end
2851-
28522867 # Gets the default type associated to atom keys in a map.
28532868 defp map_key_tag_to_type ( :open ) , do: term_or_optional ( )
28542869 defp map_key_tag_to_type ( :closed ) , do: not_set ( )
@@ -4965,46 +4980,34 @@ defmodule Module.Types.Descr do
49654980 # - {atom(), boolean(), ...} is encoded as {:open, [atom(), boolean()]}
49664981
49674982 defp tuple_descr ( tag , fields ) do
4968- case tuple_descr ( fields , [ ] , false ) do
4969- :empty -> % { }
4970- { fields , true } -> % { dynamic: % { tuple: tuple_new ( tag , Enum . reverse ( fields ) ) } }
4971- { _ , false } -> % { tuple: tuple_new ( tag , fields ) }
4972- end
4973- end
4983+ { static_fields , dynamic_fields , dynamic? , static_empty? } =
4984+ tuple_descr_fields ( fields , [ ] , [ ] , false , false )
4985+
4986+ dynamic_descr = tuple_descr_static ( tag , dynamic_fields )
49744987
4975- defp tuple_descr ( [ :term | rest ] , acc , dynamic? ) do
4976- tuple_descr ( rest , [ :term | acc ] , dynamic? )
4988+ cond do
4989+ not dynamic? -> dynamic_descr
4990+ static_empty? -> % { dynamic: dynamic_descr }
4991+ true -> Map . put ( tuple_descr_static ( tag , static_fields ) , :dynamic , dynamic_descr )
4992+ end
49774993 end
49784994
4979- defp tuple_descr ( [ value | rest ] , acc , dynamic? ) do
4980- # Check if the static part is empty
4981- static_empty? =
4982- case value do
4983- # Has dynamic component, check static separately
4984- % { dynamic: _ } -> false
4985- _ -> empty? ( value )
4986- end
4995+ defp tuple_descr_static ( tag , fields ) , do: % { tuple: tuple_new ( tag , :lists . reverse ( fields ) ) }
49874996
4988- if static_empty? do
4989- :empty
4990- else
4991- case :maps . take ( :dynamic , value ) do
4992- :error ->
4993- tuple_descr ( rest , [ value | acc ] , dynamic? )
4997+ defp tuple_descr_fields ( [ value | rest ] , acc , dynamic_acc , dynamic? , static_empty? ) do
4998+ { dynamic_value , static_value } = pop_dynamic ( value )
49944999
4995- { dynamic , _static } ->
4996- # Check if dynamic component is empty
4997- if empty? ( dynamic ) do
4998- :empty
4999- else
5000- tuple_descr ( rest , [ dynamic | acc ] , true )
5001- end
5002- end
5003- end
5000+ tuple_descr_fields (
5001+ rest ,
5002+ [ static_value | acc ] ,
5003+ [ dynamic_value | dynamic_acc ] ,
5004+ dynamic? or gradual? ( value ) ,
5005+ static_empty? or static_value == @ none
5006+ )
50045007 end
50055008
5006- defp tuple_descr ( [ ] , acc , dynamic? ) do
5007- { acc , dynamic? }
5009+ defp tuple_descr_fields ( [ ] , acc , dynamic_acc , dynamic? , static_empty ?) do
5010+ { acc , dynamic_acc , dynamic? , static_empty ?}
50085011 end
50095012
50105013 defp tuple_new ( tag , elements ) , do: bdd_leaf_new ( tag , elements )
@@ -5023,7 +5026,14 @@ defmodule Module.Types.Descr do
50235026 end
50245027 end
50255028
5026- defp tuple_literal_intersection ( :open , [ ] , tag , elements ) , do: { tag , elements }
5029+ # Detecting tuples built with none() fields
5030+ defp tuple_literal_intersection ( :open , [ ] , tag , elements ) do
5031+ if Enum . any? ( elements , & empty? / 1 ) do
5032+ :empty
5033+ else
5034+ { tag , elements }
5035+ end
5036+ end
50275037
50285038 defp tuple_literal_intersection ( tag1 , elements1 , tag2 , elements2 ) do
50295039 case tuple_sizes_strategy ( tag1 , length ( elements1 ) , tag2 , length ( elements2 ) ) do
@@ -5050,8 +5060,13 @@ defmodule Module.Types.Descr do
50505060 defp tuple_sizes_strategy ( _ , _ , _ , _ ) , do: :none
50515061
50525062 # Intersects two lists of types, and _appends_ the extra elements to the result.
5053- defp zip_non_empty_intersection! ( [ ] , types2 , acc ) , do: Enum . reverse ( acc , types2 )
5054- defp zip_non_empty_intersection! ( types1 , [ ] , acc ) , do: Enum . reverse ( acc , types1 )
5063+ defp zip_non_empty_intersection! ( [ ] , types2 , acc ) do
5064+ if Enum . any? ( types2 , & empty? / 1 ) , do: throw ( :empty ) , else: Enum . reverse ( acc , types2 )
5065+ end
5066+
5067+ defp zip_non_empty_intersection! ( types1 , [ ] , acc ) do
5068+ if Enum . any? ( types1 , & empty? / 1 ) , do: throw ( :empty ) , else: Enum . reverse ( acc , types1 )
5069+ end
50555070
50565071 defp zip_non_empty_intersection! ( [ type1 | rest1 ] , [ type2 | rest2 ] , acc ) do
50575072 zip_non_empty_intersection! ( rest1 , rest2 , [ non_empty_intersection! ( type1 , type2 ) | acc ] )
@@ -5662,7 +5677,7 @@ defmodule Module.Types.Descr do
56625677 def tuple_values ( descr ) do
56635678 case :maps . take ( :dynamic , descr ) do
56645679 :error ->
5665- if tuple_only ?( descr ) do
5680+ if non_empty_tuple_only ?( descr ) do
56665681 process_tuples_values ( Map . get ( descr , :tuple , :bdd_bot ) )
56675682 else
56685683 :badtuple
@@ -5708,7 +5723,7 @@ defmodule Module.Types.Descr do
57085723 case :maps . take ( :dynamic , descr ) do
57095724 :error ->
57105725 # Note: the empty type is not a valid input
5711- is_proper_tuple? = descr_key? ( descr , :tuple ) and tuple_only ?( descr )
5726+ is_proper_tuple? = descr_key? ( descr , :tuple ) and non_empty_tuple_only ?( descr )
57125727 is_proper_size? = tuple_of_size_at_least_static? ( descr , index + 1 )
57135728
57145729 cond do
@@ -5777,7 +5792,7 @@ defmodule Module.Types.Descr do
57775792 case :maps . take ( :dynamic , descr ) do
57785793 :error ->
57795794 # Note: the empty type is not a valid input
5780- is_proper_tuple? = descr_key? ( descr , :tuple ) and tuple_only ?( descr )
5795+ is_proper_tuple? = descr_key? ( descr , :tuple ) and non_empty_tuple_only ?( descr )
57815796 is_proper_size? = index == 0 or tuple_of_size_at_least_static? ( descr , index )
57825797
57835798 cond do
0 commit comments