Skip to content

Commit 5111448

Browse files
committed
Full 3 optis
1 parent 263462d commit 5111448

File tree

1 file changed

+54
-41
lines changed

1 file changed

+54
-41
lines changed

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

Lines changed: 54 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -138,7 +138,7 @@ defmodule Module.Types.Descr do
138138
Creates a function from overlapping function clauses.
139139
"""
140140
def fun_from_inferred_clauses(args_clauses) do
141-
if false do
141+
if true do
142142
domain_clauses =
143143
Enum.reduce(args_clauses, [], fn {args, return}, acc ->
144144
domain = args |> Enum.map(&upper_bound/1) |> args_to_domain()
@@ -1187,6 +1187,7 @@ defmodule Module.Types.Descr do
11871187

11881188
static_arrows == [] ->
11891189
# TODO: We need to validate this within the theory
1190+
arguments = Enum.map(arguments, &upper_bound/1)
11901191
{:ok, dynamic(fun_apply_static(arguments, dynamic_arrows, false))}
11911192

11921193
true ->
@@ -1305,22 +1306,25 @@ defmodule Module.Types.Descr do
13051306
type_args = args_to_domain(arguments)
13061307

13071308
# Optimization: short-circuits when inner loop is none() or outer loop is term()
1308-
if maybe_empty? and empty?(type_args) do
1309-
Enum.reduce_while(arrows, none(), fn intersection_of_arrows, acc ->
1310-
Enum.reduce_while(intersection_of_arrows, term(), fn
1311-
{_dom, _ret}, acc when acc == @none -> {:halt, acc}
1312-
{_dom, ret}, acc -> {:cont, intersection(acc, ret)}
1309+
result =
1310+
if maybe_empty? and empty?(type_args) do
1311+
Enum.reduce_while(arrows, none(), fn intersection_of_arrows, acc ->
1312+
Enum.reduce_while(intersection_of_arrows, term(), fn
1313+
{_dom, _ret}, acc when acc == @none -> {:halt, acc}
1314+
{_dom, ret}, acc -> {:cont, intersection(acc, ret)}
1315+
end)
1316+
|> case do
1317+
:term -> {:halt, :term}
1318+
inner -> {:cont, union(inner, acc)}
1319+
end
13131320
end)
1314-
|> case do
1315-
:term -> {:halt, :term}
1316-
inner -> {:cont, union(inner, acc)}
1317-
end
1318-
end)
1319-
else
1320-
Enum.reduce(arrows, none(), fn intersection_of_arrows, acc ->
1321-
aux_apply(acc, type_args, term(), intersection_of_arrows)
1322-
end)
1323-
end
1321+
else
1322+
Enum.reduce(arrows, none(), fn intersection_of_arrows, acc ->
1323+
aux_apply(acc, type_args, term(), intersection_of_arrows)
1324+
end)
1325+
end
1326+
1327+
result
13241328
end
13251329

13261330
# Helper function for function application that handles the application of
@@ -1337,11 +1341,32 @@ defmodule Module.Types.Descr do
13371341
# - arrow_intersections: The list of function arrows to process
13381342

13391343
# For more details, see Definitions 2.20 or 6.11 in https://vlanvin.fr/papers/thesis.pdf
1340-
defp aux_apply(result, _input, rets_reached, []) do
1344+
defp aux_apply(result, _input, rets_reached, arrow_intersections, depth \\ 0)
1345+
1346+
defp aux_apply(result, _input, rets_reached, [], depth) do
13411347
if subtype?(rets_reached, result), do: result, else: union(result, rets_reached)
13421348
end
13431349

1344-
defp aux_apply(result, input, returns_reached, [{dom, ret} | arrow_intersections]) do
1350+
defp aux_apply(result, input, returns_reached, [{dom, ret} | arrow_intersections], depth) do
1351+
# Performance warning thresholds
1352+
if Map.has_key?(input, :dynamic) do
1353+
IO.puts("aux_apply called with dynamic input")
1354+
raise "aux_apply called with dynamic input"
1355+
end
1356+
1357+
max_depth = 15
1358+
1359+
if depth > max_depth do
1360+
IO.puts("PERFORMANCE WARNING: aux_apply depth #{depth} (threshold: #{max_depth})")
1361+
IO.puts("aux_apply [depth:#{depth}]")
1362+
IO.puts("input: #{inspect(input)}")
1363+
IO.puts("returns_reached: #{inspect(returns_reached)}")
1364+
IO.puts("dom: #{inspect(dom)}")
1365+
IO.puts("ret: #{inspect(ret)}")
1366+
IO.puts("arrow_intersections: #{inspect(arrow_intersections)}")
1367+
IO.puts("--------------------------------")
1368+
end
1369+
13451370
# Calculate the part of the input not covered by this arrow's domain
13461371
dom_subtract = difference(input, args_to_domain(dom))
13471372

@@ -1359,7 +1384,7 @@ defmodule Module.Types.Descr do
13591384
if empty?(dom_subtract) do
13601385
result
13611386
else
1362-
aux_apply(result, dom_subtract, returns_reached, arrow_intersections)
1387+
aux_apply(result, dom_subtract, returns_reached, arrow_intersections, depth + 1)
13631388
end
13641389

13651390
# 2. Return type refinement
@@ -1369,7 +1394,7 @@ defmodule Module.Types.Descr do
13691394

13701395
# e.g. (integer()->atom()) and (integer()->pid()) when applied to integer()
13711396
# should result in (atom() ∩ pid()), which is none().
1372-
aux_apply(result, input, ret_refine, arrow_intersections)
1397+
aux_apply(result, input, ret_refine, arrow_intersections, depth + 1)
13731398
end
13741399

13751400
# Takes all the paths from the root to the leaves finishing with a 1,
@@ -1556,36 +1581,20 @@ defmodule Module.Types.Descr do
15561581
# and that applying the input type of the arrow to the intersection gives sth that is a subtype of the return type of the arrow
15571582
if all_non_empty_domains?(positives) and all_non_empty_domains?([{arguments, return}]) do
15581583
return = negation(return)
1584+
15591585
type_positives =
15601586
Enum.map(positives, fn {args, ret} -> fun(args, ret) end) |> Enum.reduce(&intersection/2)
15611587

15621588
{:ok, _dom, static_arrows} = fun_normalize(type_positives, length(arguments), :static)
15631589
result = fun_apply_static(arguments, static_arrows, false)
15641590

15651591
r = subtype?(result, return)
1592+
15661593
if r do
15671594
r
15681595
else
15691596
false
15701597
end
1571-
1572-
# positives_domain =
1573-
# Enum.reduce(positives, none(), fn {args, _ret}, acc ->
1574-
# union(acc, args_to_domain(args))
1575-
# end)
1576-
1577-
# 1. the positives domain must be a supertype of the domain of the arrow
1578-
# result1 = subtype?(args_to_domain(arguments), positives_domain)
1579-
1580-
# if result1 do
1581-
# # 2. if we apply the input type of the arrow to the intersection, the result must be a subtype of the return type of the arrow
1582-
# # 2.a) build the intersection of positives
1583-
1584-
# # 2.b) check that the result is a subtype of the return type of the arrow
1585-
# result2 = subtype?(apply_result, return)
1586-
# else
1587-
# false
1588-
# end
15891598
else
15901599
# Show the caller of this function
15911600
# IO.puts("Starting phi starter with arguments: #{inspect(arguments)}")
@@ -1603,7 +1612,6 @@ defmodule Module.Types.Descr do
16031612
# end)
16041613
# )
16051614

1606-
16071615
# start_time = DateTime.utc_now()
16081616

16091617
n = length(arguments)
@@ -3265,7 +3273,8 @@ defmodule Module.Types.Descr do
32653273
defp tuple_difference(dnf1, dnf2) do
32663274
Enum.reduce(dnf2, dnf1, fn {tag2, elements2}, dnf1 ->
32673275
Enum.reduce(dnf1, [], fn {tag1, elements1}, acc ->
3268-
tuple_eliminate_single_negation(tag1, elements1, {tag2, elements2}) ++ acc
3276+
tuple_eliminate_single_negation(tag1, elements1, {tag2, elements2})
3277+
|> tuple_union(acc)
32693278
end)
32703279
end)
32713280
end
@@ -3280,8 +3289,10 @@ defmodule Module.Types.Descr do
32803289
if (tag == :closed and n < m) or (neg_tag == :closed and n > m) do
32813290
[{tag, elements}]
32823291
else
3283-
tuple_elim_content([], tag, elements, neg_elements) ++
3292+
tuple_union(
3293+
tuple_elim_content([], tag, elements, neg_elements),
32843294
tuple_elim_size(n, m, tag, elements, neg_tag)
3295+
)
32853296
end
32863297
end
32873298

@@ -3945,4 +3956,6 @@ defmodule Module.Types.Descr do
39453956
defp non_empty_map_or([head | tail], fun) do
39463957
Enum.reduce(tail, fun.(head), &{:or, [], [&2, fun.(&1)]})
39473958
end
3959+
3960+
# Performance tracking helpers for aux_apply
39483961
end

0 commit comments

Comments
 (0)