From 05eb3473cbedc11abad7bc8e5c2dba5dfaf904a5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Eric=20Meadows-J=C3=B6nsson?= Date: Mon, 23 May 2016 14:39:20 +0200 Subject: [PATCH] Fix binary typespecs * Removes <<_::size*unit>> * Adds <<_::size, _::_*unit>> --- lib/elixir/lib/kernel/typespec.ex | 20 +++++++-------- lib/elixir/pages/Typespecs.md | 6 ++--- .../test/elixir/kernel/typespec_test.exs | 25 ++++++++++++++++--- 3 files changed, 34 insertions(+), 17 deletions(-) diff --git a/lib/elixir/lib/kernel/typespec.ex b/lib/elixir/lib/kernel/typespec.ex index 008f5d6a847..220d42a037b 100644 --- a/lib/elixir/lib/kernel/typespec.ex +++ b/lib/elixir/lib/kernel/typespec.ex @@ -586,13 +586,13 @@ defmodule Kernel.Typespec do defp typespec_to_ast({:type, line, :binary, [arg1, arg2]}) do [arg1, arg2] = for arg <- [arg1, arg2], do: typespec_to_ast(arg) - cond do - arg2 == 0 -> + case {typespec_to_ast(arg1), typespec_to_ast(arg2)} do + {arg1, 0} -> quote line: line, do: <<_ :: unquote(arg1)>> - arg1 == 0 -> + {0, arg2} -> quote line: line, do: <<_ :: _ * unquote(arg2)>> - true -> - quote line: line, do: <<_ :: unquote(arg1) * unquote(arg2)>> + {arg1, arg2} -> + quote line: line, do: <<_ :: unquote(arg1), _ :: _ * unquote(arg2)>> end end @@ -719,16 +719,16 @@ defmodule Kernel.Typespec do {:type, line(meta), :binary, [{:integer, line(meta), 0}, {:integer, line(unit_meta), unit}]} end - defp typespec({:<<>>, meta, [{:::, shared_meta, [{:_, _, ctx}, {:*, _, [size, unit]}]}]}, _, _) - when is_atom(ctx) and is_integer(unit) and is_integer(size) do - {:type, line(meta), :binary, [{:integer, line(shared_meta), size}, {:integer, line(shared_meta), unit}]} - end - defp typespec({:<<>>, meta, [{:::, size_meta, [{:_, _, ctx}, size]}]}, _, _) when is_atom(ctx) and is_integer(size) do {:type, line(meta), :binary, [{:integer, line(size_meta), size}, {:integer, line(meta), 0}]} end + defp typespec({:<<>>, meta, [{:::, size_meta, [{:_, _, ctx1}, size]}, {:::, unit_meta, [{:_, _, ctx2}, {:*, _, [{:_, _, ctx3}, unit]}]}]}, _, _) + when is_atom(ctx1) and is_atom(ctx2) and is_atom(ctx3) and is_integer(size) and is_integer(unit) do + {:type, line(meta), :binary, [{:integer, line(size_meta), size}, {:integer, line(unit_meta), unit}]} + end + ## Handle maps and structs defp typespec({:map, meta, args}, _vars, _caller) when args == [] or is_atom(args) do {:type, line(meta), :map, :any} diff --git a/lib/elixir/pages/Typespecs.md b/lib/elixir/pages/Typespecs.md index 72104cca4f1..8f580447f2c 100644 --- a/lib/elixir/pages/Typespecs.md +++ b/lib/elixir/pages/Typespecs.md @@ -46,9 +46,9 @@ The following literals are also supported in typespecs: | 1.0 ## Floats | <<>> ## Bitstrings - | <<_::size>> # size is 0 or a positive integer - | <<_::_ * unit>> # unit is an integer from 1 to 256 - | <<_::size * unit>> + | <<_::size>> # size is 0 or a positive integer + | <<_::_*unit>> # unit is an integer from 1 to 256 + | <<_::size, _::_*unit>> | [type] ## Lists | [] # empty list diff --git a/lib/elixir/test/elixir/kernel/typespec_test.exs b/lib/elixir/test/elixir/kernel/typespec_test.exs index 37661956118..fd61b08bfe6 100644 --- a/lib/elixir/test/elixir/kernel/typespec_test.exs +++ b/lib/elixir/test/elixir/kernel/typespec_test.exs @@ -144,7 +144,7 @@ defmodule Kernel.TypespecTest do test "@type with a binary with a base size" do module = test_module do - @type mytype :: <<_ :: 3>> + @type mytype :: <<_::3>> end assert [type: {:mytype, {:type, _, :binary, [{:integer, _, 3}, {:integer, _, 0}]}, []}] = @@ -160,6 +160,23 @@ defmodule Kernel.TypespecTest do types(module) end + test "@type with a binary with a size and unit size" do + module = test_module do + @type mytype :: <<_::3, _::_*8>> + end + + assert [type: {:mytype, {:type, _, :binary, [{:integer, _, 3}, {:integer, _, 8}]}, []}] = + types(module) + end + + test "@type with invalid binary spec" do + assert_raise CompileError, fn -> + test_module do + @type mytype :: <<_::3*8>> + end + end + end + test "@type with a range op" do module = test_module do @type mytype :: 1..10 @@ -545,9 +562,9 @@ defmodule Kernel.TypespecTest do (quote do: @type simple_type() :: integer()), (quote do: @type param_type(p) :: [p]), (quote do: @type union_type() :: integer() | binary() | boolean()), - (quote do: @type binary_type1() :: <<_ :: _ * 8>>), - (quote do: @type binary_type2() :: <<_ :: 3 * 8>>), - (quote do: @type binary_type3() :: <<_ :: 3>>), + (quote do: @type binary_type1() :: <<_::_*8>>), + (quote do: @type binary_type2() :: <<_::3>>), + (quote do: @type binary_type3() :: <<_::3, _::_*8>>), (quote do: @type tuple_type() :: {integer()}), (quote do: @type ftype() :: (() -> any()) | (() -> integer()) | ((integer() -> integer()))), (quote do: @type cl() :: charlist()),