diff --git a/lib/elixir/lib/module/types/descr.ex b/lib/elixir/lib/module/types/descr.ex index 063ed4a8fb..a99bf79e30 100644 --- a/lib/elixir/lib/module/types/descr.ex +++ b/lib/elixir/lib/module/types/descr.ex @@ -1169,12 +1169,14 @@ defmodule Module.Types.Descr do :term -> :undefined - %{atom: {:union, set}} - when map_size(descr) == 1 and set in @false_or_nil_atoms -> - :always_false + %{atom: {:union, set}} when set in @false_or_nil_atoms -> + cond do + map_size(descr) == 1 -> :always_false + empty?(Map.delete(descr, :atom)) -> :always_false + true -> :undefined + end - %{atom: {:union, set}} - when map_size(descr) == 1 and not is_map_key(set, false) and not is_map_key(set, nil) -> + %{atom: {:union, set}} when not is_map_key(set, false) and not is_map_key(set, nil) -> :always_true %{atom: {:negation, %{nil => _, false => _}}} -> @@ -1186,8 +1188,8 @@ defmodule Module.Types.Descr do _ when map_size(descr) == 0 -> :undefined - _ -> - :always_true + descr -> + if empty?(descr), do: :undefined, else: :always_true end end diff --git a/lib/elixir/test/elixir/module/types/descr_test.exs b/lib/elixir/test/elixir/module/types/descr_test.exs index 1278f2b821..d9b21a5a22 100644 --- a/lib/elixir/test/elixir/module/types/descr_test.exs +++ b/lib/elixir/test/elixir/module/types/descr_test.exs @@ -1505,6 +1505,20 @@ defmodule Module.Types.DescrTest do assert truthiness(type) == :always_true assert truthiness(dynamic(type)) == :always_true end + + assert truthiness(union(atom([true]), integer())) == :always_true + + empty_descr = + difference(tuple([number(), integer()]), open_tuple([float(), term()])) + |> difference(tuple([integer(), integer()])) + + assert empty?(empty_descr) + + assert truthiness(empty_descr) == :undefined + assert truthiness(dynamic(empty_descr)) == :undefined + assert truthiness(union(atom([nil]), empty_descr)) == :always_false + + assert truthiness(union(atom([false]), empty_descr)) == :always_false end test "atom_fetch" do diff --git a/lib/elixir/test/elixir/module/types/expr_test.exs b/lib/elixir/test/elixir/module/types/expr_test.exs index c0a5483a26..93698df811 100644 --- a/lib/elixir/test/elixir/module/types/expr_test.exs +++ b/lib/elixir/test/elixir/module/types/expr_test.exs @@ -1596,6 +1596,34 @@ defmodule Module.Types.ExprTest do # from: types_test.ex:LINE-1 y = 123 """ + + assert typewarn!( + [x], + cond do + if(x, do: true, else: 1) -> :if + x -> :x + end + ) == + {atom([:if, :x]), + ~l""" + this clause in cond will always match: + + if x do + true + else + 1 + end + + since it has type: + + true or integer() + + where "x" was given the type: + + # type: dynamic() + # from: types_test.ex:LINE-7 + x + """} end test "Integer.to_string/1" do