Skip to content

Commit 4064905

Browse files
committed
Do not perform structural operations on leaf difference
1 parent 6cb9140 commit 4064905

1 file changed

Lines changed: 17 additions & 52 deletions

File tree

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

Lines changed: 17 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -3080,29 +3080,30 @@ defmodule Module.Types.Descr do
30803080
defp map_difference(_, bdd_leaf(:open, [])),
30813081
do: :bdd_bot
30823082

3083-
defp map_difference(bdd_leaf(tag, fields) = map1, bdd_leaf(:open, [{key, v2}])) do
3083+
defp map_difference(bdd1, bdd2),
3084+
do: bdd_difference(bdd1, bdd2, &map_leaf_difference/3)
3085+
3086+
# We only apply this particular optimization when comparing leafs (type == :none).
3087+
# Applying it in other scenarios lead to slow compilation, likely because the
3088+
# introduction of `a_int` and `a_union` lead to additional nodes and large rehashes
3089+
# of the tree.
3090+
#
3091+
# Outside of this particular scenario, the `a_int` optimization has been useful,
3092+
# but we haven't measured benefits for `a_union`.
3093+
defp map_leaf_difference(bdd_leaf(tag, fields), bdd_leaf(:open, [{key, v2}]), :none) do
30843094
{found?, v1} =
30853095
case fields_find(key, fields) do
30863096
{:ok, value} -> {true, value}
30873097
:error -> {false, map_key_tag_to_type(tag)}
30883098
end
30893099

30903100
if tag == :closed and not found? and not is_optional_static(v2) do
3091-
map1
3101+
:disjoint
30923102
else
3093-
v_diff = difference(v1, v2)
3094-
3095-
if empty?(v_diff) do
3096-
:bdd_bot
3097-
else
3098-
bdd_leaf(tag, fields_store(key, v_diff, fields))
3099-
end
3103+
map_leaf_one_key_difference(tag, fields, key, v1, v2, :none)
31003104
end
31013105
end
31023106

3103-
defp map_difference(bdd1, bdd2),
3104-
do: bdd_difference(bdd1, bdd2, &map_leaf_difference/3)
3105-
31063107
defp map_leaf_difference(bdd_leaf(tag, fields), bdd_leaf(neg_tag, neg_fields), type) do
31073108
case map_difference_strategy(fields, neg_fields, tag, neg_tag) do
31083109
:disjoint ->
@@ -5884,17 +5885,6 @@ defmodule Module.Types.Descr do
58845885

58855886
## Optimize differences
58865887

5887-
defp bdd_difference(bdd_leaf(_, _) = bdd1, bdd_leaf(_, _) = bdd2, leaf_compare) do
5888-
case leaf_compare.(bdd1, bdd2, :none) do
5889-
:disjoint -> bdd1
5890-
{:one_key_difference, a_diff, _a_none} -> a_diff
5891-
:subtype -> :bdd_bot
5892-
:none when bdd2 < bdd1 -> {bdd2, :bdd_bot, :bdd_bot, bdd1}
5893-
:none when bdd1 < bdd2 -> {bdd1, bdd_negation(bdd2), :bdd_bot, :bdd_bot}
5894-
:none -> :bdd_bot
5895-
end
5896-
end
5897-
58985888
# For the right-side being a leaf, we have:
58995889
#
59005890
# ((a1 and C1) or U1 or (not a1 and D1)) and not a2
@@ -5933,21 +5923,8 @@ defmodule Module.Types.Descr do
59335923
:subtype ->
59345924
bdd_union(bdd_difference(u1, bdd2, leaf_compare), bdd_difference(d1, bdd2, leaf_compare))
59355925

5936-
:none when a1 < bdd2 ->
5937-
{a1, bdd_difference(c1, bdd2, leaf_compare), bdd_difference(u1, bdd2, leaf_compare),
5938-
bdd_difference(d1, bdd2, leaf_compare)}
5939-
5940-
:none when bdd2 < a1 ->
5941-
{bdd2, :bdd_bot, :bdd_bot, bdd1}
5942-
59435926
:none ->
5944-
# There is no point in traversing down if they are equal,
5945-
# as we can assume this check already happened when building bdd1
5946-
{bdd2, :bdd_bot, :bdd_bot, bdd_union(u1, d1)}
5947-
end
5948-
|> case do
5949-
{_, :bdd_bot, u, :bdd_bot} -> u
5950-
other -> other
5927+
bdd_difference(bdd1, bdd2)
59515928
end
59525929
end
59535930

@@ -5993,8 +5970,9 @@ defmodule Module.Types.Descr do
59935970
#
59945971
defp bdd_difference(bdd_leaf(_, _) = bdd1, bdd2, leaf_compare) when is_tuple(bdd2) do
59955972
{a2, c2, u2, d2} = bdd_expand(bdd2)
5973+
type = if c2 == :bdd_top, do: :none, else: :intersection
59965974

5997-
case leaf_compare.(bdd1, a2, :intersection) do
5975+
case leaf_compare.(bdd1, a2, type) do
59985976
:disjoint ->
59995977
bdd1 |> bdd_difference(d2, leaf_compare) |> bdd_difference(u2, leaf_compare)
60005978

@@ -6007,21 +5985,8 @@ defmodule Module.Types.Descr do
60075985
:subtype ->
60085986
bdd1 |> bdd_difference(c2, leaf_compare) |> bdd_difference(u2, leaf_compare)
60095987

6010-
:none when a2 < bdd1 ->
6011-
{a2, bdd_difference(bdd1, bdd_union(c2, u2), leaf_compare), :bdd_bot,
6012-
bdd_difference(bdd1, bdd_union(d2, u2), leaf_compare)}
6013-
6014-
:none when bdd1 < a2 ->
6015-
{bdd1, bdd_negation(bdd2), :bdd_bot, :bdd_bot}
6016-
60175988
:none ->
6018-
# There is no point in traversing down if they are equal,
6019-
# as we can assume this check already happened when building bdd2
6020-
{bdd1, bdd_negation(bdd_union(c2, u2)), :bdd_bot, :bdd_bot}
6021-
end
6022-
|> case do
6023-
{_, :bdd_bot, u, :bdd_bot} -> u
6024-
other -> other
5989+
bdd_difference(bdd1, bdd2)
60255990
end
60265991
end
60275992

0 commit comments

Comments
 (0)