diff --git a/lib/elixir/lib/code/normalizer.ex b/lib/elixir/lib/code/normalizer.ex index 851e7f1e35..68f5408055 100644 --- a/lib/elixir/lib/code/normalizer.ex +++ b/lib/elixir/lib/code/normalizer.ex @@ -419,8 +419,28 @@ defmodule Code.Normalizer do defp normalize_kw_args(elems, state, keyword? \\ false) + defp normalize_kw_args( + [{{:__block__, key_meta, [key]}, value} = first | rest] = current, + state, + keyword? + ) + when is_atom(key) do + keyword? = keyword? or keyword?(current) + + first = + if key_meta[:format] == :keyword and not keyword? do + key_meta = Keyword.delete(key_meta, :format) + line = key_meta[:line] || meta_line(state) + {:__block__, [line: line], [{{:__block__, key_meta, [key]}, value}]} + else + first + end + + [first | normalize_kw_args(rest, state, keyword?)] + end + defp normalize_kw_args([{left, right} | rest] = current, state, keyword?) do - keyword? = keyword? or Inspect.List.keyword?(current) + keyword? = keyword? or keyword?(current) left = if keyword? do @@ -500,4 +520,22 @@ defmodule Code.Normalizer do [] end end + + defp keyword?([{{:__block__, key_meta, [key]}, _} | rest]) when is_atom(key) do + if key_meta[:format] == :keyword do + keyword?(rest) + else + false + end + end + + defp keyword?([{key, _value} | rest]) when is_atom(key) do + case Atom.to_charlist(key) do + 'Elixir.' ++ _ -> false + _ -> keyword?(rest) + end + end + + defp keyword?([]), do: true + defp keyword?(_other), do: false end diff --git a/lib/elixir/test/elixir/code_normalizer/quoted_ast_test.exs b/lib/elixir/test/elixir/code_normalizer/quoted_ast_test.exs index 4412ba6133..c39e185033 100644 --- a/lib/elixir/test/elixir/code_normalizer/quoted_ast_test.exs +++ b/lib/elixir/test/elixir/code_normalizer/quoted_ast_test.exs @@ -469,6 +469,10 @@ defmodule Code.Normalizer.QuotedASTTest do assert quoted_to_string(quote(do: [a: 1, b: 1 + 2])) == "[a: 1, b: 1 + 2]" assert quoted_to_string(quote(do: ["a.b": 1, c: 1 + 2])) == "[\"a.b\": 1, c: 1 + 2]" + tuple = {{:__block__, [format: :keyword], [:a]}, {:b, [], nil}} + assert quoted_to_string([tuple, :foo, tuple]) == "[{:a, b}, :foo, a: b]" + assert quoted_to_string([tuple, :foo, {:c, :d}, tuple]) == "[{:a, b}, :foo, c: :d, a: b]" + # Not keyword lists assert quoted_to_string(quote(do: [{binary(), integer()}])) == "[{binary(), integer()}]" end