Skip to content

Commit

Permalink
Improve error message for invalid default arguments
Browse files Browse the repository at this point in the history
  • Loading branch information
josevalim committed Jan 2, 2025
1 parent 8e796fc commit d713e47
Show file tree
Hide file tree
Showing 3 changed files with 52 additions and 6 deletions.
23 changes: 18 additions & 5 deletions lib/elixir/lib/module/types/apply.ex
Original file line number Diff line number Diff line change
Expand Up @@ -796,7 +796,7 @@ defmodule Module.Types.Apply do
def format_diagnostic({:badlocal, expr, args_types, domain, clauses, context}) do
traces = collect_traces(expr, context)
converter = &Function.identity/1
{fun, _, _} = expr
{fun, meta, _} = expr

explanation =
empty_arg_reason(args_types) ||
Expand All @@ -805,16 +805,29 @@ defmodule Module.Types.Apply do
#{clauses_args_to_quoted_string(clauses, converter, [])}
"""

%{
details: %{typing_traces: traces},
message:
IO.iodata_to_binary([
banner =
case fun == :super && meta[:default] && meta[:super] do
{_kind, fun} ->
"""
incompatible types given as default arguments to #{fun}/#{length(args_types)}:
"""

_ ->
"""
incompatible types given to #{fun}/#{length(args_types)}:
#{expr_to_string(expr) |> indent(4)}
given types:
"""
end

%{
details: %{typing_traces: traces},
message:
IO.iodata_to_binary([
banner,
"""
#{args_to_quoted_string(args_types, domain, converter) |> indent(4)}
Expand Down
2 changes: 1 addition & 1 deletion lib/elixir/src/elixir_def.erl
Original file line number Diff line number Diff line change
Expand Up @@ -314,7 +314,7 @@ unpack_defaults(Kind, Meta, Name, Args, S, E) ->
unpack_expanded(Kind, Meta, Name, [{'\\\\', DefaultMeta, [Expr, _]} | T] = List, VersionOffset, Acc, Clauses) ->
Base = match_defaults(Acc, length(Acc) + VersionOffset, []),
{Args, Invoke} = extract_defaults(List, length(Base) + VersionOffset, [], []),
Clause = {Meta, Base ++ Args, [], {super, [{super, {Kind, Name}} | DefaultMeta], Base ++ Invoke}},
Clause = {Meta, Base ++ Args, [], {super, [{super, {Kind, Name}}, {default, true} | DefaultMeta], Base ++ Invoke}},
unpack_expanded(Kind, Meta, Name, T, VersionOffset, [Expr | Acc], [Clause | Clauses]);
unpack_expanded(Kind, Meta, Name, [H | T], VersionOffset, Acc, Clauses) ->
unpack_expanded(Kind, Meta, Name, T, VersionOffset, [H | Acc], Clauses);
Expand Down
33 changes: 33 additions & 0 deletions lib/elixir/test/elixir/module/types/integration_test.exs
Original file line number Diff line number Diff line change
Expand Up @@ -494,6 +494,39 @@ defmodule Module.Types.IntegrationTest do
assert_warnings(files, warnings, consolidate_protocols: true)
end

test "incompatible default argument" do
files = %{
"a.ex" => """
defmodule A do
def ok(x = :ok \\\\ nil) do
x
end
end
"""
}

warnings = [
~S"""
warning: incompatible types given as default arguments to ok/1:
-nil-
but expected one of:
dynamic(:ok)
typing violation found at:
2 │ def ok(x = :ok \\ nil) do
│ ~
└─ a.ex:2:18: A.ok/0
"""
]

assert_warnings(files, warnings)
end

test "returns diagnostics with source and file" do
files = %{
"a.ex" => """
Expand Down

0 comments on commit d713e47

Please sign in to comment.