@@ -70,18 +70,13 @@ defmodule Module.Types.Descr do
70
70
def non_empty_list ( type , tail \\ @ empty_list ) , do: list_descr ( type , tail , false )
71
71
def open_map ( ) , do: % { map: @ map_top }
72
72
def open_map ( pairs ) , do: map_descr ( :open , pairs )
73
+ def open_tuple ( elements ) , do: tuple_descr ( :open , elements )
73
74
def pid ( ) , do: % { bitmap: @ bit_pid }
74
75
def port ( ) , do: % { bitmap: @ bit_port }
75
76
def reference ( ) , do: % { bitmap: @ bit_reference }
76
77
def tuple ( ) , do: % { tuple: @ tuple_top }
77
- def open_tuple ( elements ) , do: tuple_descr ( :open , elements )
78
78
def tuple ( elements ) , do: tuple_descr ( :closed , elements )
79
79
80
- # Tuple helper
81
- defp tuple_of_size_at_least ( n ) when is_integer ( n ) and n >= 0 do
82
- open_tuple ( List . duplicate ( term ( ) , n ) )
83
- end
84
-
85
80
@ boolset :sets . from_list ( [ true , false ] , version: 2 )
86
81
def boolean ( ) , do: % { atom: { :union , @ boolset } }
87
82
@@ -1166,19 +1161,23 @@ defmodule Module.Types.Descr do
1166
1161
end
1167
1162
end
1168
1163
1169
- defp map_put_static_descr ( static , _ , _ ) when static == @ none , do: @ none
1170
-
1171
1164
# Directly inserts a key of a given type into every positive and negative map
1172
1165
defp map_put_static_descr ( descr , key , type ) do
1173
- map_delete_static ( descr , key )
1174
- |> Map . update! ( :map , fn dnf ->
1175
- Enum . map ( dnf , fn { tag , fields , negs } ->
1176
- { tag , Map . put ( fields , key , type ) ,
1177
- Enum . map ( negs , fn { neg_tag , neg_fields } ->
1178
- { neg_tag , Map . put ( neg_fields , key , type ) }
1179
- end ) }
1180
- end )
1181
- end )
1166
+ case map_delete_static ( descr , key ) do
1167
+ % { map: dnf } = descr ->
1168
+ dnf =
1169
+ Enum . map ( dnf , fn { tag , fields , negs } ->
1170
+ { tag , Map . put ( fields , key , type ) ,
1171
+ Enum . map ( negs , fn { neg_tag , neg_fields } ->
1172
+ { neg_tag , Map . put ( neg_fields , key , type ) }
1173
+ end ) }
1174
+ end )
1175
+
1176
+ % { descr | map: dnf }
1177
+
1178
+ % { } ->
1179
+ descr
1180
+ end
1182
1181
end
1183
1182
1184
1183
defp pop_optional_static ( type ) do
@@ -1883,6 +1882,11 @@ defmodule Module.Types.Descr do
1883
1882
end
1884
1883
end
1885
1884
1885
+ @ doc """
1886
+ Delete an element from the tuple.
1887
+
1888
+ It returns the same as `tuple_fetch/2`.
1889
+ """
1886
1890
# Same as tuple_delete but checks if the index is out of range.
1887
1891
def tuple_delete_at ( :term , _key ) , do: :badtuple
1888
1892
@@ -1891,21 +1895,22 @@ defmodule Module.Types.Descr do
1891
1895
:error ->
1892
1896
# Note: the empty type is not a valid input
1893
1897
is_proper_tuple? = descr_key? ( descr , :tuple ) and tuple_only? ( descr )
1894
- is_proper_size? = subtype? ( Map . take ( descr , [ :tuple ] ) , tuple_of_size_at_least ( index + 1 ) )
1898
+ is_proper_size? = tuple_of_size_at_least? ( descr , index + 1 )
1895
1899
1896
1900
cond do
1897
1901
is_proper_tuple? and is_proper_size? -> tuple_delete_static ( descr , index )
1898
- is_proper_tuple? -> :badrange
1902
+ is_proper_tuple? -> :badindex
1899
1903
true -> :badtuple
1900
1904
end
1901
1905
1902
1906
{ dynamic , static } ->
1903
1907
is_proper_tuple? = descr_key? ( dynamic , :tuple ) and tuple_only? ( static )
1904
- is_proper_size? = subtype? ( Map . take ( static , [ :tuple ] ) , tuple_of_size_at_least ( index + 1 ) )
1908
+ is_proper_size? = tuple_of_size_at_least? ( static , index + 1 )
1905
1909
1906
1910
cond do
1907
1911
is_proper_tuple? and is_proper_size? ->
1908
1912
static_result = tuple_delete_static ( static , index )
1913
+
1909
1914
# Prune for dynamic values make the intersection succeed
1910
1915
dynamic_result =
1911
1916
intersection ( dynamic , tuple_of_size_at_least ( index ) )
@@ -1915,7 +1920,7 @@ defmodule Module.Types.Descr do
1915
1920
1916
1921
# Highlight the case where the issue is an index out of range from the tuple
1917
1922
is_proper_tuple? ->
1918
- :badrange
1923
+ :badindex
1919
1924
1920
1925
true ->
1921
1926
:badtuple
@@ -1925,45 +1930,47 @@ defmodule Module.Types.Descr do
1925
1930
1926
1931
def tuple_delete_at ( _ , _ ) , do: :badindex
1927
1932
1933
+ @ doc """
1934
+ Insert an element at the tuple.
1935
+
1936
+ It returns the same as `tuple_fetch/2` but with `:badrange` instead of `:badindex`.
1937
+ """
1928
1938
def tuple_insert_at ( :term , _key , _type ) , do: :badtuple
1929
1939
1930
1940
def tuple_insert_at ( descr , index , type ) when is_integer ( index ) and index >= 0 do
1931
1941
case :maps . take ( :dynamic , unfold ( type ) ) do
1932
- :error -> tuple_insert_static_value ( descr , index , type )
1933
- { dynamic , _static } -> dynamic ( tuple_insert_static_value ( descr , index , dynamic ) )
1942
+ :error -> tuple_insert_at_checked ( descr , index , type )
1943
+ { dynamic , _static } -> dynamic ( tuple_insert_at_checked ( descr , index , dynamic ) )
1934
1944
end
1935
1945
end
1936
1946
1937
- def tuple_insert_at ( _ , _ , _ ) , do: :badindex
1947
+ def tuple_insert_at ( _ , _ , _ ) , do: :badrange
1938
1948
1939
- defp tuple_insert_static_value ( descr , index , type ) do
1949
+ defp tuple_insert_at_checked ( descr , index , type ) do
1940
1950
case :maps . take ( :dynamic , descr ) do
1941
1951
:error ->
1942
1952
# Note: the empty type is not a valid input
1943
1953
is_proper_tuple? = descr_key? ( descr , :tuple ) and tuple_only? ( descr )
1944
-
1945
- is_proper_size? =
1946
- index == 0 or subtype? ( Map . take ( descr , [ :tuple ] ) , tuple_of_size_at_least ( index ) )
1954
+ is_proper_size? = index == 0 or tuple_of_size_at_least? ( descr , index )
1947
1955
1948
1956
cond do
1949
- is_proper_tuple? and is_proper_size? -> insert_element ( descr , index , type )
1957
+ is_proper_tuple? and is_proper_size? -> tuple_insert_static ( descr , index , type )
1950
1958
is_proper_tuple? -> :badrange
1951
1959
true -> :badtuple
1952
1960
end
1953
1961
1954
1962
{ dynamic , static } ->
1955
1963
is_proper_tuple? = descr_key? ( dynamic , :tuple ) and tuple_only? ( static )
1956
-
1957
- is_proper_size? =
1958
- index == 0 or subtype? ( Map . take ( static , [ :tuple ] ) , tuple_of_size_at_least ( index ) )
1964
+ is_proper_size? = index == 0 or tuple_of_size_at_least? ( static , index )
1959
1965
1960
1966
cond do
1961
1967
is_proper_tuple? and is_proper_size? ->
1962
- static_result = insert_element ( static , index , type )
1968
+ static_result = tuple_insert_static ( static , index , type )
1969
+
1963
1970
# Prune for dynamic values that make the intersection succeed
1964
1971
dynamic_result =
1965
1972
intersection ( dynamic , tuple_of_size_at_least ( index ) )
1966
- |> insert_element ( index , type )
1973
+ |> tuple_insert_static ( index , type )
1967
1974
1968
1975
union ( dynamic ( dynamic_result ) , static_result )
1969
1976
@@ -1977,9 +1984,9 @@ defmodule Module.Types.Descr do
1977
1984
end
1978
1985
end
1979
1986
1980
- defp insert_element ( descr , _ , _ ) when descr == @ none , do: none ( )
1987
+ defp tuple_insert_static ( descr , _ , _ ) when descr == @ none , do: none ( )
1981
1988
1982
- defp insert_element ( descr , index , type ) do
1989
+ defp tuple_insert_static ( descr , index , type ) do
1983
1990
Map . update! ( descr , :tuple , fn dnf ->
1984
1991
Enum . map ( dnf , fn { tag , elements , negs } ->
1985
1992
{ tag , List . insert_at ( elements , index , type ) ,
@@ -2021,6 +2028,14 @@ defmodule Module.Types.Descr do
2021
2028
( tag == :closed and n < m ) or ( neg_tag == :closed and n > m )
2022
2029
end
2023
2030
2031
+ defp tuple_of_size_at_least ( n ) when is_integer ( n ) and n >= 0 do
2032
+ open_tuple ( List . duplicate ( term ( ) , n ) )
2033
+ end
2034
+
2035
+ defp tuple_of_size_at_least? ( descr , index ) do
2036
+ subtype? ( Map . take ( descr , [ :tuple ] ) , tuple_of_size_at_least ( index ) )
2037
+ end
2038
+
2024
2039
## Pairs
2025
2040
#
2026
2041
# To simplify disjunctive normal forms of e.g., map types, it is useful to
0 commit comments