diff --git a/lib/elixir/lib/module/types/descr.ex b/lib/elixir/lib/module/types/descr.ex index 620c03e956..7dd4169f24 100644 --- a/lib/elixir/lib/module/types/descr.ex +++ b/lib/elixir/lib/module/types/descr.ex @@ -950,7 +950,13 @@ defmodule Module.Types.Descr do domain of a function. It is used to refine dynamic types as we traverse the program. """ - def compatible_intersection(other, :term), do: {:ok, remove_optional(other)} + def compatible_intersection(other, :term) do + if empty?(other) do + {:error, other} + else + {:ok, remove_optional(other)} + end + end def compatible_intersection(left, right) do {left_dynamic, left_static} = pop_dynamic(left) diff --git a/lib/elixir/test/elixir/module/types/descr_test.exs b/lib/elixir/test/elixir/module/types/descr_test.exs index 198b0c6d69..ef5346b902 100644 --- a/lib/elixir/test/elixir/module/types/descr_test.exs +++ b/lib/elixir/test/elixir/module/types/descr_test.exs @@ -1180,6 +1180,17 @@ defmodule Module.Types.DescrTest do assert compatible?(dynamic(list(term())), list(integer())) assert compatible?(dynamic(list(term(), term())), list(integer(), integer())) end + + test "compatible_intersection agrees with compatible? on empty inputs" do + refute compatible?(none(), term()) + assert compatible_intersection(none(), term()) == {:error, none()} + + refute compatible?(dynamic(none()), term()) + assert compatible_intersection(dynamic(none()), term()) == {:error, dynamic(none())} + + assert compatible_intersection(integer(), term()) == {:ok, integer()} + assert compatible_intersection(dynamic(integer()), term()) == {:ok, dynamic(integer())} + end end describe "empty?" do