diff --git a/lib/elixir/lib/module/types/descr.ex b/lib/elixir/lib/module/types/descr.ex index 9ad6f166c3..ee6e1a93d2 100644 --- a/lib/elixir/lib/module/types/descr.ex +++ b/lib/elixir/lib/module/types/descr.ex @@ -5853,10 +5853,22 @@ defmodule Module.Types.Descr do :error -> tuple_insert_at_checked(descr, index, type) - {dynamic_type, _static} -> + {dynamic_type, static_type} -> case tuple_insert_at_checked(descr, index, dynamic_type) do - atom when atom in [:badtuple, :badindex] -> atom - result -> dynamic(result) + dynamic_result when is_descr(dynamic_result) -> + dynamic_result = dynamic(dynamic_result) + + if empty?(static_type) do + dynamic_result + else + case tuple_insert_at_checked(descr, index, static_type) do + static_result when is_descr(static_result) -> union(dynamic_result, static_result) + error -> error + end + end + + error -> + error end 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 d7e3357d14..7f6eb465db 100644 --- a/lib/elixir/test/elixir/module/types/descr_test.exs +++ b/lib/elixir/test/elixir/module/types/descr_test.exs @@ -1844,6 +1844,18 @@ defmodule Module.Types.DescrTest do assert tuple_insert_at(tuple([integer(), atom()]), 1, dynamic()) == dynamic(tuple([integer(), term(), atom()])) + assert tuple_insert_at( + tuple([boolean()]), + 1, + union(dynamic(integer()), atom([:inserted])) + ) + |> equal?( + union( + tuple([boolean(), atom([:inserted])]), + dynamic(tuple([boolean(), integer()])) + ) + ) + # Test inserting into a dynamic tuple assert tuple_insert_at(dynamic(tuple([integer(), atom()])), 1, boolean()) == dynamic(tuple([integer(), boolean(), atom()])) diff --git a/lib/elixir/test/elixir/module/types/expr_test.exs b/lib/elixir/test/elixir/module/types/expr_test.exs index 5ace329d3a..0e1869ad9a 100644 --- a/lib/elixir/test/elixir/module/types/expr_test.exs +++ b/lib/elixir/test/elixir/module/types/expr_test.exs @@ -838,6 +838,16 @@ defmodule Module.Types.ExprTest do assert typecheck!(Tuple.insert_at({:ok, 123}, 2, "foo")) == tuple([atom([:ok]), integer(), binary()]) + assert typeerror!( + [x], + ( + value = if :rand.uniform() > 0.5, do: :inserted, else: x + tuple = Tuple.insert_at({:ok}, 1, value) + Integer.to_string(elem(tuple, 1)) + ) + ) + |> strip_ansi() =~ "incompatible types given to Integer.to_string/1" + assert typeerror!([<>], Tuple.insert_at(x, 0, "foo")) |> strip_ansi() == ~l""" incompatible types given to Tuple.insert_at/3: