Skip to content

Commit abe5965

Browse files
committed
Update rustc_on_unimplemented docs
1 parent 28684f9 commit abe5965

File tree

1 file changed

+102
-61
lines changed

1 file changed

+102
-61
lines changed

src/diagnostics.md

Lines changed: 102 additions & 61 deletions
Original file line numberDiff line numberDiff line change
@@ -866,19 +866,17 @@ struct](https://doc.rust-lang.org/nightly/nightly-rustc/rustc_errors/json/struct
866866
(and sub-structs) for the JSON serialization. Don't confuse this with
867867
[`errors::Diag`](https://doc.rust-lang.org/nightly/nightly-rustc/rustc_errors/struct.Diag.html)!
868868

869-
## `#[rustc_on_unimplemented(...)]`
869+
## `#[rustc_on_unimplemented]`
870870

871-
The `#[rustc_on_unimplemented]` attribute allows trait definitions to add specialized
872-
notes to error messages when an implementation was expected but not found.
873-
You can refer to the trait's generic arguments by name and to the resolved type using `Self`.
874-
875-
For example:
871+
This attribute allows trait definitions to modify error messages when an implementation was
872+
expected but not found. The string literals in the attribute are format strings and can be
873+
formatted with named parameters. See the Formatting
874+
section below for what parameters are permitted.
876875

877876
```rust,ignore
878-
#![feature(rustc_attrs)]
879-
880-
#[rustc_on_unimplemented="an iterator over elements of type `{A}` \
881-
cannot be built from a collection of type `{Self}`"]
877+
#[rustc_on_unimplemented(message = "an iterator over \
878+
elements of type `{A}` cannot be built from a \
879+
collection of type `{Self}`")]
882880
trait MyIterator<A> {
883881
fn next(&mut self) -> A;
884882
}
@@ -895,32 +893,26 @@ fn main() {
895893
When the user compiles this, they will see the following;
896894

897895
```txt
898-
error[E0277]: the trait bound `&[{integer}]: MyIterator<char>` is not satisfied
899-
--> <anon>:14:5
896+
error[E0277]: an iterator over elements of type `char` cannot be built from a collection of type `&[{integer}]`
897+
--> src/main.rs:13:19
900898
|
901-
14 | iterate_chars(&[1, 2, 3][..]);
902-
| ^^^^^^^^^^^^^ an iterator over elements of type `char` cannot be built from a collection of type `&[{integer}]`
899+
13 | iterate_chars(&[1, 2, 3][..]);
900+
| ------------- ^^^^^^^^^^^^^^ the trait `MyIterator<char>` is not implemented for `&[{integer}]`
901+
| |
902+
| required by a bound introduced by this call
903903
|
904-
= help: the trait `MyIterator<char>` is not implemented for `&[{integer}]`
905-
= note: required by `iterate_chars`
904+
note: required by a bound in `iterate_chars`
906905
```
907906

908-
`rustc_on_unimplemented` also supports advanced filtering for better targeting
909-
of messages, as well as modifying specific parts of the error message. You
910-
target the text of:
911-
907+
You can modify the contents of:
912908
- the main error message (`message`)
913909
- the label (`label`)
914-
- an extra note (`note`)
910+
- the note(s) (`note`)
915911

916912
For example, the following attribute
917913

918914
```rust,ignore
919-
#[rustc_on_unimplemented(
920-
message="message",
921-
label="label",
922-
note="note"
923-
)]
915+
#[rustc_on_unimplemented(message = "message", label = "label", note = "note")]
924916
trait MyIterator<A> {
925917
fn next(&mut self) -> A;
926918
}
@@ -930,45 +922,62 @@ Would generate the following output:
930922

931923
```text
932924
error[E0277]: message
933-
--> <anon>:14:5
925+
--> <file>>:10:19
934926
|
935-
14 | iterate_chars(&[1, 2, 3][..]);
936-
| ^^^^^^^^^^^^^ label
927+
10 | iterate_chars(&[1, 2, 3][..]);
928+
| ------------- ^^^^^^^^^^^^^^ label
929+
| |
930+
| required by a bound introduced by this call
937931
|
938-
= note: note
939932
= help: the trait `MyIterator<char>` is not implemented for `&[{integer}]`
940-
= note: required by `iterate_chars`
933+
= note: note
934+
note: required by a bound in `iterate_chars`
941935
```
942936

937+
The functionality discussed so far is also available with
938+
[`#[diagnostic::on_unimplemented]`](https://doc.rust-lang.org/nightly/reference/attributes/diagnostics.html#the-diagnosticon_unimplemented-attribute).
939+
If you can, you should use that instead.
940+
941+
### Filtering
942+
943943
To allow more targeted error messages, it is possible to filter the
944-
application of these fields based on a variety of attributes when using
945-
`on`:
944+
application of these fields with `on`.
946945

946+
You can filter on the following boolean flags:
947947
- `crate_local`: whether the code causing the trait bound to not be
948948
fulfilled is part of the user's crate. This is used to avoid suggesting
949949
code changes that would require modifying a dependency.
950-
- Any of the generic arguments that can be substituted in the text can be
951-
referred by name as well for filtering, like `Rhs="i32"`, except for
952-
`Self`.
953-
- `_Self`: to filter only on a particular calculated trait resolution, like
954-
`Self="std::iter::Iterator<char>"`. This is needed because `Self` is a
955-
keyword which cannot appear in attributes.
956-
- `direct`: user-specified rather than derived obligation.
957-
- `from_desugaring`: usable both as boolean (whether the flag is present)
958-
or matching against a particular desugaring. The desugaring is identified
959-
with its variant name in the `DesugaringKind` enum.
960-
961-
For example, the `Iterator` trait can be annotated in the following way:
950+
- `direct`: whether this is an user-specified rather than derived obligation.
951+
- `from_desugaring`: whether we are in some kind of desugaring, like `?`
952+
or a `try` block for example. This flag can also be matched on, see below.
953+
954+
You can match on the following names and values, using `name = "value"`:
955+
- `cause`: Match against one variant of the `ObligationCauseCode`
956+
enum. Only `"MainFunctionType"` is supported.
957+
- `from_desugaring`: Match against a particular variant of the `DesugaringKind`
958+
enum. The desugaring is identified by its variant name, for example
959+
`"QuestionMark"` for `?` desugaring or `"TryBlock"` for `try` blocks.
960+
- `Self` and any generic arguments of the trait, like `Self = "alloc::string::String"`
961+
or `Rhs="i32"`. You may see older uses of the attribute use `_Self` (rather than `Self`)
962+
because using keywords in attributes used to not be permitted.
963+
964+
The compiler can provide several values to match on, for example:
965+
- the self_ty, pretty printed with and without type arguments resolved.
966+
- `"{integral}"`, if self_ty is an integral of which the type is known.
967+
- `"[]"`, `"[{ty}]"`, `"[{ty}; _]"`, `"[{ty}; $N]"` when applicable.
968+
- references to said slices and arrays.
969+
- `"fn"`, `"unsafe fn"` or `"#[target_feature] fn"` when self is a function.
970+
- `"{integer}"` and `"{float}"` if the type is a number but we haven't inferred it yet.
971+
- combinations of the above, like `"[{integral}; _]"`.
972+
973+
For example, the `Iterator` trait can be filtered in the following way:
962974

963975
```rust,ignore
964976
#[rustc_on_unimplemented(
965-
on(
966-
_Self="&str",
967-
note="call `.chars()` or `.as_bytes()` on `{Self}`"
968-
),
969-
message="`{Self}` is not an iterator",
970-
label="`{Self}` is not an iterator",
971-
note="maybe try calling `.iter()` or a similar method"
977+
on(Self = "&str", note = "call `.chars()` or `.as_bytes()` on `{Self}`"),
978+
message = "`{Self}` is not an iterator",
979+
label = "`{Self}` is not an iterator",
980+
note = "maybe try calling `.iter()` or a similar method"
972981
)]
973982
pub trait Iterator {}
974983
```
@@ -997,15 +1006,47 @@ error[E0277]: `&str` is not an iterator
9971006
= note: required by `std::iter::IntoIterator::into_iter`
9981007
```
9991008

1000-
If you need to filter on multiple attributes, you can use `all`, `any` or
1001-
`not` in the following way:
1009+
The `on` filter accepts `all`, `any` and `not` predicates similar to the `cfg` attribute:
10021010

10031011
```rust,ignore
1004-
#[rustc_on_unimplemented(
1005-
on(
1006-
all(_Self="&str", T="std::string::String"),
1007-
note="you can coerce a `{T}` into a `{Self}` by writing `&*variable`"
1008-
)
1009-
)]
1010-
pub trait From<T>: Sized { /* ... */ }
1012+
#[rustc_on_unimplemented(on(
1013+
all(Self = "&str", T = "alloc::string::String"),
1014+
note = "you can coerce a `{T}` into a `{Self}` by writing `&*variable`"
1015+
))]
1016+
pub trait From<T>: Sized {
1017+
/* ... */
1018+
}
1019+
```
1020+
1021+
### Formatting
1022+
1023+
The string literals are format strings that accept parameters wrapped in braces
1024+
but positional and listed parameters and format specifiers are not accepted.
1025+
The following parameter names are valid:
1026+
- `Self` and all generic parameters of the trait.
1027+
- `This`: the name of the trait the attribute is on, without generics.
1028+
- `Trait`: the name of the "sugared" trait. See `TraitRefPrintSugared`.
1029+
- `ItemContext`: the kind of `hir::Node` we're in, things like `"an async block"`,
1030+
`"a function"`, `"an async function"`, etc.
1031+
1032+
Something like:
1033+
1034+
```rust,ignore
1035+
#![feature(rustc_attrs)]
1036+
1037+
#[rustc_on_unimplemented(message = "Self = `{Self}`, \
1038+
T = `{T}`, this = `{This}`, trait = `{Trait}`, \
1039+
context = `{ItemContext}`")]
1040+
pub trait From<T>: Sized {
1041+
fn from(x: T) -> Self;
1042+
}
1043+
1044+
fn main() {
1045+
let x: i8 = From::from(42_i32);
1046+
}
1047+
```
1048+
1049+
Will format the message into
1050+
```text
1051+
"Self = `i8`, T = `i32`, this = `From`, trait = `From<i32>`, context = `a function`"
10111052
```

0 commit comments

Comments
 (0)