@@ -6390,7 +6390,30 @@ defmodule Module.Types.Descr do
63906390 defp opt_map_difference ( bdd1 , bdd2 ) ,
63916391 do: bdd_difference ( bdd1 , bdd2 , & opt_map_leaf_difference / 3 )
63926392
6393- defp opt_map_leaf_difference ( bdd_leaf ( tag , fields ) , bdd_leaf ( :open , [ { key , v2 } ] ) , type ) do
6393+ # This clause optimizes differences with an open single-key right side:
6394+ #
6395+ # %{b: atom(), c: pid()} \ %{..., c: if_set(pid() | binary())}
6396+ #
6397+ # Depending on the surrounding BDD shape, the difference formulas ask the
6398+ # leaf comparison for a direct difference plus an optional intersection
6399+ # or optional union.
6400+ #
6401+ # Because the right-hand side is an open map with a single key, this branch
6402+ # assumes the result can be represented by updating the matching key
6403+ # on the left-hand side. For this pair, the direct difference is empty and
6404+ # the intersection is `%{b: atom(), c: pid()}`, which are both correct.
6405+ #
6406+ # However, when the formula needs the union, this shortcut would produce
6407+ # `%{b: atom(), c: if_set(pid() or binary())}` by preserving the left shape.
6408+ # This is not the semantic union, because the right side also includes maps
6409+ # without `:b`. In other words, we cannot always union them by updating only
6410+ # the matching key.
6411+ #
6412+ # Therefore, this clause is only used when `type` is `:intersection` or `:none`.
6413+ # `:union` falls through to the general clause below. The reason we have
6414+ # this long comment is because this was a regression in the past.
6415+ defp opt_map_leaf_difference ( bdd_leaf ( tag , fields ) , bdd_leaf ( :open , [ { key , v2 } ] ) , type )
6416+ when type != :union do
63946417 { found? , v1 } =
63956418 case fields_find ( key , fields ) do
63966419 { :ok , value } -> { true , value }
0 commit comments