ex_type
ex_type copied to clipboard
Local parametrised types are broken
defmodule Foo do
@type t(elem) :: [elem]
@spec mylength(t(term())) :: integer()
def mylength(_) do
23
end
end
$ mix type
** (FunctionClauseError) no function clause matching in ExType.Typespec.eval_type/2
The following arguments were given to ExType.Typespec.eval_type/2:
# 1
%ExType.Type.Any{}
# 2
{Foo, %{elem: %ExType.Type.Any{}}}
Attempted function clauses (showing 10 out of 57):
def eval_type({:any, _, []}, _)
def eval_type({:none, _, []}, _)
def eval_type({:atom, _, []}, _)
def eval_type({:map, _, []}, _)
def eval_type({:pid, _, []}, _)
def eval_type({:port, _, []}, _)
def eval_type({:reference, _, []}, _)
def eval_type({:struct, _, []}, _)
def eval_type({:tuple, _, []}, _)
def eval_type({:float, _, []}, _)
...
(47 clauses not shown)
lib/ex_type/typespec.ex:249: ExType.Typespec.eval_type/2
lib/ex_type/typespec.ex:342: ExType.Typespec.eval_type/2
(elixir 1.10.4) lib/enum.ex:1396: Enum."-map/2-lists^map/1-0-"/2
lib/ex_type/typespec.ex:666: anonymous fn/4 in ExType.Typespec.fetch_specs/3
(elixir 1.10.4) lib/enum.ex:1396: Enum."-map/2-lists^map/1-0-"/2
lib/ex_type/typespec.ex:648: ExType.Typespec.fetch_specs/3
lib/ex_type/custom_env.ex:154: ExType.CustomEnv.process_defs/5
(elixir 1.10.4) lib/enum.ex:1400: anonymous fn/3 in Enum.map/2
When I inline t
, it works:
defmodule Foo do
@spec mylength([term()]) :: integer()
def mylength(_) do
23
end
end
$ mix type
✅ Foo.mylength/1
The issue is probably in the handling of local types:
https://github.com/gyson/ex_type/blob/b23a0d9e7d70760e3eb46c73695554e99470d08e/lib/ex_type/typespec.ex#L614
There, the type variable is evaluated to %Any{}
, but it should really be a %SpecVariable{}
"applied" to %Any{}
! In fact, it seems %SpecVariable{}
doesn't even have a context, maybe they should be closures? Or they should be evaluated correctly at least.