@@ -342,3 +342,150 @@ The JSON emitter defines [its own `Diagnostic`
342
342
struct] ( https://github.com/rust-lang/rust/blob/b2c6b8c29f13f8d1f242da89e587960b95337819/src/libsyntax/json.rs#L85-L99 )
343
343
(and sub-structs) for the JSON serialization. Don't confuse this with
344
344
[ ` 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