Skip to content

Commit c4d5a69

Browse files
davidtwcotshepang
authored andcommitted
diagnostics: add translation documentation
- Add documentation on translation infrastructure and use of `SessionSubdiagnostic`. - Update diagnostic examples on other pages to be translatable since this is preferred. Signed-off-by: David Wood <[email protected]>
1 parent 56ec010 commit c4d5a69

File tree

7 files changed

+659
-246
lines changed

7 files changed

+659
-246
lines changed

book.toml

+1
Original file line numberDiff line numberDiff line change
@@ -38,3 +38,4 @@ warning-policy = "error"
3838

3939
[output.html.redirect]
4040
"/compiletest.html" = "tests/compiletest.html"
41+
"/diagnostics/sessiondiagnostic.html" = "diagnostics/diagnostic-structs.html"

src/SUMMARY.md

+4-3
Original file line numberDiff line numberDiff line change
@@ -138,10 +138,11 @@
138138
- [Two-phase-borrows](./borrow_check/two_phase_borrows.md)
139139
- [Parameter Environments](./param_env.md)
140140
- [Errors and Lints](diagnostics.md)
141-
- [Creating Errors With SessionDiagnostic](./diagnostics/sessiondiagnostic.md)
141+
- [Diagnostic and subdiagnostic structs](./diagnostics/diagnostic-structs.md)
142+
- [Translation](./diagnostics/translation.md)
142143
- [`LintStore`](./diagnostics/lintstore.md)
143-
- [Diagnostic Codes](./diagnostics/diagnostic-codes.md)
144-
- [Diagnostic Items](./diagnostics/diagnostic-items.md)
144+
- [Diagnostic codes](./diagnostics/diagnostic-codes.md)
145+
- [Diagnostic items](./diagnostics/diagnostic-items.md)
145146
- [`ErrorGuaranteed`](./diagnostics/error-guaranteed.md)
146147

147148
# MIR to Binaries

src/diagnostics.md

+55-35
Original file line numberDiff line numberDiff line change
@@ -139,10 +139,11 @@ use an error-level lint instead of a fixed error.
139139
flag. That said, don't make it so terse that it's hard to understand.
140140
- The word "illegal" is illegal. Prefer "invalid" or a more specific word
141141
instead.
142-
- Errors should document the span of code where they occur – the
143-
[`rustc_errors::diagnostic_builder::DiagnosticBuilder`][diagbuild] `span_*`
144-
methods allow to easily do this. Also `note` other spans that have
145-
contributed to the error if the span isn't too large.
142+
- Errors should document the span of code where they occur (use
143+
[`rustc_errors::diagnostic_builder::DiagnosticBuilder`][diagbuild]'s
144+
`span_*` methods or a diagnostic struct's `#[primary_span]` to easily do
145+
this). Also `note` other spans that have contributed to the error if the span
146+
isn't too large.
146147
- When emitting a message with span, try to reduce the span to the smallest
147148
amount possible that still signifies the issue
148149
- Try not to emit multiple error messages for the same error. This may require
@@ -312,6 +313,15 @@ reporting errors.
312313

313314
[errors]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_errors/index.html
314315

316+
Diagnostics can be implemented as types which implement the `SessionDiagnostic`
317+
trait. This is preferred for new diagnostics as it enforces a separation
318+
between diagnostic emitting logic and the main code paths. For less-complex
319+
diagnostics, the `SessionDiagnostic` trait can be derived -- see [Diagnostic
320+
structs][diagnostic-structs]. Within the trait implementation, the APIs
321+
described below can be used as normal.
322+
323+
[diagnostic-structs]: ./diagnostics/diagnostic-structs.md
324+
315325
[`Session`][session] and [`ParseSess`][parsesses] have
316326
methods (or fields with methods) that allow reporting errors. These methods
317327
usually have names like `span_err` or `struct_span_err` or `span_warn`, etc...
@@ -327,6 +337,12 @@ directly and ones that allow finer control over what to emit. For example,
327337
[`struct_span_err`][strspanerr] instead returns a
328338
[`DiagnosticBuilder`][diagbuild].
329339

340+
Most of these methods will accept strings, but it is recommended that typed
341+
identifiers for translatable diagnostics be used for new diagnostics (see
342+
[Translation][translation]).
343+
344+
[translation]: ./diagnostics/translation.md
345+
330346
`DiagnosticBuilder` allows you to add related notes and suggestions to an error
331347
before emitting it by calling the [`emit`][emit] method. (Failing to either
332348
emit or [cancel][cancel] a `DiagnosticBuilder` will result in an ICE.) See the
@@ -340,30 +356,30 @@ emit or [cancel][cancel] a `DiagnosticBuilder` will result in an ICE.) See the
340356

341357
```rust,ignore
342358
// Get a DiagnosticBuilder. This does _not_ emit an error yet.
343-
let mut err = sess.struct_span_err(sp, "oh no! this is an error!");
359+
let mut err = sess.struct_span_err(sp, fluent::example::example_error);
344360
345361
// In some cases, you might need to check if `sp` is generated by a macro to
346362
// avoid printing weird errors about macro-generated code.
347363
348364
if let Ok(snippet) = sess.source_map().span_to_snippet(sp) {
349365
// Use the snippet to generate a suggested fix
350-
err.span_suggestion(suggestion_sp, "try using a qux here", format!("qux {}", snippet));
366+
err.span_suggestion(suggestion_sp, fluent::example::try_qux_suggestion, format!("qux {}", snippet));
351367
} else {
352368
// If we weren't able to generate a snippet, then emit a "help" message
353369
// instead of a concrete "suggestion". In practice this is unlikely to be
354370
// reached.
355-
err.span_help(suggestion_sp, "you could use a qux here instead");
371+
err.span_help(suggestion_sp, fluent::example::qux_suggestion);
356372
}
357373
358374
// emit the error
359375
err.emit();
360376
```
361377

362-
Alternatively, for less-complex diagnostics, the `SessionDiagnostic` derive
363-
macro can be used -- see [Creating Errors With SessionDiagnostic][sessiondiagnostic].
364-
365-
[sessiondiagnostic]: ./diagnostics/sessiondiagnostic.md
366-
378+
```fluent
379+
example-example-error = oh no! this is an error!
380+
.try-qux-suggestion = try using a qux here
381+
.qux-suggestion = you could use a qux here instead
382+
```
367383

368384
## Suggestions
369385

@@ -405,17 +421,17 @@ apply them)
405421
For example, to make our `qux` suggestion machine-applicable, we would do:
406422

407423
```rust,ignore
408-
let mut err = sess.struct_span_err(sp, "oh no! this is an error!");
424+
let mut err = sess.struct_span_err(sp, fluent::example::message);
409425
410426
if let Ok(snippet) = sess.source_map().span_to_snippet(sp) {
411427
err.span_suggestion(
412428
suggestion_sp,
413-
"try using a qux here",
429+
fluent::example::try_qux_suggestion,
414430
format!("qux {}", snippet),
415431
Applicability::MachineApplicable,
416432
);
417433
} else {
418-
err.span_help(suggestion_sp, "you could use a qux here instead");
434+
err.span_help(suggestion_sp, fluent::example::qux_suggestion);
419435
}
420436
421437
err.emit();
@@ -504,9 +520,9 @@ much faster to work on.
504520

505521
Every lint is implemented via a `struct` that implements the `LintPass` `trait`
506522
(you can also implement one of the more specific lint pass traits, either
507-
`EarlyLintPass` or `LateLintPass` depending on when is best for your lint to run).
508-
The trait implementation allows you to check certain syntactic constructs
509-
as the linter walks the AST. You can then choose to emit lints in a
523+
`EarlyLintPass` or `LateLintPass` depending on when is best for your lint to run).
524+
The trait implementation allows you to check certain syntactic constructs
525+
as the linter walks the AST. You can then choose to emit lints in a
510526
very similar way to compile errors.
511527

512528
You also declare the metadata of a particular lint via the `declare_lint!`
@@ -557,13 +573,12 @@ impl EarlyLintPass for WhileTrue {
557573
if let ast::ExprKind::Lit(ref lit) = pierce_parens(cond).kind {
558574
if let ast::LitKind::Bool(true) = lit.kind {
559575
if !lit.span.from_expansion() {
560-
let msg = "denote infinite loops with `loop { ... }`";
561576
let condition_span = cx.sess.source_map().guess_head_span(e.span);
562577
cx.struct_span_lint(WHILE_TRUE, condition_span, |lint| {
563-
lint.build(msg)
578+
lint.build(fluent::example::use_loop)
564579
.span_suggestion_short(
565580
condition_span,
566-
"use `loop`",
581+
fluent::example::suggestion,
567582
"loop".to_owned(),
568583
Applicability::MachineApplicable,
569584
)
@@ -577,6 +592,11 @@ impl EarlyLintPass for WhileTrue {
577592
}
578593
```
579594

595+
```fluent
596+
example-use-loop = denote infinite loops with `loop {"{"} ... {"}"}`
597+
.suggestion = use `loop`
598+
```
599+
580600
### Edition-gated lints
581601

582602
Sometimes we want to change the behavior of a lint in a new edition. To do this,
@@ -613,15 +633,15 @@ declare_lint! {
613633
The use of the term `future-incompatible` within the compiler has a slightly
614634
broader meaning than what rustc exposes to users of the compiler.
615635

616-
Inside rustc, future-incompatible lints are for signalling to the user that code they have
636+
Inside rustc, future-incompatible lints are for signalling to the user that code they have
617637
written may not compile in the future. In general, future-incompatible code
618638
exists for two reasons:
619-
* the user has written unsound code that the compiler mistakenly accepted. While
620-
it is within Rust's backwards compatibility guarantees to fix the soundness hole
621-
(breaking the user's code), the lint is there to warn the user that this will happen
622-
in some upcoming version of rustc *regardless of which edition the code uses*. This is the
639+
* the user has written unsound code that the compiler mistakenly accepted. While
640+
it is within Rust's backwards compatibility guarantees to fix the soundness hole
641+
(breaking the user's code), the lint is there to warn the user that this will happen
642+
in some upcoming version of rustc *regardless of which edition the code uses*. This is the
623643
meaning that rustc exclusively exposes to users as "future incompatible".
624-
* the user has written code that will either no longer compiler *or* will change
644+
* the user has written code that will either no longer compiler *or* will change
625645
meaning in an upcoming *edition*. These are often called "edition lints" and can be
626646
typically seen in the various "edition compatibility" lint groups (e.g., `rust_2021_compatibility`)
627647
that are used to lint against code that will break if the user updates the crate's edition.
@@ -644,11 +664,11 @@ declare_lint! {
644664
Notice the `reason` field which describes why the future incompatible change is happening.
645665
This will change the diagnostic message the user receives as well as determine which
646666
lint groups the lint is added to. In the example above, the lint is an "edition lint"
647-
(since it's "reason" is `EditionError`) signifying to the user that the use of anonymous
667+
(since it's "reason" is `EditionError`) signifying to the user that the use of anonymous
648668
parameters will no longer compile in Rust 2018 and beyond.
649669

650-
Inside [LintStore::register_lints][fi-lint-groupings], lints with `future_incompatible`
651-
fields get placed into either edition-based lint groups (if their `reason` is tied to
670+
Inside [LintStore::register_lints][fi-lint-groupings], lints with `future_incompatible`
671+
fields get placed into either edition-based lint groups (if their `reason` is tied to
652672
an edition) or into the `future_incompatibility` lint group.
653673

654674
[fi-lint-groupings]: https://github.com/rust-lang/rust/blob/51fd129ac12d5bfeca7d216c47b0e337bf13e0c2/compiler/rustc_lint/src/context.rs#L212-L237
@@ -659,7 +679,7 @@ to support this.
659679

660680
### Renaming or removing a lint
661681

662-
If it is determined that a lint is either improperly named or no longer needed,
682+
If it is determined that a lint is either improperly named or no longer needed,
663683
the lint must be registered for renaming or removal, which will trigger a warning if a user tries
664684
to use the old lint name. To declare a rename/remove, add a line with
665685
[`store.register_renamed`] or [`store.register_removed`] to the code of the
@@ -695,11 +715,11 @@ This defines the `nonstandard_style` group which turns on the listed lints. A
695715
user can turn on these lints with a `!#[warn(nonstandard_style)]` attribute in
696716
the source code, or by passing `-W nonstandard-style` on the command line.
697717

698-
Some lint groups are created automatically in `LintStore::register_lints`. For instance,
699-
any lint declared with `FutureIncompatibleInfo` where the reason is
700-
`FutureIncompatibilityReason::FutureReleaseError` (the default when
718+
Some lint groups are created automatically in `LintStore::register_lints`. For instance,
719+
any lint declared with `FutureIncompatibleInfo` where the reason is
720+
`FutureIncompatibilityReason::FutureReleaseError` (the default when
701721
`@future_incompatible` is used in `declare_lint!`), will be added to
702-
the `future_incompatible` lint group. Editions also have their own lint groups
722+
the `future_incompatible` lint group. Editions also have their own lint groups
703723
(e.g., `rust_2021_compatibility`) automatically generated for any lints signaling
704724
future-incompatible code that will break in the specified edition.
705725

src/diagnostics/diagnostic-items.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -76,7 +76,7 @@ In rustc, diagnostic items are looked up via [`Symbol`]s from inside the
7676
[`rustc_span::symbol::sym`] module. These can then be mapped to [`DefId`]s
7777
using [`TyCtxt::get_diagnostic_item()`] or checked if they match a [`DefId`]
7878
using [`TyCtxt::is_diagnostic_item()`]. When mapping from a diagnostic item to
79-
a [`DefId`] the method will return a `Option<DefId>`. This can be `None` if
79+
a [`DefId`], the method will return a `Option<DefId>`. This can be `None` if
8080
either the symbol isn't a diagnostic item or the type is not registered, for
8181
instance when compiling with `#[no_std]`. All following examples are based on
8282
[`DefId`]s and their usage.

0 commit comments

Comments
 (0)