diff --git a/lib/elixir/lib/kernel/typespec.ex b/lib/elixir/lib/kernel/typespec.ex index fbe1b86b315..023c86f9fac 100644 --- a/lib/elixir/lib/kernel/typespec.ex +++ b/lib/elixir/lib/kernel/typespec.ex @@ -938,7 +938,7 @@ defmodule Kernel.Typespec do ## Helpers - # This is a backport of Macro.expand/2 because we want to expand + # This is a modified backport of Macro.expand/2 because we want to expand # aliases but we don't them to become compile-time references. defp expand_remote({:__aliases__, meta, list} = alias, env) do case :elixir_aliases.expand_or_concat(meta, list, env, true) do @@ -946,9 +946,12 @@ defmodule Kernel.Typespec do receiver [head | tail] -> - case Macro.expand_once(head, env) do - head when is_atom(head) -> :elixir_aliases.concat([head | tail]) - _ -> alias + case Macro.expand(head, env) do + head when is_atom(head) -> + :elixir_aliases.concat([head | tail]) + + _ -> + compile_error(env, "unexpected expression in typespec: #{Macro.to_string(alias)}") end end end diff --git a/lib/elixir/test/elixir/typespec_test.exs b/lib/elixir/test/elixir/typespec_test.exs index c81bb4682c7..7cf5e714dc3 100644 --- a/lib/elixir/test/elixir/typespec_test.exs +++ b/lib/elixir/test/elixir/typespec_test.exs @@ -75,6 +75,14 @@ defmodule TypespecTest do @type my_type :: %URI.t(){} end end + + assert_raise Kernel.TypespecError, + ~r"unexpected expression in typespec: t\.Foo", + fn -> + test_module do + @type my_type :: t.Foo + end + end end test "invalid function specification" do @@ -120,7 +128,7 @@ defmodule TypespecTest do test "redefined type" do assert_raise Kernel.TypespecError, - ~r"type foo/0 is already defined in .*test/elixir/typespec_test.exs:126", + ~r"type foo/0 is already defined in .*test/elixir/typespec_test.exs:134", fn -> test_module do @type foo :: atom @@ -129,7 +137,7 @@ defmodule TypespecTest do end assert_raise Kernel.TypespecError, - ~r"type foo/2 is already defined in .*test/elixir/typespec_test.exs:136", + ~r"type foo/2 is already defined in .*test/elixir/typespec_test.exs:144", fn -> test_module do @type foo :: atom @@ -139,7 +147,7 @@ defmodule TypespecTest do end assert_raise Kernel.TypespecError, - ~r"type foo/0 is already defined in .*test/elixir/typespec_test.exs:145", + ~r"type foo/0 is already defined in .*test/elixir/typespec_test.exs:153", fn -> test_module do @type foo :: atom @@ -841,6 +849,19 @@ defmodule TypespecTest do assert [{:atom, _, Keyword}, {:atom, _, :t}, [{:var, _, :value}]] = kw_with_value_args end + test "@type with macro in alias" do + bytecode = + test_module do + defmacro module() do + quote do: __MODULE__ + end + + @type my_type :: module().Foo + end + + assert [type: {:my_type, {:atom, _, TypespecTest.TypespecSample.Foo}, []}] = types(bytecode) + end + test "@type with a reserved signature" do assert_raise Kernel.TypespecError, ~r"type required\/1 is a reserved type and it cannot be defined",