Skip to content

Commit 193e858

Browse files
ericmjJosé Valim
authored andcommitted
Add compatibilty with OTP 18 typespec changes
Signed-off-by: José Valim <[email protected]>
1 parent a58c007 commit 193e858

File tree

4 files changed

+87
-35
lines changed

4 files changed

+87
-35
lines changed

lib/elixir/lib/kernel/typespec.ex

Lines changed: 37 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -644,6 +644,10 @@ defmodule Kernel.Typespec do
644644
[]
645645
end
646646

647+
defp typespec_to_ast({:user_type, line, name, args}) do
648+
typespec_to_ast({:type, line, name, args})
649+
end
650+
647651
defp typespec_to_ast({:type, line, :tuple, :any}) do
648652
{:tuple, [line: line], []}
649653
end
@@ -677,8 +681,13 @@ defmodule Kernel.Typespec do
677681
end
678682

679683
defp typespec_to_ast({:type, line, :map, fields}) do
680-
fields = Enum.map fields, fn {:type, _, :map_field_assoc, k, v} ->
681-
{typespec_to_ast(k), typespec_to_ast(v)}
684+
fields = Enum.map fields, fn
685+
# OTP 18
686+
{:type, _, :map_field_assoc, [k, v]} ->
687+
{typespec_to_ast(k), typespec_to_ast(v)}
688+
# OTP 17
689+
{:type, _, :map_field_assoc, k, v} ->
690+
{typespec_to_ast(k), typespec_to_ast(v)}
682691
end
683692

684693
{struct, fields} = Keyword.pop(fields, :__struct__)
@@ -821,9 +830,17 @@ defmodule Kernel.Typespec do
821830

822831
## Handle maps and structs
823832
defp typespec({:%{}, meta, fields}, vars, caller) do
824-
fields = :lists.map(fn {k, v} ->
825-
{:type, line(meta), :map_field_assoc, typespec(k, vars, caller), typespec(v, vars, caller)}
826-
end, fields)
833+
fields =
834+
if :erlang.system_info(:otp_release) >= '18' do
835+
:lists.map(fn {k, v} ->
836+
{:type, line(meta), :map_field_assoc, [typespec(k, vars, caller), typespec(v, vars, caller)]}
837+
end, fields)
838+
else
839+
:lists.map(fn {k, v} ->
840+
{:type, line(meta), :map_field_assoc, typespec(k, vars, caller), typespec(v, vars, caller)}
841+
end, fields)
842+
end
843+
827844
{:type, line(meta), :map, fields}
828845
end
829846

@@ -884,7 +901,8 @@ defmodule Kernel.Typespec do
884901

885902
# Handle ranges
886903
defp typespec({:.., meta, args}, vars, caller) do
887-
typespec({:range, meta, args}, vars, caller)
904+
args = for arg <- args, do: typespec(arg, vars, caller)
905+
{:type, line(meta), :range, args}
888906
end
889907

890908
# Handle special forms
@@ -968,9 +986,21 @@ defmodule Kernel.Typespec do
968986
typespec((quote do: :elixir.as_boolean(unquote(arg))), vars, caller)
969987
end
970988

989+
defp typespec({:fun, meta, args}, vars, caller) do
990+
args = for arg <- args, do: typespec(arg, vars, caller)
991+
{:type, line(meta), :fun, args}
992+
end
993+
971994
defp typespec({name, meta, arguments}, vars, caller) do
972995
arguments = for arg <- arguments, do: typespec(arg, vars, caller)
973-
{:type, line(meta), name, arguments}
996+
997+
if :erlang.system_info(:otp_release) >= '18' do
998+
arity = length(arguments)
999+
type = if :erl_internal.is_type(name, arity), do: :type, else: :user_type
1000+
{type, line(meta), name, arguments}
1001+
else
1002+
{:type, line(meta), name, arguments}
1003+
end
9741004
end
9751005

9761006
# Handle literals

lib/elixir/test/elixir/kernel/errors_test.exs

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -756,8 +756,13 @@ defmodule Kernel.ErrorsTest do
756756
end
757757
'''
758758

759-
assert_compile_fail CompileError,
760-
"nofile:2: spec for undefined function ErrorsTest.omg/0",
759+
if :erlang.system_info(:otp_release) >= '18' do
760+
message = "nofile:2: spec for undefined function omg/0"
761+
else
762+
message = "nofile:2: spec for undefined function ErrorsTest.omg/0"
763+
end
764+
765+
assert_compile_fail CompileError, message,
761766
'''
762767
defmodule ErrorsTest do
763768
@spec omg :: atom

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

Lines changed: 30 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -154,15 +154,6 @@ defmodule Kernel.TypespecTest do
154154
types(module)
155155
end
156156

157-
test "@type with a range" do
158-
module = test_module do
159-
@type mytype :: range(1, 10)
160-
end
161-
162-
assert [type: {:mytype, {:type, _, :range, [{:integer, _, 1}, {:integer, _, 10}]}, []}] =
163-
types(module)
164-
end
165-
166157
test "@type with a range op" do
167158
module = test_module do
168159
@type mytype :: 1..10
@@ -177,11 +168,19 @@ defmodule Kernel.TypespecTest do
177168
@type mytype :: %{hello: :world}
178169
end
179170

180-
assert [type: {:mytype,
181-
{:type, _, :map, [
182-
{:type, _, :map_field_assoc, {:atom, _, :hello}, {:atom, _, :world}}
183-
]},
184-
[]}] = types(module)
171+
if :erlang.system_info(:otp_release) >= '18' do
172+
assert [type: {:mytype,
173+
{:type, _, :map, [
174+
{:type, _, :map_field_assoc, [{:atom, _, :hello}, {:atom, _, :world}]}
175+
]},
176+
[]}] = types(module)
177+
else
178+
assert [type: {:mytype,
179+
{:type, _, :map, [
180+
{:type, _, :map_field_assoc, {:atom, _, :hello}, {:atom, _, :world}}
181+
]},
182+
[]}] = types(module)
183+
end
185184
end
186185

187186
test "@type with a struct" do
@@ -190,13 +189,23 @@ defmodule Kernel.TypespecTest do
190189
@type mytype :: %TestTypespec{hello: :world}
191190
end
192191

193-
assert [type: {:mytype,
194-
{:type, _, :map, [
195-
{:type, _, :map_field_assoc, {:atom, _, :__struct__}, {:atom, _, TestTypespec}},
196-
{:type, _, :map_field_assoc, {:atom, _, :hello}, {:atom, _, :world}},
197-
{:type, _, :map_field_assoc, {:atom, _, :other}, {:type, _, :term, []}}
198-
]},
199-
[]}] = types(module)
192+
if :erlang.system_info(:otp_release) >= '18' do
193+
assert [type: {:mytype,
194+
{:type, _, :map, [
195+
{:type, _, :map_field_assoc, [{:atom, _, :__struct__}, {:atom, _, TestTypespec}]},
196+
{:type, _, :map_field_assoc, [{:atom, _, :hello}, {:atom, _, :world}]},
197+
{:type, _, :map_field_assoc, [{:atom, _, :other}, {:type, _, :term, []}]}
198+
]},
199+
[]}] = types(module)
200+
else
201+
assert [type: {:mytype,
202+
{:type, _, :map, [
203+
{:type, _, :map_field_assoc, {:atom, _, :__struct__}, {:atom, _, TestTypespec}},
204+
{:type, _, :map_field_assoc, {:atom, _, :hello}, {:atom, _, :world}},
205+
{:type, _, :map_field_assoc, {:atom, _, :other}, {:type, _, :term, []}}
206+
]},
207+
[]}] = types(module)
208+
end
200209
end
201210

202211
test "@type with undefined struct" do

lib/elixir/test/elixir/protocol_test.exs

Lines changed: 13 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -121,11 +121,19 @@ defmodule ProtocolTest do
121121
end
122122

123123
test "protocol defines callbacks" do
124-
assert get_callbacks(Sample, :ok, 1) ==
125-
[{:type, 9, :fun, [{:type, 9, :product, [{:type, 9, :t, []}]}, {:type, 9, :boolean, []}]}]
126-
127-
assert get_callbacks(WithAny, :ok, 1) ==
128-
[{:type, 16, :fun, [{:type, 16, :product, [{:type, 16, :t, []}]}, {:type, 16, :term, []}]}]
124+
if :erlang.system_info(:otp_release) >= '18' do
125+
assert get_callbacks(Sample, :ok, 1) ==
126+
[{:type, 9, :fun, [{:type, 9, :product, [{:user_type, 9, :t, []}]}, {:type, 9, :boolean, []}]}]
127+
128+
assert get_callbacks(WithAny, :ok, 1) ==
129+
[{:type, 16, :fun, [{:type, 16, :product, [{:user_type, 16, :t, []}]}, {:type, 16, :term, []}]}]
130+
else
131+
assert get_callbacks(Sample, :ok, 1) ==
132+
[{:type, 9, :fun, [{:type, 9, :product, [{:type, 9, :t, []}]}, {:type, 9, :boolean, []}]}]
133+
134+
assert get_callbacks(WithAny, :ok, 1) ==
135+
[{:type, 16, :fun, [{:type, 16, :product, [{:type, 16, :t, []}]}, {:type, 16, :term, []}]}]
136+
end
129137
end
130138

131139
test "protocol defines attributes" do

0 commit comments

Comments
 (0)