Skip to content

Unhelpful error message if the error attribute and fmt::Display impl are missing #75

@Luro02

Description

@Luro02

Problem

This code

use thiserror::Error;

#[derive(Debug, Clone, Error, PartialEq)]
pub enum Error {
    First,
    Second,
}

produces this compiler error

error[E0277]: `Error` doesn't implement `std::fmt::Display`
 --> src/lib.rs:3:24
  |
3 | #[derive(Debug, Clone, Error, PartialEq)]
  |                        ^^^^^ `Error` cannot be formatted with the default formatter
  |
  = help: the trait `std::fmt::Display` is not implemented for `Error`
  = note: in format strings you may be able to use `{:?}` (or {:#?} for pretty-print) instead
  = note: this error originates in a derive macro (in Nightly builds, run with -Z macro-backtrace for more info)

error: aborting due to previous error

For more information about this error, try `rustc --explain E0277`.
error: could not compile `terr`.

To learn more, run the command again with --verbose.

It is not immediately obvious that you have to add attributes to the enum variants.

use thiserror::Error;

#[derive(Debug, Clone, Error, PartialEq)]
pub enum Error {
   #[error("first")]
    First,
    #[error("second")]
    Second,
}

Suggestion

A better error message would be something like this

error[E0277]: `Error` doesn't implement `std::fmt::Display`
 --> src/lib.rs:4:10
  |
4 | pub enum Error {
  |          ^^^^^ `Error` cannot be formatted with the default formatter
  |
  = help: the trait `std::fmt::Display` is not implemented for `Error`
  = note: use the `#[error("...")]` attribute on variants to derive `std::fmt::Display`

error: aborting due to previous error

For more information about this error, try `rustc --explain E0277`.
error: could not compile `terr`.

To learn more, run the command again with --verbose.

Implementation

The error happens, because this if clause

let display_impl = if input.has_display() {

in

fn impl_enum(input: Enum) -> TokenStream {

returns None, if input.has_display() is false (to support structs, which implement std::fmt::Display manually?).

I know that the suggested error message is not possible (or is it?), because proc-macros operate on tokens and can therefore not know if a type implements std::fmt::Display.


It is still possible to improve the error message (a little) by returning this in the else clause:

Some(quote_spanned! {
    ty.span() => struct _AssertDisplay where #ty: ::core::fmt::Display;
})

which should result in this compiler error

error[E0277]: `Error` doesn't implement `std::fmt::Display`
 --> src/lib.rs:4:10
  |
4 | pub enum Error {
  |          ^^^^^ `Error` cannot be formatted with the default formatter
  |
  = help: the trait `std::fmt::Display` is not implemented for `Error`
  = note: in format strings you may be able to use `{:?}` (or {:#?} for pretty-print) instead

error: aborting due to previous error

For more information about this error, try `rustc --explain E0277`.
error: could not compile `terr`.

To learn more, run the command again with --verbose.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions