Skip to content

Commit 2639028

Browse files
committed
Do not always compute one key difference in map difference
1 parent 9add533 commit 2639028

1 file changed

Lines changed: 23 additions & 22 deletions

File tree

lib/elixir/lib/module/types/descr.ex

Lines changed: 23 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -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

Comments
 (0)