Skip to content

Fix typespec with (...) -> any(), closes #1974 #1980

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Dec 15, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
48 changes: 29 additions & 19 deletions lib/ex_doc/language/erlang.ex
Original file line number Diff line number Diff line change
Expand Up @@ -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 ->
Expand Down Expand Up @@ -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)
#
Expand All @@ -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
Expand Down Expand Up @@ -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
Expand Down
6 changes: 6 additions & 0 deletions test/ex_doc/language/erlang_test.exs
Original file line number Diff line number Diff line change
Expand Up @@ -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((...) -> <a href="#t:t/0">t</a>()) | <a href="erlang_bar.html#t:t/0">erlang_bar:t</a>().]

if Version.match?(System.version(), ">= 1.18.0-rc") do
assert autolink_spec(~s"-type foo() :: fun((...) -> any()) | [any()].", c) ==
"foo() :: fun((...) -> <a href=\"https://www.erlang.org/doc/apps/erts/erlang.html#t:any/0\">any</a>()) | " <>
"[<a href=\"https://www.erlang.org/doc/apps/erts/erlang.html#t:any/0\">any</a>()]."
end
end

test "local type", c do
Expand Down