Skip to content

Commit 9bf8233

Browse files
committed
Improve error messages for bad funs
1 parent ae396c1 commit 9bf8233

File tree

2 files changed

+41
-21
lines changed

2 files changed

+41
-21
lines changed

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

Lines changed: 30 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -278,13 +278,17 @@ defmodule Module.Types.Expr do
278278
end
279279

280280
# TODO: fun.(args)
281-
def of_expr({{:., _meta1, [fun]}, _meta2, args}, stack, context) do
281+
def of_expr({{:., meta, [fun]}, _meta, args} = call, stack, context) do
282282
{fun_type, context} = of_expr(fun, stack, context)
283283
{_args_types, context} = Enum.map_reduce(args, context, &of_expr(&1, stack, &2))
284284

285285
case fun_fetch(fun_type, length(args)) do
286-
:ok -> {dynamic(), context}
287-
:error -> {dynamic(), Of.incompatible_error(fun, fun(), fun_type, stack, context)}
286+
:ok ->
287+
{dynamic(), context}
288+
289+
:error ->
290+
error = {:badfun, length(args), fun_type, fun, call, context}
291+
{error_type(), error(__MODULE__, error, meta, stack, context)}
288292
end
289293
end
290294

@@ -393,8 +397,8 @@ defmodule Module.Types.Expr do
393397
if binary_type?(right_type) do
394398
context
395399
else
396-
warning = {:badbinary, right_type, right, context}
397-
error(__MODULE__, warning, meta, stack, context)
400+
error = {:badbinary, right_type, right, context}
401+
error(__MODULE__, error, meta, stack, context)
398402
end
399403
end
400404

@@ -557,4 +561,25 @@ defmodule Module.Types.Expr do
557561
])
558562
}
559563
end
564+
565+
def format_diagnostic({:badfun, arity, type, fun_expr, call_expr, context}) do
566+
traces = collect_traces(fun_expr, context)
567+
568+
%{
569+
details: %{typing_traces: traces},
570+
message:
571+
IO.iodata_to_binary([
572+
"""
573+
expected a #{arity}-arity function on call:
574+
575+
#{expr_to_string(call_expr) |> indent(4)}
576+
577+
but got type:
578+
579+
#{to_quoted_string(type) |> indent(4)}
580+
""",
581+
format_traces(traces)
582+
])
583+
}
584+
end
560585
end

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

Lines changed: 11 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -116,26 +116,21 @@ defmodule Module.Types.ExprTest do
116116

117117
describe "funs" do
118118
test "incompatible" do
119-
assert typeerror!([%x{}], x.(1, 2)) ==
120-
~l"""
121-
incompatible types in expression:
119+
assert typeerror!([%x{}, a1, a2], x.(a1, a2)) == ~l"""
120+
expected a 2-arity function on call:
122121
123-
x
122+
x.(a1, a2)
124123
125-
got type:
126-
127-
dynamic(atom())
128-
129-
but expected type:
124+
but got type:
130125
131-
fun()
126+
dynamic(atom())
132127
133-
where "x" was given the type:
128+
where "x" was given the type:
134129
135-
# type: dynamic(atom())
136-
# from: types_test.ex:LINE-1
137-
%x{}
138-
"""
130+
# type: dynamic(atom())
131+
# from: types_test.ex:LINE
132+
%x{}
133+
"""
139134
end
140135
end
141136

@@ -784,7 +779,7 @@ defmodule Module.Types.ExprTest do
784779
where "x" was given the type:
785780
786781
# type: dynamic(:timeout)
787-
# from: types_test.ex:770
782+
# from: types_test.ex:LINE-5
788783
x = :timeout
789784
"""
790785
end

0 commit comments

Comments
 (0)