summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorEric Meadows-Jönsson <eric.meadows.jonsson@gmail.com>2020-07-06 15:42:22 +0200
committerEric Meadows-Jönsson <eric.meadows.jonsson@gmail.com>2020-07-06 15:43:23 +0200
commit1bc87cd117ee8762bfa267985aec2b3dcd7a673b (patch)
treeef4c7e83570f4b011c5a21961720002177fd70ba
parent9ff09855990c6336f030138939a95be6d3a1bb07 (diff)
downloadelixir-emj/is-map-key-optional.tar.gz
is_map_key/2 should add optional keysemj/is-map-key-optional
Closes #10148.
-rw-r--r--lib/elixir/lib/module/types/pattern.ex2
-rw-r--r--lib/elixir/test/elixir/module/types_test.exs31
2 files changed, 32 insertions, 1 deletions
diff --git a/lib/elixir/lib/module/types/pattern.ex b/lib/elixir/lib/module/types/pattern.ex
index aeaea3e2d..907875fb0 100644
--- a/lib/elixir/lib/module/types/pattern.ex
+++ b/lib/elixir/lib/module/types/pattern.ex
@@ -267,7 +267,7 @@ defmodule Module.Types.Pattern do
{:is_integer, 1} => {[:integer], :boolean},
{:is_list, 1} => {[{:list, :dynamic}], :boolean},
{:is_map, 1} => {[{:map, [{:optional, :dynamic, :dynamic}]}], :boolean},
- {:is_map_key, 2} => {[:dynamic, {:map, []}], :dynamic},
+ {:is_map_key, 2} => {[:dynamic, {:map, [{:optional, :dynamic, :dynamic}]}], :dynamic},
{:is_number, 1} => {[:number], :boolean},
{:is_pid, 1} => {[:pid], :boolean},
{:is_port, 1} => {[:port], :boolean},
diff --git a/lib/elixir/test/elixir/module/types_test.exs b/lib/elixir/test/elixir/module/types_test.exs
index a4b7f04d4..b3bee2304 100644
--- a/lib/elixir/test/elixir/module/types_test.exs
+++ b/lib/elixir/test/elixir/module/types_test.exs
@@ -19,6 +19,20 @@ defmodule Module.TypesTest do
end
end
+ defmacrop quoted_fun(patterns, guards \\ [true], body) do
+ quote do
+ {patterns, guards, body} = unquote(Macro.escape(expand_expr(patterns, guards, body)))
+
+ with {:ok, _types, context} <- Types.of_head(patterns, guards, def_expr(), new_context()),
+ {:ok, type, context} <- Types.of_body(body, context) do
+ {:ok, Types.lift_type(type, context)}
+ else
+ {:error, {Types, reason, location}} ->
+ {:error, {reason, location}}
+ end
+ end
+ end
+
defp expand_head(patterns, guards) do
{_, vars} =
Macro.prewalk(patterns, [], fn
@@ -42,6 +56,17 @@ defmodule Module.TypesTest do
{patterns, guards}
end
+ defp expand_expr(patterns, guards, body) do
+ fun =
+ quote do
+ fn unquote(patterns) when unquote(guards) -> unquote(body) end
+ end
+
+ {ast, _env} = :elixir_expand.expand(fun, __ENV__)
+ {:fn, _, [{:->, _, [[{:when, _, [patterns, guards]}], body]}]} = ast
+ {patterns, guards, body}
+ end
+
defp new_context() do
Types.context("types_test.ex", TypesTest, {:test, 0})
end
@@ -249,6 +274,12 @@ defmodule Module.TypesTest do
end
end
+ describe "of_body/2" do
+ test "not is_struct/2" do
+ assert quoted_fun([var], [not is_struct(var, URI)], var.name) == {:ok, {:var, 0}}
+ end
+ end
+
test "format_type/1" do
assert Types.format_type(:binary) == "binary()"
assert Types.format_type({:atom, true}) == "true"