@@ -2260,14 +2260,14 @@ defmodule Module.Types.Descr do
22602260 do: :bdd_bot ,
22612261 else: bdd_leaf ( list1 , difference ( last1 , last2 ) )
22622262 else
2263- bdd_difference ( bdd1 , bdd2 , & list_leaf_compare / 2 )
2263+ bdd_difference ( bdd1 , bdd2 , & list_leaf_difference / 2 )
22642264 end
22652265 end
22662266
22672267 defp list_difference ( bdd1 , bdd2 ) ,
2268- do: bdd_difference ( bdd1 , bdd2 , & list_leaf_compare / 2 )
2268+ do: bdd_difference ( bdd1 , bdd2 , & list_leaf_difference / 2 )
22692269
2270- defp list_leaf_compare ( bdd_leaf ( list1 , last1 ) , bdd_leaf ( list2 , last2 ) ) do
2270+ defp list_leaf_difference ( bdd_leaf ( list1 , last1 ) , bdd_leaf ( list2 , last2 ) ) do
22712271 if disjoint? ( list1 , list2 ) or disjoint? ( last1 , last2 ) do
22722272 :disjoint
22732273 else
@@ -3009,18 +3009,18 @@ defmodule Module.Types.Descr do
30093009 end
30103010
30113011 _ ->
3012- bdd_difference ( map1 , map2 , & map_leaf_compare / 2 )
3012+ bdd_difference ( map1 , map2 , & map_leaf_difference / 2 )
30133013 end
30143014 end
30153015
30163016 defp map_difference ( bdd_leaf ( :open , [ ] ) , bdd2 ) ,
30173017 do: bdd_negation ( bdd2 )
30183018
30193019 defp map_difference ( bdd1 , bdd2 ) do
3020- bdd_difference ( bdd1 , bdd2 , & map_leaf_compare / 2 )
3020+ bdd_difference ( bdd1 , bdd2 , & map_leaf_difference / 2 )
30213021 end
30223022
3023- defp map_leaf_compare ( bdd_leaf ( tag , fields ) , bdd_leaf ( neg_tag , neg_fields ) ) do
3023+ defp map_leaf_difference ( bdd_leaf ( tag , fields ) , bdd_leaf ( neg_tag , neg_fields ) ) do
30243024 case map_difference_strategy ( fields , neg_fields , tag , neg_tag , false ) do
30253025 :disjoint -> :disjoint
30263026 :left_subtype_of_right -> :subtype
@@ -4847,10 +4847,9 @@ defmodule Module.Types.Descr do
48474847 end
48484848
48494849 defp tuple_sizes_strategy ( :closed , n1 , :closed , n2 ) when n1 != n2 , do: :disjoint
4850- defp tuple_sizes_strategy ( :closed , n1 , _ , n2 ) when n1 == n2 , do: :maybe_subtype
4850+ defp tuple_sizes_strategy ( :closed , n1 , :closed , n2 ) when n1 == n2 , do: :left_subtype_of_right
48514851 defp tuple_sizes_strategy ( :closed , n1 , :open , n2 ) when n1 < n2 , do: :disjoint
4852- defp tuple_sizes_strategy ( _ , n1 , :open , n2 ) when n1 == n2 , do: :maybe_subtype
4853- defp tuple_sizes_strategy ( _ , n1 , :open , n2 ) when n1 > n2 , do: :maybe_subtype
4852+ defp tuple_sizes_strategy ( _ , n1 , :open , n2 ) when n1 >= n2 , do: :left_subtype_of_right
48544853 defp tuple_sizes_strategy ( :open , n1 , :closed , n2 ) when n1 > n2 , do: :disjoint
48554854 defp tuple_sizes_strategy ( _ , _ , _ , _ ) , do: :none
48564855
@@ -4879,24 +4878,24 @@ defmodule Module.Types.Descr do
48794878 do: bdd_negation ( bdd2 )
48804879
48814880 defp tuple_difference ( bdd1 , bdd2 ) ,
4882- do: bdd_difference ( bdd1 , bdd2 , & tuple_leaf_compare / 2 )
4881+ do: bdd_difference ( bdd1 , bdd2 , & tuple_leaf_difference / 2 )
48834882
4884- defp tuple_leaf_compare ( bdd_leaf ( tag1 , elements1 ) , bdd_leaf ( tag2 , elements2 ) ) do
4883+ defp tuple_leaf_difference ( bdd_leaf ( tag1 , elements1 ) , bdd_leaf ( tag2 , elements2 ) ) do
48854884 case tuple_sizes_strategy ( tag1 , length ( elements1 ) , tag2 , length ( elements2 ) ) do
48864885 :disjoint -> :disjoint
4887- other -> tuple_leaf_compare ( elements1 , elements2 , other == :maybe_subtype )
4886+ other -> tuple_leaf_difference ( elements1 , elements2 , other == :left_subtype_of_right )
48884887 end
48894888 end
48904889
4891- defp tuple_leaf_compare ( [ head1 | tail1 ] , [ head2 | tail2 ] , subtype? ) do
4890+ defp tuple_leaf_difference ( [ head1 | tail1 ] , [ head2 | tail2 ] , subtype? ) do
48924891 cond do
48934892 disjoint? ( head1 , head2 ) -> :disjoint
4894- subtype? and subtype? ( head1 , head2 ) -> tuple_leaf_compare ( tail1 , tail2 , subtype? )
4893+ subtype? and subtype? ( head1 , head2 ) -> tuple_leaf_difference ( tail1 , tail2 , subtype? )
48954894 true -> :none
48964895 end
48974896 end
48984897
4899- defp tuple_leaf_compare ( _tail1 , _tail2 , subtype? ) do
4898+ defp tuple_leaf_difference ( _tail1 , _tail2 , subtype? ) do
49004899 if subtype? , do: :subtype , else: :none
49014900 end
49024901
@@ -4996,8 +4995,8 @@ defmodule Module.Types.Descr do
49964995 [ { tag , elements } ]
49974996 else
49984997 tuple_dnf_union (
4999- tuple_elim_content ( [ ] , tag , elements , neg_elements ) ,
5000- tuple_elim_size ( n , m , tag , elements , neg_tag )
4998+ tuple_elim_size ( n , m , tag , elements , neg_tag ) ,
4999+ tuple_elim_content ( [ ] , tag , elements , neg_elements )
50015000 )
50025001 end
50035002 end
@@ -5077,17 +5076,15 @@ defmodule Module.Types.Descr do
50775076 )
50785077 end
50795078
5079+ # Prefer the smaller on the left
50805080 defp tuple_dnf_union ( dnf1 , dnf2 ) do
5081- # Union of tuple DNFs is just concatenation, but we rely on some optimization strategies to
5082- # avoid the list to grow when possible
5083-
5084- # first pass trying to identify patterns where two maps can be fused as one
5081+ # Union of tuple DNFs is just concatenation,
5082+ # but we do our best to remove duplicates.
50855083 with [ tuple1 ] <- dnf1 ,
50865084 [ tuple2 ] <- dnf2 ,
50875085 optimized when optimized != nil <- maybe_optimize_tuple_union ( tuple1 , tuple2 ) do
50885086 [ optimized ]
50895087 else
5090- # otherwise we just concatenate and remove structural duplicates
50915088 _ -> dnf1 ++ ( dnf2 -- dnf1 )
50925089 end
50935090 end
@@ -5106,7 +5103,7 @@ defmodule Module.Types.Descr do
51065103 defp tuple_union ( bdd1 , bdd2 ) , do: bdd_union ( bdd1 , bdd2 )
51075104
51085105 defp maybe_optimize_tuple_union ( { tag1 , pos1 } = tuple1 , { tag2 , pos2 } = tuple2 ) do
5109- case tuple_union_optimization_strategy ( tag1 , pos1 , tag2 , pos2 ) do
5106+ case tuple_union_strategy ( tag1 , pos1 , tag2 , pos2 ) do
51105107 :all_equal ->
51115108 tuple1
51125109
@@ -5120,75 +5117,62 @@ defmodule Module.Types.Descr do
51205117 :right_subtype_of_left ->
51215118 tuple1
51225119
5123- nil ->
5120+ :none ->
51245121 nil
51255122 end
51265123 end
51275124
5128- defp maybe_optimize_tuple_union ( _ , _ ) , do: nil
5129-
5130- defp tuple_union_optimization_strategy ( tag1 , pos1 , tag2 , pos2 )
5131- defp tuple_union_optimization_strategy ( tag , pos , tag , pos ) , do: : all_equal
5125+ defp tuple_union_strategy ( tag1 , pos1 , tag2 , pos2 ) do
5126+ case { tag1 , tag2 } do
5127+ { tag , tag } when length ( pos1 ) == length ( pos2 ) ->
5128+ tuple_union_strategy_index ( pos1 , pos2 , 0 , : all_equal)
51325129
5133- # might be one extra loop but cheap and avoids doing deep subtype comparisons
5134- defp tuple_union_optimization_strategy ( :closed , pos1 , :closed , pos2 )
5135- when length ( pos1 ) != length ( pos2 ) ,
5136- do: nil
5130+ { :open , _ } when length ( pos1 ) <= length ( pos2 ) ->
5131+ tuple_union_strategy_index ( pos1 , pos2 , 0 , :right_subtype_of_left )
51375132
5138- defp tuple_union_optimization_strategy ( tag1 , pos1 , tag2 , pos2 ) do
5139- status =
5140- case { tag1 , tag2 } do
5141- { :open , :closed } -> :right_subtype_of_left
5142- { :closed , :open } -> :left_subtype_of_right
5143- { same , same } -> :all_equal
5144- end
5133+ { _ , :open } when length ( pos1 ) >= length ( pos2 ) ->
5134+ tuple_union_strategy_index ( pos1 , pos2 , 0 , :left_subtype_of_right )
51455135
5146- do_tuple_union_optimization_strategy ( tag1 , pos1 , tag2 , pos2 , 0 , status )
5136+ { _ , _ } ->
5137+ :none
5138+ end
51475139 end
51485140
5149- defp do_tuple_union_optimization_strategy ( _tag1 , [ ] , _tag2 , [ ] , _i , status ) , do: status
5150-
5151- defp do_tuple_union_optimization_strategy ( :open , [ ] , _tag2 , _pos2 , _i , status )
5152- when status in [ :all_equal , :right_subtype_of_left ] ,
5153- do: :right_subtype_of_left
5154-
5155- defp do_tuple_union_optimization_strategy ( _tag1 , _pos1 , :open , [ ] , _i , status )
5156- when status in [ :all_equal , :left_subtype_of_right ] ,
5157- do: :left_subtype_of_right
5158-
5159- defp do_tuple_union_optimization_strategy ( tag1 , [ v1 | pos1 ] , tag2 , [ v2 | pos2 ] , i , status ) do
5160- if next_status = tuple_union_next_strategy ( i , v1 , v2 , status ) do
5161- do_tuple_union_optimization_strategy ( tag1 , pos1 , tag2 , pos2 , i + 1 , next_status )
5162- end
5141+ defp tuple_union_strategy_index ( [ v | pos1 ] , [ v | pos2 ] , i , status ) do
5142+ tuple_union_strategy_index ( pos1 , pos2 , i + 1 , status )
51635143 end
51645144
5165- defp do_tuple_union_optimization_strategy ( _tag1 , _pos1 , _tag2 , _pos2 , _i , _status ) , do: nil
5145+ defp tuple_union_strategy_index ( [ v1 | pos1 ] , [ v2 | pos2 ] , i , status ) do
5146+ case status do
5147+ :all_equal ->
5148+ tuple_union_strategy_index ( pos1 , pos2 , i + 1 , { :one_index_difference , i , v1 , v2 } )
5149+
5150+ { :one_index_difference , _ , d1 , d2 } ->
5151+ cond do
5152+ subtype? ( d1 , d2 ) and subtype? ( v1 , v2 ) ->
5153+ tuple_union_strategy_index ( pos1 , pos2 , i + 1 , :left_subtype_of_right )
51665154
5167- defp tuple_union_next_strategy ( index , v1 , v2 , status )
5155+ subtype? ( d2 , d1 ) and subtype? ( v2 , v1 ) ->
5156+ tuple_union_strategy_index ( pos1 , pos2 , i + 1 , :right_subtype_of_left )
51685157
5169- # structurally equal values do not impact the ongoing strategy
5170- defp tuple_union_next_strategy ( _index , same , same , status ) , do: status
5158+ true ->
5159+ :none
5160+ end
51715161
5172- defp tuple_union_next_strategy ( index , v1 , v2 , :all_equal ) do
5173- { :one_index_difference , index , v1 , v2 }
5174- end
5162+ :left_subtype_of_right ->
5163+ if subtype? ( v1 , v2 ) ,
5164+ do: tuple_union_strategy_index ( pos1 , pos2 , i + 1 , :left_subtype_of_right ) ,
5165+ else: :none
51755166
5176- defp tuple_union_next_strategy ( _index , v1 , v2 , { :one_index_difference , _ , d1 , d2 } ) do
5177- # we have at least two differences now, we switch strategy
5178- # if both are subtypes in one direction, keep checking
5179- cond do
5180- subtype? ( d1 , d2 ) and subtype? ( v1 , v2 ) -> :left_subtype_of_right
5181- subtype? ( d2 , d1 ) and subtype? ( v2 , v1 ) -> :right_subtype_of_left
5182- true -> nil
5167+ :right_subtype_of_left ->
5168+ if subtype? ( v2 , v1 ) ,
5169+ do: tuple_union_strategy_index ( pos1 , pos2 , i + 1 , :right_subtype_of_left ) ,
5170+ else: :none
51835171 end
51845172 end
51855173
5186- defp tuple_union_next_strategy ( _index , v1 , v2 , :left_subtype_of_right ) do
5187- if subtype? ( v1 , v2 ) , do: :left_subtype_of_right
5188- end
5189-
5190- defp tuple_union_next_strategy ( _index , v1 , v2 , :right_subtype_of_left ) do
5191- if subtype? ( v2 , v1 ) , do: :right_subtype_of_left
5174+ defp tuple_union_strategy_index ( _pos1 , _pos2 , _i , status ) do
5175+ status
51925176 end
51935177
51945178 defp tuple_to_quoted ( bdd , opts ) do
0 commit comments