summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJosé Valim <jose.valim@plataformatec.com.br>2020-01-03 17:18:22 +0100
committerJosé Valim <jose.valim@plataformatec.com.br>2020-01-03 17:18:27 +0100
commit5dd271d361bab1a86ddc72ac9512388d99d65744 (patch)
tree88b6d89502cf570b8c3ac871991aaee252f9e9ba
parent3b168073743c2c7ae963e2a8cd1ccadad1a27eca (diff)
downloadelixir-5dd271d361bab1a86ddc72ac9512388d99d65744.tar.gz
Fix bounded funs in macrocallbacks, closes #9687
-rw-r--r--lib/elixir/src/elixir_erl.erl5
-rw-r--r--lib/elixir/test/elixir/typespec_test.exs8
-rw-r--r--lib/iex/lib/iex/introspection.ex14
-rw-r--r--lib/iex/test/iex/helpers_test.exs7
4 files changed, 20 insertions, 14 deletions
diff --git a/lib/elixir/src/elixir_erl.erl b/lib/elixir/src/elixir_erl.erl
index 628842a40..1764cce8b 100644
--- a/lib/elixir/src/elixir_erl.erl
+++ b/lib/elixir/src/elixir_erl.erl
@@ -415,9 +415,10 @@ callspecs_form(Kind, Entries, Optional, Macros, Forms, ModuleMap) ->
end
end, Forms, lists:sort(Signatures)).
+spec_for_macro({type, Line, 'bounded_fun', [H | T]}) ->
+ {type, Line, 'bounded_fun', [spec_for_macro(H) | T]};
spec_for_macro({type, Line, 'fun', [{type, _, product, Args} | T]}) ->
- NewArgs = [{type, Line, term, []} | Args],
- {type, Line, 'fun', [{type, Line, product, NewArgs} | T]};
+ {type, Line, 'fun', [{type, Line, product, [{type, Line, term, []} | Args]} | T]};
spec_for_macro(Else) ->
Else.
diff --git a/lib/elixir/test/elixir/typespec_test.exs b/lib/elixir/test/elixir/typespec_test.exs
index 1a48f180c..e9f1257f4 100644
--- a/lib/elixir/test/elixir/typespec_test.exs
+++ b/lib/elixir/test/elixir/typespec_test.exs
@@ -999,8 +999,8 @@ defmodule TypespecTest do
@spec spec1 :: boolean
def spec1, do: @spec
- @callback callback2 :: boolean
- @macrocallback macrocallback2 :: boolean
+ @callback callback2 :: var when var: boolean
+ @macrocallback macrocallback2 :: var when var: boolean
@spec spec2 :: atom
def spec2, do: @spec
@@ -1029,14 +1029,14 @@ defmodule TypespecTest do
] = SpecModuleAttributes.spec4()
assert [
- {:callback, {:"::", _, [{:callback2, _, _}, {:boolean, _, _}]},
+ {:callback, {:when, _, [{:"::", _, [{:callback2, _, _}, {:var, _, _}]}, [var: {:boolean, _, _}]]},
{SpecModuleAttributes, _}},
{:callback, {:"::", _, [{:callback1, _, _}, {:integer, _, _}]},
{SpecModuleAttributes, _}}
] = SpecModuleAttributes.callback()
assert [
- {:macrocallback, {:"::", _, [{:macrocallback2, _, _}, {:boolean, _, _}]},
+ {:macrocallback, {:when, _, [{:"::", _, [{:macrocallback2, _, _}, {:var, _, _}]}, [var: {:boolean, _, _}]]},
{SpecModuleAttributes, _}},
{:macrocallback, {:"::", _, [{:macrocallback1, _, _}, {:integer, _, _}]},
{SpecModuleAttributes, _}}
diff --git a/lib/iex/lib/iex/introspection.ex b/lib/iex/lib/iex/introspection.ex
index 2eaa85b95..05b52d70b 100644
--- a/lib/iex/lib/iex/introspection.ex
+++ b/lib/iex/lib/iex/introspection.ex
@@ -576,11 +576,7 @@ defmodule IEx.Introspection do
# * The arguments contain an additional first argument: the caller
# * The arity is increased by 1
#
- specs =
- Enum.map(specs, fn {:type, line1, :fun, [{:type, line2, :product, [_ | args]}, spec]} ->
- {:type, line1, :fun, [{:type, line2, :product, args}, spec]}
- end)
-
+ specs = Enum.map(specs, &unpack_caller/1)
{kind_name_arity, specs}
kind_name_arity ->
@@ -588,6 +584,14 @@ defmodule IEx.Introspection do
end
end
+ defp unpack_caller({:type, line1, :fun, [{:type, line2, :product, [_ | args]} | tail]}) do
+ {:type, line1, :fun, [{:type, line2, :product, args} | tail]}
+ end
+
+ defp unpack_caller({:type, line, :bounded_fun, [head | tail]}) do
+ {:type, line, :bounded_fun, [unpack_caller(head) | tail]}
+ end
+
def translate_callback_name_arity({name, arity}) do
case Atom.to_string(name) do
"MACRO-" <> macro_name -> {:macrocallback, String.to_atom(macro_name), arity - 1}
diff --git a/lib/iex/test/iex/helpers_test.exs b/lib/iex/test/iex/helpers_test.exs
index 4fb923c5d..5d8dab003 100644
--- a/lib/iex/test/iex/helpers_test.exs
+++ b/lib/iex/test/iex/helpers_test.exs
@@ -644,14 +644,15 @@ defmodule IEx.HelpersTest do
content = """
defmodule Macrocallbacks do
@macrocallback test(:foo) :: integer
+ @macrocallback test(:bar) :: var when var: integer
end
"""
with_file(filename, content, fn ->
assert c(filename, ".") == [Macrocallbacks]
-
- assert capture_io(fn -> b(Macrocallbacks) end) =~
- "@macrocallback test(:foo) :: integer()\n\n"
+ callbacks = capture_io(fn -> b(Macrocallbacks) end)
+ assert callbacks =~ "@macrocallback test(:foo) :: integer()\n"
+ assert callbacks =~ "@macrocallback test(:bar) :: var when var: integer()\n"
end)
after
cleanup_modules([Macrocallbacks])