From 8d892e7d65fc3206c7369eca5c78fc6def3ab6a8 Mon Sep 17 00:00:00 2001 From: Guillaume Duboc Date: Thu, 9 Apr 2026 07:30:15 +0200 Subject: [PATCH] Reject empty args in dynamic fun_apply --- lib/elixir/lib/module/types/descr.ex | 9 +++++---- lib/elixir/test/elixir/module/types/descr_test.exs | 1 + 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/lib/elixir/lib/module/types/descr.ex b/lib/elixir/lib/module/types/descr.ex index b45400dae02..c3ca2b00b5b 100644 --- a/lib/elixir/lib/module/types/descr.ex +++ b/lib/elixir/lib/module/types/descr.ex @@ -1442,12 +1442,10 @@ defmodule Module.Types.Descr do static? = fun_dynamic == nil and Enum.all?(arguments, fn arg -> not gradual?(arg) end) arity = length(arguments) - with {:ok, domain, static_arrows, dynamic_arrows} <- + with false <- Enum.any?(arguments, &empty?/1), + {:ok, domain, static_arrows, dynamic_arrows} <- fun_normalize_both(fun_static, fun_dynamic, arity) do cond do - Enum.any?(arguments, &empty?/1) -> - {:badarg, domain_to_flat_args(domain, arity)} - # The domain here is the extended gradual domain computed by # fun_normalize_both/3. If the argument does not satisfy it, we # check compatibility before rejecting. @@ -1498,6 +1496,9 @@ defmodule Module.Types.Descr do dynamic(fun_apply_static(arguments, dynamic_arrows)) )} end + else + true -> {:badarg, arguments} + error -> error 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 b949149cfcb..7ca6c7116ff 100644 --- a/lib/elixir/test/elixir/module/types/descr_test.exs +++ b/lib/elixir/test/elixir/module/types/descr_test.exs @@ -1214,6 +1214,7 @@ defmodule Module.Types.DescrTest do assert fun_apply(dynamic_fun([integer()], atom()), [float()]) == {:ok, dynamic()} assert fun_apply(dynamic_fun([integer()], atom()), [term()]) == {:ok, dynamic()} assert fun_apply(dynamic_fun([integer()], none()), [integer()]) == {:ok, dynamic(none())} + assert fun_apply(dynamic(fun([integer()], integer())), [none()]) == {:badarg, [none()]} assert fun_apply(dynamic_fun([integer()], term()), [integer()]) == {:ok, dynamic()} # Dynamic return and dynamic args