Skip to content

Commit 8907edc

Browse files
author
José Valim
committed
Improve error message for invalid patterns in guards and matches
Closes #1092
1 parent a893d80 commit 8907edc

File tree

4 files changed

+43
-15
lines changed

4 files changed

+43
-15
lines changed

lib/elixir/src/elixir_dispatch.erl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -264,7 +264,7 @@ munge_stacktrace(_, [], _) ->
264264
%% ERROR HANDLING
265265

266266
format_error({ unrequired_module, { Receiver, Name, Arity, Required }}) ->
267-
String = string:join([elixir_errors:inspect(R) || R <- Required], ", "),
267+
String = 'Elixir.Enum':join([elixir_errors:inspect(R) || R <- Required], ", "),
268268
io_lib:format("tried to invoke macro ~ts.~ts/~B but module was not required. Required: ~ts",
269269
[elixir_errors:inspect(Receiver), Name, Arity, String]);
270270

lib/elixir/src/elixir_errors.erl

Lines changed: 1 addition & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -14,15 +14,7 @@
1414
%% Handle inspecting for exceptions
1515

1616
inspect(Atom) when is_atom(Atom) ->
17-
case atom_to_list(Atom) of
18-
"Elixir-" ++ Rest -> [to_dot(R) || R <- Rest];
19-
Else -> Else
20-
end;
21-
22-
inspect(Other) -> Other.
23-
24-
to_dot($-) -> $.;
25-
to_dot(L) -> L.
17+
'Elixir.Binary.Inspect.Atom':inspect(Atom, []).
2618

2719
%% Raised during macros translation.
2820

lib/elixir/src/elixir_translator.erl

Lines changed: 19 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -389,10 +389,12 @@ translate_each({ Atom, Meta, Args } = Original, S) when is_atom(Atom) ->
389389
Callback = fun() ->
390390
case S#elixir_scope.context of
391391
match ->
392+
syntax_error(Meta, S#elixir_scope.file, "cannot invoke function ~ts/~B inside match", [Atom, length(Args)]);
393+
guard ->
392394
Arity = length(Args),
393395
File = S#elixir_scope.file,
394396
case Arity of
395-
0 -> syntax_error(Meta, File, "unknown variable ~ts or cannot invoke local ~ts/~B inside guard", [Atom, Atom, Arity]);
397+
0 -> syntax_error(Meta, File, "unknown variable ~ts or cannot invoke function ~ts/~B inside guard", [Atom, Atom, Arity]);
396398
_ -> syntax_error(Meta, File, "cannot invoke local ~ts/~B inside guard", [Atom, Arity])
397399
end;
398400
_ ->
@@ -423,9 +425,23 @@ translate_each({ { '.', _, [Left, Right] }, Meta, Args } = Original, S) when is_
423425

424426
case TLeft of
425427
{ atom, _, Receiver } ->
426-
elixir_dispatch:dispatch_require(Meta, Receiver, Right, Args, umergev(SL, SR), Callback);
428+
elixir_dispatch:dispatch_require(Meta, Receiver, Right, Args, umergev(SL, SR), fun() ->
429+
case S#elixir_scope.context of
430+
Context when Receiver /= erlang, (Context == match) orelse (Context == guard) ->
431+
syntax_error(Meta, S#elixir_scope.file, "cannot invoke remote function ~ts.~ts/~B inside ~ts",
432+
[elixir_errors:inspect(Receiver), Right, length(Args), Context]);
433+
_ ->
434+
Callback()
435+
end
436+
end);
427437
_ ->
428-
Callback()
438+
case S#elixir_scope.context of
439+
Context when Context == match; Context == guard ->
440+
syntax_error(Meta, S#elixir_scope.file, "cannot invoke remote function ~ts/~B inside ~ts",
441+
[Right, length(Args), Context]);
442+
_ ->
443+
Callback()
444+
end
429445
end;
430446
Else -> Else
431447
end;

lib/elixir/test/elixir/kernel/errors_test.exs

Lines changed: 22 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -109,7 +109,7 @@ defmodule Kernel.ErrorsTest do
109109
end
110110

111111
test :function_import_conflict do
112-
assert "nofile:2: function exit/1 imported from both erlang and Kernel, call is ambiguous" ==
112+
assert "nofile:2: function exit/1 imported from both :erlang and Kernel, call is ambiguous" ==
113113
format_rescue 'defmodule Foo do import :erlang\n def foo, do: exit(:test)\nend'
114114
end
115115

@@ -134,7 +134,7 @@ defmodule Kernel.ErrorsTest do
134134
end
135135

136136
test :no_macros do
137-
assert "nofile:2: could not load macros from module lists" ==
137+
assert "nofile:2: could not load macros from module :lists" ==
138138
format_rescue 'defmodule Foo do\nimport :macros, :lists\nend'
139139
end
140140

@@ -259,6 +259,26 @@ defmodule Kernel.ErrorsTest do
259259
format_rescue 'if true do\n foo = [],\n baz\nend'
260260
end
261261

262+
test :invalid_var_or_function_on_guard do
263+
assert "nofile:1: unknown variable something_that_does_not_exist or cannot invoke function something_that_does_not_exist/0 inside guard" =
264+
format_rescue('case [] do; [] when something_that_does_not_exist == [] -> :ok; end')
265+
end
266+
267+
test :invalid_function_on_match do
268+
assert "nofile:1: cannot invoke function something_that_does_not_exist/0 inside match" =
269+
format_rescue('case [] do; something_that_does_not_exist() -> :ok; end')
270+
end
271+
272+
test :invalid_remote_on_match do
273+
assert "nofile:1: cannot invoke remote function Hello.something_that_does_not_exist/0 inside match" =
274+
format_rescue('case [] do; Hello.something_that_does_not_exist() -> :ok; end')
275+
end
276+
277+
test :invalid_remote_on_guard do
278+
assert "nofile:1: cannot invoke remote function Hello.something_that_does_not_exist/0 inside guard" =
279+
format_rescue('case [] do; [] when Hello.something_that_does_not_exist == [] -> :ok; end')
280+
end
281+
262282
test :macros_error_stacktrace do
263283
assert [{:erlang,:+,[1,:foo],_},{Foo,:sample,1,_}|_] =
264284
rescue_stacktrace("defmodule Foo do\ndefmacro sample(num), do: num + :foo\ndef other, do: sample(1)\nend")

0 commit comments

Comments
 (0)