Skip to content

Commit fd2600a

Browse files
committed
Optimize fun_apply_static to check for emptiness less frequently
1 parent 6b8c2dd commit fd2600a

File tree

1 file changed

+17
-14
lines changed

1 file changed

+17
-14
lines changed

lib/elixir/lib/module/types/descr.ex

Lines changed: 17 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1031,23 +1031,26 @@ defmodule Module.Types.Descr do
10311031

10321032
# For non-dynamic function and arguments, just return the static result
10331033
if fun_dynamic == nil and not args_dynamic? do
1034-
fun_apply_static(fun_static, arguments, :static)
1034+
fun_apply_static(fun_static, arguments, :static, args_dynamic?)
10351035
else
10361036
# For dynamic cases, combine static and dynamic results
1037-
{static_args, dynamic_args} =
1038-
if args_dynamic?,
1039-
do: {materialize_arguments(arguments, :up), materialize_arguments(arguments, :down)},
1040-
else: {arguments, arguments}
1037+
{static_args, dynamic_args, maybe_empty?} =
1038+
if args_dynamic? do
1039+
{materialize_arguments(arguments, :up), materialize_arguments(arguments, :down), true}
1040+
else
1041+
{arguments, arguments, false}
1042+
end
10411043

1042-
case fun_apply_static(fun_static, static_args, :static) do
1044+
case fun_apply_static(fun_static, static_args, :static, false) do
10431045
{:ok, res1} when fun_dynamic == nil ->
1044-
with {:ok, res2} <- fun_apply_static(fun_static, dynamic_args, :static) do
1046+
# We need to compute which parts are dynamic
1047+
with {:ok, res2} <- fun_apply_static(fun_static, dynamic_args, :static, maybe_empty?) do
10451048
{:ok, union(res1, dynamic(res2))}
10461049
end
10471050

10481051
{:ok, res1} when fun_dynamic != nil ->
10491052
# If static succeeded, the dynamic part can fail, we don't care
1050-
case fun_apply_static(fun_dynamic, dynamic_args, :dynamic) do
1053+
case fun_apply_static(fun_dynamic, dynamic_args, :dynamic, maybe_empty?) do
10511054
{:ok, res2} -> {:ok, union(res1, dynamic(res2))}
10521055
_ -> {:ok, res1}
10531056
end
@@ -1056,9 +1059,9 @@ defmodule Module.Types.Descr do
10561059
# Then the dynamic call has to succeed
10571060
result =
10581061
if fun_dynamic do
1059-
fun_apply_static(fun_dynamic, dynamic_args, :dynamic)
1062+
fun_apply_static(fun_dynamic, dynamic_args, :dynamic, maybe_empty?)
10601063
else
1061-
fun_apply_static(fun_static, dynamic_args, :static)
1064+
fun_apply_static(fun_static, dynamic_args, :static, maybe_empty?)
10621065
end
10631066

10641067
with {:ok, descr} <- result do
@@ -1078,15 +1081,15 @@ defmodule Module.Types.Descr do
10781081

10791082
defp are_arguments_dynamic?(arguments), do: Enum.any?(arguments, &match?(%{dynamic: _}, &1))
10801083

1081-
defp fun_apply_static(%{fun: fun_bdd}, arguments, mode) do
1084+
defp fun_apply_static(%{fun: fun_bdd}, arguments, mode, maybe_empty?) do
10821085
arity = length(arguments)
10831086

10841087
with {:ok, domain, arrows} <- fun_normalize(fun_bdd, arity, mode) do
10851088
type_args = domain_descr(arguments)
10861089

10871090
cond do
1088-
empty?(type_args) ->
1089-
# Opti: short-circuits when inner loop is none() or outer loop is term()
1091+
# Optization: short-circuits when inner loop is none() or outer loop is term()
1092+
maybe_empty? and empty?(type_args) ->
10901093
result =
10911094
Enum.reduce_while(arrows, none(), fn intersection_of_arrows, acc ->
10921095
Enum.reduce_while(intersection_of_arrows, term(), fn
@@ -1115,7 +1118,7 @@ defmodule Module.Types.Descr do
11151118
end
11161119
end
11171120

1118-
defp fun_apply_static(%{}, _arguments, _mode) do
1121+
defp fun_apply_static(%{}, _arguments, _mode, _maybe_empty?) do
11191122
:badfun
11201123
end
11211124

0 commit comments

Comments
 (0)