From c26f0eeb553ee75cdd5b834f8fac2c976c66668f Mon Sep 17 00:00:00 2001 From: Guillaume Duboc <27832828+gldubc@users.noreply.github.com> Date: Sun, 3 May 2026 22:26:51 +0200 Subject: [PATCH] Fix wrong intersection with union of dynamic() --- lib/elixir/lib/module/types/descr.ex | 2 -- lib/elixir/test/elixir/module/types/descr_test.exs | 5 +++++ lib/elixir/test/elixir/module/types/expr_test.exs | 14 ++++++++++++++ 3 files changed, 19 insertions(+), 2 deletions(-) diff --git a/lib/elixir/lib/module/types/descr.ex b/lib/elixir/lib/module/types/descr.ex index 063ed4a8fb..f074240e85 100644 --- a/lib/elixir/lib/module/types/descr.ex +++ b/lib/elixir/lib/module/types/descr.ex @@ -448,8 +448,6 @@ defmodule Module.Types.Descr do """ def intersection(:term, other), do: remove_optional(other) def intersection(other, :term), do: remove_optional(other) - def intersection(%{dynamic: :term}, other), do: dynamic(remove_optional(other)) - def intersection(other, %{dynamic: :term}), do: dynamic(remove_optional(other)) def intersection(left, right) do is_gradual_left = gradual?(left) diff --git a/lib/elixir/test/elixir/module/types/descr_test.exs b/lib/elixir/test/elixir/module/types/descr_test.exs index 1278f2b821..5eb59c512b 100644 --- a/lib/elixir/test/elixir/module/types/descr_test.exs +++ b/lib/elixir/test/elixir/module/types/descr_test.exs @@ -1500,6 +1500,11 @@ defmodule Module.Types.DescrTest do assert truthiness(dynamic(type)) == :always_false end + assert equal?( + intersection(union(atom(), dynamic()), union(atom(), dynamic())), + union(atom(), dynamic()) + ) + for type <- [negation(atom()), atom([true]), negation(atom([false, nil])), atom([:ok]), integer()] do assert truthiness(type) == :always_true diff --git a/lib/elixir/test/elixir/module/types/expr_test.exs b/lib/elixir/test/elixir/module/types/expr_test.exs index c0a5483a26..087d901a11 100644 --- a/lib/elixir/test/elixir/module/types/expr_test.exs +++ b/lib/elixir/test/elixir/module/types/expr_test.exs @@ -1425,6 +1425,20 @@ defmodule Module.Types.ExprTest do assert typecheck!([x = 123, y = 456.0], x == y) == boolean() end + test "preserves static components across gradual self-intersections" do + assert typecheck!( + [x], + ( + # y :: :foo or dynamic() + y = if :rand.uniform() > 0.5, do: :foo, else: x + # y's type intersected with itself + y = y + + y + ) + ) == union(atom([:foo]), dynamic()) + end + test "in dynamic mode" do assert typedyn!([x = 123, y = 456.0], x < y) == dynamic(boolean()) assert typedyn!([x = 123, y = 456.0], x == y) == dynamic(boolean())