diff --git a/lib/elixir/src/elixir_quote.erl b/lib/elixir/src/elixir_quote.erl index d4f0815fdc..3f872cd794 100644 --- a/lib/elixir/src/elixir_quote.erl +++ b/lib/elixir/src/elixir_quote.erl @@ -164,15 +164,7 @@ do_escape(BitString, _) when is_bitstring(BitString) -> end; do_escape(Map, Q) when is_map(Map) -> - TT = - [if - is_reference(V) -> - argument_error(<<('Elixir.Kernel':inspect(Map, []))/binary, " contains a reference (", - ('Elixir.Kernel':inspect(V, []))/binary, ") and therefore it cannot be escaped ", - "(it must be defined within a function instead). ", (bad_escape_hint())/binary>>); - true -> - {do_quote(K, Q), do_quote(V, Q)} - end || {K, V} <- lists:sort(maps:to_list(Map))], + TT = [escape_map_key_value(K, V, Map, Q) || {K, V} <- lists:sort(maps:to_list(Map))], {'%{}', [], TT}; do_escape([], _) -> @@ -206,6 +198,28 @@ do_escape(Fun, _) when is_function(Fun) -> do_escape(Other, _) -> bad_escape(Other). +escape_map_key_value(K, V, Map, Q) -> + MaybeRef = if + is_reference(V) -> V; + is_tuple(V) -> find_tuple_ref(V, 1); + true -> nil + end, + if + is_reference(MaybeRef) -> + argument_error(<<('Elixir.Kernel':inspect(Map, []))/binary, " contains a reference (", + ('Elixir.Kernel':inspect(MaybeRef, []))/binary, ") and therefore it cannot be escaped ", + "(it must be defined within a function instead). ", (bad_escape_hint())/binary>>); + true -> + {do_quote(K, Q), do_quote(V, Q)} + end. + +find_tuple_ref(Tuple, Index) when Index > tuple_size(Tuple) -> nil; +find_tuple_ref(Tuple, Index) -> + case element(Index, Tuple) of + Ref when is_reference(Ref) -> Ref; + _ -> find_tuple_ref(Tuple, Index + 1) + end. + bad_escape(Arg) -> argument_error(<<"cannot escape ", ('Elixir.Kernel':inspect(Arg, []))/binary, ". ", (bad_escape_hint())/binary>>). diff --git a/lib/elixir/test/elixir/macro_test.exs b/lib/elixir/test/elixir/macro_test.exs index 6c1503c74e..e53111362c 100644 --- a/lib/elixir/test/elixir/macro_test.exs +++ b/lib/elixir/test/elixir/macro_test.exs @@ -143,7 +143,7 @@ defmodule MacroTest do test "inspects container when a reference cannot be escaped" do assert_raise ArgumentError, ~r"~r/foo/ contains a reference", fn -> - Macro.escape(%{~r/foo/ | re_pattern: make_ref()}) + Macro.escape(%{~r/foo/ | re_pattern: {:re_pattern, 0, 0, 0, make_ref()}}) end end end