Skip to content

Commit

Permalink
Improve compiler diagnostic when HandlerFn is not implemented
Browse files Browse the repository at this point in the history
For example, if I add a `u64` parameter to a handler, the compiler now
reports this:

```
error[E0277]: Invalid command handler
  --> sable_ircd/src/command/handlers/who.rs:5:1
   |
5  | #[command_handler("WHO")]
   | ^^^^^^^^^^^^^^^^^^^^^^^^^ `for<'a, 'b, 'c, 'd, 'e> fn(&'a server::ClientServer, &'b sable_network::prelude::Network, &'c (dyn command_response::CommandResponse + 'c), source_types::UserSource<'d>, &'e str, u64) -> Result<(), command::error::CommandError> {handle_who}` is not a valid command handler
   |
   = help: the trait `handler::HandlerFn<'_, _, _>` is not implemented for fn item `for<'a, 'b, 'c, 'd, 'e> fn(&'a server::ClientServer, &'b sable_network::prelude::Network, &'c (dyn command_response::CommandResponse + 'c), source_types::UserSource<'d>, &'e str, u64) -> Result<(), command::error::CommandError> {handle_who}`
   = note: All parameter types must implement `AmbientArgument` or `PositionalArgument`
   = note: Return type must be `CommandResult`
note: required by a bound in `call_handler`
  --> sable_ircd/src/command/plumbing/mod.rs:47:20
   |
45 | pub(crate) fn call_handler<'a, Amb, Pos>(
   |               ------------ required by a bound in this function
46 |     ctx: &'a dyn Command,
47 |     handler: &impl HandlerFn<'a, Amb, Pos>,
   |                    ^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `call_handler`
   = note: this error originates in the attribute macro `command_handler` (in Nightly builds, run with -Z macro-backtrace for more info)
```

instead of this:

```
error[E0277]: the trait bound `for<'a, 'b, 'c, 'd, 'e> fn(&'a server::ClientServer, &'b sable_network::prelude::Network, &'c (dyn command_response::CommandResponse + 'c), source_types::UserSource<'d>, &'e str, u64) -> Result<(), command::error::CommandError> {handle_who}: handler::HandlerFn<'_, _, _>` is not satisfied
  --> sable_ircd/src/command/handlers/who.rs:5:1
   |
5  | #[command_handler("WHO")]
   | ^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `handler::HandlerFn<'_, _, _>` is not implemented for fn item `for<'a, 'b, 'c, 'd, 'e> fn(&'a server::ClientServer, &'b sable_network::prelude::Network, &'c (dyn command_response::CommandResponse + 'c), source_types::UserSource<'d>, &'e str, u64) -> Result<(), command::error::CommandError> {handle_who}`
   |
note: required by a bound in `call_handler`
  --> sable_ircd/src/command/plumbing/mod.rs:47:20
   |
45 | pub(crate) fn call_handler<'a, Amb, Pos>(
   |               ------------ required by a bound in this function
46 |     ctx: &'a dyn Command,
47 |     handler: &impl HandlerFn<'a, Amb, Pos>,
   |                    ^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `call_handler`
   = note: this error originates in the attribute macro `command_handler` (in Nightly builds, run with -Z macro-backtrace for more info)
```

This uses the `diagnostic::on_unimplemented` attribute stabilized by
[Rust 1.78](https://blog.rust-lang.org/2024/05/02/Rust-1.78.0.html)
  • Loading branch information
progval authored and spb committed May 4, 2024
1 parent ec555b5 commit ee0a9cc
Showing 1 changed file with 14 additions and 0 deletions.
14 changes: 14 additions & 0 deletions sable_ircd/src/command/plumbing/handler.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,23 @@
use super::*;

// TODO: once rustc implements support for it, use `if(not(Self::Output=CommandResult))`
// to pick the right note to display.
#[diagnostic::on_unimplemented(
message = "Invalid command handler",
label = "`{Self}` is not a valid command handler",
note = "All parameter types must implement `AmbientArgument` or `PositionalArgument`",
note = "Return type must be `CommandResult`"
)]
pub trait HandlerFn<'ctx, Ambient, Positional> {
fn call(&self, ctx: &'ctx dyn Command, args: ArgListIter<'ctx>) -> CommandResult;
}

#[diagnostic::on_unimplemented(
message = "Invalid command handler",
label = "`{Self}` is not a valid command handler",
note = "All parameter types must implement `AmbientArgument` or `PositionalArgument`",
note = "Return type must be `CommandResult`"
)]
pub trait AsyncHandlerFn<'ctx, Ambient, Positional>: Send + Sync {
fn call(
&'ctx self,
Expand Down

0 comments on commit ee0a9cc

Please sign in to comment.