Skip to content

Commit 25be746

Browse files
committed
Fix fun_fetch
1 parent 1854397 commit 25be746

File tree

3 files changed

+33
-13
lines changed

3 files changed

+33
-13
lines changed

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

Lines changed: 23 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -365,15 +365,6 @@ defmodule Module.Types.Descr do
365365

366366
## Bitmaps
367367

368-
@doc """
369-
Optimized version of `not empty?(intersection(fun(), type))`.
370-
"""
371-
def fun_type?(:term), do: true
372-
def fun_type?(%{dynamic: :term}), do: true
373-
def fun_type?(%{dynamic: %{bitmap: bitmap}}) when (bitmap &&& @bit_fun) != 0, do: true
374-
def fun_type?(%{bitmap: bitmap}) when (bitmap &&& @bit_fun) != 0, do: true
375-
def fun_type?(_), do: false
376-
377368
@doc """
378369
Optimized version of `not empty?(intersection(binary(), type))`.
379370
"""
@@ -434,6 +425,29 @@ defmodule Module.Types.Descr do
434425
do: {type, [], []}
435426
end
436427

428+
## Funs
429+
430+
@doc """
431+
Checks there is precisely one function with said arity.
432+
"""
433+
def fun_fetch(:term, _arity), do: :error
434+
435+
def fun_fetch(%{} = descr, _arity) do
436+
{static_or_dynamic, static} = Map.pop(descr, :dynamic, descr)
437+
438+
if fun_only?(static) do
439+
case static_or_dynamic do
440+
:term -> :ok
441+
%{bitmap: bitmap} when (bitmap &&& @bit_fun) != 0 -> :ok
442+
%{} -> :error
443+
end
444+
else
445+
:error
446+
end
447+
end
448+
449+
defp fun_only?(descr), do: empty?(difference(descr, fun()))
450+
437451
## Atoms
438452

439453
# The atom component of a type consists of pairs `{tag, set}` where `set` is a

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

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -305,10 +305,9 @@ defmodule Module.Types.Expr do
305305
{:ok, _args_types, context} <-
306306
map_reduce_ok(args, context, &of_expr(&1, stack, &2)) do
307307
context =
308-
if fun_type?(fun_type) do
309-
context
310-
else
311-
Of.incompatible_warn(fun, fun(), fun_type, stack, context)
308+
case fun_fetch(fun_type, length(args)) do
309+
:ok -> context
310+
:error -> Of.incompatible_warn(fun, fun(), fun_type, stack, context)
312311
end
313312

314313
{:ok, dynamic(), context}

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

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -271,6 +271,13 @@ defmodule Module.Types.DescrTest do
271271
end
272272

273273
describe "projections" do
274+
test "fun_fetch" do
275+
assert fun_fetch(term(), 1) == :error
276+
assert fun_fetch(union(term(), dynamic(fun())), 1) == :error
277+
assert fun_fetch(fun(), 1) == :ok
278+
assert fun_fetch(dynamic(), 1) == :ok
279+
end
280+
274281
test "atom_fetch" do
275282
assert atom_fetch(term()) == :error
276283
assert atom_fetch(union(term(), dynamic(atom([:foo, :bar])))) == :error

0 commit comments

Comments
 (0)