Skip to content

Commit ae38331

Browse files
committed
Deal with struct keys in map updates with atom domains
Closes #15055
1 parent f00cb3a commit ae38331

2 files changed

Lines changed: 55 additions & 42 deletions

File tree

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

Lines changed: 51 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -3089,22 +3089,24 @@ defmodule Module.Types.Descr do
30893089
domain_keys_type ->
30903090
{_seen, acc} =
30913091
bdd_reduce(bdd, {%{}, domain_keys_type}, fn {_tag, fields}, seen_acc ->
3092-
fields
3093-
|> Map.to_list()
3094-
|> Enum.reduce(seen_acc, fn {key, _type}, {seen, acc} ->
3095-
if Map.has_key?(seen, key) do
3096-
{seen, acc}
3097-
else
3098-
{_, value} = map_dnf_fetch_static(dnf, key)
3099-
seen = Map.put(seen, key, [])
3100-
3101-
if empty?(value) do
3092+
:maps.fold(
3093+
fn key, _type, {seen, acc} ->
3094+
if Map.has_key?(seen, key) do
31023095
{seen, acc}
31033096
else
3104-
{seen, union(acc, fun.(atom([key]), value))}
3097+
{_, value} = map_dnf_fetch_static(dnf, key)
3098+
seen = Map.put(seen, key, [])
3099+
3100+
if empty?(value) do
3101+
{seen, acc}
3102+
else
3103+
{seen, union(acc, fun.(atom([key]), value))}
3104+
end
31053105
end
3106-
end
3107-
end)
3106+
end,
3107+
seen_acc,
3108+
fields
3109+
)
31083110
end)
31093111

31103112
acc
@@ -3389,14 +3391,17 @@ defmodule Module.Types.Descr do
33893391
defp map_update_put_negated(bdd, negated, type_fun) do
33903392
bdd_map(bdd, fn {tag, fields} ->
33913393
fields =
3392-
Map.new(fields, fn {key, value} ->
3393-
if :sets.is_element(key, negated) do
3394-
{key, value}
3395-
else
3396-
{optional?, call_value} = pop_optional_static(value)
3397-
{key, union(value, type_fun.(optional?, call_value))}
3398-
end
3399-
end)
3394+
:maps.map(
3395+
fn key, value ->
3396+
if :sets.is_element(key, negated) do
3397+
value
3398+
else
3399+
{optional?, call_value} = pop_optional_static(value)
3400+
union(value, type_fun.(optional?, call_value))
3401+
end
3402+
end,
3403+
fields
3404+
)
34003405

34013406
{tag, fields}
34023407
end)
@@ -3405,34 +3410,38 @@ defmodule Module.Types.Descr do
34053410
defp map_update_merge_atom_key(bdd, dnf) do
34063411
{_seen, acc} =
34073412
bdd_reduce(bdd, {%{}, none()}, fn {_tag, fields}, seen_acc ->
3408-
fields
3409-
|> Map.to_list()
3410-
|> Enum.reduce(seen_acc, fn {key, _type}, {seen, acc} ->
3411-
if Map.has_key?(seen, key) do
3412-
{seen, acc}
3413-
else
3414-
{_, value} = map_dnf_fetch_static(dnf, key)
3415-
{Map.put(seen, key, []), union(acc, value)}
3416-
end
3417-
end)
3413+
:maps.fold(
3414+
fn key, _type, {seen, acc} ->
3415+
if Map.has_key?(seen, key) do
3416+
{seen, acc}
3417+
else
3418+
{_, value} = map_dnf_fetch_static(dnf, key)
3419+
{Map.put(seen, key, []), union(acc, value)}
3420+
end
3421+
end,
3422+
seen_acc,
3423+
fields
3424+
)
34183425
end)
34193426

34203427
acc
34213428
end
34223429

34233430
defp map_update_any_atom_key?(bdd, dnf) do
34243431
bdd_reduce(bdd, %{}, fn {_tag, fields}, acc ->
3425-
fields
3426-
|> Map.to_list()
3427-
|> Enum.reduce(acc, fn {key, _type}, acc ->
3428-
if Map.has_key?(acc, key) do
3429-
acc
3430-
else
3431-
{_, value} = map_dnf_fetch_static(dnf, key)
3432-
not empty?(value) and throw(:found_key)
3433-
Map.put(acc, key, [])
3434-
end
3435-
end)
3432+
:maps.fold(
3433+
fn key, _type, acc ->
3434+
if Map.has_key?(acc, key) do
3435+
acc
3436+
else
3437+
{_, value} = map_dnf_fetch_static(dnf, key)
3438+
not empty?(value) and throw(:found_key)
3439+
Map.put(acc, key, [])
3440+
end
3441+
end,
3442+
acc,
3443+
fields
3444+
)
34363445
end)
34373446
catch
34383447
:found_key -> true

lib/elixir/test/elixir/module/types/descr_test.exs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2116,6 +2116,10 @@ defmodule Module.Types.DescrTest do
21162116
assert map_update(dynamic(closed_map(key: atom([:value]))), dynamic(), atom([:new_value])) ==
21172117
{dynamic(atom([:value])), dynamic(closed_map(key: atom([:value, :new_value]))), []}
21182118

2119+
# Check struct fields
2120+
assert map_update(open_map(__struct__: term()), dynamic(atom()), integer()) ==
2121+
{term(), open_map(__struct__: term()), []}
2122+
21192123
# When precise dynamic keys are given, at least one must succeed
21202124
assert map_update(
21212125
closed_map(key1: atom(), key2: binary()),

0 commit comments

Comments
 (0)