Add some guidelines on diagnostics.
This commit is contained in:
parent
cf38ea60b2
commit
5ae9e9191e
|
|
@ -3,7 +3,7 @@
|
||||||
A lot of effort has been put into making `rustc` have great error messages.
|
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.
|
This chapter is about how to emit compile errors and lints from the compiler.
|
||||||
|
|
||||||
## Diagnostic output style guide
|
## Diagnostic structure
|
||||||
|
|
||||||
The main parts of a diagnostic error are the following:
|
The main parts of a diagnostic error are the following:
|
||||||
|
|
||||||
|
|
@ -61,6 +61,163 @@ error: the fobrulator needs to be krontrificated
|
||||||
When code or an identifier must appear in an message or label, it should be
|
When code or an identifier must appear in an message or label, it should be
|
||||||
surrounded with single acute accents \`.
|
surrounded with single acute accents \`.
|
||||||
|
|
||||||
|
### Error explanations
|
||||||
|
|
||||||
|
Some errors include long form descriptions. They may be viewed with the
|
||||||
|
`--explain` flag, or via the [error index]. Each explanation comes with an
|
||||||
|
example of how to trigger it and advice on how to fix it.
|
||||||
|
|
||||||
|
Please read [RFC 1567] for details on how to format and write long error
|
||||||
|
codes.
|
||||||
|
|
||||||
|
The descriptions are written in markdown, and all of them are linked in the
|
||||||
|
[`librustc_error_codes`] crate.
|
||||||
|
|
||||||
|
<!-- TODO: When should an error use an error code, and when shouldn't it? -->
|
||||||
|
|
||||||
|
[`librustc_error_codes`]: https://github.com/rust-lang/rust/blob/master/src/librustc_error_codes/error_codes.rs
|
||||||
|
[error index]: https://doc.rust-lang.org/error-index.html
|
||||||
|
[RFC 1567]: https://github.com/rust-lang/rfcs/blob/master/text/1567-long-error-codes-explanation-normalization.md
|
||||||
|
|
||||||
|
### Lints versus fixed diagnostics
|
||||||
|
|
||||||
|
Some messages are emitted via [lints](#lints), where the user can control the
|
||||||
|
level. Some are hard-coded such that the user cannot control the level.
|
||||||
|
|
||||||
|
Hard-coded warnings should be avoided for normal code, preferring to use lints
|
||||||
|
instead. Some cases, such as warnings with CLI flags will require the use of
|
||||||
|
hard-coded warnings.
|
||||||
|
|
||||||
|
See the `deny` [lint level](#diagnostic-levels) below for guidelines when to
|
||||||
|
use an error-level lint instead of a fixed error.
|
||||||
|
|
||||||
|
## Diagnostic output style guide
|
||||||
|
|
||||||
|
- Write in plain simple English. If your message, when shown on a – possibly
|
||||||
|
small – screen (which hasn't been cleaned for a while), cannot be understood
|
||||||
|
by a normal programmer, who just came out of bed after a night partying,
|
||||||
|
it's too complex.
|
||||||
|
- `Error`, `Warning`, `Note`, and `Help` messages start with a lowercase
|
||||||
|
letter and do not end with punctuation.
|
||||||
|
- Error messages should be succinct. Users will see these error messages many
|
||||||
|
times, and more verbose descriptions can be viewed with the `--explain`
|
||||||
|
flag. That said, don't make it so terse that it's hard to understand.
|
||||||
|
- The word "illegal" is illegal. Prefer "invalid" or a more specific word
|
||||||
|
instead.
|
||||||
|
- Errors should document the span of code where they occur – the `span_..`
|
||||||
|
methods allow to easily do this. Also `note` other spans that have
|
||||||
|
contributed to the error if the span isn't too large.
|
||||||
|
- When emitting a message with span, try to reduce the span to the smallest
|
||||||
|
amount possible that still signifies the issue
|
||||||
|
- Try not to emit multiple error messages for the same error. This may require
|
||||||
|
detecting duplicates.
|
||||||
|
- When the compiler has too little information for a specific error message,
|
||||||
|
lobby for annotations for library code that allow adding more. For example
|
||||||
|
see [`#[rustc_on_unimplemented]`](#rustc_on_unimplemented). Use these
|
||||||
|
annotations when available!
|
||||||
|
- Keep in mind that Rust's learning curve is rather steep, and that the
|
||||||
|
compiler messages are an important learning tool.
|
||||||
|
- When talking about the compiler, call it `the compiler`, not `Rust` or
|
||||||
|
`rustc`.
|
||||||
|
|
||||||
|
### Lint naming
|
||||||
|
|
||||||
|
From [RFC 0344], lint names should be consistent, with the following
|
||||||
|
guidelines:
|
||||||
|
|
||||||
|
The basic rule is: the lint name should make sense when read as "allow
|
||||||
|
*lint-name*" or "allow *lint-name* items". For example, "allow
|
||||||
|
`deprecated` items" and "allow `dead_code`" makes sense, while "allow
|
||||||
|
`unsafe_block`" is ungrammatical (should be plural).
|
||||||
|
|
||||||
|
- Lint names should state the bad thing being checked for, e.g. `deprecated`,
|
||||||
|
so that `#[allow(deprecated)]` (items) reads correctly. Thus `ctypes` is not
|
||||||
|
an appropriate name; `improper_ctypes` is.
|
||||||
|
|
||||||
|
- Lints that apply to arbitrary items (like the stability lints) should just
|
||||||
|
mention what they check for: use `deprecated` rather than
|
||||||
|
`deprecated_items`. This keeps lint names short. (Again, think "allow
|
||||||
|
*lint-name* items".)
|
||||||
|
|
||||||
|
- If a lint applies to a specific grammatical class, mention that class and
|
||||||
|
use the plural form: use `unused_variables` rather than `unused_variable`.
|
||||||
|
This makes `#[allow(unused_variables)]` read correctly.
|
||||||
|
|
||||||
|
- Lints that catch unnecessary, unused, or useless aspects of code should use
|
||||||
|
the term `unused`, e.g. `unused_imports`, `unused_typecasts`.
|
||||||
|
|
||||||
|
- Use snake case in the same way you would for function names.
|
||||||
|
|
||||||
|
[RFC 0344]: https://github.com/rust-lang/rfcs/blob/master/text/0344-conventions-galore.md#lints
|
||||||
|
|
||||||
|
### Diagnostic levels
|
||||||
|
|
||||||
|
Guidelines for different diagnostic levels:
|
||||||
|
|
||||||
|
- `error`: emitted when the compiler detects a problem that makes it unable to
|
||||||
|
compile the program, either because the program is invalid or the programmer
|
||||||
|
has decided to make a specific `warning` into an error.
|
||||||
|
|
||||||
|
- `warning`: emitted when the compiler detects something odd about a program.
|
||||||
|
Care should be taken when adding warnings to avoid warning fatigue, and
|
||||||
|
avoid false-positives where there really isn't a problem with the code. Some
|
||||||
|
examples of when it is appropriate to issue a warning:
|
||||||
|
|
||||||
|
- A situation where the user *should* take action, such as swap out a
|
||||||
|
deprecated item, or use a `Result`, but otherwise doesn't prevent
|
||||||
|
compilation.
|
||||||
|
- Unnecessary syntax that can be removed without affecting the semantics of
|
||||||
|
the code. For example, unused code, or unnecessary `unsafe`.
|
||||||
|
- Code that is very likely to be incorrect, dangerous, or confusing, but the
|
||||||
|
language technically allows, and is not ready or confident enough to make
|
||||||
|
an error. For example `unused_comparisons` (out of bounds comparisons) or
|
||||||
|
`bindings_with_variant_name` (the user likely did not intend to create a
|
||||||
|
binding in a pattern).
|
||||||
|
- [Future-incompatible lints](#future-incompatible), where something was
|
||||||
|
accidentally or erroneously accepted in the past, but rejecting would
|
||||||
|
cause excessive breakage in the ecosystem.
|
||||||
|
- Stylistic choices. For example, camel or snake case, or the `dyn` trait
|
||||||
|
warning in the 2018 edition. These have a high bar to be added, and should
|
||||||
|
only be used in exceptional circumstances. Other stylistic choices should
|
||||||
|
either be allow-by-default lints, or part of other tools like Clippy or
|
||||||
|
rustfmt.
|
||||||
|
|
||||||
|
- `help`: emitted following an `error` or `warning` to give additional
|
||||||
|
information to the user about how to solve their problem. The error or
|
||||||
|
warning portion should *not* suggest how to fix the problem, only the "help"
|
||||||
|
sub-diagnostic should.
|
||||||
|
|
||||||
|
- `note`: emitted to identify additional circumstances and parts of the code
|
||||||
|
that caused the warning or error. For example, the borrow checker will note
|
||||||
|
any previous conflicting borrows.
|
||||||
|
|
||||||
|
Not to be confused with *lint levels*, whose guidelines are:
|
||||||
|
|
||||||
|
- `forbid`: Lints should never default to `forbid`.
|
||||||
|
- `deny`: Equivalent to `error` diagnostic level. Some examples:
|
||||||
|
|
||||||
|
- A future-incompatible or edition-based lint that has graduated from the
|
||||||
|
warning level.
|
||||||
|
- Something that has an extremely high confidence that is incorrect, but
|
||||||
|
still want an escape hatch to allow it to pass.
|
||||||
|
|
||||||
|
- `warn`: Equivalent to the `warning` diagnostic level. See `warning` above
|
||||||
|
for guidelines.
|
||||||
|
- `allow`: Examples of the kinds of lints that should default to `allow`:
|
||||||
|
|
||||||
|
- The lint has a too high false positive rate.
|
||||||
|
- The lint is too opinionated.
|
||||||
|
- The lint is experimental.
|
||||||
|
- The lint is used for enforcing something that is not normally enforced.
|
||||||
|
For example, the `unsafe_code` lint can be used to prevent usage of unsafe
|
||||||
|
code.
|
||||||
|
|
||||||
|
More information about lint levels can be found in the [rustc
|
||||||
|
book][rustc-lint-levels] and the [reference][reference-diagnostics].
|
||||||
|
|
||||||
|
[reference-diagnostics]: https://doc.rust-lang.org/nightly/reference/attributes/diagnostics.html#lint-check-attributes
|
||||||
|
[rustc-lint-levels]: https://doc.rust-lang.org/nightly/rustc/lints/levels.html
|
||||||
|
|
||||||
## Helpful tips and options
|
## Helpful tips and options
|
||||||
|
|
||||||
### Finding the source of errors
|
### Finding the source of errors
|
||||||
|
|
@ -373,6 +530,7 @@ If you need a combination of options that's not supported by the
|
||||||
`declare_lint!` macro, you can always define your own static with a type of
|
`declare_lint!` macro, you can always define your own static with a type of
|
||||||
`&Lint` but this is currently linted against in the compiler tree.
|
`&Lint` but this is currently linted against in the compiler tree.
|
||||||
|
|
||||||
|
<a id="future-incompatible"></a>
|
||||||
#### Guidelines for creating a future incompatibility lint
|
#### Guidelines for creating a future incompatibility lint
|
||||||
|
|
||||||
- Create a lint defaulting to warn as normal, with ideally the same error
|
- Create a lint defaulting to warn as normal, with ideally the same error
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue