From 19e9828fb8f87c51175f638461a5b4051d022158 Mon Sep 17 00:00:00 2001 From: Michael Sproul Date: Sat, 4 Apr 2015 12:37:25 -0700 Subject: [PATCH 1/2] Fix printing of extended errors. --- src/librustc/diagnostics.rs | 61 +++++++++++++++++++++---------------- src/librustc_driver/lib.rs | 3 +- 2 files changed, 36 insertions(+), 28 deletions(-) diff --git a/src/librustc/diagnostics.rs b/src/librustc/diagnostics.rs index 0a29ed90ad46..34f8f34b5550 100644 --- a/src/librustc/diagnostics.rs +++ b/src/librustc/diagnostics.rs @@ -10,45 +10,52 @@ #![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() => ... +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() => ... "##, - 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 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". +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. "## + } register_diagnostics! { diff --git a/src/librustc_driver/lib.rs b/src/librustc_driver/lib.rs index b32c6829a221..89c19cfb0b02 100644 --- a/src/librustc_driver/lib.rs +++ b/src/librustc_driver/lib.rs @@ -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)); From 039a5539986b38852bca772b8709bab533ca5be0 Mon Sep 17 00:00:00 2001 From: Michael Sproul Date: Mon, 6 Apr 2015 23:49:40 -0700 Subject: [PATCH 2/2] Add more extended error messages for match exprs. --- src/librustc/diagnostics.rs | 87 ++++++++++++++++++++++++++++++++++--- 1 file changed, 81 insertions(+), 6 deletions(-) diff --git a/src/librustc/diagnostics.rs b/src/librustc/diagnostics.rs index 34f8f34b5550..b15304d6dc50 100644 --- a/src/librustc/diagnostics.rs +++ b/src/librustc/diagnostics.rs @@ -24,14 +24,24 @@ 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 +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 +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. @@ -54,14 +64,80 @@ 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 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, @@ -124,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