Ignore additional callbacks in protocol implementation, closes #15456
This commit is contained in:
@@ -136,8 +136,8 @@ defmodule Module.Types do
|
||||
defp impl_for(attrs) do
|
||||
case List.keyfind(attrs, :__impl__, 0) do
|
||||
{:__impl__, [protocol: protocol, for: for]} ->
|
||||
if Code.ensure_loaded?(protocol) and function_exported?(protocol, :behaviour_info, 1) do
|
||||
{for, protocol.behaviour_info(:callbacks)}
|
||||
if Code.ensure_loaded?(protocol) and function_exported?(protocol, :__protocol__, 1) do
|
||||
{for, protocol.__protocol__(:functions)}
|
||||
else
|
||||
nil
|
||||
end
|
||||
|
||||
@@ -154,6 +154,50 @@ defmodule Module.Types.IntegrationTest do
|
||||
|
||||
assert itself_arg.(Itself.Unknown) == dynamic(open_map(__struct__: atom([Unknown])))
|
||||
end
|
||||
|
||||
test "ignores additional callbacks on implementations" do
|
||||
files = %{
|
||||
"p.ex" => """
|
||||
defmodule InjectCallback do
|
||||
defmacro __before_compile__(_env) do
|
||||
quote do
|
||||
@callback extra() :: term()
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
defprotocol Injected do
|
||||
@before_compile InjectCallback
|
||||
def f(x)
|
||||
end
|
||||
|
||||
defimpl Injected, for: Atom do
|
||||
def f(_), do: :ok
|
||||
def extra(), do: :extra
|
||||
end
|
||||
|
||||
defprotocol Explicit do
|
||||
@callback extra() :: term()
|
||||
def f(x)
|
||||
end
|
||||
|
||||
defimpl Explicit, for: Atom do
|
||||
def f(_), do: :ok
|
||||
def extra(), do: :extra
|
||||
end
|
||||
"""
|
||||
}
|
||||
|
||||
assert capture_compile_warnings(files, []) == """
|
||||
warning: cannot define @callback extra/0 inside protocol, use def/1 to outline your protocol definition
|
||||
│
|
||||
20 │ @callback extra() :: term()
|
||||
│ ~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
│
|
||||
└─ p.ex:20: Explicit (module)
|
||||
|
||||
"""
|
||||
end
|
||||
end
|
||||
|
||||
describe "type checking" do
|
||||
|
||||
Reference in New Issue
Block a user