diff --git a/lib/elixir/lib/module/types/apply.ex b/lib/elixir/lib/module/types/apply.ex index cfd9db80d5..bf1d089209 100644 --- a/lib/elixir/lib/module/types/apply.ex +++ b/lib/elixir/lib/module/types/apply.ex @@ -109,6 +109,9 @@ defmodule Module.Types.Apply do |> opt_union(atom()) |> opt_union(tuple([atom(), atom()])) + send_options = list(atom([:noconnect, :nosuspend])) + send_result = atom([:ok, :noconnect, :nosuspend]) + basic_arith_2_args_clauses = [ {[integer(), integer()], integer()}, {[integer(), float()], float()}, @@ -239,6 +242,7 @@ defmodule Module.Types.Apply do {:erlang, :max, [{[term(), term()], dynamic()}]}, {:erlang, :min, [{[term(), term()], dynamic()}]}, {:erlang, :send, [{[send_destination, term()], dynamic()}]}, + {:erlang, :send, [{[send_destination, term(), send_options], send_result}]}, {:erlang, :setelement, [{[integer(), open_tuple([]), term()], dynamic(open_tuple([]))}]}, {:erlang, :tl, [{[non_empty_list(term(), term())], dynamic()}]}, {:erlang, :tuple_to_list, [{[open_tuple([])], dynamic(list(term()))}]}, @@ -1099,6 +1103,10 @@ defmodule Module.Types.Apply do end end + defp remote_apply(:erlang, :send, _info, [_dest, message] = args_types, stack) do + {:ok, return(message, args_types, stack)} + end + defp remote_apply(:erlang, :tl, _info, [list], stack) do case list_tl(list) do {:ok, value_type} -> {:ok, return(value_type, [list], stack)} diff --git a/lib/elixir/test/elixir/module/types/expr_test.exs b/lib/elixir/test/elixir/module/types/expr_test.exs index 0de7ebf4c7..da8b944af9 100644 --- a/lib/elixir/test/elixir/module/types/expr_test.exs +++ b/lib/elixir/test/elixir/module/types/expr_test.exs @@ -444,6 +444,36 @@ defmodule Module.Types.ExprTest do ) == dynamic(tuple([integer(), integer(), binary()])) end + test "send returns the message" do + assert typecheck!(send(self(), {:msg, 1})) == tuple([atom([:msg]), integer()]) + + assert typeerror!( + case send(self(), {:msg, 1}) do + :__probe__ -> :probe + _ -> :ok + end + ) == ~l""" + the following clause will never match: + + :__probe__ -> + + because it attempts to match on the result of: + + send(self(), {:msg, 1}) + + which has type: + + {:msg, integer()} + """ + end + + test "send with options returns status" do + result = atom([:ok, :noconnect, :nosuspend]) + + assert typecheck!(:erlang.send(self(), {:msg, 1}, [:nosuspend])) == result + assert typecheck!(Process.send(self(), {:msg, 1}, [:noconnect])) == result + end + test "undefined function warnings" do assert typewarn!(URI.unknown("foo")) == {dynamic(), "URI.unknown/1 is undefined or private"}