Elixir: Formatter incorrectly remove nested parens on unquote

Created on 7 Jul 2019  路  2Comments  路  Source: elixir-lang/elixir

quote do
  unquote(:foo)() do
    "bar"
  end
end

becomes

quote do
  unquote(:foo) do
    "bar"
  end
end

Which has different meaning (and AST).

Elixir Bug Advanced Formatter

Most helpful comment

It is a bug in the formatter. You don't need a special rule for unquote. The rule should still apply for something like foo(bar)() do ... end (this is not a semantically valid expression but the formatter does not care about it). In a nutshell, the issue is that if we see a function call with only do blocks and without any other parens, such as foo() do ... end, we automatically remove the parens into foo() do ... end. The fix is that we shouldn't remove the parens if the parens are being applied to a function call in itself.

All 2 comments

Do you expect that the fix for this will be in the parser or the formatter?

From what i can tell, the parens are present after tokenizing

elixir [ {:paren_identifier, {1, 1, nil}, :unquote}, {:"(", {1, 8, nil}}, {:atom, {1, 9, nil}, :foo}, {:")", {1, 13, nil}}, {:"(", {1, 14, nil}}, {:")", {1, 15, nil}}, {:do, {1, 17, nil}}, {:eol, {1, 19, 1}}, {:bin_string, {2, 3, nil}, ["bar"]}, {:eol, {2, 8, 1}}, {:end, {3, 1, nil}}, {:eol, {3, 4, 1}} ]

but that information is lost after parsing (which I believe is the correct behavior.)

elixir {{:unquote, [closing: [line: 1], line: 1], [{:__block__, [delimiter: ":", line: 1], [:foo]}]}, [ do: [line: 1], end: [line: 3], closing: [line: 1], closing: [line: 1], line: 1 ], [ [ {{:__block__, [line: 1], [:do]}, {:__block__, [delimiter: "\"", line: 2], ["bar"]}} ] ]}


I'm not sure how this could be fixed without some special rule regarding calls to unquote in the formatter, but that doesn't seem like a robust solution.

What do you think?

It is a bug in the formatter. You don't need a special rule for unquote. The rule should still apply for something like foo(bar)() do ... end (this is not a semantically valid expression but the formatter does not care about it). In a nutshell, the issue is that if we see a function call with only do blocks and without any other parens, such as foo() do ... end, we automatically remove the parens into foo() do ... end. The fix is that we shouldn't remove the parens if the parens are being applied to a function call in itself.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

michalmuskala picture michalmuskala  路  35Comments

wojtekmach picture wojtekmach  路  34Comments

heiko-braun picture heiko-braun  路  27Comments

pragdave picture pragdave  路  61Comments

dmorneau picture dmorneau  路  30Comments