diff --git a/lib/ex_doc/language/erlang.ex b/lib/ex_doc/language/erlang.ex
index f28878b86..1bfe73e4b 100644
--- a/lib/ex_doc/language/erlang.ex
+++ b/lib/ex_doc/language/erlang.ex
@@ -546,9 +546,14 @@ defmodule ExDoc.Language.Erlang do
{op, _, [int]}, acc when is_integer(int) and op in [:+, :-] ->
{nil, acc}
- # fun() (spec_to_quoted expands it to (... -> any())
- {:->, _, [[{name, _, _}], {:any, _, _}]}, acc when name == :... ->
- {nil, acc}
+ # fun() (spec_to_quoted expands it to (... -> any() in Elixir v1.17 and earlier)
+ # TODO: Remove me when we require Elixir v1.18+
+ {:->, _, [[{name, _, _}], {:any, _, _}]} = node, acc when name == :... ->
+ if Version.match?(System.version(), ">= 1.18.0-rc") do
+ {node, acc}
+ else
+ {nil, acc}
+ end
# record{type :: remote:type/arity}
{:field_type, _, [name, {{:., _, [r_mod, r_type]}, _, args}]}, acc ->
@@ -588,7 +593,7 @@ defmodule ExDoc.Language.Erlang do
end
|> Enum.concat()
- put(acc)
+ put_stack(acc)
# Drop and re-add type name (it, the first element in acc, is dropped there too)
#
@@ -614,16 +619,21 @@ defmodule ExDoc.Language.Erlang do
defp replace(formatted, acc, config) do
String.replace(formatted, Enum.map(acc, &"#{elem(&1, 0)}("), fn string ->
string = String.trim_trailing(string, "(")
- {other, ref} = pop()
-
- if string != other do
- Autolink.maybe_warn(
- config,
- "internal inconsistency, please submit bug: #{inspect(string)} != #{inspect(other)}",
- nil,
- nil
- )
- end
+
+ ref =
+ case get_stack() do
+ [{^string, ref} | tail] ->
+ put_stack(tail)
+ ref
+
+ _ ->
+ Autolink.maybe_warn(
+ config,
+ "internal inconsistency when processing #{inspect(formatted)}",
+ nil,
+ nil
+ )
+ end
what =
case config.current_kfa do
@@ -691,16 +701,16 @@ defmodule ExDoc.Language.Erlang do
end)
end
- defp put(items) do
+ defp put_stack(items) do
Process.put({__MODULE__, :stack}, items)
end
- defp pop() do
- [head | tail] = Process.get({__MODULE__, :stack})
- put(tail)
- head
+ defp get_stack() do
+ Process.get({__MODULE__, :stack})
end
+ defp pp(:fun), do: "fun"
+
defp pp(name) when is_atom(name) do
:io_lib.format("~p", [name]) |> IO.iodata_to_binary()
end
diff --git a/test/ex_doc/language/erlang_test.exs b/test/ex_doc/language/erlang_test.exs
index e68a15f31..9c5ffcd8a 100644
--- a/test/ex_doc/language/erlang_test.exs
+++ b/test/ex_doc/language/erlang_test.exs
@@ -806,6 +806,12 @@ defmodule ExDoc.Language.ErlangTest do
test "function - any arity", c do
assert autolink_spec(~s"-spec foo() -> fun((...) -> t()) | erlang_bar:t().", c) ==
~s[foo() -> fun((...) -> t()) | erlang_bar:t().]
+
+ if Version.match?(System.version(), ">= 1.18.0-rc") do
+ assert autolink_spec(~s"-type foo() :: fun((...) -> any()) | [any()].", c) ==
+ "foo() :: fun((...) -> any()) | " <>
+ "[any()]."
+ end
end
test "local type", c do