Skip to content

Commit d7eb581

Browse files
authored
Merge pull request #27 from esl/finish-typespec
Finish typespec
2 parents a313549 + c129963 commit d7eb581

File tree

8 files changed

+320
-56
lines changed

8 files changed

+320
-56
lines changed

lib/gradient/ast_specifier.ex

Lines changed: 21 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -131,10 +131,11 @@ defmodule Gradient.AstSpecifier do
131131
@spec mapper(form(), [token()], options()) :: {form(), [token()]}
132132
def mapper(form, tokens, opts)
133133

134-
def mapper({:attribute, anno, :spec, {name_arity, specs}}, tokens, opts) do
134+
def mapper({:attribute, anno, spec, {name_arity, specs}}, tokens, opts)
135+
when spec in [:spec, :callback] do
135136
new_specs = context_mapper_map(specs, [], opts, &spec_mapper/3)
136137

137-
{:attribute, anno, :spec, {name_arity, new_specs}}
138+
{:attribute, anno, spec, {name_arity, new_specs}}
138139
|> pass_tokens(tokens)
139140
end
140141

@@ -478,6 +479,24 @@ defmodule Gradient.AstSpecifier do
478479
|> pass_tokens(tokens)
479480
end
480481

482+
def spec_mapper({:type, anno, :constraint, [subtype, vt]}, tokens, opts) do
483+
{:ok, _, anno, opts, _} = get_line(anno, opts)
484+
{subtype, _} = spec_mapper(subtype, tokens, opts)
485+
vt = context_mapper_map(vt, tokens, opts, &spec_mapper/3)
486+
487+
{:type, anno, :constraint, [subtype, vt]}
488+
|> pass_tokens(tokens)
489+
end
490+
491+
def spec_mapper({:type, anno, :bounded_fun, [fn_type, when_type]}, tokens, opts) do
492+
{:ok, _line, anno, opts, _} = get_line(anno, opts)
493+
{fn_type, _} = spec_mapper(fn_type, tokens, opts)
494+
when_type = context_mapper_map(when_type, tokens, opts, &spec_mapper/3)
495+
496+
{:type, anno, :bounded_fun, [fn_type, when_type]}
497+
|> pass_tokens(tokens)
498+
end
499+
481500
def spec_mapper({:type, anno, type_name, args}, tokens, opts) do
482501
{:ok, _line, anno, opts, _} = get_line(anno, opts)
483502
new_args = context_mapper_map(args, tokens, opts, &spec_mapper/3)

test/examples/Elixir.Typespec.beam

2.33 KB
Binary file not shown.
1.61 KB
Binary file not shown.
1.5 KB
Binary file not shown.

test/examples/typespec.ex

Lines changed: 33 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,41 @@
11
defmodule Typespec do
22
@type mylist(t) :: [t]
33

4-
@spec missing_type() :: Unknown.atom()
5-
def missing_type, do: :ok
4+
defstruct name: "", age: 1
65

7-
@spec missing_type_arg() :: mylist(Unknown.atom())
8-
def missing_type_arg, do: [:ok]
6+
@spec spec_remote_type() :: Unknown.atom()
7+
def spec_remote_type, do: :ok
98

10-
@spec named_type(name :: Unknown.atom()) :: atom()
11-
def named_type(name), do: name
9+
@spec spec_user_type() :: mylist(:ok | atom())
10+
def spec_user_type, do: [:ok]
1211

13-
@spec atoms_type(:ok | :error) :: :ok | :error
14-
def atoms_type(name), do: name
12+
@spec spec_map_and_named_type(type :: Unknown.atom()) :: %{
13+
optional(:value) => integer(),
14+
required(:type) => Unknown.atom()
15+
}
16+
def spec_map_and_named_type(type), do: %{type: type}
1517

16-
@spec atoms_type2(:ok | :error) :: Unknown.atom(:ok | :error)
17-
def atoms_type2(name), do: name
18+
@spec spec_atom(:ok | nil | true | false) :: Unknown.atom(:ok | nil | true | false)
19+
def spec_atom(name), do: name
20+
21+
@spec spec_function() :: (atom(), %{name: String.t()} -> map())
22+
def spec_function(), do: fn id, %{name: name} -> %{id: id, name: name} end
23+
24+
@spec spec_struct(%Typespec{}) :: %Typespec{}
25+
def spec_struct(struct), do: struct
26+
27+
@spec spec_list([integer(), ...]) :: [...]
28+
def spec_list(list), do: list
29+
30+
@spec spec_range(1..10) :: [1..10]
31+
def spec_range(i), do: [i]
32+
33+
@spec spec_keyword(a: integer(), b: integer()) :: integer()
34+
def spec_keyword(a: a, b: b), do: a + b
35+
36+
@spec spec_tuple({:ok, integer()}) :: tuple()
37+
def spec_tuple({:ok, a}), do: {:ok, a + 1}
38+
39+
@spec spec_bitstring(<<_::48, _::_*8>>) :: <<>>
40+
def spec_bitstring(_), do: <<>>
1841
end

test/examples/typespec_beh.ex

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
defmodule TypespecBeh do
2+
@callback vital_fun() :: %{atom() => any()}
3+
@callback non_vital_fun() :: a when a: {integer(), atom()}
4+
@macrocallback non_vital_macro(arg :: any) :: Macro.t()
5+
@optional_callbacks non_vital_fun: 0, non_vital_macro: 1
6+
end

test/examples/typespec_when.ex

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
defmodule TypespecWhen do
2+
@spec foo({:a, x}) :: {:a, x} | {:b, x} when x: term()
3+
def foo({:a, x}) do
4+
case x do
5+
:foo ->
6+
{:a, x}
7+
8+
_ ->
9+
{:b, x}
10+
end
11+
end
12+
end

0 commit comments

Comments
 (0)