diff --git a/lib/elixir/lib/module/types/descr.ex b/lib/elixir/lib/module/types/descr.ex index cee9c6fefcc..e7cf7bc9cf3 100644 --- a/lib/elixir/lib/module/types/descr.ex +++ b/lib/elixir/lib/module/types/descr.ex @@ -407,6 +407,11 @@ defmodule Module.Types.Descr do defp pop_dynamic(:term), do: {:term, :term} defp pop_dynamic(descr), do: Map.pop(descr, :dynamic, descr) + defp put_dynamic(:term, dynamic), do: optional_to_term(%{dynamic: dynamic}) + defp put_dynamic(static, dynamic) when static == dynamic, do: static + defp put_dynamic(_static, dynamic) when dynamic == @none, do: @none + defp put_dynamic(static, dynamic), do: Map.put(static, :dynamic, dynamic) + @doc """ Computes the union of two descrs. """ @@ -502,7 +507,8 @@ defmodule Module.Types.Descr do {right_dynamic, right_static} = pop_dynamic(right) dynamic_part = bare_difference_static(left_dynamic, right_static) - Map.put(bare_difference_static(left_static, right_dynamic), :dynamic, dynamic_part) + bare_difference_static(left_static, right_dynamic) + |> put_dynamic(dynamic_part) else bare_difference_static(left, right) end @@ -6125,7 +6131,8 @@ defmodule Module.Types.Descr do {right_dynamic, right_static} = pop_dynamic(right) dynamic_part = opt_difference_static(left_dynamic, right_static) - Map.put(opt_difference_static(left_static, right_dynamic), :dynamic, dynamic_part) + opt_difference_static(left_static, right_dynamic) + |> put_dynamic(dynamic_part) else opt_difference_static(left, right) end diff --git a/lib/elixir/test/elixir/module/types/descr_test.exs b/lib/elixir/test/elixir/module/types/descr_test.exs index b48049f2c48..84e25ac0537 100644 --- a/lib/elixir/test/elixir/module/types/descr_test.exs +++ b/lib/elixir/test/elixir/module/types/descr_test.exs @@ -620,7 +620,10 @@ defmodule Module.Types.DescrTest do assert equal?(dynamic(), opt_difference(term(), dynamic())) assert empty?(opt_difference(dynamic(), term())) assert empty?(opt_difference(none(), dynamic())) - assert empty?(opt_difference(dynamic(integer()), integer())) + assert opt_difference(dynamic(integer()), integer()) == none() + + # Covers assembling a result with static :term and dynamic unfolded term. + assert opt_difference(term(), %{dynamic: none(), optional: 1}) == term() end test "tuple" do @@ -3336,6 +3339,7 @@ defmodule Module.Types.DescrTest do test "dynamic (negation)" do assert dynamic(opt_negation(integer())) |> to_quoted_string() == "dynamic(not integer())" + assert opt_negation(dynamic(none())) == term() assert opt_negation(dynamic(integer())) |> to_quoted_string() == "dynamic() or not integer()"