@@ -342,3 +342,150 @@ The JSON emitter defines [its own `Diagnostic`
342342struct] ( https://github.com/rust-lang/rust/blob/b2c6b8c29f13f8d1f242da89e587960b95337819/src/libsyntax/json.rs#L85-L99 )
343343(and sub-structs) for the JSON serialization. Don't confuse this with
344344[ ` errors::Diagnostic ` ] ( https://doc.rust-lang.org/nightly/nightly-rustc/rustc_errors/struct.Diagnostic.html ) !
345+
346+ ## ` #[rustc_on_unimplemented(...)] `
347+
348+ The ` #[rustc_on_unimplemented] ` attribute allows trait definitions to add specialized
349+ notes to error messages when an implementation was expected but not found.
350+ You can refer to the trait's generic arguments by name and to the resolved type using ` Self ` .
351+
352+ For example:
353+
354+ ``` rust,ignore
355+ #![feature(rustc_attrs)]
356+
357+ #[rustc_on_unimplemented="an iterator over elements of type `{A}` \
358+ cannot be built from a collection of type `{Self}`"]
359+ trait MyIterator<A> {
360+ fn next(&mut self) -> A;
361+ }
362+
363+ fn iterate_chars<I: MyIterator<char>>(i: I) {
364+ // ...
365+ }
366+
367+ fn main() {
368+ iterate_chars(&[1, 2, 3][..]);
369+ }
370+ ```
371+
372+ When the user compiles this, they will see the following;
373+
374+ ``` txt
375+ error[E0277]: the trait bound `&[{integer}]: MyIterator<char>` is not satisfied
376+ --> <anon>:14:5
377+ |
378+ 14 | iterate_chars(&[1, 2, 3][..]);
379+ | ^^^^^^^^^^^^^ an iterator over elements of type `char` cannot be built from a collection of type `&[{integer}]`
380+ |
381+ = help: the trait `MyIterator<char>` is not implemented for `&[{integer}]`
382+ = note: required by `iterate_chars`
383+ ```
384+
385+ ` rustc_on_unimplemented ` also supports advanced filtering for better targeting
386+ of messages, as well as modifying specific parts of the error message. You
387+ target the text of:
388+
389+ - the main error message (` message ` )
390+ - the label (` label ` )
391+ - an extra note (` note ` )
392+
393+ For example, the following attribute
394+
395+ ``` rust,ignore
396+ #[rustc_on_unimplemented(
397+ message="message",
398+ label="label",
399+ note="note"
400+ )]
401+ trait MyIterator<A> {
402+ fn next(&mut self) -> A;
403+ }
404+ ```
405+
406+ Would generate the following output:
407+
408+ ``` text
409+ error[E0277]: message
410+ --> <anon>:14:5
411+ |
412+ 14 | iterate_chars(&[1, 2, 3][..]);
413+ | ^^^^^^^^^^^^^ label
414+ |
415+ = note: note
416+ = help: the trait `MyIterator<char>` is not implemented for `&[{integer}]`
417+ = note: required by `iterate_chars`
418+ ```
419+
420+ To allow more targeted error messages, it is possible to filter the
421+ application of these fields based on a variety of attributes when using
422+ ` on ` :
423+
424+ - ` crate_local ` : whether the code causing the trait bound to not be
425+ fulfilled is part of the user's crate. This is used to avoid suggesting
426+ code changes that would require modifying a dependency.
427+ - Any of the generic arguments that can be substituted in the text can be
428+ referred by name as well for filtering, like ` Rhs="i32" ` , except for
429+ ` Self ` .
430+ - ` _Self ` : to filter only on a particular calculated trait resolution, like
431+ ` Self="std::iter::Iterator<char>" ` . This is needed because ` Self ` is a
432+ keyword which cannot appear in attributes.
433+ - ` direct ` : user-specified rather than derived obligation.
434+ - ` from_method ` : usable both as boolean (whether the flag is present, like
435+ ` crate_local ` ) or matching against a particular method. Currently used
436+ for ` try ` .
437+ - ` from_desugaring ` : usable both as boolean (whether the flag is present)
438+ or matching against a particular desugaring. The desugaring is identified
439+ with its variant name in the ` DesugaringKind ` enum.
440+
441+ For example, the ` Iterator ` trait can be annotated in the following way:
442+
443+ ``` rust,ignore
444+ #[rustc_on_unimplemented(
445+ on(
446+ _Self="&str",
447+ note="call `.chars()` or `.as_bytes()` on `{Self}"
448+ ),
449+ message="`{Self}` is not an iterator",
450+ label="`{Self}` is not an iterator",
451+ note="maybe try calling `.iter()` or a similar method"
452+ )]
453+ pub trait Iterator {}
454+ ```
455+
456+ Which would produce the following outputs:
457+
458+ ``` text
459+ error[E0277]: `Foo` is not an iterator
460+ --> src/main.rs:4:16
461+ |
462+ 4 | for foo in Foo {}
463+ | ^^^ `Foo` is not an iterator
464+ |
465+ = note: maybe try calling `.iter()` or a similar method
466+ = help: the trait `std::iter::Iterator` is not implemented for `Foo`
467+ = note: required by `std::iter::IntoIterator::into_iter`
468+
469+ error[E0277]: `&str` is not an iterator
470+ --> src/main.rs:5:16
471+ |
472+ 5 | for foo in "" {}
473+ | ^^ `&str` is not an iterator
474+ |
475+ = note: call `.chars()` or `.bytes() on `&str`
476+ = help: the trait `std::iter::Iterator` is not implemented for `&str`
477+ = note: required by `std::iter::IntoIterator::into_iter`
478+ ```
479+
480+ If you need to filter on multiple attributes, you can use ` all ` , ` any ` or
481+ ` not ` in the following way:
482+
483+ ``` rust,ignore
484+ #[rustc_on_unimplemented(
485+ on(
486+ all(_Self="&str", T="std::string::String"),
487+ note="you can coerce a `{T}` into a `{Self}` by writing `&*variable`"
488+ )
489+ )]
490+ pub trait From<T>: Sized { /* ... */ }
491+ ```
0 commit comments