@@ -34,12 +34,16 @@ defmodule Module.Types.Descr do
34
34
@ atom_top { :negation , :sets . new ( version: 2 ) }
35
35
@ map_top [ { :open , % { } , [ ] } ]
36
36
@ map_empty [ { :closed , % { } , [ ] } ]
37
+ @ none % { }
37
38
38
39
# Type definitions
39
40
40
41
def dynamic ( ) , do: % { dynamic: :term }
41
- def none ( ) , do: % { }
42
+ def none ( ) , do: @ none
42
43
def term ( ) , do: :term
44
+
45
+ defp unfold ( :term ) , do: unfolded_term ( )
46
+ defp unfold ( other ) , do: other
43
47
defp unfolded_term , do: % { bitmap: @ bit_top , atom: @ atom_top , map: @ map_top }
44
48
45
49
def atom ( as ) , do: % { atom: atom_new ( as ) }
@@ -81,9 +85,19 @@ defmodule Module.Types.Descr do
81
85
def not_set ( ) , do: @ not_set
82
86
defp term_or_optional ( ) , do: @ term_or_optional
83
87
84
- def if_set ( :term ) , do: @ term_or_optional
88
+ def if_set ( :term ) , do: term_or_optional ( )
85
89
def if_set ( type ) , do: Map . update ( type , :bitmap , @ bit_optional , & ( & 1 ||| @ bit_optional ) )
86
90
91
+ defguardp is_optional ( map )
92
+ when is_map ( map ) and
93
+ ( ( is_map_key ( map , :bitmap ) and ( map . bitmap &&& @ bit_optional ) != 0 ) or
94
+ ( is_map_key ( map , :dynamic ) and is_map ( map . dynamic ) and
95
+ is_map_key ( map . dynamic , :bitmap ) and
96
+ ( map . dynamic . bitmap &&& @ bit_optional ) != 0 ) )
97
+
98
+ defguardp is_optional_static ( map )
99
+ when is_map ( map ) and is_map_key ( map , :bitmap ) and ( map . bitmap &&& @ bit_optional ) != 0
100
+
87
101
## Set operations
88
102
89
103
def term_type? ( :term ) , do: true
@@ -107,8 +121,12 @@ defmodule Module.Types.Descr do
107
121
@ doc """
108
122
Computes the union of two descrs.
109
123
"""
110
- # TODO!!!
111
- def union ( % { } = left , % { } = right ) do
124
+ def union ( :term , other ) when not is_optional ( other ) , do: :term
125
+ def union ( other , :term ) when not is_optional ( other ) , do: :term
126
+
127
+ def union ( left , right ) do
128
+ left = unfold ( left )
129
+ right = unfold ( right )
112
130
is_gradual_left = gradual? ( left )
113
131
is_gradual_right = gradual? ( right )
114
132
@@ -135,8 +153,12 @@ defmodule Module.Types.Descr do
135
153
@ doc """
136
154
Computes the intersection of two descrs.
137
155
"""
138
- # TODO!!!
139
- def intersection ( % { } = left , % { } = right ) do
156
+ def intersection ( :term , other ) when not is_optional ( other ) , do: other
157
+ def intersection ( other , :term ) when not is_optional ( other ) , do: other
158
+
159
+ def intersection ( left , right ) do
160
+ left = unfold ( left )
161
+ right = unfold ( right )
140
162
is_gradual_left = gradual? ( left )
141
163
is_gradual_right = gradual? ( right )
142
164
@@ -164,8 +186,12 @@ defmodule Module.Types.Descr do
164
186
@ doc """
165
187
Computes the difference between two types.
166
188
"""
167
- # TODO!!!
168
- def difference ( left = % { } , right = % { } ) do
189
+ def difference ( other , :term ) when not is_optional ( other ) , do: none ( )
190
+
191
+ def difference ( left , right ) do
192
+ left = unfold ( left )
193
+ right = unfold ( right )
194
+
169
195
if gradual? ( left ) or gradual? ( right ) do
170
196
{ left_dynamic , left_static } = Map . pop ( left , :dynamic , left )
171
197
{ right_dynamic , right_static } = Map . pop ( right , :dynamic , right )
@@ -180,7 +206,6 @@ defmodule Module.Types.Descr do
180
206
end
181
207
182
208
# For static types, the difference is component-wise.
183
- # TODO!!!
184
209
defp difference_static ( left , right ) do
185
210
iterator_difference ( :maps . next ( :maps . iterator ( right ) ) , left )
186
211
end
@@ -209,11 +234,17 @@ defmodule Module.Types.Descr do
209
234
def empty? ( :term ) , do: false
210
235
211
236
def empty? ( % { } = descr ) do
212
- descr = Map . get ( descr , :dynamic , descr )
237
+ case Map . get ( descr , :dynamic , descr ) do
238
+ :term ->
239
+ false
240
+
241
+ value when value == @ none ->
242
+ true
213
243
214
- descr == none ( ) or
215
- ( not Map . has_key? ( descr , :bitmap ) and not Map . has_key? ( descr , :atom ) and
216
- ( not Map . has_key? ( descr , :map ) or map_empty? ( descr . map ) ) )
244
+ descr ->
245
+ not Map . has_key? ( descr , :bitmap ) and not Map . has_key? ( descr , :atom ) and
246
+ ( not Map . has_key? ( descr , :map ) or map_empty? ( descr . map ) )
247
+ end
217
248
end
218
249
219
250
@ doc """
@@ -265,8 +296,11 @@ defmodule Module.Types.Descr do
265
296
Because of the dynamic/static invariant in the `descr`, subtyping can be
266
297
simplified in several cases according to which type is gradual or not.
267
298
"""
268
- # TODO!!!
269
- def subtype? ( % { } = left , % { } = right ) do
299
+ def subtype? ( left , :term ) when not is_optional ( left ) , do: true
300
+
301
+ def subtype? ( left , right ) do
302
+ left = unfold ( left )
303
+ right = unfold ( right )
270
304
is_grad_left = gradual? ( left )
271
305
is_grad_right = gradual? ( right )
272
306
@@ -312,15 +346,18 @@ defmodule Module.Types.Descr do
312
346
include `dynamic()`, `integer()`, but also `dynamic() and (integer() or atom())`.
313
347
Incompatible subtypes include `integer() or list()`, `dynamic() and atom()`.
314
348
"""
315
- # TODO!!!
316
- def compatible? ( input_type , expected_type ) do
317
- { input_dynamic , input_static } = Map . pop ( input_type , :dynamic , input_type )
318
- expected_dynamic = Map . get ( expected_type , :dynamic , expected_type )
349
+ def compatible? ( left , :term ) when not is_optional ( left ) , do: true
350
+
351
+ def compatible? ( left , right ) do
352
+ left = unfold ( left )
353
+ right = unfold ( right )
354
+ { left_dynamic , left_static } = Map . pop ( left , :dynamic , left )
355
+ right_dynamic = Map . get ( right , :dynamic , right )
319
356
320
- if empty? ( input_static ) do
321
- not empty? ( intersection ( input_dynamic , expected_dynamic ) )
357
+ if empty? ( left_static ) do
358
+ not empty? ( intersection ( left_dynamic , right_dynamic ) )
322
359
else
323
- subtype_static ( input_static , expected_dynamic )
360
+ subtype_static ( left_static , right_dynamic )
324
361
end
325
362
end
326
363
@@ -568,20 +605,18 @@ defmodule Module.Types.Descr do
568
605
# `:dynamic` field is not_set, or it contains a type equal to the static component
569
606
# (that is, there are no extra dynamic values).
570
607
571
- # TODO!!!
572
- defp dynamic_intersection ( left , right ) do
573
- inter = symmetrical_intersection ( left , right , & intersection / 3 )
574
- if empty? ( inter ) , do: 0 , else: inter
575
- end
608
+ defp dynamic_union ( :term , other ) when not is_optional_static ( other ) , do: :term
609
+ defp dynamic_union ( other , :term ) when not is_optional_static ( other ) , do: :term
610
+ defp dynamic_union ( left , right ) , do: symmetrical_merge ( unfold ( left ) , unfold ( right ) , & union / 3 )
576
611
577
- # TODO!!!
578
- defp dynamic_difference ( left , right ) do
579
- diff = difference_static ( left , right )
580
- if empty? ( diff ) , do: 0 , else: diff
581
- end
612
+ defp dynamic_intersection ( :term , other ) when not is_optional_static ( other ) , do: other
613
+ defp dynamic_intersection ( other , :term ) when not is_optional_static ( other ) , do: other
614
+
615
+ defp dynamic_intersection ( left , right ) ,
616
+ do: symmetrical_intersection ( unfold ( left ) , unfold ( right ) , & intersection / 3 )
582
617
583
- # TODO!!!
584
- defp dynamic_union ( left , right ) , do: symmetrical_merge ( left , right , & union / 3 )
618
+ defp dynamic_difference ( left , :term ) when not is_optional_static ( left ) , do: % { }
619
+ defp dynamic_difference ( left , right ) , do: difference_static ( unfold ( left ) , unfold ( right ) )
585
620
586
621
defp dynamic_to_quoted ( descr ) do
587
622
cond do
@@ -631,6 +666,10 @@ defmodule Module.Types.Descr do
631
666
end
632
667
end
633
668
669
+ defp map_descr_pairs ( [ { key , :term } | rest ] , acc , dynamic? ) do
670
+ map_descr_pairs ( rest , [ { key , :term } | acc ] , dynamic? )
671
+ end
672
+
634
673
defp map_descr_pairs ( [ { key , value } | rest ] , acc , dynamic? ) do
635
674
case :maps . take ( :dynamic , value ) do
636
675
:error -> map_descr_pairs ( rest , [ { key , value } | acc ] , dynamic? )
@@ -642,9 +681,6 @@ defmodule Module.Types.Descr do
642
681
{ acc , dynamic? }
643
682
end
644
683
645
- defp optional? ( % { bitmap: bitmap } ) when ( bitmap &&& @ bit_optional ) != 0 , do: true
646
- defp optional? ( _ ) , do: false
647
-
648
684
defp map_tag_to_type ( :open ) , do: term_or_optional ( )
649
685
defp map_tag_to_type ( :closed ) , do: not_set ( )
650
686
@@ -665,7 +701,7 @@ defmodule Module.Types.Descr do
665
701
case :maps . take ( :dynamic , descr ) do
666
702
:error ->
667
703
if is_map_key ( descr , :map ) and map_only? ( descr ) do
668
- { static_optional? , static_type } = map_fetch_static ( descr , key ) |> pop_optional ( )
704
+ { static_optional? , static_type } = map_fetch_static ( descr , key ) |> pop_optional_static ( )
669
705
670
706
if static_optional? or empty? ( static_type ) do
671
707
:badkey
@@ -681,8 +717,10 @@ defmodule Module.Types.Descr do
681
717
682
718
{ dynamic , static } ->
683
719
if is_map_key ( dynamic , :map ) and map_only? ( static ) do
684
- { dynamic_optional? , dynamic_type } = map_fetch_static ( dynamic , key ) |> pop_optional ( )
685
- { static_optional? , static_type } = map_fetch_static ( static , key ) |> pop_optional ( )
720
+ { dynamic_optional? , dynamic_type } =
721
+ map_fetch_static ( dynamic , key ) |> pop_optional_static ( )
722
+
723
+ { static_optional? , static_type } = map_fetch_static ( static , key ) |> pop_optional_static ( )
686
724
687
725
if static_optional? or empty? ( dynamic_type ) do
688
726
:badkey
@@ -704,7 +742,7 @@ defmodule Module.Types.Descr do
704
742
end
705
743
end
706
744
707
- defp pop_optional ( type ) do
745
+ defp pop_optional_static ( type ) do
708
746
case type do
709
747
% { bitmap: @ bit_optional } ->
710
748
{ true , Map . delete ( type , :bitmap ) }
@@ -733,6 +771,10 @@ defmodule Module.Types.Descr do
733
771
:empty -> acc
734
772
end
735
773
end
774
+ |> case do
775
+ [ ] -> 0
776
+ acc -> acc
777
+ end
736
778
end
737
779
738
780
# Intersects two map literals; throws if their intersection is empty.
@@ -802,6 +844,10 @@ defmodule Module.Types.Descr do
802
844
end )
803
845
end )
804
846
end )
847
+ |> case do
848
+ [ ] -> 0
849
+ acc -> acc
850
+ end
805
851
end
806
852
807
853
# Emptiness checking for maps.
@@ -826,7 +872,7 @@ defmodule Module.Types.Descr do
826
872
827
873
# The key is not shared between positive and negative maps,
828
874
# and because the negative type is required, there is no value in common
829
- tag == :closed and not optional? ( neg_type ) ->
875
+ tag == :closed and not is_optional_static ( neg_type ) ->
830
876
false
831
877
832
878
# The key is not shared between positive and negative maps,
@@ -847,7 +893,7 @@ defmodule Module.Types.Descr do
847
893
empty? ( diff ) or map_empty? ( tag , Map . put ( fields , key , diff ) , negs )
848
894
849
895
% { } ->
850
- if neg_tag == :closed and not optional? ( type ) do
896
+ if neg_tag == :closed and not is_optional_static ( type ) do
851
897
false
852
898
else
853
899
# an absent key in a open negative map can be ignored
@@ -909,11 +955,11 @@ defmodule Module.Types.Descr do
909
955
defp map_empty_negation? ( tag , fields , { neg_tag , neg_fields } ) do
910
956
( tag == :closed and
911
957
Enum . any? ( neg_fields , fn { neg_key , neg_type } ->
912
- not is_map_key ( fields , neg_key ) and not optional? ( neg_type )
958
+ not is_map_key ( fields , neg_key ) and not is_optional_static ( neg_type )
913
959
end ) ) or
914
960
( neg_tag == :closed and
915
961
Enum . any? ( fields , fn { key , type } ->
916
- not is_map_key ( neg_fields , key ) and not optional? ( type )
962
+ not is_map_key ( neg_fields , key ) and not is_optional_static ( type )
917
963
end ) )
918
964
end
919
965
@@ -970,7 +1016,7 @@ defmodule Module.Types.Descr do
970
1016
keyword? = Inspect.List . keyword? ( sorted )
971
1017
972
1018
for { key , type } <- sorted ,
973
- not ( tag == :open and optional? ( type ) and term_type? ( type ) ) do
1019
+ not ( tag == :open and is_optional_static ( type ) and term_type? ( type ) ) do
974
1020
key =
975
1021
if keyword? do
976
1022
{ :__block__ , [ format: :keyword ] , [ key ] }
@@ -979,7 +1025,7 @@ defmodule Module.Types.Descr do
979
1025
end
980
1026
981
1027
cond do
982
- not optional? ( type ) -> { key , to_quoted ( type ) }
1028
+ not is_optional_static ( type ) -> { key , to_quoted ( type ) }
983
1029
empty? ( type ) -> { key , { :not_set , [ ] , [ ] } }
984
1030
true -> { key , { :if_set , [ ] , [ to_quoted ( type ) ] } }
985
1031
end
@@ -1122,7 +1168,7 @@ defmodule Module.Types.Descr do
1122
1168
% { ^ key => v2 } ->
1123
1169
case fun . ( key , v1 , v2 ) do
1124
1170
0 -> acc
1125
- [ ] -> acc
1171
+ value when value == @ none -> acc
1126
1172
value -> [ { key , value } | acc ]
1127
1173
end
1128
1174
0 commit comments