]> git.lizzy.rs Git - rust.git/blob - src/doc/unstable-book/src/language-features/on-unimplemented.md
Remove GlobalArenas and use Arena instead
[rust.git] / src / doc / unstable-book / src / language-features / on-unimplemented.md
1 # `on_unimplemented`
2
3 The tracking issue for this feature is: [#29628]
4
5 [#29628]: https://github.com/rust-lang/rust/issues/29628
6
7 ------------------------
8
9 The `on_unimplemented` feature provides the `#[rustc_on_unimplemented]`
10 attribute, which allows trait definitions to add specialized notes to error
11 messages when an implementation was expected but not found. You can refer
12 to the trait's generic arguments by name and to the resolved type using
13 `Self`.
14
15 For example:
16
17 ```rust,compile_fail
18 #![feature(on_unimplemented)]
19
20 #[rustc_on_unimplemented="an iterator over elements of type `{A}` \
21     cannot be built from a collection of type `{Self}`"]
22 trait MyIterator<A> {
23     fn next(&mut self) -> A;
24 }
25
26 fn iterate_chars<I: MyIterator<char>>(i: I) {
27     // ...
28 }
29
30 fn main() {
31     iterate_chars(&[1, 2, 3][..]);
32 }
33 ```
34
35 When the user compiles this, they will see the following;
36
37 ```txt
38 error[E0277]: the trait bound `&[{integer}]: MyIterator<char>` is not satisfied
39   --> <anon>:14:5
40    |
41 14 |     iterate_chars(&[1, 2, 3][..]);
42    |     ^^^^^^^^^^^^^ an iterator over elements of type `char` cannot be built from a collection of type `&[{integer}]`
43    |
44    = help: the trait `MyIterator<char>` is not implemented for `&[{integer}]`
45    = note: required by `iterate_chars`
46 ```
47
48 `on_unimplemented` also supports advanced filtering for better targeting
49 of messages, as well as modifying specific parts of the error message. You
50 target the text of:
51
52  - the main error message (`message`)
53  - the label (`label`)
54  - an extra note (`note`)
55
56 For example, the following attribute
57
58 ```rust,compile_fail
59 #[rustc_on_unimplemented(
60     message="message",
61     label="label",
62     note="note"
63 )]
64 trait MyIterator<A> {
65     fn next(&mut self) -> A;
66 }
67 ```
68
69 Would generate the following output:
70
71 ```text
72 error[E0277]: message
73   --> <anon>:14:5
74    |
75 14 |     iterate_chars(&[1, 2, 3][..]);
76    |     ^^^^^^^^^^^^^ label
77    |
78    = note: note
79    = help: the trait `MyIterator<char>` is not implemented for `&[{integer}]`
80    = note: required by `iterate_chars`
81 ```
82
83 To allow more targeted error messages, it is possible to filter the
84 application of these fields based on a variety of attributes when using
85 `on`:
86
87  - `crate_local`: whether the code causing the trait bound to not be
88    fulfilled is part of the user's crate. This is used to avoid suggesting
89    code changes that would require modifying a dependency.
90  - Any of the generic arguments that can be substituted in the text can be
91    referred by name as well for filtering, like `Rhs="i32"`, except for
92    `Self`.
93  - `_Self`: to filter only on a particular calculated trait resolution, like
94    `Self="std::iter::Iterator<char>"`. This is needed because `Self` is a
95    keyword which cannot appear in attributes.
96  - `direct`: user-specified rather than derived obligation.
97  - `from_method`: usable both as boolean (whether the flag is present, like
98    `crate_local`) or matching against a particular method. Currently used
99    for `try`.
100  - `from_desugaring`: usable both as boolean (whether the flag is present)
101    or matching against a particular desugaring.
102
103 For example, the `Iterator` trait can be annotated in the following way:
104
105 ```rust,compile_fail
106 #[rustc_on_unimplemented(
107     on(
108         _Self="&str",
109         note="call `.chars()` or `.as_bytes()` on `{Self}"
110     ),
111     message="`{Self}` is not an iterator",
112     label="`{Self}` is not an iterator",
113     note="maybe try calling `.iter()` or a similar method"
114 )]
115 pub trait Iterator {}
116 ```
117
118 Which would produce the following outputs:
119
120 ```text
121 error[E0277]: `Foo` is not an iterator
122  --> src/main.rs:4:16
123   |
124 4 |     for foo in Foo {}
125   |                ^^^ `Foo` is not an iterator
126   |
127   = note: maybe try calling `.iter()` or a similar method
128   = help: the trait `std::iter::Iterator` is not implemented for `Foo`
129   = note: required by `std::iter::IntoIterator::into_iter`
130
131 error[E0277]: `&str` is not an iterator
132  --> src/main.rs:5:16
133   |
134 5 |     for foo in "" {}
135   |                ^^ `&str` is not an iterator
136   |
137   = note: call `.chars()` or `.bytes() on `&str`
138   = help: the trait `std::iter::Iterator` is not implemented for `&str`
139   = note: required by `std::iter::IntoIterator::into_iter`
140 ```
141
142 If you need to filter on multiple attributes, you can use `all`, `any` or
143 `not` in the following way:
144
145 ```rust,compile_fail
146 #[rustc_on_unimplemented(
147     on(
148         all(_Self="&str", T="std::string::String"),
149         note="you can coerce a `{T}` into a `{Self}` by writing `&*variable`"
150     )
151 )]
152 pub trait From<T>: Sized { /* ... */ }
153 ```