Skip to content

Commit 57b4c3b

Browse files
mkaputmhanberg
authored andcommitted
fix: guard infix reassociation against malformed operands
Recent fn-head parsing changes introduced infix reassociation branches that assume comma/when operands always carry list arguments. In the absinthe matrix CI run, a malformed intermediate AST used , which passed the guard and crashed in . This change hardens the parser by requiring list operands before reassociation in , and by making fn-head nested-parens validation a no-op for non-list argument payloads. This preserves existing behavior for valid AST shapes while preventing parser crashes on recoverable malformed intermediates encountered during large real-world repo parsing.
1 parent 76931b3 commit 57b4c3b

1 file changed

Lines changed: 5 additions & 3 deletions

File tree

lib/spitfire.ex

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1357,7 +1357,7 @@ defmodule Spitfire do
13571357

13581358
# Reject nested grouped tuple/keyword arguments inside fn heads, for example
13591359
# `fn (a, (b, c)) -> ... end` and `fn ((a, b), c) -> ... end`.
1360-
defp maybe_error_invalid_fn_head_args(parser, args) do
1360+
defp maybe_error_invalid_fn_head_args(parser, args) when is_list(args) do
13611361
Enum.reduce(args, parser, fn arg, parser ->
13621362
case arg do
13631363
{:comma, [{:parens, parens_meta} | _], _} ->
@@ -1375,6 +1375,8 @@ defmodule Spitfire do
13751375
end)
13761376
end
13771377

1378+
defp maybe_error_invalid_fn_head_args(parser, _args), do: parser
1379+
13781380
# Reject top-level fn-head wrappers that carry more than one parens entry,
13791381
# such as `((a, b))` and `((a: 1))`.
13801382
defp maybe_error_nested_top_parens(parser, meta) do
@@ -1569,11 +1571,11 @@ defmodule Spitfire do
15691571

15701572
_ ->
15711573
case lhs do
1572-
{:comma, comma_meta, args} when args != [] ->
1574+
{:comma, comma_meta, args} when is_list(args) and args != [] ->
15731575
{leading, [last]} = Enum.split(args, -1)
15741576
{:comma, comma_meta, leading ++ [{token, newlines ++ meta, [last, rhs]}]}
15751577

1576-
{:when, when_meta, when_args} when length(when_args) > 2 ->
1578+
{:when, when_meta, when_args} when is_list(when_args) and length(when_args) > 2 ->
15771579
{leading, [second_last, guard]} = Enum.split(when_args, -2)
15781580
when_node = {:when, when_meta, [second_last, guard]}
15791581
{:comma, [], leading ++ [{token, newlines ++ meta, [when_node, rhs]}]}

0 commit comments

Comments
 (0)