Skip to content

Conversation

eksperimental
Copy link
Contributor

@eksperimental eksperimental commented Oct 5, 2025

There was a bug in the warning when we try to implement a callback of a behaviour that does not exist.

Example:

defmodule BehaviourNotDefined do
  @behaviour FooBehaviour

  @impl FooBehaviour
  def foo(), do: :foo
end

Will give us two warnings:

     warning: @behaviour FooBehaviour does not exist (in module BehaviourNotDefined)
     │
  17 │ defmodule BehaviourNotDefined do
     │ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
     │
     └─ lib/behaviour_not_defined.ex:17: BehaviourNotDefined (module)

     warning: got "@impl FooBehaviour" for function foo/0 but this behaviour does not specify such callback. There are no known callbacks, please specify the proper @behaviour and make sure it defines callbacks
     │
  21 │   def foo(), do: :foo
     │   ~~~~~~~~~~~~~~~~~~~
     │
     └─ lib/behaviour_not_defined.ex:21: BehaviourNotDefined (module)

The first warning is correct. The behaviour does not exist.

The second one is misleadingly telling us that the behaviour does not specify such callback, when the behaviour doesn't even exist.

The internal atom for this error was :behaviour_not_defined but what was being checked was actually that the callback was not defined.
So :behaviour_not_defined has been renamed as :callback_not_defined, while keeping the original message.

And the missing detection for :behaviour_not_defined has been implemented.

…viour

There was a bug in the warning when we try to implement a callback of a behaviour that does not exist.

Example:

```elixir
defmodule BehaviourNotDefined do
  @behaviour FooBehaviour

  @impl FooBehaviour
  def foo(), do: :foo
end
```

Will give us two warnings:

```
     warning: @behaviour FooBehaviour does not exist (in module BehaviourNotDefined)
     │
  17 │ defmodule BehaviourNotDefined do
     │ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
     │
     └─ lib/behaviour_not_defined.ex:17: BehaviourNotDefined (module)

     warning: got "@impl FooBehaviour" for function foo/0 but this behaviour does not specify such callback. There are no known callbacks, please specify the proper @behaviour and make sure it defines callbacks
     │
  21 │   def foo(), do: :foo
     │   ~~~~~~~~~~~~~~~~~~~
     │
     └─ lib/behaviour_not_defined.ex:21: BehaviourNotDefined (module)
```

The first warning is correct. The behaviour does not exist.

The second one is misleadingly telling us that the behaviour does not specify such callback, when the behaviour doesn't even exist.

The internal atom for this error was `:behaviour_not_defined` but what was being checked was actually that the callback was not defined.
So `:behaviour_not_defined` has been renamed as `:callback_not_defined`, while keeping the original message.

And the missing detection for `:behaviour_not_defined` has been implemented.
@eksperimental eksperimental force-pushed the fix/behaviour-not-defined branch from 6e40b9e to eda7a60 Compare October 5, 2025 22:10
@sabiwara
Copy link
Contributor

sabiwara commented Oct 5, 2025

I think the There are no known callbacks, please specify the proper @behaviour and make sure it defines callbacks clause already kind of addresses this, perhaps we can simply replace the "this behaviour" confusing part?

- got "@impl FooBehaviour" for function foo/0 but this behaviour does not specify such callback. There are no known callbacks, please specify the proper @behaviour and make sure it defines callbacks
+ got "@impl FooBehaviour" for function foo/0 but FooBehaviour does not specify such callback. There are no known callbacks, please specify the proper @behaviour and make sure it defines callbacks

@eksperimental
Copy link
Contributor Author

I think the There are no known callbacks, please specify the proper @behaviour and make sure it defines callbacks clause already kind of addresses this, perhaps we can simply replace the "this behaviour" confusing part?

- got "@impl FooBehaviour" for function foo/0 but this behaviour does not specify such callback. There are no known callbacks, please specify the proper @behaviour and make sure it defines callbacks
+ got "@impl FooBehaviour" for function foo/0 but FooBehaviour does not specify such callback. There are no known callbacks for this module, please specify the proper @behaviour and make sure it defines callbacks

I think that your suggestion is an improvement to the error message, but it does not solve the issue here. There are times where you will get a list of defined callbacks, and the issue will still remain, for example:

defmodule BehaviourNotDefined2 do
  @behaviour GenServer
  @behaviour FooBehaviour

  @impl GenServer
  def init(_init_arg), do: {:ok, []}

  @impl FooBehaviour
  def foo(), do: :foo
end

You will get these warnings:

    warning: @behaviour FooBehaviour does not exist (in module BehaviourNotDefined2)
    │
 28 │ defmodule BehaviourNotDefined2 do
    │ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    │
    └─ lib/behaviour_not_defined2.ex:28: BehaviourNotDefined2 (module)

    warning: got "@impl FooBehaviour" for function foo/0 but this behaviour does not specify such callback. The known callbacks are:

      * GenServer.code_change/3 (function)
      * GenServer.format_status/1 (function)
      * GenServer.format_status/2 (function)
      * GenServer.handle_call/3 (function)
      * GenServer.handle_cast/2 (function)
      * GenServer.handle_continue/2 (function)
      * GenServer.handle_info/2 (function)
      * GenServer.init/1 (function)
      * GenServer.terminate/2 (function)

    │
 36 │   def foo(), do: :foo
    │   ~~~~~~~~~~~~~~~~~~~
    │
    └─ lib/behaviour_not_defined2.ex:36: BehaviourNotDefined2 (module)

The key point is mentioning that the behaviour does not exist, not that the behaviour does not implement that callback in particular.

@sabiwara
Copy link
Contributor

sabiwara commented Oct 6, 2025

Oh OK, I didn't consider the case we have multiple callbacks. Makes sense to me!

@eksperimental
Copy link
Contributor Author

eksperimental commented Oct 6, 2025

One thing that I noticed is that we have maybe too many different errors. Maybe we should reconsider unifying them.
With the one introduced in this PR, we would have:

  • :no_behaviours
  • :module_not_defined
  • :behaviour_not_declared
  • :behaviour_not_defined
  • :callback_not_defined

@eksperimental
Copy link
Contributor Author

@sabiwara I have implemented your suggestions

Copy link
Contributor

@sabiwara sabiwara left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM!

@eksperimental
Copy link
Contributor Author

eksperimental commented Oct 6, 2025

@josevalim I have already implemented your suggestions.

So now the following modules will only give the following warnings:

defmodule BehaviourNotDefined do
  @behaviour FooBehaviour

  @impl FooBehaviour
  def foo(), do: :foo
end

defmodule BehaviourNotDefined2 do
  @behaviour GenServer
  @behaviour FooBehaviour

  @impl GenServer
  def init(_init_arg), do: {:ok, []}

  @impl FooBehaviour
  def foo(), do: :foo
end

defmodule ModuleDoesNotDefineBehaviour do
  @behaviour Enum

  @impl Enum
  def foo(), do: :foo
end
    warning: @behaviour FooBehaviour does not exist (in module BehaviourNotDefined)
    │
  1 │ defmodule BehaviourNotDefined do
    │ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    │
    └─ lib/modules.ex:1: BehaviourNotDefined (module)

    warning: @behaviour FooBehaviour does not exist (in module BehaviourNotDefined2)
    │
  8 │ defmodule BehaviourNotDefined2 do
    │ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    │
    └─ lib/modules.ex:8: BehaviourNotDefined2 (module)

    warning: module Enum is not a behaviour (in module ModuleDoesNotDefineBehaviour)
    │
 19 │ defmodule ModuleDoesNotDefineBehaviour do
    │ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    │
    └─ lib/modules.ex:19: ModuleDoesNotDefineBehaviour (module)

@josevalim josevalim merged commit 92a2860 into elixir-lang:main Oct 6, 2025
12 of 13 checks passed
@josevalim
Copy link
Member

💚 💙 💜 💛 ❤️

@eksperimental eksperimental deleted the fix/behaviour-not-defined branch October 6, 2025 14:13
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Development

Successfully merging this pull request may close these issues.

3 participants