Skip to content

Commit f58e02a

Browse files
committed
Type check Map.get/2, Map.get/3, Map.get_lazy/3
1 parent 5c586da commit f58e02a

File tree

2 files changed

+395
-212
lines changed

2 files changed

+395
-212
lines changed

lib/elixir/lib/module/types/apply.ex

Lines changed: 67 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -245,6 +245,9 @@ defmodule Module.Types.Apply do
245245

246246
## Map
247247
{Map, :from_struct, [{[open_map()], open_map(__struct__: not_set())}]},
248+
{Map, :get, [{[open_map(), term()], term()}]},
249+
{Map, :get, [{[open_map(), term(), term()], term()}]},
250+
{Map, :get_lazy, [{[open_map(), term(), fun(0)], term()}]},
248251
{Map, :pop, [{[open_map(), term()], tuple([term(), open_map()])}]},
249252
{Map, :pop, [{[open_map(), term(), term()], tuple([term(), open_map()])}]},
250253
{Map, :pop!, [{[open_map(), term()], tuple([term(), open_map()])}]},
@@ -409,40 +412,6 @@ defmodule Module.Types.Apply do
409412
end
410413
end
411414

412-
defp remote_apply(:maps, :from_keys, _info, [list, value_type] = args_types, stack) do
413-
case list_of(list) do
414-
{true, nil} ->
415-
{:ok, return(empty_map(), args_types, stack)}
416-
417-
{empty_list?, key_type} ->
418-
if key_type == dynamic() or key_type == term() do
419-
{:ok, return(open_map(), args_types, stack)}
420-
else
421-
value_type = if_set(value_type)
422-
domain_keys = to_domain_keys(key_type)
423-
424-
keys =
425-
case atom_fetch(key_type) do
426-
{:finite, atom_keys} -> [List.delete(domain_keys, :atom) | atom_keys]
427-
_ -> [domain_keys]
428-
end
429-
430-
map = closed_map(Enum.map(keys, &{&1, value_type}))
431-
432-
map_and_maybe_empty_map =
433-
case empty_list? do
434-
true -> map
435-
false -> difference(map, empty_map())
436-
end
437-
438-
{:ok, return(map_and_maybe_empty_map, args_types, stack)}
439-
end
440-
441-
:badproperlist ->
442-
{:error, badremote(:maps, :from_keys, args_types)}
443-
end
444-
end
445-
446415
@struct_key atom([:__struct__])
447416
@nil_atom atom([nil])
448417

@@ -454,6 +423,36 @@ defmodule Module.Types.Apply do
454423
end
455424
end
456425

426+
defp remote_apply(Map, :get, _info, [map, key] = args_types, stack) do
427+
case map_get(map, key) do
428+
{:ok, value} -> {:ok, return(union(value, @nil_atom), args_types, stack)}
429+
:badmap -> {:error, badremote(:maps, :get, args_types)}
430+
:error -> {:error, {:badkeydomain, map, key, @nil_atom}}
431+
end
432+
end
433+
434+
defp remote_apply(Map, :get, _info, [map, key, default] = args_types, stack) do
435+
case map_get(map, key) do
436+
{:ok, value} -> {:ok, return(union(value, default), args_types, stack)}
437+
:badmap -> {:error, badremote(:maps, :get, args_types)}
438+
:error -> {:error, {:badkeydomain, map, key, default}}
439+
end
440+
end
441+
442+
defp remote_apply(Map, :get_lazy, _info, [map, key, fun] = args_types, stack) do
443+
case fun_apply(fun, []) do
444+
{:ok, default} ->
445+
case map_get(map, key) do
446+
{:ok, value} -> {:ok, return(union(value, default), args_types, stack)}
447+
:badmap -> {:error, badremote(:maps, :get, args_types)}
448+
:error -> {:error, {:badkeydomain, map, key, default}}
449+
end
450+
451+
reason ->
452+
{:error, {:badapply, fun, [], reason}}
453+
end
454+
end
455+
457456
defp remote_apply(Map, :pop, _info, args_types, stack) do
458457
[map, key, default] =
459458
case args_types do
@@ -522,6 +521,40 @@ defmodule Module.Types.Apply do
522521
end
523522
end
524523

524+
defp remote_apply(:maps, :from_keys, _info, [list, value_type] = args_types, stack) do
525+
case list_of(list) do
526+
{true, nil} ->
527+
{:ok, return(empty_map(), args_types, stack)}
528+
529+
{empty_list?, key_type} ->
530+
if key_type == dynamic() or key_type == term() do
531+
{:ok, return(open_map(), args_types, stack)}
532+
else
533+
value_type = if_set(value_type)
534+
domain_keys = to_domain_keys(key_type)
535+
536+
keys =
537+
case atom_fetch(key_type) do
538+
{:finite, atom_keys} -> [List.delete(domain_keys, :atom) | atom_keys]
539+
_ -> [domain_keys]
540+
end
541+
542+
map = closed_map(Enum.map(keys, &{&1, value_type}))
543+
544+
map_and_maybe_empty_map =
545+
case empty_list? do
546+
true -> map
547+
false -> difference(map, empty_map())
548+
end
549+
550+
{:ok, return(map_and_maybe_empty_map, args_types, stack)}
551+
end
552+
553+
:badproperlist ->
554+
{:error, badremote(:maps, :from_keys, args_types)}
555+
end
556+
end
557+
525558
defp remote_apply(:maps, :get, _info, [key, map] = args_types, stack) do
526559
case map_get(map, key) do
527560
{:ok, value} -> {:ok, return(value, args_types, stack)}

0 commit comments

Comments
 (0)