summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorfelipe stival <14948182+v0idpwn@users.noreply.github.com>2022-01-06 01:48:04 +0200
committerGitHub <noreply@github.com>2022-01-06 00:48:04 +0100
commit953c730cc8addd23a079dfa3a4850a40d299c2a0 (patch)
treea11a3884bf56d424537f2bbf57118fe6d1933f92
parent64ac646a24f8e0d7f0eb6f0ae2152a578df5cebe (diff)
downloadelixir-953c730cc8addd23a079dfa3a4850a40d299c2a0.tar.gz
EEP 52: Allow pins inside map keys in matches (#11544)
-rw-r--r--lib/elixir/src/elixir_map.erl11
-rw-r--r--lib/elixir/test/elixir/kernel/expansion_test.exs17
-rw-r--r--lib/elixir/test/elixir/module/types/map_test.exs7
3 files changed, 16 insertions, 19 deletions
diff --git a/lib/elixir/src/elixir_map.erl b/lib/elixir/src/elixir_map.erl
index 3da517ae8..560b7a437 100644
--- a/lib/elixir/src/elixir_map.erl
+++ b/lib/elixir/src/elixir_map.erl
@@ -60,10 +60,10 @@ clean_struct_key_from_map_assocs(Meta, Assocs, E) ->
Assocs
end.
-validate_match_key(Meta, {'^', _, [{Name, _, Context}]}, E) when is_atom(Name), is_atom(Context) ->
- form_error(Meta, E, ?MODULE, {invalid_pin_in_map_key_match, Name});
validate_match_key(Meta, {Name, _, Context}, E) when is_atom(Name), is_atom(Context) ->
form_error(Meta, E, ?MODULE, {invalid_variable_in_map_key_match, Name});
+validate_match_key(_, {'^', _, [{Name, _, Context}]}, _) when is_atom(Name), is_atom(Context) ->
+ ok;
validate_match_key(_, {'%{}', _, [_ | _]}, _) ->
ok;
validate_match_key(Meta, {Left, _, Right}, E) ->
@@ -102,8 +102,6 @@ is_literal(_) -> true.
validate_kv(Meta, KV, Original, #{context := Context} = E) ->
lists:foldl(fun
- ({{'^', _, [_]}, _}, {Index, Used}) ->
- {Index + 1, Used};
({K, _V}, {Index, Used}) ->
(Context == match) andalso validate_match_key(Meta, K, E),
NewUsed = validate_not_repeated(Meta, K, Used, E),
@@ -202,11 +200,6 @@ format_error({invalid_struct_name_in_match, Expr}) ->
format_error({invalid_struct_name, Expr}) ->
Message = "expected struct name to be a compile time atom or alias, got: ~ts",
io_lib:format(Message, ['Elixir.Macro':to_string(Expr)]);
-format_error({invalid_pin_in_map_key_match, Name}) ->
- Message =
- "cannot use pin operator ^~ts inside a data structure as a map key in a pattern. "
- "The pin operator can only be used as the whole key",
- io_lib:format(Message, [Name]);
format_error({invalid_variable_in_map_key_match, Name}) ->
Message =
"cannot use variable ~ts as map key inside a pattern. Map keys in patterns can only be literals "
diff --git a/lib/elixir/test/elixir/kernel/expansion_test.exs b/lib/elixir/test/elixir/kernel/expansion_test.exs
index 360058d4a..8282a094d 100644
--- a/lib/elixir/test/elixir/kernel/expansion_test.exs
+++ b/lib/elixir/test/elixir/kernel/expansion_test.exs
@@ -475,16 +475,13 @@ defmodule Kernel.ExpansionTest do
assert expand(ast) == ast
- assert_raise CompileError,
- ~r"cannot use pin operator \^x inside a data structure as a map key in a pattern",
- fn ->
- expand(
- quote do
- x = 1
- %{{^x} => 1} = %{}
- end
- )
- end
+ ast =
+ quote do
+ x = 1
+ %{{^x} => 1} = %{{1} => 1}
+ end
+
+ assert expand(ast) == ast
assert_raise CompileError, ~r"cannot use variable x as map key inside a pattern", fn ->
expand(quote(do: %{x => 1} = %{}))
diff --git a/lib/elixir/test/elixir/module/types/map_test.exs b/lib/elixir/test/elixir/module/types/map_test.exs
index f416d77da..5324c8453 100644
--- a/lib/elixir/test/elixir/module/types/map_test.exs
+++ b/lib/elixir/test/elixir/module/types/map_test.exs
@@ -160,6 +160,13 @@ defmodule Module.Types.MapTest do
)
) == {:ok, {:map, [{:required, {:atom, :a}, {:atom, :b}}]}}
+ assert quoted_expr(
+ (
+ a = :a
+ %{{^a, :b} => :c} = %{{:a, :b} => :c}
+ )
+ ) == {:ok, {:map, [{:required, {:tuple, 2, [{:atom, :a}, {:atom, :b}]}, {:atom, :c}}]}}
+
assert {:error,
{:unable_unify,
{{:map, [{:required, {:atom, :c}, {:atom, :d}}]},