Remove improper_list from type specification
This commit is contained in:
@@ -360,14 +360,14 @@ defmodule Module.Types.Apply do
|
||||
|
||||
defp remote_apply(:erlang, :hd, _info, [list], _stack) do
|
||||
case list_hd(list) do
|
||||
{_, value_type} -> {:ok, value_type}
|
||||
{:ok, value_type} -> {:ok, value_type}
|
||||
:badnonemptylist -> {:error, badremote(:erlang, :hd, 1)}
|
||||
end
|
||||
end
|
||||
|
||||
defp remote_apply(:erlang, :tl, _info, [list], _stack) do
|
||||
case list_tl(list) do
|
||||
{_, value_type} -> {:ok, value_type}
|
||||
{:ok, value_type} -> {:ok, value_type}
|
||||
:badnonemptylist -> {:error, badremote(:erlang, :tl, 1)}
|
||||
end
|
||||
end
|
||||
|
||||
@@ -54,7 +54,6 @@ defmodule Module.Types.Descr do
|
||||
@list_top %{bitmap: @bit_empty_list, list: @non_empty_list_top}
|
||||
@empty_list %{bitmap: @bit_empty_list}
|
||||
@not_non_empty_list Map.delete(@term, :list)
|
||||
@not_list Map.replace!(@not_non_empty_list, :bitmap, @bit_top - @bit_empty_list)
|
||||
|
||||
@not_set %{optional: 1}
|
||||
@term_or_optional Map.put(@term, :optional, 1)
|
||||
@@ -1972,7 +1971,7 @@ defmodule Module.Types.Descr do
|
||||
static_value = list_hd_static(descr)
|
||||
|
||||
if non_empty_list_only?(descr) and not empty?(static_value) do
|
||||
{false, static_value}
|
||||
{:ok, static_value}
|
||||
else
|
||||
:badnonemptylist
|
||||
end
|
||||
@@ -1981,7 +1980,7 @@ defmodule Module.Types.Descr do
|
||||
dynamic_value = list_hd_static(dynamic)
|
||||
|
||||
if non_empty_list_only?(static) and not empty?(dynamic_value) do
|
||||
{true, union(dynamic(dynamic_value), list_hd_static(static))}
|
||||
{:ok, union(dynamic(dynamic_value), list_hd_static(static))}
|
||||
else
|
||||
:badnonemptylist
|
||||
end
|
||||
@@ -2015,7 +2014,7 @@ defmodule Module.Types.Descr do
|
||||
static_value = list_tl_static(descr)
|
||||
|
||||
if non_empty_list_only?(descr) and not empty?(static_value) do
|
||||
{false, static_value}
|
||||
{:ok, static_value}
|
||||
else
|
||||
:badnonemptylist
|
||||
end
|
||||
@@ -2024,7 +2023,7 @@ defmodule Module.Types.Descr do
|
||||
dynamic_value = list_tl_static(dynamic)
|
||||
|
||||
if non_empty_list_only?(static) and not empty?(dynamic_value) do
|
||||
{true, union(dynamic(dynamic_value), list_tl_static(static))}
|
||||
{:ok, union(dynamic(dynamic_value), list_tl_static(static))}
|
||||
else
|
||||
:badnonemptylist
|
||||
end
|
||||
@@ -2048,10 +2047,6 @@ defmodule Module.Types.Descr do
|
||||
|
||||
defp list_tl_static(%{}), do: none()
|
||||
|
||||
defp list_improper_static?(:term), do: false
|
||||
defp list_improper_static?(%{bitmap: bitmap}) when (bitmap &&& @bit_empty_list) != 0, do: false
|
||||
defp list_improper_static?(term), do: equal?(term, @not_list)
|
||||
|
||||
defp list_to_quoted(bdd, empty?, opts) do
|
||||
dnf = list_normalize(bdd)
|
||||
|
||||
@@ -2059,17 +2054,12 @@ defmodule Module.Types.Descr do
|
||||
dnf
|
||||
|> Enum.reduce({[], false}, fn {list_type, last_type, negs}, {acc, list_rendered?} ->
|
||||
{name, arguments, list_rendered?} =
|
||||
cond do
|
||||
list_type == term() and list_improper_static?(last_type) ->
|
||||
{:improper_list, [], list_rendered?}
|
||||
|
||||
subtype?(last_type, @empty_list) ->
|
||||
name = if empty?, do: :list, else: :non_empty_list
|
||||
{name, [to_quoted(list_type, opts)], empty?}
|
||||
|
||||
true ->
|
||||
args = [to_quoted(list_type, opts), to_quoted(last_type, opts)]
|
||||
{:non_empty_list, args, list_rendered?}
|
||||
if subtype?(last_type, @empty_list) do
|
||||
name = if empty?, do: :list, else: :non_empty_list
|
||||
{name, [to_quoted(list_type, opts)], empty?}
|
||||
else
|
||||
args = [to_quoted(list_type, opts), to_quoted(last_type, opts)]
|
||||
{:non_empty_list, args, list_rendered?}
|
||||
end
|
||||
|
||||
acc =
|
||||
|
||||
@@ -94,7 +94,7 @@ defmodule Module.Types.Expr do
|
||||
else
|
||||
hd_type =
|
||||
case list_hd(expected) do
|
||||
{_, type} -> type
|
||||
{:ok, type} -> type
|
||||
_ -> term()
|
||||
end
|
||||
|
||||
@@ -106,8 +106,8 @@ defmodule Module.Types.Expr do
|
||||
else
|
||||
tl_type =
|
||||
case list_tl(expected) do
|
||||
{_, type} -> type
|
||||
_ -> term()
|
||||
{:ok, type} -> type
|
||||
:badnonemptylist -> term()
|
||||
end
|
||||
|
||||
of_expr(suffix, tl_type, expr, stack, context)
|
||||
|
||||
@@ -305,7 +305,7 @@ defmodule Module.Types.Pattern do
|
||||
|
||||
defp of_pattern_var([{:head, counter} | rest], type, _reachable_var?, info, context) do
|
||||
case list_hd(type) do
|
||||
{_, head} ->
|
||||
{:ok, head} ->
|
||||
tree = Map.fetch!(info, -counter)
|
||||
type = intersection(of_pattern_tree(tree, context), head)
|
||||
of_pattern_var(rest, type, false, info, context)
|
||||
@@ -317,8 +317,8 @@ defmodule Module.Types.Pattern do
|
||||
|
||||
defp of_pattern_var([:tail | rest], type, reachable_var?, info, context) do
|
||||
case list_tl(type) do
|
||||
{_, tail} -> of_pattern_var(rest, tail, reachable_var?, info, context)
|
||||
_ -> :error
|
||||
{:ok, tail} -> of_pattern_var(rest, tail, reachable_var?, info, context)
|
||||
:badnonemptylist -> :error
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
@@ -5,6 +5,32 @@
|
||||
|
||||
# Set-theoretic types cheatsheet
|
||||
|
||||
## Set operators
|
||||
|
||||
#### Union
|
||||
|
||||
```elixir
|
||||
type1 or type2
|
||||
```
|
||||
|
||||
#### Intersection
|
||||
|
||||
```elixir
|
||||
type1 and type2
|
||||
```
|
||||
|
||||
#### Difference
|
||||
|
||||
```elixir
|
||||
type1 and not type2
|
||||
```
|
||||
|
||||
#### Negation
|
||||
|
||||
```elixir
|
||||
not type
|
||||
```
|
||||
|
||||
## Data types
|
||||
|
||||
### Indivisible types
|
||||
|
||||
@@ -1246,12 +1246,12 @@ defmodule Module.Types.DescrTest do
|
||||
assert list_hd(term()) == :badnonemptylist
|
||||
assert list_hd(list(term())) == :badnonemptylist
|
||||
assert list_hd(empty_list()) == :badnonemptylist
|
||||
assert list_hd(non_empty_list(term())) == {false, term()}
|
||||
assert list_hd(non_empty_list(integer())) == {false, integer()}
|
||||
assert list_hd(difference(list(number()), list(integer()))) == {false, number()}
|
||||
assert list_hd(non_empty_list(term())) == {:ok, term()}
|
||||
assert list_hd(non_empty_list(integer())) == {:ok, integer()}
|
||||
assert list_hd(difference(list(number()), list(integer()))) == {:ok, number()}
|
||||
|
||||
assert list_hd(dynamic()) == {true, dynamic()}
|
||||
assert list_hd(dynamic(list(integer()))) == {true, dynamic(integer())}
|
||||
assert list_hd(dynamic()) == {:ok, dynamic()}
|
||||
assert list_hd(dynamic(list(integer()))) == {:ok, dynamic(integer())}
|
||||
assert list_hd(union(dynamic(), atom())) == :badnonemptylist
|
||||
assert list_hd(union(dynamic(), list(term()))) == :badnonemptylist
|
||||
|
||||
@@ -1259,12 +1259,12 @@ defmodule Module.Types.DescrTest do
|
||||
assert list_hd(dynamic(difference(list(number()), list(number())))) == :badnonemptylist
|
||||
|
||||
assert list_hd(union(dynamic(list(float())), non_empty_list(atom()))) ==
|
||||
{true, union(dynamic(float()), atom())}
|
||||
{:ok, union(dynamic(float()), atom())}
|
||||
|
||||
# If term() is in the tail, it means list(term()) is in the tail
|
||||
# and therefore any term can be returned from hd.
|
||||
assert list_hd(non_empty_list(atom(), term())) == {false, term()}
|
||||
assert list_hd(non_empty_list(atom(), negation(list(term(), term())))) == {false, atom()}
|
||||
assert list_hd(non_empty_list(atom(), term())) == {:ok, term()}
|
||||
assert list_hd(non_empty_list(atom(), negation(list(term(), term())))) == {:ok, atom()}
|
||||
end
|
||||
|
||||
test "list_tl" do
|
||||
@@ -1274,27 +1274,27 @@ defmodule Module.Types.DescrTest do
|
||||
assert list_tl(list(integer())) == :badnonemptylist
|
||||
assert list_tl(difference(list(number()), list(number()))) == :badnonemptylist
|
||||
|
||||
assert list_tl(non_empty_list(integer())) == {false, list(integer())}
|
||||
assert list_tl(non_empty_list(integer())) == {:ok, list(integer())}
|
||||
|
||||
assert list_tl(non_empty_list(integer(), atom())) ==
|
||||
{false, union(atom(), non_empty_list(integer(), atom()))}
|
||||
{:ok, union(atom(), non_empty_list(integer(), atom()))}
|
||||
|
||||
# The tail of either a (non empty) list of integers with an atom tail or a (non empty) list
|
||||
# of tuples with a float tail is either an atom, or a float, or a (possibly empty) list of
|
||||
# integers with an atom tail, or a (possibly empty) list of tuples with a float tail.
|
||||
assert list_tl(union(non_empty_list(integer(), atom()), non_empty_list(tuple(), float()))) ==
|
||||
{false,
|
||||
{:ok,
|
||||
atom()
|
||||
|> union(float())
|
||||
|> union(
|
||||
union(non_empty_list(integer(), atom()), non_empty_list(tuple(), float()))
|
||||
)}
|
||||
|
||||
assert list_tl(dynamic()) == {true, dynamic()}
|
||||
assert list_tl(dynamic(list(integer()))) == {true, dynamic(list(integer()))}
|
||||
assert list_tl(dynamic()) == {:ok, dynamic()}
|
||||
assert list_tl(dynamic(list(integer()))) == {:ok, dynamic(list(integer()))}
|
||||
|
||||
assert list_tl(dynamic(list(integer(), atom()))) ==
|
||||
{true, dynamic(union(atom(), list(integer(), atom())))}
|
||||
{:ok, dynamic(union(atom(), list(integer(), atom())))}
|
||||
end
|
||||
|
||||
test "tuple_fetch" do
|
||||
@@ -2374,9 +2374,6 @@ defmodule Module.Types.DescrTest do
|
||||
assert list(term(), term()) |> to_quoted_string() ==
|
||||
"empty_list() or non_empty_list(term(), term())"
|
||||
|
||||
assert non_empty_list(term(), difference(term(), list(term()))) |> to_quoted_string() ==
|
||||
"improper_list()"
|
||||
|
||||
# Test normalization
|
||||
|
||||
# Remove duplicates
|
||||
|
||||
Reference in New Issue
Block a user