Skip to content

Commit c4301b6

Browse files
committed
Progress?
1 parent bc8948f commit c4301b6

File tree

3 files changed

+61
-40
lines changed

3 files changed

+61
-40
lines changed

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

Lines changed: 21 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1000,15 +1000,21 @@ defmodule Module.Types.Descr do
10001000
end
10011001

10021002
# Optimize the cases where dynamic closes over all function types
1003-
{:term, fun_static} when fun_static == %{} ->
1004-
{:ok, dynamic()}
1003+
# {:term, fun_static} when fun_static == %{} ->
1004+
# {:ok, dynamic()}
10051005

1006-
{%{fun: @fun_top}, fun_static} when fun_static == %{} ->
1007-
{:ok, dynamic()}
1006+
# {%{fun: @fun_top}, fun_static} when fun_static == %{} ->
1007+
# {:ok, dynamic()}
10081008

10091009
{fun_dynamic, fun_static} ->
10101010
if fun_only?(fun_static) do
1011-
fun_apply_with_strategy(fun_static, fun_dynamic, arguments)
1011+
with :badarg <- fun_apply_with_strategy(fun_static, fun_dynamic, arguments) do
1012+
if compatible?(fun, fun(arguments, term())) do
1013+
{:ok, dynamic()}
1014+
else
1015+
:badarg
1016+
end
1017+
end
10121018
else
10131019
:badfun
10141020
end
@@ -1106,11 +1112,19 @@ defmodule Module.Types.Descr do
11061112
#
11071113
# This function is used internally by `fun_apply_*`, and others to
11081114
# ensure consistent handling of function types in all operations.
1115+
defp fun_normalize(:term, arity, mode) do
1116+
fun_normalize(%{fun: @fun_top}, arity, mode)
1117+
end
1118+
11091119
defp fun_normalize(%{fun: bdd}, arity, mode) do
11101120
{domain, arrows, bad_arities} =
11111121
Enum.reduce(fun_get(bdd), {term(), [], []}, fn
1112-
{[{args, _} | _] = pos_funs, neg_funs}, {domain, arrows, bad_arities} ->
1113-
arrow_arity = length(args)
1122+
{pos_funs, neg_funs}, {domain, arrows, bad_arities} ->
1123+
arrow_arity =
1124+
case pos_funs do
1125+
[{args, _} | _] -> length(args)
1126+
_ -> arity
1127+
end
11141128

11151129
cond do
11161130
arrow_arity != arity ->
@@ -1393,8 +1407,6 @@ defmodule Module.Types.Descr do
13931407
end
13941408

13951409
# Converts a function BDD (Binary Decision Diagram) to its quoted representation.
1396-
defp fun_to_quoted(:fun, _opts), do: [{:fun, [], []}]
1397-
13981410
defp fun_to_quoted(bdd, opts) do
13991411
arrows = fun_get(bdd)
14001412

lib/elixir/lib/module/types/expr.ex

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@ defmodule Module.Types.Expr do
5151
@stacktrace list(
5252
union(
5353
tuple([atom(), atom(), args_or_arity, extra_info]),
54-
tuple([fun(), args_or_arity, extra_info])
54+
tuple([dynamic(fun()), args_or_arity, extra_info])
5555
)
5656
)
5757

lib/elixir/test/elixir/module/types/descr_test.exs

Lines changed: 39 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ end
1010
defmodule Module.Types.DescrTest do
1111
use ExUnit.Case, async: true
1212

13-
import Module.Types.Descr
13+
import Module.Types.Descr, except: [fun: 1]
1414

1515
describe "union" do
1616
test "bitmap" do
@@ -111,7 +111,7 @@ defmodule Module.Types.DescrTest do
111111

112112
test "fun" do
113113
assert equal?(union(fun(), fun()), fun())
114-
assert equal?(union(fun(), fun(1)), fun())
114+
assert equal?(union(fun(), none_fun(1)), fun())
115115

116116
dynamic_fun = intersection(fun(), dynamic())
117117
assert equal?(union(dynamic_fun, fun()), fun())
@@ -335,7 +335,7 @@ defmodule Module.Types.DescrTest do
335335
end
336336

337337
test "function" do
338-
assert not empty?(intersection(negation(fun(2)), negation(fun(3))))
338+
assert not empty?(intersection(negation(none_fun(2)), negation(none_fun(3))))
339339
end
340340
end
341341

@@ -528,19 +528,19 @@ defmodule Module.Types.DescrTest do
528528

529529
test "fun" do
530530
for arity <- [0, 1, 2, 3] do
531-
assert empty?(difference(fun(arity), fun(arity)))
531+
assert empty?(difference(none_fun(arity), none_fun(arity)))
532532
end
533533

534534
assert empty?(difference(fun(), fun()))
535-
assert empty?(difference(fun(3), fun()))
536-
refute empty?(difference(fun(), fun(1)))
537-
refute empty?(difference(fun(2), fun(3)))
538-
assert empty?(intersection(fun(2), fun(3)))
535+
assert empty?(difference(none_fun(3), fun()))
536+
refute empty?(difference(fun(), none_fun(1)))
537+
refute empty?(difference(none_fun(2), none_fun(3)))
538+
assert empty?(intersection(none_fun(2), none_fun(3)))
539539

540-
f1f2 = union(fun(1), fun(2))
541-
assert f1f2 |> difference(fun(1)) |> difference(fun(2)) |> empty?()
542-
assert fun(1) |> difference(difference(f1f2, fun(2))) |> empty?()
543-
assert f1f2 |> difference(fun(1)) |> equal?(fun(2))
540+
f1f2 = union(none_fun(1), none_fun(2))
541+
assert f1f2 |> difference(none_fun(1)) |> difference(none_fun(2)) |> empty?()
542+
assert none_fun(1) |> difference(difference(f1f2, none_fun(2))) |> empty?()
543+
assert f1f2 |> difference(none_fun(1)) |> equal?(none_fun(2))
544544

545545
assert fun([integer()], term()) |> difference(fun([none()], term())) |> empty?()
546546
end
@@ -742,25 +742,27 @@ defmodule Module.Types.DescrTest do
742742

743743
test "fun" do
744744
refute empty?(fun())
745-
refute empty?(fun(1))
745+
refute empty?(none_fun(1))
746746
refute empty?(fun([integer()], atom()))
747747

748-
assert empty?(intersection(fun(1), fun(2)))
749-
refute empty?(intersection(fun(), fun(1)))
750-
assert empty?(difference(fun(1), union(fun(1), fun(2))))
748+
assert empty?(intersection(none_fun(1), none_fun(2)))
749+
refute empty?(intersection(fun(), none_fun(1)))
750+
assert empty?(difference(none_fun(1), union(none_fun(1), none_fun(2))))
751751
end
752752
end
753753

754754
describe "function application" do
755+
defp none_fun(arity), do: fun(List.duplicate(none(), arity), term())
756+
755757
test "non funs" do
756758
assert fun_apply(term(), [integer()]) == :badfun
757-
assert fun_apply(union(integer(), fun(1)), [integer()]) == :badfun
759+
assert fun_apply(union(integer(), none_fun(1)), [integer()]) == :badfun
758760
end
759761

760762
test "static" do
761763
# Full static
762-
assert fun_apply(fun(), [integer()]) == {:ok, term()}
763-
assert fun_apply(difference(fun(), fun(2)), [integer()]) == {:ok, term()}
764+
assert fun_apply(fun(), [integer()]) == :badarg
765+
assert fun_apply(difference(fun(), none_fun(2)), [integer()]) == :badarg
764766

765767
# Basic function application scenarios
766768
assert fun_apply(fun([integer()], atom()), [integer()]) == {:ok, atom()}
@@ -776,7 +778,13 @@ defmodule Module.Types.DescrTest do
776778
assert fun_apply(fun([integer()], integer()), [term(), term()]) == {:badarity, [1]}
777779
assert fun_apply(fun([integer(), atom()], boolean()), [integer()]) == {:badarity, [2]}
778780

779-
# Function intersection tests - basic
781+
# Function intersection tests (no overlap)
782+
fun0 = intersection(fun([integer()], atom()), fun([float()], binary()))
783+
assert fun_apply(fun0, [integer()]) == {:ok, atom()}
784+
assert fun_apply(fun0, [float()]) == {:ok, binary()}
785+
assert fun_apply(fun0, [union(integer(), float())]) == {:ok, union(atom(), binary())}
786+
787+
# Function intersection tests (overlap)
780788
fun1 = intersection(fun([integer()], atom()), fun([number()], term()))
781789
assert fun_apply(fun1, [integer()]) == {:ok, atom()}
782790
assert fun_apply(fun1, [float()]) == {:ok, term()}
@@ -816,8 +824,8 @@ defmodule Module.Types.DescrTest do
816824

817825
fun = fun([dynamic(integer())], atom())
818826
assert fun_apply(fun, [dynamic(integer())]) |> elem(1) |> equal?(atom())
819-
assert fun_apply(fun, [dynamic(number())]) == :badarg
820-
assert fun_apply(fun, [integer()]) == :badarg
827+
assert fun_apply(fun, [dynamic(number())]) == {:ok, dynamic()}
828+
assert fun_apply(fun, [integer()]) == {:ok, dynamic()}
821829
assert fun_apply(fun, [float()]) == :badarg
822830
end
823831

@@ -826,12 +834,13 @@ defmodule Module.Types.DescrTest do
826834
test "dynamic" do
827835
# Full dynamic
828836
assert fun_apply(dynamic(), [integer()]) == {:ok, dynamic()}
829-
assert fun_apply(difference(dynamic(), integer()), [integer()]) == {:ok, dynamic()}
837+
assert fun_apply(dynamic(none_fun(1)), [integer()]) == {:ok, dynamic()}
838+
assert fun_apply(difference(dynamic(), none_fun(2)), [integer()]) == {:ok, dynamic()}
830839

831840
# Basic function application scenarios
832841
assert fun_apply(dynamic_fun([integer()], atom()), [integer()]) == {:ok, dynamic(atom())}
833-
assert fun_apply(dynamic_fun([integer()], atom()), [float()]) == :badarg
834-
assert fun_apply(dynamic_fun([integer()], atom()), [term()]) == :badarg
842+
assert fun_apply(dynamic_fun([integer()], atom()), [float()]) == {:ok, dynamic()}
843+
assert fun_apply(dynamic_fun([integer()], atom()), [term()]) == {:ok, dynamic()}
835844
assert fun_apply(dynamic_fun([integer()], none()), [integer()]) == {:ok, dynamic(none())}
836845
assert fun_apply(dynamic_fun([integer()], term()), [integer()]) == {:ok, dynamic()}
837846

@@ -841,7 +850,7 @@ defmodule Module.Types.DescrTest do
841850
fun = dynamic_fun([integer()], binary())
842851
assert fun_apply(fun, [integer()]) == {:ok, dynamic(binary())}
843852
assert fun_apply(fun, [dynamic(integer())]) == {:ok, dynamic(binary())}
844-
assert fun_apply(fun, [dynamic(atom())]) == :badarg
853+
assert fun_apply(fun, [dynamic(atom())]) == {:ok, dynamic()}
845854

846855
# Arity mismatches
847856
assert fun_apply(dynamic_fun([integer()], integer()), [term(), term()]) == {:badarity, [1]}
@@ -916,20 +925,20 @@ defmodule Module.Types.DescrTest do
916925
dynamic_fun([integer()], binary())
917926
)
918927

919-
assert fun_args |> fun_apply([atom()]) == :badarg
928+
assert fun_args |> fun_apply([atom()]) == {:ok, dynamic()}
920929
assert fun_args |> fun_apply([integer()]) == :badarg
921930

922931
# Badfun
923932
assert union(
924933
fun([atom()], integer()),
925-
dynamic_fun([integer()], binary()) |> intersection(fun(2))
934+
dynamic_fun([integer()], binary()) |> intersection(none_fun(2))
926935
)
927936
|> fun_apply([atom()])
928937
|> elem(1)
929938
|> equal?(integer())
930939

931940
assert union(
932-
fun([atom()], integer()) |> intersection(fun(2)),
941+
fun([atom()], integer()) |> intersection(none_fun(2)),
933942
dynamic_fun([integer()], binary())
934943
)
935944
|> fun_apply([integer()]) == {:ok, dynamic(binary())}
@@ -1744,7 +1753,7 @@ defmodule Module.Types.DescrTest do
17441753

17451754
test "function" do
17461755
assert fun() |> to_quoted_string() == "fun()"
1747-
assert fun(1) |> to_quoted_string() == "(none() -> term())"
1756+
assert none_fun(1) |> to_quoted_string() == "(none() -> term())"
17481757

17491758
assert fun([dynamic(integer())], float()) |> to_quoted_string() ==
17501759
"dynamic((none() -> float())) or (integer() -> float())"

0 commit comments

Comments
 (0)