]>
Commit | Line | Data |
---|---|---|
8bb4bdeb XL |
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 | ||
7cac9316 XL |
9 | The `on_unimplemented` feature provides the `#[rustc_on_unimplemented]` |
10 | attribute, which allows trait definitions to add specialized notes to error | |
b7449926 XL |
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`. | |
8bb4bdeb | 14 | |
7cac9316 XL |
15 | For example: |
16 | ||
17 | ```rust,compile_fail | |
18 | #![feature(on_unimplemented)] | |
19 | ||
abe05a73 XL |
20 | #[rustc_on_unimplemented="an iterator over elements of type `{A}` \ |
21 | cannot be built from a collection of type `{Self}`"] | |
7cac9316 XL |
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][..]); | |
abe05a73 | 42 | | ^^^^^^^^^^^^^ an iterator over elements of type `char` cannot be built from a collection of type `&[{integer}]` |
7cac9316 | 43 | | |
abe05a73 | 44 | = help: the trait `MyIterator<char>` is not implemented for `&[{integer}]` |
7cac9316 | 45 | = note: required by `iterate_chars` |
b7449926 XL |
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`: | |
7cac9316 | 86 | |
b7449926 XL |
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) | |
416331ca XL |
101 | or matching against a particular desugaring. The desugaring is identified |
102 | with its variant name in the `DesugaringKind` enum. | |
b7449926 XL |
103 | |
104 | For example, the `Iterator` trait can be annotated in the following way: | |
105 | ||
106 | ```rust,compile_fail | |
107 | #[rustc_on_unimplemented( | |
108 | on( | |
109 | _Self="&str", | |
110 | note="call `.chars()` or `.as_bytes()` on `{Self}" | |
111 | ), | |
112 | message="`{Self}` is not an iterator", | |
113 | label="`{Self}` is not an iterator", | |
114 | note="maybe try calling `.iter()` or a similar method" | |
115 | )] | |
116 | pub trait Iterator {} | |
7cac9316 | 117 | ``` |
8bb4bdeb | 118 | |
b7449926 XL |
119 | Which would produce the following outputs: |
120 | ||
121 | ```text | |
122 | error[E0277]: `Foo` is not an iterator | |
123 | --> src/main.rs:4:16 | |
124 | | | |
125 | 4 | for foo in Foo {} | |
126 | | ^^^ `Foo` is not an iterator | |
127 | | | |
128 | = note: maybe try calling `.iter()` or a similar method | |
129 | = help: the trait `std::iter::Iterator` is not implemented for `Foo` | |
130 | = note: required by `std::iter::IntoIterator::into_iter` | |
131 | ||
132 | error[E0277]: `&str` is not an iterator | |
133 | --> src/main.rs:5:16 | |
134 | | | |
135 | 5 | for foo in "" {} | |
136 | | ^^ `&str` is not an iterator | |
137 | | | |
138 | = note: call `.chars()` or `.bytes() on `&str` | |
139 | = help: the trait `std::iter::Iterator` is not implemented for `&str` | |
140 | = note: required by `std::iter::IntoIterator::into_iter` | |
141 | ``` | |
532ac7d7 XL |
142 | |
143 | If you need to filter on multiple attributes, you can use `all`, `any` or | |
144 | `not` in the following way: | |
145 | ||
146 | ```rust,compile_fail | |
147 | #[rustc_on_unimplemented( | |
148 | on( | |
149 | all(_Self="&str", T="std::string::String"), | |
150 | note="you can coerce a `{T}` into a `{Self}` by writing `&*variable`" | |
151 | ) | |
152 | )] | |
153 | pub trait From<T>: Sized { /* ... */ } | |
154 | ``` |