Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Improve extended errors (rustc --explain). #24143

Merged
merged 2 commits into from
Apr 8, 2015
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
144 changes: 113 additions & 31 deletions src/librustc/diagnostics.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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.
"##,

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 { }`.
"##,

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() => ...
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() => ...
"##,

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.
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".
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".
"##,

// 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.
// 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.
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
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Option should be surrounded by ` for consistency.

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,
Expand Down Expand Up @@ -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
Expand Down
3 changes: 2 additions & 1 deletion src/librustc_driver/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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));
Expand Down