Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 29 additions & 1 deletion lib/elixir/lib/module/behaviour.ex
Original file line number Diff line number Diff line change
Expand Up @@ -181,8 +181,11 @@ defmodule Module.Behaviour do
behaviour not in behaviours ->
{:error, {:behaviour_not_declared, behaviour}}

true ->
not behaviour_defined?(callbacks, behaviour) ->
{:error, {:behaviour_not_defined, behaviour, callbacks}}

true ->
{:error, {:callback_not_defined, behaviour, callbacks}}
end
end

Expand Down Expand Up @@ -215,6 +218,18 @@ defmodule Module.Behaviour do
end
end

# Determines whether there is at least one callback defined for the given behaviour.
# If not, that means that the behaviour has not been defined.
defp behaviour_defined?(callbacks, behaviour) do
callbacks
|> Map.values()
|> List.flatten()
|> Enum.any?(fn
{_kind, ^behaviour, _optional?} -> true
{_kind, _behaviour, _optional?} -> false
end)
end

defp warn_missing_impls(%{callbacks: callbacks} = context, _impl_contexts, _defs)
when map_size(callbacks) == 0 do
context
Expand Down Expand Up @@ -391,6 +406,19 @@ defmodule Module.Behaviour do
end

defp format_warning({:behaviour_not_defined, callback, kind, behaviour, callbacks}) do
[
"got \"@impl ",
inspect(behaviour),
"\" for ",
format_definition(kind, callback),
" but behaviour ",
inspect(behaviour),
" does not exist",
known_callbacks(callbacks)
]
end

defp format_warning({:callback_not_defined, callback, kind, behaviour, callbacks}) do
[
"got \"@impl ",
inspect(behaviour),
Expand Down
5 changes: 3 additions & 2 deletions lib/elixir/test/elixir/kernel/impl_test.exs
Original file line number Diff line number Diff line change
Expand Up @@ -122,7 +122,7 @@ defmodule Kernel.ImplTest do
end
end

test "warns for undefined value" do
test "warns for undefined behaviour" do
assert capture_err(fn ->
Code.eval_string("""
defmodule Kernel.ImplTest.ImplAttributes do
Expand All @@ -133,7 +133,8 @@ defmodule Kernel.ImplTest do
end
""")
end) =~
"got \"@impl :abc\" for function foo/0 but this behaviour does not specify such callback. There are no known callbacks"
"got \"@impl :abc\" for function foo/0 but behaviour :abc does not exist. " <>
"There are no known callbacks, please specify the proper @behaviour and make sure it defines callbacks"
end

test "warns for callbacks without impl and @impl has been set before" do
Expand Down