Skip to content

Commit ae396c1

Browse files
committed
Type timeouts in receive
1 parent 9f182f9 commit ae396c1

File tree

2 files changed

+57
-4
lines changed

2 files changed

+57
-4
lines changed

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

Lines changed: 31 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -239,10 +239,16 @@ defmodule Module.Types.Expr do
239239
{:do, clauses}, context ->
240240
of_clauses(clauses, stack, context)
241241

242-
{:after, [{:->, _meta, [head, body]}]}, context ->
243-
{_type, context} = of_expr(head, stack, context)
244-
{_type, context} = of_expr(body, stack, context)
245-
context
242+
{:after, [{:->, meta, [[timeout], body]}]}, context ->
243+
{timeout_type, context} = of_expr(timeout, stack, context)
244+
{_body_type, context} = of_expr(body, stack, context)
245+
246+
if integer_type?(timeout_type) do
247+
context
248+
else
249+
error = {:badtimeout, timeout_type, timeout, context}
250+
error(__MODULE__, error, meta, stack, context)
251+
end
246252
end)
247253

248254
{dynamic(), context}
@@ -530,4 +536,25 @@ defmodule Module.Types.Expr do
530536
])
531537
}
532538
end
539+
540+
def format_diagnostic({:badtimeout, type, expr, context}) do
541+
traces = collect_traces(expr, context)
542+
543+
%{
544+
details: %{typing_traces: traces},
545+
message:
546+
IO.iodata_to_binary([
547+
"""
548+
expected "after" timeout given to receive to be an integer:
549+
550+
#{expr_to_string(expr) |> indent(4)}
551+
552+
but got type:
553+
554+
#{to_quoted_string(type) |> indent(4)}
555+
""",
556+
format_traces(traces)
557+
])
558+
}
559+
end
533560
end

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

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -764,6 +764,32 @@ defmodule Module.Types.ExprTest do
764764
end
765765
end
766766

767+
describe "receive" do
768+
test "errors on bad timeout" do
769+
assert typeerror!(
770+
[x = :timeout],
771+
receive do
772+
after
773+
x -> :ok
774+
end
775+
) == ~l"""
776+
expected "after" timeout given to receive to be an integer:
777+
778+
x
779+
780+
but got type:
781+
782+
dynamic(:timeout)
783+
784+
where "x" was given the type:
785+
786+
# type: dynamic(:timeout)
787+
# from: types_test.ex:770
788+
x = :timeout
789+
"""
790+
end
791+
end
792+
767793
describe "try" do
768794
test "warns on undefined exceptions" do
769795
assert typewarn!(

0 commit comments

Comments
 (0)