Skip to content

Commit a568869

Browse files
committed
Allow <<_::3*8>> in typespecs
1 parent 965ee9b commit a568869

File tree

3 files changed

+29
-8
lines changed

3 files changed

+29
-8
lines changed

lib/elixir/lib/code/typespec.ex

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -283,7 +283,6 @@ defmodule Code.Typespec do
283283
end
284284

285285
defp typespec_to_quoted({:type, anno, :binary, [arg1, arg2]}) do
286-
[arg1, arg2] = for arg <- [arg1, arg2], do: typespec_to_quoted(arg)
287286
line = meta(anno)[:line]
288287

289288
case {typespec_to_quoted(arg1), typespec_to_quoted(arg2)} do
@@ -329,10 +328,14 @@ defmodule Code.Typespec do
329328
{erl_to_ex_var(var), meta(anno), nil}
330329
end
331330

332-
defp typespec_to_quoted({:op, anno, op, arg}) do
331+
defp typespec_to_quoted({:op, anno, op, arg}) when op in [:+, :-] do
333332
{op, meta(anno), [typespec_to_quoted(arg)]}
334333
end
335334

335+
defp typespec_to_quoted({:op, anno, :*, arg1, arg2}) do
336+
{:*, meta(anno), [typespec_to_quoted(arg1), typespec_to_quoted(arg2)]}
337+
end
338+
336339
defp typespec_to_quoted({:remote_type, anno, [mod, name, args]}) do
337340
remote_type(anno, mod, name, args)
338341
end

lib/elixir/lib/kernel/typespec.ex

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -493,6 +493,24 @@ defmodule Kernel.Typespec do
493493
state}
494494
end
495495

496+
defp typespec(
497+
{:<<>>, meta, [{:"::", _, [{:_, _, ctx1}, {:*, prod_meta, [size, unit]}]}]},
498+
_,
499+
_,
500+
state
501+
)
502+
when is_atom(ctx1) and is_integer(size) and size >= 0 and unit in 1..256 do
503+
location = location(meta)
504+
prod_location = location(prod_meta)
505+
506+
{{:type, location, :binary,
507+
[
508+
{:op, prod_location, :*, {:integer, prod_location, size},
509+
{:integer, prod_location, unit}},
510+
{:integer, location, 0}
511+
]}, state}
512+
end
513+
496514
defp typespec({:<<>>, meta, [{:"::", size_meta, [{:_, _, ctx}, size]}]}, _, _, state)
497515
when is_atom(ctx) and is_integer(size) and size >= 0 do
498516
location = location(meta)

lib/elixir/test/elixir/typespec_test.exs

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -393,6 +393,7 @@ defmodule TypespecTest do
393393
@type size :: <<_::3>>
394394
@type unit :: <<_::_*8>>
395395
@type size_and_unit :: <<_::3, _::_*8>>
396+
@type size_prod_unit :: <<_::3*8>>
396397
end
397398

398399
assert [
@@ -401,17 +402,15 @@ defmodule TypespecTest do
401402
type: {:size, {:type, _, :binary, [{:integer, _, 3}, {:integer, _, 0}]}, []},
402403
type:
403404
{:size_and_unit, {:type, _, :binary, [{:integer, _, 3}, {:integer, _, 8}]}, []},
405+
type:
406+
{:size_prod_unit,
407+
{:type, _, :binary,
408+
[{:op, _, :*, {:integer, _, 3}, {:integer, _, 8}}, {:integer, _, 0}]}, []},
404409
type: {:unit, {:type, _, :binary, [{:integer, _, 0}, {:integer, _, 8}]}, []}
405410
] = types(bytecode)
406411
end
407412

408413
test "@type with invalid binary spec" do
409-
assert_raise Kernel.TypespecError, ~r"invalid binary specification", fn ->
410-
test_module do
411-
@type my_type :: <<_::3*8>>
412-
end
413-
end
414-
415414
assert_raise Kernel.TypespecError, ~r"invalid binary specification", fn ->
416415
test_module do
417416
@type my_type :: <<_::atom()>>
@@ -1217,6 +1216,7 @@ defmodule TypespecTest do
12171216
quote(do: @type(binary_type1() :: <<_::_*8>>)),
12181217
quote(do: @type(binary_type2() :: <<_::3>>)),
12191218
quote(do: @type(binary_type3() :: <<_::3, _::_*8>>)),
1219+
quote(do: @type(binary_type4() :: <<_::3*8>>)),
12201220
quote(do: @type(tuple_type() :: {integer()})),
12211221
quote(do: @type(ftype() :: (-> any()) | (-> integer()) | (integer() -> integer()))),
12221222
quote(do: @type(cl() :: charlist())),

0 commit comments

Comments
 (0)