Skip to content

Commit 719a912

Browse files
committed
Simplify list_bdd_to_pos_dnf by removing unnecessary checks.
1 parent 0fc582f commit 719a912

File tree

2 files changed

+33
-48
lines changed

2 files changed

+33
-48
lines changed

lib/elixir/lib/module/types/descr.ex

Lines changed: 22 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -1844,38 +1844,23 @@ defmodule Module.Types.Descr do
18441844
acc
18451845

18461846
{list, last} ->
1847-
if empty?(list) or empty?(last) do
1848-
acc
1849-
else
1850-
Enum.reduce_while(negs, {list_tail_unfold(last), []}, fn {neg_type, neg_last},
1851-
{acc_last, acc_negs} ->
1852-
if subtype?(list, neg_type) do
1853-
difference = difference(acc_last, neg_last)
1854-
if empty?(difference), do: {:halt, nil}, else: {:cont, {difference, acc_negs}}
1855-
else
1856-
{:cont, {acc_last, [{neg_type, neg_last} | acc_negs]}}
1857-
end
1858-
end)
1859-
|> case do
1860-
{:halt, nil} -> acc
1861-
{last, negs} -> [{list, last, Enum.reverse(negs)} | acc]
1847+
Enum.reduce_while(negs, {list_tail_unfold(last), []}, fn {neg_type, neg_last},
1848+
{acc_last, acc_negs} ->
1849+
if subtype?(list, neg_type) do
1850+
difference = difference(acc_last, neg_last)
1851+
if empty?(difference), do: {:halt, nil}, else: {:cont, {difference, acc_negs}}
1852+
else
1853+
{:cont, {acc_last, [{neg_type, neg_last} | acc_negs]}}
18621854
end
1855+
end)
1856+
|> case do
1857+
nil -> acc
1858+
{last, negs} -> [{list, last, Enum.reverse(negs)} | acc]
18631859
end
18641860
end
18651861
end)
18661862
end
18671863

1868-
# Compute the head of a list (faster because we discard computations on the last type).
1869-
defp list_bdd_to_hd(bdd) do
1870-
bdd_to_dnf(bdd)
1871-
|> Enum.reduce(none(), fn {pos_list, neg_list}, acc ->
1872-
case non_empty_list_literals_intersection(pos_list) do
1873-
:empty -> acc
1874-
{list, last} -> if list_line_empty?(list, last, neg_list), do: acc, else: union(acc, list)
1875-
end
1876-
end)
1877-
end
1878-
18791864
defp list_pop_dynamic(:term), do: {false, :term}
18801865

18811866
defp list_pop_dynamic(descr) do
@@ -1898,16 +1883,7 @@ defmodule Module.Types.Descr do
18981883
Checks if a list type is a proper list (terminated by empty list).
18991884
"""
19001885
def list_proper?(:term), do: false
1901-
1902-
def list_proper?(%{} = descr) do
1903-
case :maps.take(:dynamic, descr) do
1904-
:error ->
1905-
list_proper_static?(descr)
1906-
1907-
{dynamic, static} ->
1908-
list_proper_static?(static) and (list_proper_static?(dynamic) or empty?(dynamic))
1909-
end
1910-
end
1886+
def list_proper?(%{} = descr), do: Map.get(descr, :dynamic, descr) |> list_proper_static?()
19111887

19121888
defp list_proper_static?(:term), do: false
19131889

@@ -1926,7 +1902,7 @@ defmodule Module.Types.Descr do
19261902
empty?(Map.delete(descr, :list)) and list_bdd_proper?(bdd)
19271903

19281904
%{} ->
1929-
false
1905+
empty?(descr)
19301906
end
19311907
end
19321908

@@ -2045,20 +2021,19 @@ defmodule Module.Types.Descr do
20452021

20462022
defp list_hd_static(:term), do: :term
20472023

2048-
defp list_hd_static(%{list: bdd}), do: list_bdd_to_hd(bdd)
2024+
defp list_hd_static(%{list: bdd}) do
2025+
list_bdd_to_pos_dnf(bdd)
2026+
|> Enum.reduce(none(), fn {list, _last, _negs}, acc -> union(acc, list) end)
2027+
end
20492028

20502029
defp list_hd_static(%{}), do: none()
20512030

20522031
@doc """
2053-
Computes the type of the tail of a non-empty list type.
2054-
2055-
Returns `{dynamic?, type}` on success, where `dynamic?` indicates whether
2056-
the result contains a dynamic component. Returns `:badnonemptylist` if the
2057-
input type is not guaranteed to be a non-empty list.
2032+
Returns the tail of a list.
20582033
2059-
For a `non_empty_list(t)`, the tail type is `list(t)` (possibly empty).
2034+
For a `non_empty_list(t)`, the tail type is `list(t)`.
20602035
For an improper list `non_empty_list(t, s)`, the tail type is
2061-
`list(t, s) or s` (either the rest of the list or the terminator).
2036+
`list(t, s) or s` (either the rest of the list or the terminator)
20622037
"""
20632038
def list_tl(:term), do: :badnonemptylist
20642039

@@ -2097,8 +2072,7 @@ defmodule Module.Types.Descr do
20972072
end
20982073

20992074
list_bdd_to_pos_dnf(bdd)
2100-
|> Enum.reduce(none(), fn {_list, last, _negs}, acc -> union(acc, last) end)
2101-
|> union(initial)
2075+
|> Enum.reduce(initial, fn {_list, last, _negs}, acc -> union(acc, last) end)
21022076
end
21032077

21042078
defp list_tl_static(%{}), do: none()
@@ -2126,6 +2100,7 @@ defmodule Module.Types.Descr do
21262100
name = if empty?, do: :list, else: :non_empty_list
21272101
{name, [to_quoted(list_type, opts)], empty?}
21282102

2103+
# Sugar: print the last type as term() if it only misses non empty lists.
21292104
subtype?(@not_non_empty_list, last_type) ->
21302105
args = [to_quoted(list_type, opts), {:term, [], []}]
21312106
{:non_empty_list, args, list_rendered?}

lib/elixir/test/elixir/module/types/descr_test.exs

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1270,13 +1270,23 @@ defmodule Module.Types.DescrTest do
12701270

12711271
test "list_proper?" do
12721272
assert list_proper?(term()) == false
1273-
assert list_proper?(none()) == false
1273+
assert list_proper?(none()) == true
12741274
assert list_proper?(empty_list()) == true
12751275
assert list_proper?(non_empty_list(integer())) == true
12761276
assert list_proper?(non_empty_list(integer(), atom())) == false
12771277
assert list_proper?(non_empty_list(integer(), term())) == false
12781278
assert list_proper?(non_empty_list(integer(), list(term()))) == true
12791279
assert list_proper?(list(integer()) |> union(list(integer(), integer()))) == false
1280+
assert list_proper?(dynamic(list(integer()))) == true
1281+
assert list_proper?(dynamic(list(integer(), atom()))) == false
1282+
1283+
# An empty list
1284+
list_with_tail =
1285+
non_empty_list(atom(), union(integer(), empty_list()))
1286+
|> difference(non_empty_list(atom([:ok]), integer()))
1287+
|> difference(non_empty_list(atom(), term()))
1288+
1289+
assert list_proper?(list_with_tail) == true
12801290
end
12811291

12821292
test "list_tl" do

0 commit comments

Comments
 (0)