Elixir 1.10.3 (compiled with Erlang/OTP 21)
Given the following module:
defmodule Example do
@type tuple(_param) :: any()
@type example :: tuple(3)
end
when checking the type example:
iex> t Example.example
@type example() :: {3}
iex> t Example.example
@type example() :: any()
or possibly
iex> t Example.example
@type example() :: tuple(3)
or possibly
iex> t Example.example @type example() :: tuple(3)Correct. This is what it should return
tuple(3). Look at the example below
For the record: these are the types that are failing.
The code is shared here: https://gist.github.com/eksperimental/55f1e207ab5878a668668546f57a3f90
It lists all the types defined in the Typespecs page, and 4 of them are giving unexpected results.
defmodule TypespecExample do
@type map(key) :: [key]
@type tuple(key) :: [key]
@type list(key, key) :: [key]
@type nonempty_list(key, key) :: [key]
@type example_map() :: map(3)
@type example_tuple() :: tuple(3)
@type example_list(key, key) :: list(3)
@type example_nonempty_list(key, key) :: nonempty_list(3)
end
iex(4)> t Elixir.TypespecExample.example_map/0
** (FunctionClauseError) no function clause matching in anonymous fn/1 in Code.Typespec.typespec_to_quoted/1
The following arguments were given to anonymous fn/1 in Code.Typespec.typespec_to_quoted/1:
# 1
{:integer, 0, 3}
(elixir 1.10.3) lib/code/typespec.ex:261: anonymous fn/1 in Code.Typespec.typespec_to_quoted/1
(elixir 1.10.3) lib/enum.ex:1396: Enum."-map/2-lists^map/1-0-"/2
(elixir 1.10.3) lib/code/typespec.ex:261: Code.Typespec.typespec_to_quoted/1
(elixir 1.10.3) lib/code/typespec.ex:76: Code.Typespec.type_to_quoted/1
(iex 1.10.3) lib/iex/introspection.ex:731: IEx.Introspection.format_type/1
(iex 1.10.3) lib/iex/introspection.ex:719: IEx.Introspection.type_doc/4
(iex 1.10.3) lib/iex/introspection.ex:703: IEx.Introspection.t/1
iex(7)> t Elixir.TypespecExample.example_tuple/0
@type example_tuple() :: {3}
iex(13)> t Elixir.TypespecExample.example_list/2
@type example_list(key, key) :: [3]
iex(14)> t Elixir.TypespecExample.example_nonempty_list/2
@type example_nonempty_list(key, key) :: [3, ...]
Wow, thank you for such a thorough investigation!
A further observation: Wouldn't types like @type example_list(key, key) :: list(3) be expected to raise a "type variable key is unused" CompileError?
Maybe there is an additional problem related to type-variable hygiene, or maybe it is another symptom of the same problem.
For completion's sake, I have tried it with remote types as well.
defmodule Other do
@type tuple(_int) :: any()
end
defmodule Example do
@type example :: Other.tuple(3)
end
In this case, the definition of Example.example remains Other.tuple(3) as expected.
This was already fixed on master thanks to 70da7098817c3fb8c5ff87142a829c7518372329. I have pushed more tests.
@josevalim list and nonempty_list are still not working as expected.
iex(15)> t Elixir.TypespecExample.example_list/2
@type example_list(key, key) :: [3]
iex(16)> t Elixir.TypespecExample.example_nonempty_list/2
@type example_nonempty_list(key, key) :: [3, ...]
You are calling list(3) and list(3) is the same as [3]. The same for nonempty_list.
You are calling
list(3)andlist(3)is the same as[3]. The same for nonempty_list.
correct.
All is working as expected.