Skip to main content

rustc_on_unimplemented

Attribute rustc_on_unimplemented 

Source
Expand description

Customize the error message when a trait is not implemented.

It must be used on the declaration of said trait.

§Syntax

RustcOnUnimplementedAttribute ->
    rustc_on_unimplemented ( ( Directive ),+ )

Directive ->
      on ( Filter, ( DirectiveOption ),+ )
    | ( DirectiveOption ),*

DirectiveOption ->
      message = STRING_LITERAL
    | label = STRING_LITERAL
    | note = STRING_LITERAL

Filter ->
      FilterAll
    | FilterAny
    | FilterNot
    | FilterOption

FilterAll ->
   all ( ( Filter ),* )

FilterAny ->
   any ( ( Filter ),* )

FilterNot ->
   not ( Filter )

FilterOption ->
      crate_local
    | direct
    | from_desugaring ( = STRING_LITERAL )?
    | cause = STRING_LITERAL
    | IDENTIFIER = STRING_LITERAL

The following keys have the given meaning. At least one must be specified.

  • on - filters the application of the attribute. See #Filters.
  • message — The text for the top level error message. May only be specified at most once.
  • label — The text for the label shown inline in the broken code in the error message. May only be specified at most once.
  • note — Provides additional note(s)

message, label, and note are available with the diagnostic::on_unimplemented attribute. If possible, use that instead.

§Example

ⓘ
//@ dont-require-annotations: ERROR
//@ compile-flags: --crate-type lib -Z ui-testing=no

#![feature(rustc_attrs)]

#[rustc_on_unimplemented(
    message = "cannot add `{Rhs}` to `{Self}`",
    label = "no implementation for `{Self} + {Rhs}`",
)]
pub trait MyAdd<Rhs = Self> {
    fn add(self, rhs: Rhs) -> Self;
}

fn main() {
    MyAdd::add(42_u8, 42.0);
}

produces:

error[E0277]: cannot add `_` to `u8`
 --> $DIR/rustc_on_unimplemented.rs:15:16
  |
15 |     MyAdd::add(42_u8, 42.0);
  |     ---------- ^^^^^ no implementation for `u8 + _`
  |     |
  |     required by a bound introduced by this call
  |
  = help: the trait `MyAdd<_>` is not implemented for `u8`
help: this trait has no implementations, consider adding one
 --> $DIR/rustc_on_unimplemented.rs:10:1
  |
10 | pub trait MyAdd<Rhs = Self> {
  | ^^^^^^^^^^^^^^^^^^^^^^^^^^^

error: aborting due to 1 previous error

For more information about this error, try `rustc --explain E0277`.

§Filters

To allow more targeted error messages, it is possible to filter the application of these keys with on.

You can filter on the following boolean flags:

  • crate_local: whether the code causing the trait bound to not be fulfilled is part of the user’s crate. This is used to avoid suggesting code changes that would require modifying a dependency.
  • direct: whether this is a user-specified rather than derived obligation.
  • from_desugaring: whether we are in some kind of desugaring, like ? or a try block for example. This flag can also be matched on, see below.

You can match on the following names and values, using name = "value":

  • cause: Match against one variant of the ObligationCauseCode enum. Only "MainFunctionType" is supported.
  • from_desugaring: Match against a particular variant of the DesugaringKind enum. The desugaring is identified by its variant name, for example "QuestionMark" for ? desugaring, or "TryBlock" for try blocks.
  • Self and any generic arguments of the trait, like Self = "alloc::string::String" or Rhs="i32".

The compiler provides several values to match on, for example:

  • the self_ty, pretty printed with and without type arguments resolved.
  • "{integral}", if self_ty is an integral of which the type is known.
  • "[]", "[{ty}]", "[{ty}; _]", "[{ty}; $N]" when applicable.
  • references to said slices and arrays.
  • "fn", "unsafe fn" or "#[target_feature] fn" when self is a function.
  • "{integer}" and "{float}" if the type is a number but we haven’t inferred it yet.
  • "{struct}", "{enum}" and "{union}" to match self as an ADT
  • combinations of the above, like "[{integral}; _]".
ⓘ
//@ dont-require-annotations: ERROR
//@ compile-flags: --crate-type lib -Z ui-testing=no

#![feature(rustc_attrs)]

#[rustc_on_unimplemented(
    on(all(Self = "{integer}", Rhs = "{float}"), message = "cannot add a float to an integer",),
    on(all(Self = "{float}", Rhs = "{integer}"), message = "cannot add an integer to a float",),
    message = "cannot add `{Rhs}` to `{Self}`",
    label = "no implementation for `{Self} + {Rhs}`"
)]
pub trait MyAdd<Rhs = Self> {
    fn add(self, rhs: Rhs) -> Self;
}

fn main() {
    MyAdd::add(42_u8, 42.0);
}

produces:

error[E0277]: cannot add `_` to `u8`
 --> $DIR/rustc_on_unimplemented_filter.rs:17:16
  |
17 |     MyAdd::add(42_u8, 42.0);
  |     ---------- ^^^^^ no implementation for `u8 + _`
  |     |
  |     required by a bound introduced by this call
  |
  = help: the trait `MyAdd<_>` is not implemented for `u8`
help: this trait has no implementations, consider adding one
 --> $DIR/rustc_on_unimplemented_filter.rs:12:1
  |
12 | pub trait MyAdd<Rhs = Self> {
  | ^^^^^^^^^^^^^^^^^^^^^^^^^^^

error: aborting due to 1 previous error

For more information about this error, try `rustc --explain E0277`.

§Formatting

The string literals are format strings that accept parameters wrapped in braces - positional and listed parameters are not accepted. The following parameter names are valid:

  • Self and all generic parameters of the trait.
  • This: the name of the trait the attribute is on, without generics.
  • This:path: the full path of the trait the attribute is on, with unresolved generics.
  • This:resolved: the full path of the trait the attribute is on, with resolved generics. Additionally, this will “sugar” the Fn(...) traits.
  • ItemContext: the kind of hir::Node we’re in, things like "an async block", "a function", "an async function", etc.
ⓘ
//@ dont-require-annotations: ERROR
//@ compile-flags: --crate-type lib -Z ui-testing=no

#![feature(rustc_attrs)]

#[rustc_on_unimplemented(message = "Self = `{Self}`, \n \
    T = `{T}`, this = `{This}`, path = `{This:path}`, \n \
    resolved = `{This:resolved}`, context = `{ItemContext}`")]
pub trait From<T>: Sized {
    fn from(x: T) -> Self;
}

fn main() {
    let x: i8 = From::from(42_i32);
}

produces:

error[E0277]: Self = `i8`, 
              T = `i32`, this = `From`, path = `From<T>`, 
              resolved = `From<i32>`, context = `a function`
 --> $DIR/rustc_on_unimplemented_format.rs:14:28
  |
14 |     let x: i8 = From::from(42_i32);
  |                 ---------- ^^^^^^ the trait `From<i32>` is not implemented for `i8`
  |                 |
  |                 required by a bound introduced by this call
  |
help: this trait has no implementations, consider adding one
 --> $DIR/rustc_on_unimplemented_format.rs:9:1
  |
9 | pub trait From<T>: Sized {
  | ^^^^^^^^^^^^^^^^^^^^^^^^

error: aborting due to 1 previous error

For more information about this error, try `rustc --explain E0277`.