@@ -2974,7 +2974,7 @@ defmodule Module.Types.Descr do
29742974 end
29752975
29762976 _ when is_atom ( tag ) and is_atom ( neg_tag ) ->
2977- case map_difference_strategy ( fields , neg_fields , tag , neg_tag ) do
2977+ case map_difference_strategy ( fields , neg_fields , tag , neg_tag , true ) do
29782978 :disjoint ->
29792979 bdd_leaf ( tag , fields )
29802980
@@ -3007,7 +3007,7 @@ defmodule Module.Types.Descr do
30073007 end
30083008
30093009 defp map_leaf_compare ( bdd_leaf ( tag , fields ) , bdd_leaf ( neg_tag , neg_fields ) ) do
3010- case map_difference_strategy ( fields , neg_fields , tag , neg_tag ) do
3010+ case map_difference_strategy ( fields , neg_fields , tag , neg_tag , false ) do
30113011 :disjoint -> :disjoint
30123012 :left_subtype_of_right -> :subtype
30133013 { :one_key_difference , _ , v1 , v2 } -> if subtype? ( v1 , v2 ) , do: :subtype , else: :none
@@ -4359,7 +4359,7 @@ defmodule Module.Types.Descr do
43594359 if empty_intersection? do
43604360 { acc_fields , acc_negs }
43614361 else
4362- case map_difference_strategy ( acc_fields , neg_fields , tag , neg_tag ) do
4362+ case map_difference_strategy ( acc_fields , neg_fields , tag , neg_tag , true ) do
43634363 { :one_key_difference , key , v1 , v2 } ->
43644364 { fields_store ( key , difference ( v1 , v2 ) , acc_fields ) , acc_negs }
43654365
@@ -4373,16 +4373,16 @@ defmodule Module.Types.Descr do
43734373 end )
43744374 end
43754375
4376- defp map_difference_strategy ( fields1 , fields2 , tag1 , tag2 ) do
4376+ defp map_difference_strategy ( fields1 , fields2 , tag1 , tag2 , okd? ) do
43774377 if is_atom ( tag1 ) and is_atom ( tag2 ) do
43784378 status = if tag1 == tag2 or tag2 == :open , do: :all_equal , else: :none
4379- map_difference_strategy ( fields1 , fields2 , tag1 , tag2 , status )
4379+ map_difference_strategy ( fields1 , fields2 , tag1 , tag2 , okd? , status )
43804380 else
43814381 :none
43824382 end
43834383 end
43844384
4385- defp map_difference_strategy ( [ { k1 , value } | t1 ] , [ { k2 , _ } | _ ] = l2 , tag1 , tag2 , status )
4385+ defp map_difference_strategy ( [ { k1 , value } | t1 ] , [ { k2 , _ } | _ ] = l2 , tag1 , tag2 , okd? , status )
43864386 when k1 < k2 do
43874387 # Left side has a key the right side does not have,
43884388 # left can only be a subtype if the right side is open.
@@ -4392,70 +4392,71 @@ defmodule Module.Types.Descr do
43924392 if not is_optional_static ( value ) do
43934393 :disjoint
43944394 else
4395- map_difference_strategy ( t1 , l2 , tag1 , tag2 , :none )
4395+ map_difference_strategy ( t1 , l2 , tag1 , tag2 , okd? , :none )
43964396 end
43974397
43984398 :all_equal ->
4399- map_difference_strategy ( t1 , l2 , tag1 , tag2 , :left_subtype_of_right )
4399+ map_difference_strategy ( t1 , l2 , tag1 , tag2 , okd? , :left_subtype_of_right )
44004400
44014401 { :one_key_difference , _ , p1 , p2 } ->
44024402 if subtype? ( p1 , p2 ) ,
4403- do: map_difference_strategy ( t1 , l2 , tag1 , tag2 , :left_subtype_of_right ) ,
4403+ do: map_difference_strategy ( t1 , l2 , tag1 , tag2 , okd? , :left_subtype_of_right ) ,
44044404 else: :none
44054405
44064406 :left_subtype_of_right ->
4407- map_difference_strategy ( t1 , l2 , tag1 , tag2 , :left_subtype_of_right )
4407+ map_difference_strategy ( t1 , l2 , tag1 , tag2 , okd? , :left_subtype_of_right )
44084408
44094409 _ ->
44104410 :none
44114411 end
44124412 end
44134413
4414- defp map_difference_strategy ( [ { k1 , _ } | _ ] = l1 , [ { k2 , value } | t2 ] , tag1 , tag2 , _status )
4414+ defp map_difference_strategy ( [ { k1 , _ } | _ ] = l1 , [ { k2 , value } | t2 ] , tag1 , tag2 , okd? , _status )
44154415 when k1 > k2 do
44164416 # Right side has a key the left side does not have,
44174417 # if left-side is closed, they are disjoint.
44184418 if tag1 == :closed and not is_optional_static ( value ) do
44194419 :disjoint
44204420 else
4421- map_difference_strategy ( l1 , t2 , tag1 , tag2 , :none )
4421+ map_difference_strategy ( l1 , t2 , tag1 , tag2 , okd? , :none )
44224422 end
44234423 end
44244424
4425- defp map_difference_strategy ( [ { _ , v } | t1 ] , [ { _ , v } | t2 ] , tag1 , tag2 , status ) do
4425+ defp map_difference_strategy ( [ { _ , v } | t1 ] , [ { _ , v } | t2 ] , tag1 , tag2 , okd? , status ) do
44264426 # Same key and same value, nothing changes
4427- map_difference_strategy ( t1 , t2 , tag1 , tag2 , status )
4427+ map_difference_strategy ( t1 , t2 , tag1 , tag2 , okd? , status )
44284428 end
44294429
4430- defp map_difference_strategy ( [ { k1 , v1 } | t1 ] , [ { _ , v2 } | t2 ] , tag1 , tag2 , status ) do
4430+ defp map_difference_strategy ( [ { k1 , v1 } | t1 ] , [ { _ , v2 } | t2 ] , tag1 , tag2 , okd? , status ) do
44314431 # They have the same key but different values
44324432 if disjoint? ( v1 , v2 ) do
44334433 :disjoint
44344434 else
44354435 case status do
4436- :all_equal when tag1 == tag2 ->
4437- map_difference_strategy ( t1 , t2 , tag1 , tag2 , { :one_key_difference , k1 , v1 , v2 } )
4436+ # Only upgrade to one key difference if we can do something with it
4437+ :all_equal when okd? and tag1 == tag2 ->
4438+ map_difference_strategy ( t1 , t2 , tag1 , tag2 , okd? , { :one_key_difference , k1 , v1 , v2 } )
44384439
44394440 { :one_key_difference , _key , p1 , p2 } ->
44404441 if subtype? ( p1 , p2 ) and subtype? ( v1 , v2 ) do
4441- map_difference_strategy ( t1 , t2 , tag1 , tag2 , :left_subtype_of_right )
4442+ map_difference_strategy ( t1 , t2 , tag1 , tag2 , okd? , :left_subtype_of_right )
44424443 else
44434444 :none
44444445 end
44454446
44464447 _ ->
44474448 if status in [ :all_equal , :left_subtype_of_right ] and subtype? ( v1 , v2 ) ,
4448- do: map_difference_strategy ( t1 , t2 , tag1 , tag2 , :left_subtype_of_right ) ,
4449- else: map_difference_strategy ( t1 , t2 , tag1 , tag2 , :none )
4449+ do: map_difference_strategy ( t1 , t2 , tag1 , tag2 , okd? , :left_subtype_of_right ) ,
4450+ else: map_difference_strategy ( t1 , t2 , tag1 , tag2 , okd? , :none )
44504451 end
44514452 end
44524453 end
44534454
4454- defp map_difference_strategy ( [ ] , [ ] , _tag1 , _tag2 , status ) do
4455+ defp map_difference_strategy ( [ ] , [ ] , _tag1 , _tag2 , _okd? , status ) do
44554456 if status == :all_equal , do: :left_subtype_of_right , else: status
44564457 end
44574458
4458- defp map_difference_strategy ( l1 , l2 , tag1 , tag2 , status ) do
4459+ defp map_difference_strategy ( l1 , l2 , tag1 , tag2 , _okd? , status ) do
44594460 cond do
44604461 tag2 == :open and l2 == [ ] ->
44614462 case status do
0 commit comments