Skip to content

Commit c319bc4

Browse files
whatyouhideJosé Valim
authored andcommitted
Support module attributes in remote types (#4891)
For example, @for.t in protocols or similar use cases. Signed-off-by: José Valim <jose.valim@plataformatec.com.br>
1 parent a9ed654 commit c319bc4

File tree

2 files changed

+34
-0
lines changed

2 files changed

+34
-0
lines changed

lib/elixir/lib/kernel/typespec.ex

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -864,6 +864,19 @@ defmodule Kernel.Typespec do
864864
{:op, line(meta), op, {:integer, line(meta), integer}}
865865
end
866866

867+
# Handle remote calls in the form of @module_attribute.type.
868+
# These are not handled by the general remote type clause as calling
869+
# Macro.expand/2 on the remote does not expand module attributes (but expands
870+
# things like __MODULE__).
871+
defp typespec({{:., meta, [{:@, _, [{attr, _, _}]}, name]}, _, args} = orig, vars, caller) do
872+
remote = Module.get_attribute(caller.module, attr)
873+
unless is_atom(remote) and remote != nil do
874+
message = "invalid remote in typespec: #{Macro.to_string(orig)} (@#{attr} is #{inspect remote})"
875+
compile_error(caller, message)
876+
end
877+
remote_type({typespec(remote, vars, caller), meta, typespec(name, vars, caller), args}, vars, caller)
878+
end
879+
867880
# Handle remote calls
868881
defp typespec({{:., meta, [remote, name]}, _, args} = orig, vars, caller) do
869882
remote = Macro.expand remote, caller

lib/elixir/test/elixir/kernel/typespec_test.exs

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -455,6 +455,27 @@ defmodule Kernel.TypespecTest do
455455
types(module)
456456
end
457457

458+
test "@type with module attributes" do
459+
module = test_module do
460+
@keyword Keyword
461+
@type kw :: @keyword.t
462+
@type kw(value) :: @keyword.t(value)
463+
end
464+
465+
assert [type: {:kw, {:remote_type, _, [{:atom, _, Keyword}, {:atom, _, :t}, []]}, _},
466+
type: {:kw, {:remote_type, _, [{:atom, _, Keyword}, {:atom, _, :t}, [{:var, _, :value}]]}, [{:var, _, :value}]}] =
467+
types(module)
468+
end
469+
470+
test "invalid remote @type with module attribute that does not evaluate to a module" do
471+
assert_raise CompileError, ~r/(@foo is "bar")/, fn ->
472+
test_module do
473+
@foo "bar"
474+
@type t :: @foo.t
475+
end
476+
end
477+
end
478+
458479
test "defines_type?" do
459480
test_module do
460481
@type mytype :: tuple

0 commit comments

Comments
 (0)