@@ -651,8 +651,8 @@ defmodule Module.Types.Descr do
651
651
652
652
# Intersects two map literals; throws if their intersection is empty.
653
653
defp map_literal_intersection ( tag1 , map1 , tag2 , map2 ) do
654
- default1 = if tag1 == :open , do: term_or_not_set ( ) , else: not_set ( )
655
- default2 = if tag2 == :open , do: term_or_not_set ( ) , else: not_set ( )
654
+ default1 = map_tag_to_type ( tag1 )
655
+ default2 = map_tag_to_type ( tag2 )
656
656
657
657
# if any intersection of values is empty, the whole intersection is empty
658
658
new_fields =
@@ -690,7 +690,11 @@ defmodule Module.Types.Descr do
690
690
end )
691
691
end
692
692
693
- # Emptiness checking for maps. Short-circuits if it finds a non-empty map literal in the union.
693
+ # Emptiness checking for maps.
694
+ #
695
+ # Short-circuits if it finds a non-empty map literal in the union.
696
+ # Since the algorithm is recursive, we implement the short-circuiting
697
+ # as throw/catch.
694
698
defp map_empty? ( dnf ) do
695
699
try do
696
700
for { tag , pos , negs } <- dnf do
@@ -709,20 +713,27 @@ defmodule Module.Types.Descr do
709
713
710
714
defp map_empty? ( tag , fields , [ { neg_tag , neg_fields } | negs ] ) do
711
715
try do
712
- # keys that are present in the negative map, but not in the positive one
716
+ # Keys that are present in the negative map, but not in the positive one
713
717
for { neg_key , neg_type } <- neg_fields , not is_map_key ( fields , neg_key ) do
714
718
cond do
715
- # key is required, and the positive map is closed: empty intersection
719
+ # The key is not shared between positive and negative maps,
720
+ # and because the negative type is required, there is no value in common
716
721
tag == :closed and not optional? ( neg_type ) ->
717
- throw ( :no_intersection )
722
+ throw ( :discard_negative )
723
+
724
+ # The key is not shared between positive and negative maps,
725
+ # but because the negative type is not required, there may be a value in common
726
+ tag == :closed ->
727
+ true
718
728
719
- # if the positive map is open
729
+ # There may be value in common
720
730
tag == :open ->
721
731
diff = difference ( term_or_not_set ( ) , neg_type )
722
732
empty? ( diff ) or map_empty? ( tag , Map . put ( fields , neg_key , diff ) , negs )
723
733
end
724
734
end
725
735
736
+ # Keys from the positive map that may be present in the negative one
726
737
for { key , type } <- fields do
727
738
case neg_fields do
728
739
% { ^ key => neg_type } ->
@@ -731,20 +742,24 @@ defmodule Module.Types.Descr do
731
742
732
743
% { } ->
733
744
if neg_tag == :closed and not optional? ( type ) do
734
- throw ( :no_intersection )
745
+ throw ( :discard_negative )
735
746
else
736
747
# an absent key in a open negative map can be ignored
737
- default2 = if neg_tag == :open , do: @ term_or_not_set , else: @ not_set
738
- diff = difference ( type , default2 )
748
+ diff = difference ( type , map_tag_to_type ( neg_tag ) )
739
749
empty? ( diff ) or map_empty? ( tag , Map . put ( fields , key , diff ) , negs )
740
750
end
741
751
end
742
752
end
753
+
754
+ true
743
755
catch
744
- :no_intersection -> map_empty? ( tag , fields , negs )
756
+ :discard_negative -> map_empty? ( tag , fields , negs )
745
757
end
746
758
end
747
759
760
+ defp map_tag_to_type ( :open ) , do: term_or_not_set ( )
761
+ defp map_tag_to_type ( :closed ) , do: not_set ( )
762
+
748
763
# Takes a map bdd and a key, and returns an equivalent dnf of pairs, in which
749
764
# the type of the key in the map can be found in the first element of the pair.
750
765
# See `split_line_on_key/5`.
0 commit comments