Skip to content

Commit 699f969

Browse files
committed
Simplify list_bdd_to_pos_dnf by removing unnecessary checks.
1 parent 4e5179d commit 699f969

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
@@ -1854,38 +1854,23 @@ defmodule Module.Types.Descr do
18541854
acc
18551855

18561856
{list, last} ->
1857-
if empty?(list) or empty?(last) do
1858-
acc
1859-
else
1860-
Enum.reduce_while(negs, {list_tail_unfold(last), []}, fn {neg_type, neg_last},
1861-
{acc_last, acc_negs} ->
1862-
if subtype?(list, neg_type) do
1863-
difference = difference(acc_last, neg_last)
1864-
if empty?(difference), do: {:halt, nil}, else: {:cont, {difference, acc_negs}}
1865-
else
1866-
{:cont, {acc_last, [{neg_type, neg_last} | acc_negs]}}
1867-
end
1868-
end)
1869-
|> case do
1870-
{:halt, nil} -> acc
1871-
{last, negs} -> [{list, last, Enum.reverse(negs)} | acc]
1857+
Enum.reduce_while(negs, {list_tail_unfold(last), []}, fn {neg_type, neg_last},
1858+
{acc_last, acc_negs} ->
1859+
if subtype?(list, neg_type) do
1860+
difference = difference(acc_last, neg_last)
1861+
if empty?(difference), do: {:halt, nil}, else: {:cont, {difference, acc_negs}}
1862+
else
1863+
{:cont, {acc_last, [{neg_type, neg_last} | acc_negs]}}
18721864
end
1865+
end)
1866+
|> case do
1867+
nil -> acc
1868+
{last, negs} -> [{list, last, Enum.reverse(negs)} | acc]
18731869
end
18741870
end
18751871
end)
18761872
end
18771873

1878-
# Compute the head of a list (faster because we discard computations on the last type).
1879-
defp list_bdd_to_hd(bdd) do
1880-
bdd_to_dnf(bdd)
1881-
|> Enum.reduce(none(), fn {pos_list, neg_list}, acc ->
1882-
case non_empty_list_literals_intersection(pos_list) do
1883-
:empty -> acc
1884-
{list, last} -> if list_line_empty?(list, last, neg_list), do: acc, else: union(acc, list)
1885-
end
1886-
end)
1887-
end
1888-
18891874
defp list_pop_dynamic(:term), do: {false, :term}
18901875

18911876
defp list_pop_dynamic(descr) do
@@ -1908,16 +1893,7 @@ defmodule Module.Types.Descr do
19081893
Checks if a list type is a proper list (terminated by empty list).
19091894
"""
19101895
def list_proper?(:term), do: false
1911-
1912-
def list_proper?(%{} = descr) do
1913-
case :maps.take(:dynamic, descr) do
1914-
:error ->
1915-
list_proper_static?(descr)
1916-
1917-
{dynamic, static} ->
1918-
list_proper_static?(static) and (list_proper_static?(dynamic) or empty?(dynamic))
1919-
end
1920-
end
1896+
def list_proper?(%{} = descr), do: Map.get(descr, :dynamic, descr) |> list_proper_static?()
19211897

19221898
defp list_proper_static?(:term), do: false
19231899

@@ -1936,7 +1912,7 @@ defmodule Module.Types.Descr do
19361912
empty?(Map.delete(descr, :list)) and list_bdd_proper?(bdd)
19371913

19381914
%{} ->
1939-
false
1915+
empty?(descr)
19401916
end
19411917
end
19421918

@@ -2055,20 +2031,19 @@ defmodule Module.Types.Descr do
20552031

20562032
defp list_hd_static(:term), do: :term
20572033

2058-
defp list_hd_static(%{list: bdd}), do: list_bdd_to_hd(bdd)
2034+
defp list_hd_static(%{list: bdd}) do
2035+
list_bdd_to_pos_dnf(bdd)
2036+
|> Enum.reduce(none(), fn {list, _last, _negs}, acc -> union(acc, list) end)
2037+
end
20592038

20602039
defp list_hd_static(%{}), do: none()
20612040

20622041
@doc """
2063-
Computes the type of the tail of a non-empty list type.
2064-
2065-
Returns `{dynamic?, type}` on success, where `dynamic?` indicates whether
2066-
the result contains a dynamic component. Returns `:badnonemptylist` if the
2067-
input type is not guaranteed to be a non-empty list.
2042+
Returns the tail of a list.
20682043
2069-
For a `non_empty_list(t)`, the tail type is `list(t)` (possibly empty).
2044+
For a `non_empty_list(t)`, the tail type is `list(t)`.
20702045
For an improper list `non_empty_list(t, s)`, the tail type is
2071-
`list(t, s) or s` (either the rest of the list or the terminator).
2046+
`list(t, s) or s` (either the rest of the list or the terminator)
20722047
"""
20732048
def list_tl(:term), do: :badnonemptylist
20742049

@@ -2107,8 +2082,7 @@ defmodule Module.Types.Descr do
21072082
end
21082083

21092084
list_bdd_to_pos_dnf(bdd)
2110-
|> Enum.reduce(none(), fn {_list, last, _negs}, acc -> union(acc, last) end)
2111-
|> union(initial)
2085+
|> Enum.reduce(initial, fn {_list, last, _negs}, acc -> union(acc, last) end)
21122086
end
21132087

21142088
defp list_tl_static(%{}), do: none()
@@ -2132,6 +2106,7 @@ defmodule Module.Types.Descr do
21322106
name = if empty?, do: :list, else: :non_empty_list
21332107
{name, [to_quoted(list_type, opts)], empty?}
21342108

2109+
# Sugar: print the last type as term() if it only misses non empty lists.
21352110
subtype?(@not_non_empty_list, last_type) ->
21362111
args = [to_quoted(list_type, opts), {:term, [], []}]
21372112
{: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
@@ -1272,13 +1272,23 @@ defmodule Module.Types.DescrTest do
12721272

12731273
test "list_proper?" do
12741274
assert list_proper?(term()) == false
1275-
assert list_proper?(none()) == false
1275+
assert list_proper?(none()) == true
12761276
assert list_proper?(empty_list()) == true
12771277
assert list_proper?(non_empty_list(integer())) == true
12781278
assert list_proper?(non_empty_list(integer(), atom())) == false
12791279
assert list_proper?(non_empty_list(integer(), term())) == false
12801280
assert list_proper?(non_empty_list(integer(), list(term()))) == true
12811281
assert list_proper?(list(integer()) |> union(list(integer(), integer()))) == false
1282+
assert list_proper?(dynamic(list(integer()))) == true
1283+
assert list_proper?(dynamic(list(integer(), atom()))) == false
1284+
1285+
# An empty list
1286+
list_with_tail =
1287+
non_empty_list(atom(), union(integer(), empty_list()))
1288+
|> difference(non_empty_list(atom([:ok]), integer()))
1289+
|> difference(non_empty_list(atom(), term()))
1290+
1291+
assert list_proper?(list_with_tail) == true
12821292
end
12831293

12841294
test "list_tl" do

0 commit comments

Comments
 (0)