Skip to content

Commit 2fd3506

Browse files
authored
Fix truthiness implementation (#15339)
1 parent 002e382 commit 2fd3506

3 files changed

Lines changed: 51 additions & 7 deletions

File tree

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

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1169,12 +1169,14 @@ defmodule Module.Types.Descr do
11691169
:term ->
11701170
:undefined
11711171

1172-
%{atom: {:union, set}}
1173-
when map_size(descr) == 1 and set in @false_or_nil_atoms ->
1174-
:always_false
1172+
%{atom: {:union, set}} when set in @false_or_nil_atoms ->
1173+
cond do
1174+
map_size(descr) == 1 -> :always_false
1175+
empty?(Map.delete(descr, :atom)) -> :always_false
1176+
true -> :undefined
1177+
end
11751178

1176-
%{atom: {:union, set}}
1177-
when map_size(descr) == 1 and not is_map_key(set, false) and not is_map_key(set, nil) ->
1179+
%{atom: {:union, set}} when not is_map_key(set, false) and not is_map_key(set, nil) ->
11781180
:always_true
11791181

11801182
%{atom: {:negation, %{nil => _, false => _}}} ->
@@ -1186,8 +1188,8 @@ defmodule Module.Types.Descr do
11861188
_ when map_size(descr) == 0 ->
11871189
:undefined
11881190

1189-
_ ->
1190-
:always_true
1191+
descr ->
1192+
if empty?(descr), do: :undefined, else: :always_true
11911193
end
11921194
end
11931195

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

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1505,6 +1505,20 @@ defmodule Module.Types.DescrTest do
15051505
assert truthiness(type) == :always_true
15061506
assert truthiness(dynamic(type)) == :always_true
15071507
end
1508+
1509+
assert truthiness(union(atom([true]), integer())) == :always_true
1510+
1511+
empty_descr =
1512+
difference(tuple([number(), integer()]), open_tuple([float(), term()]))
1513+
|> difference(tuple([integer(), integer()]))
1514+
1515+
assert empty?(empty_descr)
1516+
1517+
assert truthiness(empty_descr) == :undefined
1518+
assert truthiness(dynamic(empty_descr)) == :undefined
1519+
assert truthiness(union(atom([nil]), empty_descr)) == :always_false
1520+
1521+
assert truthiness(union(atom([false]), empty_descr)) == :always_false
15081522
end
15091523

15101524
test "atom_fetch" do

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

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1596,6 +1596,34 @@ defmodule Module.Types.ExprTest do
15961596
# from: types_test.ex:LINE-1
15971597
y = 123
15981598
"""
1599+
1600+
assert typewarn!(
1601+
[x],
1602+
cond do
1603+
if(x, do: true, else: 1) -> :if
1604+
x -> :x
1605+
end
1606+
) ==
1607+
{atom([:if, :x]),
1608+
~l"""
1609+
this clause in cond will always match:
1610+
1611+
if x do
1612+
true
1613+
else
1614+
1
1615+
end
1616+
1617+
since it has type:
1618+
1619+
true or integer()
1620+
1621+
where "x" was given the type:
1622+
1623+
# type: dynamic()
1624+
# from: types_test.ex:LINE-7
1625+
x
1626+
"""}
15991627
end
16001628

16011629
test "Integer.to_string/1" do

0 commit comments

Comments
 (0)