diff --git a/src/diagnostics.md b/src/diagnostics.md index 50da15c2..51d6c27a 100644 --- a/src/diagnostics.md +++ b/src/diagnostics.md @@ -3,6 +3,90 @@ A lot of effort has been put into making `rustc` have great error messages. This chapter is about how to emit compile errors and lints from the compiler. +## Diagnostic output style guide + +The main parts of a diagnostic error are the following: + +``` +error[E0000]: main error message + --> file.rs:LL:CC + | +LL | + | -^^^^- secondary label + | | + | primary label + | + = note: note without a `Span`, created with `.note` +note: sub-diagnostic message for `.span_note` + --> file.rs:LL:CC + | +LL | more code + | ^^^^ +``` + +- Description (`error`, `warning`, etc.). +- Code (for example, for "mismatched types", it is `E0308`). It helps + users get more information about the current error through an extended + description of the problem in the error code index. +- Message. It is the main description of the problem. It should be general and + able to stand on its own, so that it can make sense even in isolation. +- Diagnostic window. This contains several things: + - The path, line number and column of the beginning of the primary span. + - The users' affected code and its surroundings. + - Primary and secondary spans underlying the users' code. These spans can + optionally contain one or more labels. + - Primary spans should have enough text to descrive the problem in such a + way that if it where the only thing being displayed (for example, in an + IDE) it would still make sense. Because it is "spatially aware" (it + points at the code), it can generally be more succinct than the error + message. + - If cluttered output can be foreseen in cases when multiple span labels + overlap, it is a good idea to tweak the output appropriately. For + example, the `if/else arms have incompatible types` error uses different + spans depending on whether the arms are all in the same line, if one of + the arms is empty and if none of those cases applies. +- Sub-diagnostics. Any error can have multiple sub-diagnostics that look + similar to the main part of the error. These are used for cases where the + order of the explanation might not correspond with the order of the code. If + the order of the explanation can be "order free", leveraging secondary labels + in the main diagnostic is preferred, as it is typically less verbose. + +The text should be matter of fact and avoid capitalization and periods, unless +multiple sentences are _needed_: + +``` +error: the fobrulator needs to be krontrificated +``` + +When code or an identifier must appear in an message or label, it should be +surrounded with single acute accents \`. + +## Helpful tips and options + +### Finding the source of errors + +There are two main ways to find where a given error is emitted: + +- `grep` for either a sub-part of the error message/label or error code. This + usually works well and is straightforward, but there are some cases where + the error emitting code is removed from the code where the error is + constructed behind a relatively deep call-stack. Even then, it is a good way + to get your bearings. +- Invoking `rustc` with the nightly-only flag `-Ztreat-err-as-bug=1`, which + will treat the first error being emitted as an Internal Compiler Error, which + allows you to use the environment variable `RUST_BACKTRACE=full` to get a + stack trace at the point the error has been emitted. Change the `1` to + something else if you whish to trigger on a later error. Some limitations + with this approach is that some calls get elided from the stack trace because + they get inlined in the compiled `rustc`, and the same problem we faced with + the prior approach, where the _construction_ of the error is far away from + where it is _emitted_. In some cases we buffer multiple errors in order to + emit them in order. + +The regular development practices apply: judicious use of `debug!()` statements +and use of a debugger to trigger break points in order to figure out in what +order things are happening. + ## `Span` [`Span`][span] is the primary data structure in `rustc` used to represent a @@ -84,11 +168,29 @@ Server][rls] and [`rustfix`][rustfix]. [rls]: https://github.com/rust-lang/rls [rustfix]: https://github.com/rust-lang/rustfix -Not all suggestions should be applied mechanically. Use the +Not all suggestions should be applied mechanically, they have a degree of +confidence in the suggested code, from high +(`Applicability::MachineApplicable`) to low (`Applicability::MaybeIncorrect`). +Be conservative when choosing the level. Use the [`span_suggestion`][span_suggestion] method of `DiagnosticBuilder` to make a suggestion. The last argument provides a hint to tools whether the suggestion is mechanically applicable or not. +Suggestions point to one or more spans with corresponding code that will +replace their current content. + +The message that accompanies them should be understandable in the following +contexts: + +- shown as an independent sug-diagnostic (this is the default output) +- shown as a label pointing at the affected span (this is done automatically if +the some heuristics for verbosity are met) +- shown as a `help` sub-diagnostic with no content (used for cases where the +suggestion is obvious from the text, but we still want to let tools to apply +them)) +- not shown (used for _very_ obvious cases, but we still want to allow tools to +apply them) + [span_suggestion]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_errors/struct.DiagnosticBuilder.html#method.span_suggestion For example, to make our `qux` suggestion machine-applicable, we would do: diff --git a/src/ice-breaker/diagnostics.md b/src/ice-breaker/diagnostics.md index 3b5f353b..96450d88 100644 --- a/src/ice-breaker/diagnostics.md +++ b/src/ice-breaker/diagnostics.md @@ -38,111 +38,6 @@ but don't. [D-edition]: https://github.com/rust-lang/rust/labels/D-edition [A-diagnostic-suggestions]: https://github.com/rust-lang/rust/labels/A-diagnostic-suggestions -## Diagnostic output style guide +For more information, visit the [diagnostics page]. -The main parts of a diagnostic error are the following: - -``` -error[E0000]: main error message - --> file.rs:LL:CC - | -LL | - | -^^^^- secondary label - | | - | primary label - | - = note: note without a `Span`, created with `.note` -note: sub-diagnostic message for `.span_note` - --> file.rs:LL:CC - | -LL | more code - | ^^^^ -``` - -- Description (`error`, `warning`, etc.). -- Code (for example, for "mismatched types", it is `E0308`). It helps - users get more information about the current error through an extended - description of the problem in the error code index. -- Message. It is the main description of the problem. It should be general and - able to stand on its own, so that it can make sense even in isolation. -- Diagnostic window. This contains several things: - - The path, line number and column of the beginning of the primary span. - - The users' affected code and its surroundings. - - Primary and secondary spans underlying the users' code. These spans can - optionally contain one or more labels. - - Primary spans should have enough text to descrive the problem in such a - way that if it where the only thing being displayed (for example, in an - IDE) it would still make sense. Because it is "spatially aware" (it - points at the code), it can generally be more succinct than the error - message. - - If cluttered output can be foreseen in cases when multiple span labels - overlap, it is a good idea to tweak the output appropriately. For - example, the `if/else arms have incompatible types` error uses different - spans depending on whether the arms are all in the same line, if one of - the arms is empty and if none of those cases applies. -- Sub-diagnostics. Any error can have multiple sub-diagnostics that look - similar to the main part of the error. These are used for cases where the - order of the explanation might not correspond with the order of the code. If - the order of the explanation can be "order free", leveraging secondary labels - in the main diagnostic is preferred, as it is typically less verbose. - -The text should be matter of fact and avoid capitalization and periods, unless -multiple sentences are _needed_: - -``` -error: the fobrulator needs to be krontrificated -``` - -When code or an identifier must appear in an message or label, it should be -surrounded with single acute accents \`. - -### Structured suggestions - -Structured suggestions are a special kind of annotation in a diagnostic that -let third party tools (like `rustfix` and `rust-analyzer`) apply these changes -with no or minimal user interaction. These suggestions have a degree of -confidence in the suggested code, from high -(`Applicability::MachineApplicable`) to low (`Applicability::MaybeIncorrect`). -Be conservative when choosing the level. - -They point to one or more spans with corresponding code that will replace their -current content. - -The message that accompanies them should be understandable in the following -contexts: - -- shown as an independent sug-diagnostic (this is the default output) -- shown as a label pointing at the affected span (this is done automatically if -the some heuristics for verbosity are met) -- shown as a `help` sub-diagnostic with no content (used for cases where the -suggestion is obvious from the text, but we still want to let tools to apply -them)) -- not shown (used for _very_ obvious cases, but we still want to allow tools to -apply them) - - -## Helpful tips and options - -### Finding the source of errors - -There are two main ways to find where a given error is emitted: - -- `grep` for either a sub-part of the error message/label or error code. This - usually works well and is straightforward, but there are some cases where - the error emitting code is removed from the code where the error is - constructed behind a relatively deep call-stack. Even then, it is a good way - to get your bearings. -- Invoking `rustc` with the nightly-only flag `-Ztreat-err-as-bug=1`, which - will treat the first error being emitted as an Internal Compiler Error, which - allows you to use the environment variable `RUST_BACKTRACE=full` to get a - stack trace at the point the error has been emitted. Change the `1` to - something else if you whish to trigger on a later error. Some limitations - with this approach is that some calls get elided from the stack trace because - they get inlined in the compiled `rustc`, and the same problem we faced with - the prior approach, where the _construction_ of the error is far away from - where it is _emitted_. In some cases we buffer multiple errors in order to - emit them in order. - -The regular development practices apply: judicious use of `debug!()` statements -and use of a debugger to trigger break points in order to figure out in what -order things are happening. +[diagnostics page]: ../diagnostics.md