From 302cf6db74102e0a0438d83ec7f68085cf931bb9 Mon Sep 17 00:00:00 2001 From: Yuki Okushi Date: Wed, 13 Nov 2019 08:27:53 +0900 Subject: [PATCH 1/2] Tweak non-char/numeric in range pattern diagnostic --- src/librustc_typeck/check/pat.rs | 35 ++++++++- src/test/ui/error-codes/E0029-teach.stderr | 7 +- src/test/ui/error-codes/E0029.stderr | 8 +-- src/test/ui/match/match-range-fail.rs | 9 +-- src/test/ui/match/match-range-fail.stderr | 28 +++++--- src/test/ui/parser/recover-range-pats.stderr | 72 +++++++------------ .../pattern/patkind-litrange-no-expr.stderr | 8 +-- .../ui/qualified/qualified-path-params.stderr | 7 +- 8 files changed, 94 insertions(+), 80 deletions(-) diff --git a/src/librustc_typeck/check/pat.rs b/src/librustc_typeck/check/pat.rs index a4c9862bc74..e7ec176614d 100644 --- a/src/librustc_typeck/check/pat.rs +++ b/src/librustc_typeck/check/pat.rs @@ -380,9 +380,38 @@ fn check_pat_range( E0029, "only char and numeric types are allowed in range patterns" ); - err.span_label(span, "ranges require char or numeric types"); - err.note(&format!("start type: {}", self.ty_to_string(lhs_ty))); - err.note(&format!("end type: {}", self.ty_to_string(rhs_ty))); + if !lhs_compat && !rhs_compat { + err.span_label( + begin.span, + &format!("this is of type `{}` but it should be `char` or numeric", lhs_ty) + ); + err.span_label( + end.span, + &format!("this is of type `{}` but it should be `char` or numeric", rhs_ty) + ); + } else if !lhs_compat { + err.span_label( + begin.span, + &format!("this is of type `{}` but it should be `char` or numeric", lhs_ty) + ); + if !rhs_ty.references_error() { + err.span_label( + end.span, + &format!("this is of type `{}`", rhs_ty) + ); + } + } else { + err.span_label( + end.span, + &format!("this is of type `{}` but it should be `char` or numeric", rhs_ty) + ); + if !lhs_ty.references_error() { + err.span_label( + begin.span, + &format!("this is of type `{}`", lhs_ty) + ); + } + } if self.tcx.sess.teach(&err.get_code().unwrap()) { err.note( "In a match expression, only numbers and characters can be matched \ diff --git a/src/test/ui/error-codes/E0029-teach.stderr b/src/test/ui/error-codes/E0029-teach.stderr index 998ef4bc1d7..ec146ca86f5 100644 --- a/src/test/ui/error-codes/E0029-teach.stderr +++ b/src/test/ui/error-codes/E0029-teach.stderr @@ -2,10 +2,11 @@ error[E0029]: only char and numeric types are allowed in range patterns --> $DIR/E0029-teach.rs:7:9 | LL | "hello" ..= "world" => {} - | ^^^^^^^^^^^^^^^^^^^ ranges require char or numeric types + | -------^^^^^------- + | | | + | | this is of type `&'static str` but it should be `char` or numeric + | this is of type `&'static str` but it should be `char` or numeric | - = note: start type: &'static str - = note: end type: &'static str = note: In a match expression, only numbers and characters can be matched against a range. This is because the compiler checks that the range is non-empty at compile-time, and is unable to evaluate arbitrary comparison functions. If you want to capture values of an orderable type between two end-points, you can use a guard. error: aborting due to previous error diff --git a/src/test/ui/error-codes/E0029.stderr b/src/test/ui/error-codes/E0029.stderr index 209d219191c..e54722ae7b9 100644 --- a/src/test/ui/error-codes/E0029.stderr +++ b/src/test/ui/error-codes/E0029.stderr @@ -2,10 +2,10 @@ error[E0029]: only char and numeric types are allowed in range patterns --> $DIR/E0029.rs:5:9 | LL | "hello" ..= "world" => {} - | ^^^^^^^^^^^^^^^^^^^ ranges require char or numeric types - | - = note: start type: &'static str - = note: end type: &'static str + | -------^^^^^------- + | | | + | | this is of type `&'static str` but it should be `char` or numeric + | this is of type `&'static str` but it should be `char` or numeric error: aborting due to previous error diff --git a/src/test/ui/match/match-range-fail.rs b/src/test/ui/match/match-range-fail.rs index 8a3678577b4..252d4cbf162 100644 --- a/src/test/ui/match/match-range-fail.rs +++ b/src/test/ui/match/match-range-fail.rs @@ -3,15 +3,16 @@ fn main() { "bar" ..= "foo" => { } }; //~^^ ERROR only char and numeric types are allowed in range - //~| start type: &'static str - //~| end type: &'static str match "wow" { 10 ..= "what" => () }; //~^^ ERROR only char and numeric types are allowed in range - //~| start type: {integer} - //~| end type: &'static str + + match "wow" { + true ..= "what" => {} + }; + //~^^ ERROR only char and numeric types are allowed in range match 5 { 'c' ..= 100 => { } diff --git a/src/test/ui/match/match-range-fail.stderr b/src/test/ui/match/match-range-fail.stderr index 3fd2a499e2b..25fa9c2f618 100644 --- a/src/test/ui/match/match-range-fail.stderr +++ b/src/test/ui/match/match-range-fail.stderr @@ -2,22 +2,30 @@ error[E0029]: only char and numeric types are allowed in range patterns --> $DIR/match-range-fail.rs:3:9 | LL | "bar" ..= "foo" => { } - | ^^^^^^^^^^^^^^^ ranges require char or numeric types - | - = note: start type: &'static str - = note: end type: &'static str + | -----^^^^^----- + | | | + | | this is of type `&'static str` but it should be `char` or numeric + | this is of type `&'static str` but it should be `char` or numeric error[E0029]: only char and numeric types are allowed in range patterns - --> $DIR/match-range-fail.rs:10:16 + --> $DIR/match-range-fail.rs:8:16 | LL | 10 ..= "what" => () - | ^^^^^^ ranges require char or numeric types + | -- ^^^^^^ this is of type `&'static str` but it should be `char` or numeric + | | + | this is of type `{integer}` + +error[E0029]: only char and numeric types are allowed in range patterns + --> $DIR/match-range-fail.rs:13:9 | - = note: start type: {integer} - = note: end type: &'static str +LL | true ..= "what" => {} + | ----^^^^^------ + | | | + | | this is of type `&'static str` but it should be `char` or numeric + | this is of type `bool` but it should be `char` or numeric error[E0308]: mismatched types - --> $DIR/match-range-fail.rs:17:9 + --> $DIR/match-range-fail.rs:18:9 | LL | 'c' ..= 100 => { } | ^^^^^^^^^^^ expected integer, found char @@ -25,7 +33,7 @@ LL | 'c' ..= 100 => { } = note: expected type `{integer}` found type `char` -error: aborting due to 3 previous errors +error: aborting due to 4 previous errors Some errors have detailed explanations: E0029, E0308. For more information about an error, try `rustc --explain E0029`. diff --git a/src/test/ui/parser/recover-range-pats.stderr b/src/test/ui/parser/recover-range-pats.stderr index 89ec059cb82..160ab18e34a 100644 --- a/src/test/ui/parser/recover-range-pats.stderr +++ b/src/test/ui/parser/recover-range-pats.stderr @@ -401,19 +401,17 @@ error[E0029]: only char and numeric types are allowed in range patterns --> $DIR/recover-range-pats.rs:19:12 | LL | if let true..Y = 0 {} - | ^^^^ ranges require char or numeric types - | - = note: start type: bool - = note: end type: u8 + | ^^^^ - this is of type `u8` + | | + | this is of type `bool` but it should be `char` or numeric error[E0029]: only char and numeric types are allowed in range patterns --> $DIR/recover-range-pats.rs:20:15 | LL | if let X..true = 0 {} - | ^^^^ ranges require char or numeric types - | - = note: start type: u8 - = note: end type: bool + | - ^^^^ this is of type `bool` but it should be `char` or numeric + | | + | this is of type `u8` error[E0308]: mismatched types --> $DIR/recover-range-pats.rs:21:12 @@ -437,19 +435,17 @@ error[E0029]: only char and numeric types are allowed in range patterns --> $DIR/recover-range-pats.rs:32:12 | LL | if let true..=Y = 0 {} - | ^^^^ ranges require char or numeric types - | - = note: start type: bool - = note: end type: u8 + | ^^^^ - this is of type `u8` + | | + | this is of type `bool` but it should be `char` or numeric error[E0029]: only char and numeric types are allowed in range patterns --> $DIR/recover-range-pats.rs:33:16 | LL | if let X..=true = 0 {} - | ^^^^ ranges require char or numeric types - | - = note: start type: u8 - = note: end type: bool + | - ^^^^ this is of type `bool` but it should be `char` or numeric + | | + | this is of type `u8` error[E0308]: mismatched types --> $DIR/recover-range-pats.rs:34:12 @@ -473,19 +469,17 @@ error[E0029]: only char and numeric types are allowed in range patterns --> $DIR/recover-range-pats.rs:45:12 | LL | if let true...Y = 0 {} - | ^^^^ ranges require char or numeric types - | - = note: start type: bool - = note: end type: u8 + | ^^^^ - this is of type `u8` + | | + | this is of type `bool` but it should be `char` or numeric error[E0029]: only char and numeric types are allowed in range patterns --> $DIR/recover-range-pats.rs:47:16 | LL | if let X...true = 0 {} - | ^^^^ ranges require char or numeric types - | - = note: start type: u8 - = note: end type: bool + | - ^^^^ this is of type `bool` but it should be `char` or numeric + | | + | this is of type `u8` error[E0308]: mismatched types --> $DIR/recover-range-pats.rs:49:12 @@ -509,10 +503,7 @@ error[E0029]: only char and numeric types are allowed in range patterns --> $DIR/recover-range-pats.rs:60:12 | LL | if let true.. = 0 {} - | ^^^^ ranges require char or numeric types - | - = note: start type: bool - = note: end type: [type error] + | ^^^^ this is of type `bool` but it should be `char` or numeric error[E0308]: mismatched types --> $DIR/recover-range-pats.rs:62:12 @@ -527,10 +518,7 @@ error[E0029]: only char and numeric types are allowed in range patterns --> $DIR/recover-range-pats.rs:70:12 | LL | if let true..= = 0 {} - | ^^^^ ranges require char or numeric types - | - = note: start type: bool - = note: end type: [type error] + | ^^^^ this is of type `bool` but it should be `char` or numeric error[E0308]: mismatched types --> $DIR/recover-range-pats.rs:72:12 @@ -545,10 +533,7 @@ error[E0029]: only char and numeric types are allowed in range patterns --> $DIR/recover-range-pats.rs:82:12 | LL | if let true... = 0 {} - | ^^^^ ranges require char or numeric types - | - = note: start type: bool - = note: end type: [type error] + | ^^^^ this is of type `bool` but it should be `char` or numeric error[E0308]: mismatched types --> $DIR/recover-range-pats.rs:85:12 @@ -563,10 +548,7 @@ error[E0029]: only char and numeric types are allowed in range patterns --> $DIR/recover-range-pats.rs:94:14 | LL | if let ..true = 0 {} - | ^^^^ ranges require char or numeric types - | - = note: start type: [type error] - = note: end type: bool + | ^^^^ this is of type `bool` but it should be `char` or numeric error[E0308]: mismatched types --> $DIR/recover-range-pats.rs:96:12 @@ -581,10 +563,7 @@ error[E0029]: only char and numeric types are allowed in range patterns --> $DIR/recover-range-pats.rs:104:15 | LL | if let ..=true = 0 {} - | ^^^^ ranges require char or numeric types - | - = note: start type: [type error] - = note: end type: bool + | ^^^^ this is of type `bool` but it should be `char` or numeric error[E0308]: mismatched types --> $DIR/recover-range-pats.rs:106:12 @@ -599,10 +578,7 @@ error[E0029]: only char and numeric types are allowed in range patterns --> $DIR/recover-range-pats.rs:116:15 | LL | if let ...true = 0 {} - | ^^^^ ranges require char or numeric types - | - = note: start type: [type error] - = note: end type: bool + | ^^^^ this is of type `bool` but it should be `char` or numeric error[E0308]: mismatched types --> $DIR/recover-range-pats.rs:119:12 diff --git a/src/test/ui/pattern/patkind-litrange-no-expr.stderr b/src/test/ui/pattern/patkind-litrange-no-expr.stderr index 7474d326793..78768d282e7 100644 --- a/src/test/ui/pattern/patkind-litrange-no-expr.stderr +++ b/src/test/ui/pattern/patkind-litrange-no-expr.stderr @@ -7,11 +7,11 @@ LL | Arith = 1 + 1, error[E0029]: only char and numeric types are allowed in range patterns --> $DIR/patkind-litrange-no-expr.rs:20:13 | +LL | $( $value ..= 42 => Some($name::$variant), )* // PatKind::Range + | -- this is of type `{integer}` +... LL | Arith = 1 + 1, - | ^^^^^ ranges require char or numeric types - | - = note: start type: {integer} - = note: end type: {integer} + | ^^^^^ this is of type `_` but it should be `char` or numeric error: aborting due to 2 previous errors diff --git a/src/test/ui/qualified/qualified-path-params.stderr b/src/test/ui/qualified/qualified-path-params.stderr index 92792f2e86a..7a74a37021b 100644 --- a/src/test/ui/qualified/qualified-path-params.stderr +++ b/src/test/ui/qualified/qualified-path-params.stderr @@ -8,10 +8,9 @@ error[E0029]: only char and numeric types are allowed in range patterns --> $DIR/qualified-path-params.rs:22:15 | LL | 0 ..= ::A::f:: => {} - | ^^^^^^^^^^^^^^^^^^^^^ ranges require char or numeric types - | - = note: start type: {integer} - = note: end type: fn() {S::f::} + | - ^^^^^^^^^^^^^^^^^^^^^ this is of type `fn() {S::f::}` but it should be `char` or numeric + | | + | this is of type `{integer}` error: aborting due to 2 previous errors From 030fa9a337cb7f224c1d74fda04304c69e07787a Mon Sep 17 00:00:00 2001 From: Yuki Okushi Date: Wed, 13 Nov 2019 23:22:48 +0900 Subject: [PATCH 2/2] Avoid using same code --- src/librustc_typeck/check/pat.rs | 119 ++++++++++++++++--------------- 1 file changed, 61 insertions(+), 58 deletions(-) diff --git a/src/librustc_typeck/check/pat.rs b/src/librustc_typeck/check/pat.rs index e7ec176614d..9421dbc2b2c 100644 --- a/src/librustc_typeck/check/pat.rs +++ b/src/librustc_typeck/check/pat.rs @@ -362,66 +362,13 @@ fn check_pat_range( || ty.is_char() || ty.references_error() }; - let lhs_compat = numeric_or_char(lhs_ty); - let rhs_compat = numeric_or_char(rhs_ty); + let lhs_fail = !numeric_or_char(lhs_ty); + let rhs_fail = !numeric_or_char(rhs_ty); - if !lhs_compat || !rhs_compat { - let span = if !lhs_compat && !rhs_compat { - span - } else if !lhs_compat { - begin.span - } else { - end.span - }; - - let mut err = struct_span_err!( - self.tcx.sess, - span, - E0029, - "only char and numeric types are allowed in range patterns" + if lhs_fail || rhs_fail { + self.emit_err_pat_range( + span, begin.span, end.span, lhs_fail, rhs_fail, lhs_ty, rhs_ty ); - if !lhs_compat && !rhs_compat { - err.span_label( - begin.span, - &format!("this is of type `{}` but it should be `char` or numeric", lhs_ty) - ); - err.span_label( - end.span, - &format!("this is of type `{}` but it should be `char` or numeric", rhs_ty) - ); - } else if !lhs_compat { - err.span_label( - begin.span, - &format!("this is of type `{}` but it should be `char` or numeric", lhs_ty) - ); - if !rhs_ty.references_error() { - err.span_label( - end.span, - &format!("this is of type `{}`", rhs_ty) - ); - } - } else { - err.span_label( - end.span, - &format!("this is of type `{}` but it should be `char` or numeric", rhs_ty) - ); - if !lhs_ty.references_error() { - err.span_label( - begin.span, - &format!("this is of type `{}`", lhs_ty) - ); - } - } - if self.tcx.sess.teach(&err.get_code().unwrap()) { - err.note( - "In a match expression, only numbers and characters can be matched \ - against a range. This is because the compiler checks that the range \ - is non-empty at compile-time, and is unable to evaluate arbitrary \ - comparison functions. If you want to capture values of an orderable \ - type between two end-points, you can use a guard." - ); - } - err.emit(); return None; } @@ -435,6 +382,62 @@ fn check_pat_range( Some(common_type) } + fn emit_err_pat_range( + &self, + span: Span, + begin_span: Span, + end_span: Span, + lhs_fail: bool, + rhs_fail: bool, + lhs_ty: Ty<'tcx>, + rhs_ty: Ty<'tcx>, + ) { + let span = if lhs_fail && rhs_fail { + span + } else if lhs_fail { + begin_span + } else { + end_span + }; + + let mut err = struct_span_err!( + self.tcx.sess, + span, + E0029, + "only char and numeric types are allowed in range patterns" + ); + let msg = |ty| { + format!("this is of type `{}` but it should be `char` or numeric", ty) + }; + let mut one_side_err = |first_span, first_ty, second_span, second_ty: Ty<'_>| { + err.span_label(first_span, &msg(first_ty)); + if !second_ty.references_error() { + err.span_label( + second_span, + &format!("this is of type `{}`", second_ty) + ); + } + }; + if lhs_fail && rhs_fail { + err.span_label(begin_span, &msg(lhs_ty)); + err.span_label(end_span, &msg(rhs_ty)); + } else if lhs_fail { + one_side_err(begin_span, lhs_ty, end_span, rhs_ty); + } else { + one_side_err(end_span, rhs_ty, begin_span, lhs_ty); + } + if self.tcx.sess.teach(&err.get_code().unwrap()) { + err.note( + "In a match expression, only numbers and characters can be matched \ + against a range. This is because the compiler checks that the range \ + is non-empty at compile-time, and is unable to evaluate arbitrary \ + comparison functions. If you want to capture values of an orderable \ + type between two end-points, you can use a guard." + ); + } + err.emit(); + } + fn check_pat_ident( &self, pat: &Pat,