From 612e6ac49f982aa3c3f9a3b0f27295f4d180bb0d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20=C5=9Awi=C4=85tkowski?= Date: Wed, 4 Mar 2026 13:15:56 +0100 Subject: [PATCH 1/2] fix: prevent infinite loop when typing out anonymous function `fn ->)` is a common intermediate state when writing anonymous function and when the editor closes the bracket, putting the cursor inside. This was causing an infinite loop, because it did not consume a token. This is because of special handling of some tokens. Same happened to :eof. --- lib/spitfire.ex | 2 +- test/spitfire_test.exs | 7 +++++++ 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/lib/spitfire.ex b/lib/spitfire.ex index 534dd58..8c8942e 100644 --- a/lib/spitfire.ex +++ b/lib/spitfire.ex @@ -2180,7 +2180,7 @@ defmodule Spitfire do {ast, parser} = cond do - current_token(parser) == :-> and peek_token(parser) == :end -> + current_token(parser) == :-> and peek_token(parser) in [:")", :end, :eof] -> parser = next_token(parser) {ast, parser} diff --git a/test/spitfire_test.exs b/test/spitfire_test.exs index a746909..55a44db 100644 --- a/test/spitfire_test.exs +++ b/test/spitfire_test.exs @@ -2348,6 +2348,13 @@ defmodule SpitfireTest do end) end + test "fn -> followed by closing delimiter does not hang" do + assert {:error, _ast, _errors} = Spitfire.parse("fn ->)") + assert {:error, _ast, _errors} = Spitfire.parse("fn ->") + assert {:error, _ast, _errors} = Spitfire.parse("Enum.map(fn ->)") + assert {:error, _ast, _errors} = Spitfire.parse("fn ->\n)") + end + test "missing bitstring brackets" do code = """ < Date: Wed, 4 Mar 2026 07:49:04 -0500 Subject: [PATCH 2/2] Update spitfire_test.exs Co-authored-by: Marek Kaput --- test/spitfire_test.exs | 1 + 1 file changed, 1 insertion(+) diff --git a/test/spitfire_test.exs b/test/spitfire_test.exs index 55a44db..a0b921d 100644 --- a/test/spitfire_test.exs +++ b/test/spitfire_test.exs @@ -2348,6 +2348,7 @@ defmodule SpitfireTest do end) end + # https://github.com/elixir-lang/expert/issues/461 test "fn -> followed by closing delimiter does not hang" do assert {:error, _ast, _errors} = Spitfire.parse("fn ->)") assert {:error, _ast, _errors} = Spitfire.parse("fn ->")