- `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 can provide 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.
- combinations of the above, like `"[{integral}; _]"`.
For example, the `Iterator` trait can be filtered in the following way:
```rust,ignore
#[rustc_on_unimplemented(
on(Self = "&str", note = "call `.chars()` or `.as_bytes()` on `{Self}`"),
message = "`{Self}` is not an iterator",
label = "`{Self}` is not an iterator",
note = "maybe try calling `.iter()` or a similar method"
)]
pub trait Iterator {}
```
Which would produce the following outputs:
```text
error[E0277]: `Foo` is not an iterator
--> src/main.rs:4:16
|
4 | for foo in Foo {}
| ^^^ `Foo` is not an iterator
|
= note: maybe try calling `.iter()` or a similar method
= help: the trait `std::iter::Iterator` is not implemented for `Foo`
= note: required by `std::iter::IntoIterator::into_iter`
error[E0277]: `&str` is not an iterator
--> src/main.rs:5:16
|
5 | for foo in "" {}
| ^^ `&str` is not an iterator
|
= note: call `.chars()` or `.bytes() on `&str`
= help: the trait `std::iter::Iterator` is not implemented for `&str`
= note: required by `std::iter::IntoIterator::into_iter`
```
The `on` filter accepts `all`, `any` and `not` predicates similar to the `cfg` attribute:
```rust,ignore
#[rustc_on_unimplemented(on(
all(Self = "&str", T = "alloc::string::String"),
note = "you can coerce a `{T}` into a `{Self}` by writing `&*variable`"
))]
pub trait From<T>: Sized {
/* ... */
}
```
### Formatting
The string literals are format strings that accept parameters wrapped in braces
but positional and listed parameters and format specifiers 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.
- `Trait`: the name of the "sugared" trait. See `TraitRefPrintSugared`.
- `ItemContext`: the kind of `hir::Node` we're in, things like `"an async block"`,
`"a function"`, `"an async function"`, etc.
Something like:
```rust,ignore
#![feature(rustc_attrs)]
#[rustc_on_unimplemented(message = "Self = `{Self}`, \
T = `{T}`, this = `{This}`, trait = `{Trait}`, \
context = `{ItemContext}`")]
pub trait From<T>: Sized {
fn from(x: T) -> Self;
}
fn main() {
let x: i8 = From::from(42_i32);
}
```
Will format the message into
```text
"Self = `i8`, T = `i32`, this = `From`, trait = `From<i32>`, context = `a function`"
```