Skip to content

Commit ec5906b

Browse files
committed
Updated the handling of positive and negative functions in fun_normalize and fun_get
1 parent 415a3a2 commit ec5906b

File tree

1 file changed

+14
-22
lines changed

1 file changed

+14
-22
lines changed

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

Lines changed: 14 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -196,7 +196,6 @@ defmodule Module.Types.Descr do
196196
# We emit `{common, union(return, acc_return)}` for the shared part,
197197
# keep `{left, acc_return}` (if any), and continue inserting `diff`
198198
# into the remainder of the list to handle further overlaps.
199-
200199
defp pivot_overlapping_clause(domain, return, [{acc_domain, acc_return} | acc]) do
201200
common = intersection(domain, acc_domain)
202201

@@ -1314,7 +1313,7 @@ defmodule Module.Types.Descr do
13141313
defp fun_normalize(%{fun: bdd}, arity, mode) do
13151314
{domain, arrows, bad_arities} =
13161315
Enum.reduce(fun_get(bdd), {term(), [], []}, fn
1317-
{pos_funs, neg_funs}, {domain, arrows, bad_arities} ->
1316+
{pos_funs, _neg_funs}, {domain, arrows, bad_arities} ->
13181317
arrow_arity =
13191318
case pos_funs do
13201319
[{args, _} | _] -> length(args)
@@ -1325,9 +1324,6 @@ defmodule Module.Types.Descr do
13251324
arrow_arity != arity ->
13261325
{domain, arrows, [arrow_arity | bad_arities]}
13271326

1328-
fun_empty?(pos_funs, neg_funs) ->
1329-
{domain, arrows, bad_arities}
1330-
13311327
true ->
13321328
# Calculate domain from all positive functions
13331329
path_domain =
@@ -1363,13 +1359,13 @@ defmodule Module.Types.Descr do
13631359
end)
13641360
end
13651361

1366-
defp apply_disjoint(arguments, arrows) do
1367-
type_args = args_to_domain(arguments)
1362+
# A fast way to do function application when the arguments of the function are disjoint.
1363+
# Just build the union of all the return types of arrows that match the input.
1364+
defp apply_disjoint(input_arguments, arrows) do
1365+
type_input = args_to_domain(input_arguments)
13681366

13691367
Enum.reduce(arrows, none(), fn {args, ret}, acc_return ->
1370-
dom = args_to_domain(args)
1371-
1372-
if empty?(intersection(dom, type_args)) do
1368+
if empty?(intersection(args_to_domain(args), type_input)) do
13731369
acc_return
13741370
else
13751371
union(acc_return, ret)
@@ -1399,6 +1395,9 @@ defmodule Module.Types.Descr do
13991395
# Calculate the part of the input not covered by this arrow's domain
14001396
dom_subtract = difference(input, args_to_domain(args))
14011397

1398+
# Refine the return type by intersecting with this arrow's return type
1399+
ret_refine = intersection(returns_reached, ret)
1400+
14021401
# Phase 1: Domain partitioning
14031402
# If the input is not fully covered by the arrow's domain, then the result type should be
14041403
# _augmented_ with the outputs obtained by applying the remaining arrows to the non-covered
@@ -1418,9 +1417,6 @@ defmodule Module.Types.Descr do
14181417
# the same part of the input, then the result type is an intersection of the return types of
14191418
# those arrows.
14201419

1421-
# Refine the return type by intersecting with this arrow's return type
1422-
ret_refine = intersection(returns_reached, ret)
1423-
14241420
# e.g. (integer()->atom()) and (integer()->pid()) when applied to integer()
14251421
# should result in (atom() ∩ pid()), which is none().
14261422
aux_apply(result, input, ret_refine, arrow_intersections)
@@ -1434,7 +1430,7 @@ defmodule Module.Types.Descr do
14341430
defp fun_get(acc, pos, neg, bdd) do
14351431
case bdd do
14361432
:bdd_bot -> acc
1437-
:bdd_top -> [{pos, neg} | acc]
1433+
:bdd_top -> if fun_empty?(pos, neg), do: acc, else: [{pos, neg} | acc]
14381434
{fun, left, right} -> fun_get(fun_get(acc, [fun | pos], neg, left), pos, [fun | neg], right)
14391435
end
14401436
end
@@ -1451,13 +1447,7 @@ defmodule Module.Types.Descr do
14511447
# - `fun(1) and not fun(1)` is empty
14521448
# - `fun(integer() -> atom()) and not fun(none() -> term())` is empty
14531449
# - `fun(integer() -> atom()) and not fun(atom() -> integer())` is not empty
1454-
defp fun_empty?(bdd) do
1455-
case bdd do
1456-
:bdd_bot -> true
1457-
:bdd_top -> false
1458-
bdd -> fun_get(bdd) |> Enum.all?(fn {posits, negats} -> fun_empty?(posits, negats) end)
1459-
end
1460-
end
1450+
defp fun_empty?(bdd), do: fun_get(bdd) == []
14611451

14621452
# Checks if a function type represented by positive and negative function literals is empty.
14631453

@@ -1660,6 +1650,8 @@ defmodule Module.Types.Descr do
16601650
end
16611651
end
16621652

1653+
# Note: using this for functions instead of bdd_intersection because the printing
1654+
# fun_denormalize relies on the order of functions in the bdd.
16631655
defp fun_bdd_intersection(bdd1, bdd2) do
16641656
case {bdd1, bdd2} do
16651657
# Base cases
@@ -1817,7 +1809,7 @@ defmodule Module.Types.Descr do
18171809
end
18181810

18191811
defp fun_get_pos(bdd) do
1820-
for {pos, negs} <- fun_get(bdd), not fun_empty?(pos, negs) do
1812+
for {pos, _negs} <- fun_get(bdd) do
18211813
fun_filter_subset(pos, [])
18221814
end
18231815
end

0 commit comments

Comments
 (0)