Rollup merge of #24143 - michaelsproul:extended-errors, r=pnkfelix
I've taken another look at extended errors - fixing up the printing and adding a few more for match expressions. With regards to printing, the previous behaviour was to just print the error message string directly, despite it containing indentation which caused it to overflow the standard terminal width of 80 columns (try `rustc --explain E0004`). The first approach I considered was to strip the leading whitespace from each line and lay out the text dynamically, inserting spaces in between. This approach became quite messy when taking multi-paragraph errors into account (and seemed overkill). The approach I settled on removes the indentation in the string itself and begins each message with a newline that is stripped before printing. I feel like complete extended errors would be nice to have for 1.0.0 and I'm happy to spearhead an effort to get them written. Brian got me onto writing them at an SF meetup and I think it shouldn't be too hard to get the remaining 80 or so written with the help of people who don't really work on compiler innards.
This commit is contained in:
commit
ac3cc6c427
@ -10,51 +10,134 @@
|
||||
|
||||
#![allow(non_snake_case)]
|
||||
|
||||
// Error messages for EXXXX errors.
|
||||
// Each message should start and end with a new line, and be wrapped to 80 characters.
|
||||
// In vim you can `:set tw=80` and use `gq` to wrap paragraphs. Use `:set tw=0` to disable.
|
||||
register_long_diagnostics! {
|
||||
E0001: r##"
|
||||
This error suggests that the expression arm corresponding to the noted pattern
|
||||
will never be reached as for all possible values of the expression being matched,
|
||||
one of the preceding patterns will match.
|
||||
|
||||
This means that perhaps some of the preceding patterns are too general, this
|
||||
one is too specific or the ordering is incorrect.
|
||||
E0001: r##"
|
||||
This error suggests that the expression arm corresponding to the noted pattern
|
||||
will never be reached as for all possible values of the expression being
|
||||
matched, one of the preceding patterns will match.
|
||||
|
||||
This means that perhaps some of the preceding patterns are too general, this one
|
||||
is too specific or the ordering is incorrect.
|
||||
"##,
|
||||
|
||||
E0003: r##"
|
||||
Not-a-Number (NaN) values can not be compared for equality and hence can never match
|
||||
the input to a match expression. To match against NaN values, you should instead use
|
||||
the `is_nan` method in a guard, as in: x if x.is_nan() => ...
|
||||
E0002: r##"
|
||||
This error indicates that an empty match expression is illegal because the type
|
||||
it is matching on is non-empty (there exist values of this type). In safe code
|
||||
it is impossible to create an instance of an empty type, so empty match
|
||||
expressions are almost never desired. This error is typically fixed by adding
|
||||
one or more cases to the match expression.
|
||||
|
||||
An example of an empty type is `enum Empty { }`.
|
||||
"##,
|
||||
|
||||
E0004: r##"
|
||||
This error indicates that the compiler can not guarantee a matching pattern for one
|
||||
or more possible inputs to a match expression. Guaranteed matches are required in order
|
||||
to assign values to match expressions, or alternatively, determine the flow of execution.
|
||||
|
||||
If you encounter this error you must alter your patterns so that every possible value of
|
||||
the input type is matched. For types with a small number of variants (like enums) you
|
||||
should probably cover all cases explicitly. Alternatively, the underscore `_` wildcard
|
||||
pattern can be added after all other patterns to match "anything else".
|
||||
E0003: r##"
|
||||
Not-a-Number (NaN) values cannot be compared for equality and hence can never
|
||||
match the input to a match expression. To match against NaN values, you should
|
||||
instead use the `is_nan` method in a guard, as in: x if x.is_nan() => ...
|
||||
"##,
|
||||
|
||||
// FIXME: Remove duplication here?
|
||||
E0005: r##"
|
||||
Patterns used to bind names must be irrefutable, that is, they must guarantee that a
|
||||
name will be extracted in all cases. If you encounter this error you probably need
|
||||
to use a `match` or `if let` to deal with the possibility of failure.
|
||||
E0004: r##"
|
||||
This error indicates that the compiler cannot guarantee a matching pattern for
|
||||
one or more possible inputs to a match expression. Guaranteed matches are
|
||||
required in order to assign values to match expressions, or alternatively,
|
||||
determine the flow of execution.
|
||||
|
||||
If you encounter this error you must alter your patterns so that every possible
|
||||
value of the input type is matched. For types with a small number of variants
|
||||
(like enums) you should probably cover all cases explicitly. Alternatively, the
|
||||
underscore `_` wildcard pattern can be added after all other patterns to match
|
||||
"anything else".
|
||||
"##,
|
||||
|
||||
E0006: r##"
|
||||
Patterns used to bind names must be irrefutable, that is, they must guarantee that a
|
||||
name will be extracted in all cases. If you encounter this error you probably need
|
||||
to use a `match` or `if let` to deal with the possibility of failure.
|
||||
// FIXME: Remove duplication here?
|
||||
E0005: r##"
|
||||
Patterns used to bind names must be irrefutable, that is, they must guarantee that a
|
||||
name will be extracted in all cases. If you encounter this error you probably need
|
||||
to use a `match` or `if let` to deal with the possibility of failure.
|
||||
"##,
|
||||
|
||||
E0006: r##"
|
||||
Patterns used to bind names must be irrefutable, that is, they must guarantee that a
|
||||
name will be extracted in all cases. If you encounter this error you probably need
|
||||
to use a `match` or `if let` to deal with the possibility of failure.
|
||||
"##,
|
||||
|
||||
E0007: r##"
|
||||
This error indicates that the bindings in a match arm would require a value to
|
||||
be moved into more than one location, thus violating unique ownership. Code like
|
||||
the following is invalid as it requires the entire Option<String> to be moved
|
||||
into a variable called `op_string` while simultaneously requiring the inner
|
||||
String to be moved into a variable called `s`.
|
||||
|
||||
let x = Some("s".to_string());
|
||||
match x {
|
||||
op_string @ Some(s) => ...
|
||||
None => ...
|
||||
}
|
||||
|
||||
See also Error 303.
|
||||
"##,
|
||||
|
||||
E0008: r##"
|
||||
Names bound in match arms retain their type in pattern guards. As such, if a
|
||||
name is bound by move in a pattern, it should also be moved to wherever it is
|
||||
referenced in the pattern guard code. Doing so however would prevent the name
|
||||
from being available in the body of the match arm. Consider the following:
|
||||
|
||||
match Some("hi".to_string()) {
|
||||
Some(s) if s.len() == 0 => // use s.
|
||||
...
|
||||
}
|
||||
|
||||
The variable `s` has type String, and its use in the guard is as a variable of
|
||||
type String. The guard code effectively executes in a separate scope to the body
|
||||
of the arm, so the value would be moved into this anonymous scope and therefore
|
||||
become unavailable in the body of the arm. Although this example seems
|
||||
innocuous, the problem is most clear when considering functions that take their
|
||||
argument by value.
|
||||
|
||||
match Some("hi".to_string()) {
|
||||
Some(s) if { drop(s); false } => (),
|
||||
Some(s) => // use s.
|
||||
...
|
||||
}
|
||||
|
||||
The value would be dropped in the guard then become unavailable not only in the
|
||||
body of that arm but also in all subsequent arms! The solution is to bind by
|
||||
reference when using guards or refactor the entire expression, perhaps by
|
||||
putting the condition inside the body of the arm.
|
||||
"##,
|
||||
|
||||
E0303: r##"
|
||||
In certain cases it is possible for sub-bindings to violate memory safety.
|
||||
Updates to the borrow checker in a future version of Rust may remove this
|
||||
restriction, but for now patterns must be rewritten without sub-bindings.
|
||||
|
||||
// Code like this...
|
||||
match Some(5) {
|
||||
ref op_num @ Some(num) => ...
|
||||
None => ...
|
||||
}
|
||||
|
||||
// ... should be updated to code like this.
|
||||
match Some(5) {
|
||||
Some(num) => {
|
||||
let op_num = &Some(num);
|
||||
...
|
||||
}
|
||||
None => ...
|
||||
}
|
||||
|
||||
See also https://github.com/rust-lang/rust/issues/14587
|
||||
"##
|
||||
|
||||
}
|
||||
|
||||
register_diagnostics! {
|
||||
E0002,
|
||||
E0007,
|
||||
E0008,
|
||||
E0009,
|
||||
E0010,
|
||||
E0011,
|
||||
@ -117,7 +200,6 @@ register_diagnostics! {
|
||||
E0300, // unexpanded macro
|
||||
E0301, // cannot mutable borrow in a pattern guard
|
||||
E0302, // cannot assign in a pattern guard
|
||||
E0303, // pattern bindings are not allowed after an `@`
|
||||
E0304, // expected signed integer constant
|
||||
E0305, // expected constant
|
||||
E0306, // expected positive integer for repeat count
|
||||
|
@ -277,7 +277,8 @@ impl<'a> CompilerCalls<'a> for RustcDefaultCalls {
|
||||
Some(ref code) => {
|
||||
match descriptions.find_description(&code[..]) {
|
||||
Some(ref description) => {
|
||||
println!("{}", description);
|
||||
// Slice off the leading newline and print.
|
||||
print!("{}", &description[1..]);
|
||||
}
|
||||
None => {
|
||||
early_error(&format!("no extended information for {}", code));
|
||||
|
Loading…
x
Reference in New Issue
Block a user