From 73db83aa70bea7973fa4bb1f025de199a19d5282 Mon Sep 17 00:00:00 2001 From: Mazdak Farrokhzad Date: Mon, 30 Dec 2019 06:53:02 +0100 Subject: [PATCH 01/10] cleanup check_pat --- src/librustc_typeck/check/pat.rs | 32 +++++++++++--------------------- 1 file changed, 11 insertions(+), 21 deletions(-) diff --git a/src/librustc_typeck/check/pat.rs b/src/librustc_typeck/check/pat.rs index 2f53378303b58..397f8682ede73 100644 --- a/src/librustc_typeck/check/pat.rs +++ b/src/librustc_typeck/check/pat.rs @@ -72,7 +72,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let is_nrp = self.is_non_ref_pat(pat, path_resolution.map(|(res, ..)| res)); let (expected, def_bm) = self.calc_default_binding_mode(pat, expected, def_bm, is_nrp); - let ty = match &pat.kind { + let ty = match pat.kind { PatKind::Wild => expected, PatKind::Lit(lt) => self.check_pat_lit(pat.span, lt, expected, discrim_span), PatKind::Range(begin, end, _) => { @@ -82,50 +82,40 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } } PatKind::Binding(ba, var_id, _, sub) => { - let sub = sub.as_deref(); - self.check_pat_ident(pat, *ba, *var_id, sub, expected, def_bm, discrim_span) + self.check_pat_ident(pat, ba, var_id, sub, expected, def_bm, discrim_span) } - PatKind::TupleStruct(qpath, subpats, ddpos) => self.check_pat_tuple_struct( + PatKind::TupleStruct(ref qpath, subpats, ddpos) => self.check_pat_tuple_struct( pat, qpath, subpats, - *ddpos, + ddpos, expected, def_bm, discrim_span, ), - PatKind::Path(qpath) => { + PatKind::Path(ref qpath) => { self.check_pat_path(pat, path_resolution.unwrap(), qpath, expected) } - PatKind::Struct(qpath, fields, etc) => { - self.check_pat_struct(pat, qpath, fields, *etc, expected, def_bm, discrim_span) + PatKind::Struct(ref qpath, fields, etc) => { + self.check_pat_struct(pat, qpath, fields, etc, expected, def_bm, discrim_span) } PatKind::Or(pats) => { - for pat in *pats { + for pat in pats { self.check_pat(pat, expected, def_bm, discrim_span); } expected } PatKind::Tuple(elements, ddpos) => { - self.check_pat_tuple(pat.span, *elements, *ddpos, expected, def_bm, discrim_span) + self.check_pat_tuple(pat.span, elements, ddpos, expected, def_bm, discrim_span) } PatKind::Box(inner) => { self.check_pat_box(pat.span, inner, expected, def_bm, discrim_span) } PatKind::Ref(inner, mutbl) => { - self.check_pat_ref(pat, inner, *mutbl, expected, def_bm, discrim_span) + self.check_pat_ref(pat, inner, mutbl, expected, def_bm, discrim_span) } PatKind::Slice(before, slice, after) => { - let slice = slice.as_deref(); - self.check_pat_slice( - pat.span, - *before, - slice, - *after, - expected, - def_bm, - discrim_span, - ) + self.check_pat_slice(pat.span, before, slice, after, expected, def_bm, discrim_span) } }; From ab050d6a83a9bdc5856a20402b6ea440d474638c Mon Sep 17 00:00:00 2001 From: Mazdak Farrokhzad Date: Mon, 30 Dec 2019 07:02:24 +0100 Subject: [PATCH 02/10] MatchExpressionArmPattern: Use more generic wording. The existing wording was inappropriate for e.g. `if let Ok(_) = expr { .. }`. The diagnostic would leak the fact that we desugar to a `match`. --- src/librustc/infer/error_reporting/mod.rs | 2 +- src/test/ui/block-result/issue-13624.stderr | 2 +- src/test/ui/error-codes/E0308-4.stderr | 2 +- ...exclusive_range_pattern_syntax_collision.stderr | 2 +- ...xclusive_range_pattern_syntax_collision2.stderr | 2 +- ...xclusive_range_pattern_syntax_collision3.stderr | 4 ++-- src/test/ui/issues/issue-11844.stderr | 2 +- src/test/ui/issues/issue-12552.stderr | 2 +- src/test/ui/issues/issue-13466.stderr | 4 ++-- src/test/ui/issues/issue-15896.stderr | 2 +- src/test/ui/issues/issue-16401.stderr | 2 +- src/test/ui/issues/issue-3680.stderr | 2 +- src/test/ui/issues/issue-5100.stderr | 2 +- src/test/ui/issues/issue-5358-1.stderr | 2 +- src/test/ui/issues/issue-57741-1.stderr | 4 ++-- src/test/ui/issues/issue-57741.stderr | 8 ++++---- src/test/ui/issues/issue-7092.stderr | 2 +- src/test/ui/match/match-struct.stderr | 2 +- src/test/ui/match/match-tag-unary.stderr | 2 +- src/test/ui/parser/pat-tuple-5.stderr | 2 +- src/test/ui/pattern/pattern-error-continue.stderr | 2 +- src/test/ui/pattern/pattern-tyvar.stderr | 2 +- .../disallowed-positions.stderr | 14 +++++++------- .../structure-constructor-type-mismatch.stderr | 6 +++--- 24 files changed, 38 insertions(+), 38 deletions(-) diff --git a/src/librustc/infer/error_reporting/mod.rs b/src/librustc/infer/error_reporting/mod.rs index 027143a3d22c0..f0f0e2cdeb9c1 100644 --- a/src/librustc/infer/error_reporting/mod.rs +++ b/src/librustc/infer/error_reporting/mod.rs @@ -584,7 +584,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { ObligationCauseCode::MatchExpressionArmPattern { span, ty } => { if ty.is_suggestable() { // don't show type `_` - err.span_label(span, format!("this match expression has type `{}`", ty)); + err.span_label(span, format!("this expression has type `{}`", ty)); } if let Some(ty::error::ExpectedFound { found, .. }) = exp_found { if ty.is_box() && ty.boxed_ty() == found { diff --git a/src/test/ui/block-result/issue-13624.stderr b/src/test/ui/block-result/issue-13624.stderr index 90ffb4b2e52bc..416f055251b04 100644 --- a/src/test/ui/block-result/issue-13624.stderr +++ b/src/test/ui/block-result/issue-13624.stderr @@ -10,7 +10,7 @@ error[E0308]: mismatched types --> $DIR/issue-13624.rs:20:9 | LL | match enum_struct_variant { - | ------------------- this match expression has type `()` + | ------------------- this expression has type `()` LL | a::Enum::EnumStructVariant { x, y, z } => { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `()`, found enum `a::Enum` diff --git a/src/test/ui/error-codes/E0308-4.stderr b/src/test/ui/error-codes/E0308-4.stderr index 46805d6e13b7c..39c0676373794 100644 --- a/src/test/ui/error-codes/E0308-4.stderr +++ b/src/test/ui/error-codes/E0308-4.stderr @@ -2,7 +2,7 @@ error[E0308]: mismatched types --> $DIR/E0308-4.rs:4:15 | LL | match x { - | - this match expression has type `u8` + | - this expression has type `u8` LL | 0u8..=3i8 => (), | --- ^^^ expected `u8`, found `i8` | | diff --git a/src/test/ui/exclusive-range/exclusive_range_pattern_syntax_collision.stderr b/src/test/ui/exclusive-range/exclusive_range_pattern_syntax_collision.stderr index 04538cd74b195..580c80f66c3ca 100644 --- a/src/test/ui/exclusive-range/exclusive_range_pattern_syntax_collision.stderr +++ b/src/test/ui/exclusive-range/exclusive_range_pattern_syntax_collision.stderr @@ -8,7 +8,7 @@ error[E0308]: mismatched types --> $DIR/exclusive_range_pattern_syntax_collision.rs:5:13 | LL | match [5..4, 99..105, 43..44] { - | ----------------------- this match expression has type `std::ops::Range<{integer}>` + | ----------------------- this expression has type `std::ops::Range<{integer}>` LL | [_, 99.., _] => {}, | ^^ expected struct `std::ops::Range`, found integer | diff --git a/src/test/ui/exclusive-range/exclusive_range_pattern_syntax_collision2.stderr b/src/test/ui/exclusive-range/exclusive_range_pattern_syntax_collision2.stderr index c918d0a385c75..88d45f16ff6c9 100644 --- a/src/test/ui/exclusive-range/exclusive_range_pattern_syntax_collision2.stderr +++ b/src/test/ui/exclusive-range/exclusive_range_pattern_syntax_collision2.stderr @@ -14,7 +14,7 @@ error[E0308]: mismatched types --> $DIR/exclusive_range_pattern_syntax_collision2.rs:5:13 | LL | match [5..4, 99..105, 43..44] { - | ----------------------- this match expression has type `std::ops::Range<{integer}>` + | ----------------------- this expression has type `std::ops::Range<{integer}>` LL | [_, 99..] => {}, | ^^ expected struct `std::ops::Range`, found integer | diff --git a/src/test/ui/exclusive-range/exclusive_range_pattern_syntax_collision3.stderr b/src/test/ui/exclusive-range/exclusive_range_pattern_syntax_collision3.stderr index e6ee3817b3558..6abba7d7cab10 100644 --- a/src/test/ui/exclusive-range/exclusive_range_pattern_syntax_collision3.stderr +++ b/src/test/ui/exclusive-range/exclusive_range_pattern_syntax_collision3.stderr @@ -8,7 +8,7 @@ error[E0308]: mismatched types --> $DIR/exclusive_range_pattern_syntax_collision3.rs:5:12 | LL | match [5..4, 99..105, 43..44] { - | ----------------------- this match expression has type `std::ops::Range<{integer}>` + | ----------------------- this expression has type `std::ops::Range<{integer}>` LL | [..9, 99..100, _] => {}, | ^ expected struct `std::ops::Range`, found integer | @@ -19,7 +19,7 @@ error[E0308]: mismatched types --> $DIR/exclusive_range_pattern_syntax_collision3.rs:5:15 | LL | match [5..4, 99..105, 43..44] { - | ----------------------- this match expression has type `std::ops::Range<{integer}>` + | ----------------------- this expression has type `std::ops::Range<{integer}>` LL | [..9, 99..100, _] => {}, | ^^ --- this is of type `{integer}` | | diff --git a/src/test/ui/issues/issue-11844.stderr b/src/test/ui/issues/issue-11844.stderr index 1b22d6f45cf20..57533ba5e370b 100644 --- a/src/test/ui/issues/issue-11844.stderr +++ b/src/test/ui/issues/issue-11844.stderr @@ -2,7 +2,7 @@ error[E0308]: mismatched types --> $DIR/issue-11844.rs:6:9 | LL | match a { - | - this match expression has type `std::option::Option>` + | - this expression has type `std::option::Option>` LL | Ok(a) => | ^^^^^ expected enum `std::option::Option`, found enum `std::result::Result` | diff --git a/src/test/ui/issues/issue-12552.stderr b/src/test/ui/issues/issue-12552.stderr index ecafef259d3c9..60c4cceac51be 100644 --- a/src/test/ui/issues/issue-12552.stderr +++ b/src/test/ui/issues/issue-12552.stderr @@ -2,7 +2,7 @@ error[E0308]: mismatched types --> $DIR/issue-12552.rs:6:5 | LL | match t { - | - this match expression has type `std::result::Result<_, {integer}>` + | - this expression has type `std::result::Result<_, {integer}>` LL | Some(k) => match k { | ^^^^^^^ expected enum `std::result::Result`, found enum `std::option::Option` | diff --git a/src/test/ui/issues/issue-13466.stderr b/src/test/ui/issues/issue-13466.stderr index fc20615757aa8..52d9e2a91b971 100644 --- a/src/test/ui/issues/issue-13466.stderr +++ b/src/test/ui/issues/issue-13466.stderr @@ -2,7 +2,7 @@ error[E0308]: mismatched types --> $DIR/issue-13466.rs:8:9 | LL | let _x: usize = match Some(1) { - | ------- this match expression has type `std::option::Option<{integer}>` + | ------- this expression has type `std::option::Option<{integer}>` LL | Ok(u) => u, | ^^^^^ expected enum `std::option::Option`, found enum `std::result::Result` | @@ -13,7 +13,7 @@ error[E0308]: mismatched types --> $DIR/issue-13466.rs:14:9 | LL | let _x: usize = match Some(1) { - | ------- this match expression has type `std::option::Option<{integer}>` + | ------- this expression has type `std::option::Option<{integer}>` ... LL | Err(e) => panic!(e) | ^^^^^^ expected enum `std::option::Option`, found enum `std::result::Result` diff --git a/src/test/ui/issues/issue-15896.stderr b/src/test/ui/issues/issue-15896.stderr index f553be9df55eb..0ad49ea1e7fe5 100644 --- a/src/test/ui/issues/issue-15896.stderr +++ b/src/test/ui/issues/issue-15896.stderr @@ -2,7 +2,7 @@ error[E0308]: mismatched types --> $DIR/issue-15896.rs:11:11 | LL | let u = match e { - | - this match expression has type `main::R` + | - this expression has type `main::R` LL | E::B( LL | Tau{t: x}, | ^^^^^^^^^ expected enum `main::R`, found struct `main::Tau` diff --git a/src/test/ui/issues/issue-16401.stderr b/src/test/ui/issues/issue-16401.stderr index d3d6108be9d1d..f8ea0907099a5 100644 --- a/src/test/ui/issues/issue-16401.stderr +++ b/src/test/ui/issues/issue-16401.stderr @@ -2,7 +2,7 @@ error[E0308]: mismatched types --> $DIR/issue-16401.rs:8:9 | LL | match () { - | -- this match expression has type `()` + | -- this expression has type `()` LL | Slice { data: data, len: len } => (), | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `()`, found struct `Slice` | diff --git a/src/test/ui/issues/issue-3680.stderr b/src/test/ui/issues/issue-3680.stderr index 8856f0e3a4844..713e4b5ccd575 100644 --- a/src/test/ui/issues/issue-3680.stderr +++ b/src/test/ui/issues/issue-3680.stderr @@ -2,7 +2,7 @@ error[E0308]: mismatched types --> $DIR/issue-3680.rs:3:9 | LL | match None { - | ---- this match expression has type `std::option::Option<_>` + | ---- this expression has type `std::option::Option<_>` LL | Err(_) => () | ^^^^^^ expected enum `std::option::Option`, found enum `std::result::Result` | diff --git a/src/test/ui/issues/issue-5100.stderr b/src/test/ui/issues/issue-5100.stderr index 9e1011496c45d..c47e8689436ee 100644 --- a/src/test/ui/issues/issue-5100.stderr +++ b/src/test/ui/issues/issue-5100.stderr @@ -29,7 +29,7 @@ error[E0308]: mismatched types --> $DIR/issue-5100.rs:33:9 | LL | match (true, false) { - | ------------- this match expression has type `(bool, bool)` + | ------------- this expression has type `(bool, bool)` LL | box (true, false) => () | ^^^^^^^^^^^^^^^^^ expected tuple, found struct `std::boxed::Box` | diff --git a/src/test/ui/issues/issue-5358-1.stderr b/src/test/ui/issues/issue-5358-1.stderr index ec79d874d0339..314d1fddbd76a 100644 --- a/src/test/ui/issues/issue-5358-1.stderr +++ b/src/test/ui/issues/issue-5358-1.stderr @@ -2,7 +2,7 @@ error[E0308]: mismatched types --> $DIR/issue-5358-1.rs:6:9 | LL | match S(Either::Left(5)) { - | ------------------ this match expression has type `S` + | ------------------ this expression has type `S` LL | Either::Right(_) => {} | ^^^^^^^^^^^^^^^^ expected struct `S`, found enum `Either` | diff --git a/src/test/ui/issues/issue-57741-1.stderr b/src/test/ui/issues/issue-57741-1.stderr index db6fa9db8ff47..a4f1ac94825d5 100644 --- a/src/test/ui/issues/issue-57741-1.stderr +++ b/src/test/ui/issues/issue-57741-1.stderr @@ -2,7 +2,7 @@ error[E0308]: mismatched types --> $DIR/issue-57741-1.rs:14:9 | LL | let y = match x { - | - this match expression has type `std::boxed::Box` + | - this expression has type `std::boxed::Box` LL | S::A { a } | S::B { b: a } => a, | ^^^^^^^^^^ expected struct `std::boxed::Box`, found enum `S` | @@ -13,7 +13,7 @@ error[E0308]: mismatched types --> $DIR/issue-57741-1.rs:14:22 | LL | let y = match x { - | - this match expression has type `std::boxed::Box` + | - this expression has type `std::boxed::Box` LL | S::A { a } | S::B { b: a } => a, | ^^^^^^^^^^^^^ expected struct `std::boxed::Box`, found enum `S` | diff --git a/src/test/ui/issues/issue-57741.stderr b/src/test/ui/issues/issue-57741.stderr index c36dea7bf5547..6f9e5b08a833f 100644 --- a/src/test/ui/issues/issue-57741.stderr +++ b/src/test/ui/issues/issue-57741.stderr @@ -4,7 +4,7 @@ error[E0308]: mismatched types LL | let y = match x { | - | | - | this match expression has type `std::boxed::Box` + | this expression has type `std::boxed::Box` | help: consider dereferencing the boxed value: `*x` LL | T::A(a) | T::B(a) => a, | ^^^^^^^ expected struct `std::boxed::Box`, found enum `T` @@ -18,7 +18,7 @@ error[E0308]: mismatched types LL | let y = match x { | - | | - | this match expression has type `std::boxed::Box` + | this expression has type `std::boxed::Box` | help: consider dereferencing the boxed value: `*x` LL | T::A(a) | T::B(a) => a, | ^^^^^^^ expected struct `std::boxed::Box`, found enum `T` @@ -32,7 +32,7 @@ error[E0308]: mismatched types LL | let y = match x { | - | | - | this match expression has type `std::boxed::Box` + | this expression has type `std::boxed::Box` | help: consider dereferencing the boxed value: `*x` LL | S::A { a } | S::B { b: a } => a, | ^^^^^^^^^^ expected struct `std::boxed::Box`, found enum `S` @@ -46,7 +46,7 @@ error[E0308]: mismatched types LL | let y = match x { | - | | - | this match expression has type `std::boxed::Box` + | this expression has type `std::boxed::Box` | help: consider dereferencing the boxed value: `*x` LL | S::A { a } | S::B { b: a } => a, | ^^^^^^^^^^^^^ expected struct `std::boxed::Box`, found enum `S` diff --git a/src/test/ui/issues/issue-7092.stderr b/src/test/ui/issues/issue-7092.stderr index 05c00da16b1b1..590dd40c65364 100644 --- a/src/test/ui/issues/issue-7092.stderr +++ b/src/test/ui/issues/issue-7092.stderr @@ -2,7 +2,7 @@ error[E0308]: mismatched types --> $DIR/issue-7092.rs:6:9 | LL | match x { - | - this match expression has type `Whatever` + | - this expression has type `Whatever` LL | Some(field) => | ^^^^^^^^^^^ expected enum `Whatever`, found enum `std::option::Option` | diff --git a/src/test/ui/match/match-struct.stderr b/src/test/ui/match/match-struct.stderr index c23451d51ec5a..a475bd5e5819c 100644 --- a/src/test/ui/match/match-struct.stderr +++ b/src/test/ui/match/match-struct.stderr @@ -2,7 +2,7 @@ error[E0308]: mismatched types --> $DIR/match-struct.rs:6:9 | LL | match (S { a: 1 }) { - | ------------ this match expression has type `S` + | ------------ this expression has type `S` LL | E::C(_) => (), | ^^^^^^^ expected struct `S`, found enum `E` diff --git a/src/test/ui/match/match-tag-unary.stderr b/src/test/ui/match/match-tag-unary.stderr index db5dcd2be3b51..31f77bdff8b1f 100644 --- a/src/test/ui/match/match-tag-unary.stderr +++ b/src/test/ui/match/match-tag-unary.stderr @@ -4,7 +4,7 @@ error[E0308]: mismatched types LL | fn main() { let x: A = A::A(0); match x { B::B(y) => { } } } | - ^^^^^^^ expected enum `A`, found enum `B` | | - | this match expression has type `A` + | this expression has type `A` error: aborting due to previous error diff --git a/src/test/ui/parser/pat-tuple-5.stderr b/src/test/ui/parser/pat-tuple-5.stderr index 5b0253cd2738a..8ff4f948a05ec 100644 --- a/src/test/ui/parser/pat-tuple-5.stderr +++ b/src/test/ui/parser/pat-tuple-5.stderr @@ -17,7 +17,7 @@ error[E0308]: mismatched types --> $DIR/pat-tuple-5.rs:5:10 | LL | match (0, 1) { - | ------ this match expression has type `({integer}, {integer})` + | ------ this expression has type `({integer}, {integer})` LL | (PAT ..) => {} | ^^^ expected tuple, found `u8` | diff --git a/src/test/ui/pattern/pattern-error-continue.stderr b/src/test/ui/pattern/pattern-error-continue.stderr index 2f9fe1981bcbc..60f76796c0396 100644 --- a/src/test/ui/pattern/pattern-error-continue.stderr +++ b/src/test/ui/pattern/pattern-error-continue.stderr @@ -28,7 +28,7 @@ error[E0308]: mismatched types --> $DIR/pattern-error-continue.rs:22:9 | LL | match 'c' { - | --- this match expression has type `char` + | --- this expression has type `char` LL | S { .. } => (), | ^^^^^^^^ expected `char`, found struct `S` diff --git a/src/test/ui/pattern/pattern-tyvar.stderr b/src/test/ui/pattern/pattern-tyvar.stderr index b2afeacdf68c2..1e671e8d8eff3 100644 --- a/src/test/ui/pattern/pattern-tyvar.stderr +++ b/src/test/ui/pattern/pattern-tyvar.stderr @@ -2,7 +2,7 @@ error[E0308]: mismatched types --> $DIR/pattern-tyvar.rs:5:18 | LL | match t { - | - this match expression has type `std::option::Option>` + | - this expression has type `std::option::Option>` LL | Bar::T1(_, Some::(x)) => { | ^^^^^^^^^^^^^^^^ expected struct `std::vec::Vec`, found `isize` | diff --git a/src/test/ui/rfc-2497-if-let-chains/disallowed-positions.stderr b/src/test/ui/rfc-2497-if-let-chains/disallowed-positions.stderr index 1143bddfe45a3..a69011d745080 100644 --- a/src/test/ui/rfc-2497-if-let-chains/disallowed-positions.stderr +++ b/src/test/ui/rfc-2497-if-let-chains/disallowed-positions.stderr @@ -630,7 +630,7 @@ error[E0308]: mismatched types --> $DIR/disallowed-positions.rs:67:12 | LL | if let Range { start: _, end: _ } = true..true && false {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ ---- this match expression has type `bool` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ ---- this expression has type `bool` | | | expected `bool`, found struct `std::ops::Range` | @@ -650,7 +650,7 @@ error[E0308]: mismatched types --> $DIR/disallowed-positions.rs:71:12 | LL | if let Range { start: _, end: _ } = true..true || false {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ ---- this match expression has type `bool` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ ---- this expression has type `bool` | | | expected `bool`, found struct `std::ops::Range` | @@ -697,7 +697,7 @@ error[E0308]: mismatched types --> $DIR/disallowed-positions.rs:86:12 | LL | if let Range { start: true, end } = t..&&false {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ - this match expression has type `bool` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ - this expression has type `bool` | | | expected `bool`, found struct `std::ops::Range` | @@ -818,7 +818,7 @@ error[E0308]: mismatched types --> $DIR/disallowed-positions.rs:131:15 | LL | while let Range { start: _, end: _ } = true..true && false {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ ---- this match expression has type `bool` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ ---- this expression has type `bool` | | | expected `bool`, found struct `std::ops::Range` | @@ -838,7 +838,7 @@ error[E0308]: mismatched types --> $DIR/disallowed-positions.rs:135:15 | LL | while let Range { start: _, end: _ } = true..true || false {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ ---- this match expression has type `bool` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ ---- this expression has type `bool` | | | expected `bool`, found struct `std::ops::Range` | @@ -885,7 +885,7 @@ error[E0308]: mismatched types --> $DIR/disallowed-positions.rs:150:15 | LL | while let Range { start: true, end } = t..&&false {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ - this match expression has type `bool` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ - this expression has type `bool` | | | expected `bool`, found struct `std::ops::Range` | @@ -961,7 +961,7 @@ error[E0308]: mismatched types --> $DIR/disallowed-positions.rs:198:10 | LL | (let Range { start: _, end: _ } = true..true || false); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ ---- this match expression has type `bool` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ ---- this expression has type `bool` | | | expected `bool`, found struct `std::ops::Range` | diff --git a/src/test/ui/structs/structure-constructor-type-mismatch.stderr b/src/test/ui/structs/structure-constructor-type-mismatch.stderr index 4bd3acac532df..8cfa118a2dac2 100644 --- a/src/test/ui/structs/structure-constructor-type-mismatch.stderr +++ b/src/test/ui/structs/structure-constructor-type-mismatch.stderr @@ -86,7 +86,7 @@ error[E0308]: mismatched types --> $DIR/structure-constructor-type-mismatch.rs:54:9 | LL | match (Point { x: 1, y: 2 }) { - | ---------------------- this match expression has type `Point<{integer}>` + | ---------------------- this expression has type `Point<{integer}>` LL | PointF:: { .. } => {} | ^^^^^^^^^^^^^^^^^^^^ expected integer, found `f32` | @@ -97,7 +97,7 @@ error[E0308]: mismatched types --> $DIR/structure-constructor-type-mismatch.rs:59:9 | LL | match (Point { x: 1, y: 2 }) { - | ---------------------- this match expression has type `Point<{integer}>` + | ---------------------- this expression has type `Point<{integer}>` LL | PointF { .. } => {} | ^^^^^^^^^^^^^ expected integer, found `f32` | @@ -108,7 +108,7 @@ error[E0308]: mismatched types --> $DIR/structure-constructor-type-mismatch.rs:67:9 | LL | match (Pair { x: 1, y: 2 }) { - | --------------------- this match expression has type `Pair<{integer}, {integer}>` + | --------------------- this expression has type `Pair<{integer}, {integer}>` LL | PairF:: { .. } => {} | ^^^^^^^^^^^^^^^^^^^ expected integer, found `f32` | From 960acb044bcefc46520cee263b6877160fd296ca Mon Sep 17 00:00:00 2001 From: Mazdak Farrokhzad Date: Mon, 30 Dec 2019 07:27:56 +0100 Subject: [PATCH 03/10] Show scrutinee expr type for struct fields. TODO: The type is wrong and will be fixed in later commits. --- src/librustc_typeck/check/pat.rs | 15 ++++++++++++--- .../ui/pattern/pat-struct-field-expr-has-type.rs | 9 +++++++++ .../pattern/pat-struct-field-expr-has-type.stderr | 14 ++++++++++++++ 3 files changed, 35 insertions(+), 3 deletions(-) create mode 100644 src/test/ui/pattern/pat-struct-field-expr-has-type.rs create mode 100644 src/test/ui/pattern/pat-struct-field-expr-has-type.stderr diff --git a/src/librustc_typeck/check/pat.rs b/src/librustc_typeck/check/pat.rs index 397f8682ede73..1f374c3fe2089 100644 --- a/src/librustc_typeck/check/pat.rs +++ b/src/librustc_typeck/check/pat.rs @@ -577,8 +577,16 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { self.demand_eqtype_pat(pat.span, expected, pat_ty, discrim_span); // Type-check subpatterns. - if self.check_struct_pat_fields(pat_ty, pat.hir_id, pat.span, variant, fields, etc, def_bm) - { + if self.check_struct_pat_fields( + pat_ty, + pat.hir_id, + pat.span, + variant, + fields, + etc, + def_bm, + discrim_span, + ) { pat_ty } else { self.tcx.types.err @@ -859,6 +867,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { fields: &'tcx [hir::FieldPat<'tcx>], etc: bool, def_bm: BindingMode, + discrim_span: Option, ) -> bool { let tcx = self.tcx; @@ -908,7 +917,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } }; - self.check_pat(&field.pat, field_ty, def_bm, None); + self.check_pat(&field.pat, field_ty, def_bm, discrim_span); } let mut unmentioned_fields = variant diff --git a/src/test/ui/pattern/pat-struct-field-expr-has-type.rs b/src/test/ui/pattern/pat-struct-field-expr-has-type.rs new file mode 100644 index 0000000000000..1d18214de7f08 --- /dev/null +++ b/src/test/ui/pattern/pat-struct-field-expr-has-type.rs @@ -0,0 +1,9 @@ +struct S { + f: u8, +} + +fn main() { + match (S { f: 42 }) { + S { f: Ok(_) } => {} //~ ERROR mismatched types + } +} diff --git a/src/test/ui/pattern/pat-struct-field-expr-has-type.stderr b/src/test/ui/pattern/pat-struct-field-expr-has-type.stderr new file mode 100644 index 0000000000000..7962c376a92a8 --- /dev/null +++ b/src/test/ui/pattern/pat-struct-field-expr-has-type.stderr @@ -0,0 +1,14 @@ +error[E0308]: mismatched types + --> $DIR/pat-struct-field-expr-has-type.rs:7:16 + | +LL | match (S { f: 42 }) { + | ------------- this expression has type `u8` +LL | S { f: Ok(_) } => {} + | ^^^^^ expected `u8`, found enum `std::result::Result` + | + = note: expected type `u8` + found enum `std::result::Result<_, _>` + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0308`. From e952377ddc7bdddfee03ee09f3530a1c025f1d99 Mon Sep 17 00:00:00 2001 From: Mazdak Farrokhzad Date: Mon, 30 Dec 2019 07:42:46 +0100 Subject: [PATCH 04/10] MatchExpressionArmPattern -> Pattern Current name is too specific for incoming changes. --- src/librustc/infer/error_reporting/mod.rs | 2 +- src/librustc/traits/error_reporting.rs | 2 +- src/librustc/traits/mod.rs | 4 ++-- src/librustc/traits/structural_impls.rs | 4 +--- src/librustc_typeck/check/demand.rs | 5 +---- 5 files changed, 6 insertions(+), 11 deletions(-) diff --git a/src/librustc/infer/error_reporting/mod.rs b/src/librustc/infer/error_reporting/mod.rs index f0f0e2cdeb9c1..ae629adf8fb53 100644 --- a/src/librustc/infer/error_reporting/mod.rs +++ b/src/librustc/infer/error_reporting/mod.rs @@ -581,7 +581,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { exp_found: Option>>, ) { match cause.code { - ObligationCauseCode::MatchExpressionArmPattern { span, ty } => { + ObligationCauseCode::Pattern { span, ty } => { if ty.is_suggestable() { // don't show type `_` err.span_label(span, format!("this expression has type `{}`", ty)); diff --git a/src/librustc/traits/error_reporting.rs b/src/librustc/traits/error_reporting.rs index 878675f981259..5819e7aa5c25d 100644 --- a/src/librustc/traits/error_reporting.rs +++ b/src/librustc/traits/error_reporting.rs @@ -2580,7 +2580,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { match *cause_code { ObligationCauseCode::ExprAssignable | ObligationCauseCode::MatchExpressionArm { .. } - | ObligationCauseCode::MatchExpressionArmPattern { .. } + | ObligationCauseCode::Pattern { .. } | ObligationCauseCode::IfExpression { .. } | ObligationCauseCode::IfExpressionWithNoElse | ObligationCauseCode::MainFunctionType diff --git a/src/librustc/traits/mod.rs b/src/librustc/traits/mod.rs index e6ecf1b676e85..6142dc25f2228 100644 --- a/src/librustc/traits/mod.rs +++ b/src/librustc/traits/mod.rs @@ -249,8 +249,8 @@ pub enum ObligationCauseCode<'tcx> { /// Computing common supertype in the arms of a match expression MatchExpressionArm(Box>), - /// Computing common supertype in the pattern guard for the arms of a match expression - MatchExpressionArmPattern { + /// Type error arising from type checking a pattern against an expected type. + Pattern { span: Span, ty: Ty<'tcx>, }, diff --git a/src/librustc/traits/structural_impls.rs b/src/librustc/traits/structural_impls.rs index ed0842d80988f..cfc27438b50fd 100644 --- a/src/librustc/traits/structural_impls.rs +++ b/src/librustc/traits/structural_impls.rs @@ -521,9 +521,7 @@ impl<'a, 'tcx> Lift<'tcx> for traits::ObligationCauseCode<'a> { discrim_hir_id, }) }), - super::MatchExpressionArmPattern { span, ty } => { - tcx.lift(&ty).map(|ty| super::MatchExpressionArmPattern { span, ty }) - } + super::Pattern { span, ty } => tcx.lift(&ty).map(|ty| super::Pattern { span, ty }), super::IfExpression(box super::IfExpressionCause { then, outer, semicolon }) => { Some(super::IfExpression(box super::IfExpressionCause { then, outer, semicolon })) } diff --git a/src/librustc_typeck/check/demand.rs b/src/librustc_typeck/check/demand.rs index 68f2943e9e1d2..c11bd6704e4c3 100644 --- a/src/librustc_typeck/check/demand.rs +++ b/src/librustc_typeck/check/demand.rs @@ -87,10 +87,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { match_expr_span: Option, ) -> Option> { let cause = if let Some(span) = match_expr_span { - self.cause( - cause_span, - ObligationCauseCode::MatchExpressionArmPattern { span, ty: expected }, - ) + self.cause(cause_span, ObligationCauseCode::Pattern { span, ty: expected }) } else { self.misc(cause_span) }; From 6137ad49e45713c7bdd3703814829d6362bf1dd1 Mon Sep 17 00:00:00 2001 From: Mazdak Farrokhzad Date: Mon, 30 Dec 2019 07:48:16 +0100 Subject: [PATCH 05/10] move demand_eqtype_pat* to pat.rs --- src/librustc_typeck/check/demand.rs | 28 +--------------------------- src/librustc_typeck/check/pat.rs | 29 +++++++++++++++++++++++++++++ 2 files changed, 30 insertions(+), 27 deletions(-) diff --git a/src/librustc_typeck/check/demand.rs b/src/librustc_typeck/check/demand.rs index c11bd6704e4c3..8120183e6e135 100644 --- a/src/librustc_typeck/check/demand.rs +++ b/src/librustc_typeck/check/demand.rs @@ -1,6 +1,6 @@ use crate::check::FnCtxt; use rustc::infer::InferOk; -use rustc::traits::{self, ObligationCause, ObligationCauseCode}; +use rustc::traits::{self, ObligationCause}; use errors::{Applicability, DiagnosticBuilder}; use rustc::hir::{self, is_range_literal, print, Node}; @@ -79,32 +79,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } } - pub fn demand_eqtype_pat_diag( - &self, - cause_span: Span, - expected: Ty<'tcx>, - actual: Ty<'tcx>, - match_expr_span: Option, - ) -> Option> { - let cause = if let Some(span) = match_expr_span { - self.cause(cause_span, ObligationCauseCode::Pattern { span, ty: expected }) - } else { - self.misc(cause_span) - }; - self.demand_eqtype_with_origin(&cause, expected, actual) - } - - pub fn demand_eqtype_pat( - &self, - cause_span: Span, - expected: Ty<'tcx>, - actual: Ty<'tcx>, - match_expr_span: Option, - ) { - self.demand_eqtype_pat_diag(cause_span, expected, actual, match_expr_span) - .map(|mut err| err.emit()); - } - pub fn demand_coerce( &self, expr: &hir::Expr<'_>, diff --git a/src/librustc_typeck/check/pat.rs b/src/librustc_typeck/check/pat.rs index 1f374c3fe2089..c7986311242b4 100644 --- a/src/librustc_typeck/check/pat.rs +++ b/src/librustc_typeck/check/pat.rs @@ -6,6 +6,7 @@ use rustc::hir::pat_util::EnumerateAndAdjustIterator; use rustc::hir::{self, HirId, Pat, PatKind}; use rustc::infer; use rustc::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind}; +use rustc::traits::Pattern; use rustc::ty::subst::GenericArg; use rustc::ty::{self, BindingMode, Ty, TypeFoldable}; use syntax::ast; @@ -29,6 +30,34 @@ pointers. If you encounter this error you should try to avoid dereferencing the You can read more about trait objects in the Trait Objects section of the Reference: \ https://doc.rust-lang.org/reference/types.html#trait-objects"; +impl<'tcx> FnCtxt<'_, 'tcx> { + fn demand_eqtype_pat_diag( + &self, + cause_span: Span, + expected: Ty<'tcx>, + actual: Ty<'tcx>, + match_expr_span: Option, + ) -> Option> { + let cause = if let Some(span) = match_expr_span { + self.cause(cause_span, Pattern { span, ty: expected }) + } else { + self.misc(cause_span) + }; + self.demand_eqtype_with_origin(&cause, expected, actual) + } + + fn demand_eqtype_pat( + &self, + cause_span: Span, + expected: Ty<'tcx>, + actual: Ty<'tcx>, + match_expr_span: Option, + ) { + self.demand_eqtype_pat_diag(cause_span, expected, actual, match_expr_span) + .map(|mut err| err.emit()); + } +} + impl<'a, 'tcx> FnCtxt<'a, 'tcx> { pub fn check_pat_top( &self, From f35840f77cbb496dc35645331318f4b52c9a5b2a Mon Sep 17 00:00:00 2001 From: Mazdak Farrokhzad Date: Mon, 30 Dec 2019 08:17:32 +0100 Subject: [PATCH 06/10] Pass the span of `` in `let = ;` when type checking ``. --- src/librustc_typeck/check/mod.rs | 10 +++++----- src/librustc_typeck/check/pat.rs | 9 ++------- src/test/ui/issues/issue-14541.stderr | 4 +++- src/test/ui/issues/issue-16338.stderr | 4 +++- src/test/ui/issues/issue-37026.stderr | 4 +++- ...ssue-67037-pat-tup-scrut-ty-diff-less-fields.stderr | 4 +++- 6 files changed, 19 insertions(+), 16 deletions(-) diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index c6c3ada49e312..583a0409fb9f4 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -4275,17 +4275,17 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } pub fn check_decl_local(&self, local: &'tcx hir::Local<'tcx>) { - let t = self.local_ty(local.span, local.hir_id).decl_ty; - self.write_ty(local.hir_id, t); + let ty = self.local_ty(local.span, local.hir_id).decl_ty; + self.write_ty(local.hir_id, ty); if let Some(ref init) = local.init { let init_ty = self.check_decl_initializer(local, &init); - self.overwrite_local_ty_if_err(local, t, init_ty); + self.overwrite_local_ty_if_err(local, ty, init_ty); } - self.check_pat_top(&local.pat, t, None); + self.check_pat_top(&local.pat, ty, local.init.map(|init| init.span)); let pat_ty = self.node_ty(local.pat.hir_id); - self.overwrite_local_ty_if_err(local, t, pat_ty); + self.overwrite_local_ty_if_err(local, ty, pat_ty); } fn overwrite_local_ty_if_err( diff --git a/src/librustc_typeck/check/pat.rs b/src/librustc_typeck/check/pat.rs index c7986311242b4..b18a7ac75a282 100644 --- a/src/librustc_typeck/check/pat.rs +++ b/src/librustc_typeck/check/pat.rs @@ -59,14 +59,9 @@ impl<'tcx> FnCtxt<'_, 'tcx> { } impl<'a, 'tcx> FnCtxt<'a, 'tcx> { - pub fn check_pat_top( - &self, - pat: &'tcx Pat<'tcx>, - expected: Ty<'tcx>, - discrim_span: Option, - ) { + pub fn check_pat_top(&self, pat: &'tcx Pat<'tcx>, expected: Ty<'tcx>, span: Option) { let def_bm = BindingMode::BindByValue(hir::Mutability::Not); - self.check_pat(pat, expected, def_bm, discrim_span); + self.check_pat(pat, expected, def_bm, span); } /// `discrim_span` argument having a `Span` indicates that this pattern is part of a match diff --git a/src/test/ui/issues/issue-14541.stderr b/src/test/ui/issues/issue-14541.stderr index c5512e03007df..cf155f428c6a0 100644 --- a/src/test/ui/issues/issue-14541.stderr +++ b/src/test/ui/issues/issue-14541.stderr @@ -2,7 +2,9 @@ error[E0308]: mismatched types --> $DIR/issue-14541.rs:5:9 | LL | let Vec3 { y: _, z: _ } = v; - | ^^^^^^^^^^^^^^^^^^^ expected struct `Vec2`, found struct `Vec3` + | ^^^^^^^^^^^^^^^^^^^ - this expression has type `Vec2` + | | + | expected struct `Vec2`, found struct `Vec3` error: aborting due to previous error diff --git a/src/test/ui/issues/issue-16338.stderr b/src/test/ui/issues/issue-16338.stderr index c35edb0c8c0e3..03eb93821b5f2 100644 --- a/src/test/ui/issues/issue-16338.stderr +++ b/src/test/ui/issues/issue-16338.stderr @@ -2,7 +2,9 @@ error[E0308]: mismatched types --> $DIR/issue-16338.rs:7:9 | LL | let Slice { data: data, len: len } = "foo"; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `str`, found struct `Slice` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ----- this expression has type `str` + | | + | expected `str`, found struct `Slice` | = note: expected type `str` found struct `Slice<_>` diff --git a/src/test/ui/issues/issue-37026.stderr b/src/test/ui/issues/issue-37026.stderr index 00952356b1830..361369e68bc08 100644 --- a/src/test/ui/issues/issue-37026.stderr +++ b/src/test/ui/issues/issue-37026.stderr @@ -8,7 +8,9 @@ error[E0308]: mismatched types --> $DIR/issue-37026.rs:7:9 | LL | let empty_struct::XEmpty6(..) = (); - | ^^^^^^^^^^^^^^^^^^^^^^^^^ expected `()`, found struct `empty_struct::XEmpty6` + | ^^^^^^^^^^^^^^^^^^^^^^^^^ -- this expression has type `()` + | | + | expected `()`, found struct `empty_struct::XEmpty6` error: aborting due to 2 previous errors diff --git a/src/test/ui/issues/issue-67037-pat-tup-scrut-ty-diff-less-fields.stderr b/src/test/ui/issues/issue-67037-pat-tup-scrut-ty-diff-less-fields.stderr index 521dd0256f7d5..6e8ea6bf618f2 100644 --- a/src/test/ui/issues/issue-67037-pat-tup-scrut-ty-diff-less-fields.stderr +++ b/src/test/ui/issues/issue-67037-pat-tup-scrut-ty-diff-less-fields.stderr @@ -2,7 +2,9 @@ error[E0308]: mismatched types --> $DIR/issue-67037-pat-tup-scrut-ty-diff-less-fields.rs:19:9 | LL | let P() = U {}; - | ^^^ expected struct `U`, found struct `P` + | ^^^ ---- this expression has type `U` + | | + | expected struct `U`, found struct `P` | = note: expected struct `U` found struct `P<_>` From d7e2f3aee5508538c5de14211ab5b31362e1164a Mon Sep 17 00:00:00 2001 From: Mazdak Farrokhzad Date: Mon, 30 Dec 2019 09:08:18 +0100 Subject: [PATCH 07/10] refactor and fix this-expression-has-type note --- src/librustc/infer/error_reporting/mod.rs | 1 + src/librustc_typeck/check/pat.rs | 173 +++++++++--------- src/test/ui/destructure-trait-ref.stderr | 4 +- ...sive_range_pattern_syntax_collision.stderr | 2 +- ...ive_range_pattern_syntax_collision2.stderr | 2 +- ...ive_range_pattern_syntax_collision3.stderr | 6 +- src/test/ui/issues/issue-15896.stderr | 2 +- src/test/ui/issues/issue-16338.stderr | 2 +- src/test/ui/mismatched_types/E0409.stderr | 2 + .../ui/or-patterns/already-bound-name.stderr | 4 +- .../ui/or-patterns/inconsistent-modes.stderr | 8 +- .../ui/or-patterns/or-pattern-mismatch.stderr | 2 +- src/test/ui/parser/recover-range-pats.stderr | 15 +- .../pat-struct-field-expr-has-type.stderr | 2 +- src/test/ui/pattern/pattern-tyvar.stderr | 2 +- .../resolve-inconsistent-binding-mode.stderr | 6 + .../resolve/resolve-inconsistent-names.stderr | 2 + .../disallowed-positions.stderr | 4 +- 18 files changed, 135 insertions(+), 104 deletions(-) diff --git a/src/librustc/infer/error_reporting/mod.rs b/src/librustc/infer/error_reporting/mod.rs index ae629adf8fb53..5c561a87b0547 100644 --- a/src/librustc/infer/error_reporting/mod.rs +++ b/src/librustc/infer/error_reporting/mod.rs @@ -582,6 +582,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { ) { match cause.code { ObligationCauseCode::Pattern { span, ty } => { + let ty = self.resolve_vars_if_possible(&ty); if ty.is_suggestable() { // don't show type `_` err.span_label(span, format!("this expression has type `{}`", ty)); diff --git a/src/librustc_typeck/check/pat.rs b/src/librustc_typeck/check/pat.rs index b18a7ac75a282..a3ef41f0de5b5 100644 --- a/src/librustc_typeck/check/pat.rs +++ b/src/librustc_typeck/check/pat.rs @@ -30,16 +30,48 @@ pointers. If you encounter this error you should try to avoid dereferencing the You can read more about trait objects in the Trait Objects section of the Reference: \ https://doc.rust-lang.org/reference/types.html#trait-objects"; +/// Information about the expected type at the top level of type checking a pattern. +/// +/// **NOTE:** This is only for use by diagnostics. Do NOT use for type checking logic! +#[derive(Copy, Clone)] +struct TopInfo<'tcx> { + /// The `expected` type at the top level of type checking a pattern. + expected: Ty<'tcx>, + /// The span giving rise to the `expected` type, if one could be provided. + /// + /// This is the span of the scrutinee as in: + /// + /// - `match scrutinee { ... }` + /// - `let _ = scrutinee;` + /// + /// This is used to point to add context in type errors. + /// In the following example, `span` corresponds to the `a + b` expression: + /// + /// ```text + /// error[E0308]: mismatched types + /// --> src/main.rs:L:C + /// | + /// L | let temp: usize = match a + b { + /// | ----- this expression has type `usize` + /// L | Ok(num) => num, + /// | ^^^^^^^ expected `usize`, found enum `std::result::Result` + /// | + /// = note: expected type `usize` + /// found type `std::result::Result<_, _>` + /// ``` + span: Option, +} + impl<'tcx> FnCtxt<'_, 'tcx> { fn demand_eqtype_pat_diag( &self, cause_span: Span, expected: Ty<'tcx>, actual: Ty<'tcx>, - match_expr_span: Option, + ti: TopInfo<'tcx>, ) -> Option> { - let cause = if let Some(span) = match_expr_span { - self.cause(cause_span, Pattern { span, ty: expected }) + let cause = if let Some(span) = ti.span { + self.cause(cause_span, Pattern { span, ty: ti.expected }) } else { self.misc(cause_span) }; @@ -51,41 +83,33 @@ impl<'tcx> FnCtxt<'_, 'tcx> { cause_span: Span, expected: Ty<'tcx>, actual: Ty<'tcx>, - match_expr_span: Option, + ti: TopInfo<'tcx>, ) { - self.demand_eqtype_pat_diag(cause_span, expected, actual, match_expr_span) - .map(|mut err| err.emit()); + self.demand_eqtype_pat_diag(cause_span, expected, actual, ti).map(|mut err| err.emit()); } } impl<'a, 'tcx> FnCtxt<'a, 'tcx> { + /// Type check the given top level pattern against the `expected` type. + /// + /// If a `Some(span)` is provided, then the `span` represents the scrutinee's span. + /// The scrutinee is found in e.g. `match scrutinee { ... }` and `let pat = scrutinee;`. pub fn check_pat_top(&self, pat: &'tcx Pat<'tcx>, expected: Ty<'tcx>, span: Option) { let def_bm = BindingMode::BindByValue(hir::Mutability::Not); - self.check_pat(pat, expected, def_bm, span); + self.check_pat(pat, expected, def_bm, TopInfo { expected, span }); } - /// `discrim_span` argument having a `Span` indicates that this pattern is part of a match - /// expression arm guard, and it points to the match discriminant to add context in type errors. - /// In the following example, `discrim_span` corresponds to the `a + b` expression: + /// Type check the given `pat` against the `expected` type + /// with the provided `def_bm` (default binding mode). /// - /// ```text - /// error[E0308]: mismatched types - /// --> src/main.rs:5:9 - /// | - /// 4 | let temp: usize = match a + b { - /// | ----- this expression has type `usize` - /// 5 | Ok(num) => num, - /// | ^^^^^^^ expected `usize`, found enum `std::result::Result` - /// | - /// = note: expected type `usize` - /// found type `std::result::Result<_, _>` - /// ``` + /// Outside of this module, `check_pat_top` should always be used. + /// Conversely, inside this module, `check_pat_top` should never be used. fn check_pat( &self, pat: &'tcx Pat<'tcx>, expected: Ty<'tcx>, def_bm: BindingMode, - discrim_span: Option, + ti: TopInfo<'tcx>, ) { debug!("check_pat(pat={:?},expected={:?},def_bm={:?})", pat, expected, def_bm); @@ -98,48 +122,40 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let ty = match pat.kind { PatKind::Wild => expected, - PatKind::Lit(lt) => self.check_pat_lit(pat.span, lt, expected, discrim_span), + PatKind::Lit(lt) => self.check_pat_lit(pat.span, lt, expected, ti), PatKind::Range(begin, end, _) => { - match self.check_pat_range(pat.span, begin, end, expected, discrim_span) { + match self.check_pat_range(pat.span, begin, end, expected, ti) { None => return, Some(ty) => ty, } } PatKind::Binding(ba, var_id, _, sub) => { - self.check_pat_ident(pat, ba, var_id, sub, expected, def_bm, discrim_span) + self.check_pat_ident(pat, ba, var_id, sub, expected, def_bm, ti) + } + PatKind::TupleStruct(ref qpath, subpats, ddpos) => { + self.check_pat_tuple_struct(pat, qpath, subpats, ddpos, expected, def_bm, ti) } - PatKind::TupleStruct(ref qpath, subpats, ddpos) => self.check_pat_tuple_struct( - pat, - qpath, - subpats, - ddpos, - expected, - def_bm, - discrim_span, - ), PatKind::Path(ref qpath) => { self.check_pat_path(pat, path_resolution.unwrap(), qpath, expected) } PatKind::Struct(ref qpath, fields, etc) => { - self.check_pat_struct(pat, qpath, fields, etc, expected, def_bm, discrim_span) + self.check_pat_struct(pat, qpath, fields, etc, expected, def_bm, ti) } PatKind::Or(pats) => { for pat in pats { - self.check_pat(pat, expected, def_bm, discrim_span); + self.check_pat(pat, expected, def_bm, ti); } expected } PatKind::Tuple(elements, ddpos) => { - self.check_pat_tuple(pat.span, elements, ddpos, expected, def_bm, discrim_span) - } - PatKind::Box(inner) => { - self.check_pat_box(pat.span, inner, expected, def_bm, discrim_span) + self.check_pat_tuple(pat.span, elements, ddpos, expected, def_bm, ti) } + PatKind::Box(inner) => self.check_pat_box(pat.span, inner, expected, def_bm, ti), PatKind::Ref(inner, mutbl) => { - self.check_pat_ref(pat, inner, mutbl, expected, def_bm, discrim_span) + self.check_pat_ref(pat, inner, mutbl, expected, def_bm, ti) } PatKind::Slice(before, slice, after) => { - self.check_pat_slice(pat.span, before, slice, after, expected, def_bm, discrim_span) + self.check_pat_slice(pat.span, before, slice, after, expected, def_bm, ti) } }; @@ -316,7 +332,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { span: Span, lt: &hir::Expr<'tcx>, expected: Ty<'tcx>, - discrim_span: Option, + ti: TopInfo<'tcx>, ) -> Ty<'tcx> { // We've already computed the type above (when checking for a non-ref pat), // so avoid computing it again. @@ -350,7 +366,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // then that's equivalent to there existing a LUB. if let Some(mut err) = self.demand_suptype_diag(span, expected, pat_ty) { err.emit_unless( - discrim_span + ti.span .filter(|&s| { // In the case of `if`- and `while`-expressions we've already checked // that `scrutinee: bool`. We know that the pattern is `true`, @@ -370,7 +386,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { lhs: &'tcx hir::Expr<'tcx>, rhs: &'tcx hir::Expr<'tcx>, expected: Ty<'tcx>, - discrim_span: Option, + ti: TopInfo<'tcx>, ) -> Option> { let lhs_ty = self.check_expr(lhs); let rhs_ty = self.check_expr(rhs); @@ -391,7 +407,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // Subtyping doesn't matter here, as the value is some kind of scalar. let demand_eqtype = |x_span, y_span, x_ty, y_ty| { - self.demand_eqtype_pat_diag(x_span, expected, x_ty, discrim_span).map(|mut err| { + self.demand_eqtype_pat_diag(x_span, expected, x_ty, ti).map(|mut err| { self.endpoint_has_type(&mut err, y_span, y_ty); err.emit(); }); @@ -465,7 +481,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { sub: Option<&'tcx Pat<'tcx>>, expected: Ty<'tcx>, def_bm: BindingMode, - discrim_span: Option, + ti: TopInfo<'tcx>, ) -> Ty<'tcx> { // Determine the binding mode... let bm = match ba { @@ -495,17 +511,17 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { expected } }; - self.demand_eqtype_pat(pat.span, eq_ty, local_ty, discrim_span); + self.demand_eqtype_pat(pat.span, eq_ty, local_ty, ti); // If there are multiple arms, make sure they all agree on // what the type of the binding `x` ought to be. if var_id != pat.hir_id { let vt = self.local_ty(pat.span, var_id).decl_ty; - self.demand_eqtype_pat(pat.span, vt, local_ty, discrim_span); + self.demand_eqtype_pat(pat.span, vt, local_ty, ti); } if let Some(p) = sub { - self.check_pat(&p, expected, def_bm, discrim_span); + self.check_pat(&p, expected, def_bm, ti); } local_ty @@ -584,7 +600,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { etc: bool, expected: Ty<'tcx>, def_bm: BindingMode, - discrim_span: Option, + ti: TopInfo<'tcx>, ) -> Ty<'tcx> { // Resolve the path and check the definition for errors. let (variant, pat_ty) = if let Some(variant_ty) = self.check_struct_path(qpath, pat.hir_id) @@ -592,25 +608,18 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { variant_ty } else { for field in fields { - self.check_pat(&field.pat, self.tcx.types.err, def_bm, discrim_span); + self.check_pat(&field.pat, self.tcx.types.err, def_bm, ti); } return self.tcx.types.err; }; // Type-check the path. - self.demand_eqtype_pat(pat.span, expected, pat_ty, discrim_span); + self.demand_eqtype_pat(pat.span, expected, pat_ty, ti); // Type-check subpatterns. - if self.check_struct_pat_fields( - pat_ty, - pat.hir_id, - pat.span, - variant, - fields, - etc, - def_bm, - discrim_span, - ) { + if self + .check_struct_pat_fields(pat_ty, pat.hir_id, pat.span, variant, fields, etc, def_bm, ti) + { pat_ty } else { self.tcx.types.err @@ -660,12 +669,12 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ddpos: Option, expected: Ty<'tcx>, def_bm: BindingMode, - match_arm_pat_span: Option, + ti: TopInfo<'tcx>, ) -> Ty<'tcx> { let tcx = self.tcx; let on_error = || { for pat in subpats { - self.check_pat(&pat, tcx.types.err, def_bm, match_arm_pat_span); + self.check_pat(&pat, tcx.types.err, def_bm, ti); } }; let report_unexpected_res = |res: Res| { @@ -726,7 +735,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let pat_ty = pat_ty.no_bound_vars().expect("expected fn type"); // Type-check the tuple struct pattern against the expected type. - let diag = self.demand_eqtype_pat_diag(pat.span, expected, pat_ty, match_arm_pat_span); + let diag = self.demand_eqtype_pat_diag(pat.span, expected, pat_ty, ti); let had_err = diag.is_some(); diag.map(|mut err| err.emit()); @@ -740,7 +749,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { }; for (i, subpat) in subpats.iter().enumerate_and_adjust(variant.fields.len(), ddpos) { let field_ty = self.field_ty(subpat.span, &variant.fields[i], substs); - self.check_pat(&subpat, field_ty, def_bm, match_arm_pat_span); + self.check_pat(&subpat, field_ty, def_bm, ti); self.tcx.check_stability(variant.fields[i].did, Some(pat.hir_id), subpat.span); } @@ -844,7 +853,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ddpos: Option, expected: Ty<'tcx>, def_bm: BindingMode, - discrim_span: Option, + ti: TopInfo<'tcx>, ) -> Ty<'tcx> { let tcx = self.tcx; let mut expected_len = elements.len(); @@ -871,12 +880,12 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // further errors being emitted when using the bindings. #50333 let element_tys_iter = (0..max_len).map(|_| tcx.types.err); for (_, elem) in elements.iter().enumerate_and_adjust(max_len, ddpos) { - self.check_pat(elem, &tcx.types.err, def_bm, discrim_span); + self.check_pat(elem, &tcx.types.err, def_bm, ti); } tcx.mk_tup(element_tys_iter) } else { for (i, elem) in elements.iter().enumerate_and_adjust(max_len, ddpos) { - self.check_pat(elem, &element_tys[i].expect_ty(), def_bm, discrim_span); + self.check_pat(elem, &element_tys[i].expect_ty(), def_bm, ti); } pat_ty } @@ -891,7 +900,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { fields: &'tcx [hir::FieldPat<'tcx>], etc: bool, def_bm: BindingMode, - discrim_span: Option, + ti: TopInfo<'tcx>, ) -> bool { let tcx = self.tcx; @@ -941,7 +950,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } }; - self.check_pat(&field.pat, field_ty, def_bm, discrim_span); + self.check_pat(&field.pat, field_ty, def_bm, ti); } let mut unmentioned_fields = variant @@ -1118,7 +1127,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { inner: &'tcx Pat<'tcx>, expected: Ty<'tcx>, def_bm: BindingMode, - discrim_span: Option, + ti: TopInfo<'tcx>, ) -> Ty<'tcx> { let tcx = self.tcx; let (box_ty, inner_ty) = if self.check_dereferenceable(span, expected, &inner) { @@ -1129,12 +1138,12 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { span: inner.span, }); let box_ty = tcx.mk_box(inner_ty); - self.demand_eqtype_pat(span, expected, box_ty, discrim_span); + self.demand_eqtype_pat(span, expected, box_ty, ti); (box_ty, inner_ty) } else { (tcx.types.err, tcx.types.err) }; - self.check_pat(&inner, inner_ty, def_bm, discrim_span); + self.check_pat(&inner, inner_ty, def_bm, ti); box_ty } @@ -1145,7 +1154,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { mutbl: hir::Mutability, expected: Ty<'tcx>, def_bm: BindingMode, - discrim_span: Option, + ti: TopInfo<'tcx>, ) -> Ty<'tcx> { let tcx = self.tcx; let expected = self.shallow_resolve(expected); @@ -1180,7 +1189,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } else { (tcx.types.err, tcx.types.err) }; - self.check_pat(&inner, inner_ty, def_bm, discrim_span); + self.check_pat(&inner, inner_ty, def_bm, ti); rptr_ty } @@ -1209,7 +1218,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { after: &'tcx [&'tcx Pat<'tcx>], expected: Ty<'tcx>, def_bm: BindingMode, - discrim_span: Option, + ti: TopInfo<'tcx>, ) -> Ty<'tcx> { let err = self.tcx.types.err; let expected = self.structurally_resolved_type(span, expected); @@ -1234,15 +1243,15 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // Type check all the patterns before `slice`. for elt in before { - self.check_pat(&elt, inner_ty, def_bm, discrim_span); + self.check_pat(&elt, inner_ty, def_bm, ti); } // Type check the `slice`, if present, against its expected type. if let Some(slice) = slice { - self.check_pat(&slice, slice_ty, def_bm, discrim_span); + self.check_pat(&slice, slice_ty, def_bm, ti); } // Type check the elements after `slice`, if present. for elt in after { - self.check_pat(&elt, inner_ty, def_bm, discrim_span); + self.check_pat(&elt, inner_ty, def_bm, ti); } expected } diff --git a/src/test/ui/destructure-trait-ref.stderr b/src/test/ui/destructure-trait-ref.stderr index f77291969d2db..c78166f411d28 100644 --- a/src/test/ui/destructure-trait-ref.stderr +++ b/src/test/ui/destructure-trait-ref.stderr @@ -44,7 +44,9 @@ error[E0308]: mismatched types --> $DIR/destructure-trait-ref.rs:42:13 | LL | let box box x = box 1isize as Box; - | ^^^^^ expected trait `T`, found struct `std::boxed::Box` + | ^^^^^ ------------------------ this expression has type `std::boxed::Box` + | | + | expected trait `T`, found struct `std::boxed::Box` | = note: expected trait object `dyn T` found struct `std::boxed::Box<_>` diff --git a/src/test/ui/exclusive-range/exclusive_range_pattern_syntax_collision.stderr b/src/test/ui/exclusive-range/exclusive_range_pattern_syntax_collision.stderr index 580c80f66c3ca..76ae7241ff277 100644 --- a/src/test/ui/exclusive-range/exclusive_range_pattern_syntax_collision.stderr +++ b/src/test/ui/exclusive-range/exclusive_range_pattern_syntax_collision.stderr @@ -8,7 +8,7 @@ error[E0308]: mismatched types --> $DIR/exclusive_range_pattern_syntax_collision.rs:5:13 | LL | match [5..4, 99..105, 43..44] { - | ----------------------- this expression has type `std::ops::Range<{integer}>` + | ----------------------- this expression has type `[std::ops::Range<{integer}>; 3]` LL | [_, 99.., _] => {}, | ^^ expected struct `std::ops::Range`, found integer | diff --git a/src/test/ui/exclusive-range/exclusive_range_pattern_syntax_collision2.stderr b/src/test/ui/exclusive-range/exclusive_range_pattern_syntax_collision2.stderr index 88d45f16ff6c9..5c96f8041feb2 100644 --- a/src/test/ui/exclusive-range/exclusive_range_pattern_syntax_collision2.stderr +++ b/src/test/ui/exclusive-range/exclusive_range_pattern_syntax_collision2.stderr @@ -14,7 +14,7 @@ error[E0308]: mismatched types --> $DIR/exclusive_range_pattern_syntax_collision2.rs:5:13 | LL | match [5..4, 99..105, 43..44] { - | ----------------------- this expression has type `std::ops::Range<{integer}>` + | ----------------------- this expression has type `[std::ops::Range<{integer}>; 3]` LL | [_, 99..] => {}, | ^^ expected struct `std::ops::Range`, found integer | diff --git a/src/test/ui/exclusive-range/exclusive_range_pattern_syntax_collision3.stderr b/src/test/ui/exclusive-range/exclusive_range_pattern_syntax_collision3.stderr index 6abba7d7cab10..17e10324db181 100644 --- a/src/test/ui/exclusive-range/exclusive_range_pattern_syntax_collision3.stderr +++ b/src/test/ui/exclusive-range/exclusive_range_pattern_syntax_collision3.stderr @@ -8,7 +8,7 @@ error[E0308]: mismatched types --> $DIR/exclusive_range_pattern_syntax_collision3.rs:5:12 | LL | match [5..4, 99..105, 43..44] { - | ----------------------- this expression has type `std::ops::Range<{integer}>` + | ----------------------- this expression has type `[std::ops::Range<{integer}>; 3]` LL | [..9, 99..100, _] => {}, | ^ expected struct `std::ops::Range`, found integer | @@ -19,7 +19,7 @@ error[E0308]: mismatched types --> $DIR/exclusive_range_pattern_syntax_collision3.rs:5:15 | LL | match [5..4, 99..105, 43..44] { - | ----------------------- this expression has type `std::ops::Range<{integer}>` + | ----------------------- this expression has type `[std::ops::Range<{integer}>; 3]` LL | [..9, 99..100, _] => {}, | ^^ --- this is of type `{integer}` | | @@ -32,7 +32,7 @@ error[E0308]: mismatched types --> $DIR/exclusive_range_pattern_syntax_collision3.rs:5:19 | LL | match [5..4, 99..105, 43..44] { - | ----------------------- this match expression has type `std::ops::Range<{integer}>` + | ----------------------- this expression has type `[std::ops::Range<{integer}>; 3]` LL | [..9, 99..100, _] => {}, | -- ^^^ expected struct `std::ops::Range`, found integer | | diff --git a/src/test/ui/issues/issue-15896.stderr b/src/test/ui/issues/issue-15896.stderr index 0ad49ea1e7fe5..b3f0907b81d25 100644 --- a/src/test/ui/issues/issue-15896.stderr +++ b/src/test/ui/issues/issue-15896.stderr @@ -2,7 +2,7 @@ error[E0308]: mismatched types --> $DIR/issue-15896.rs:11:11 | LL | let u = match e { - | - this expression has type `main::R` + | - this expression has type `main::E` LL | E::B( LL | Tau{t: x}, | ^^^^^^^^^ expected enum `main::R`, found struct `main::Tau` diff --git a/src/test/ui/issues/issue-16338.stderr b/src/test/ui/issues/issue-16338.stderr index 03eb93821b5f2..6878600b02983 100644 --- a/src/test/ui/issues/issue-16338.stderr +++ b/src/test/ui/issues/issue-16338.stderr @@ -2,7 +2,7 @@ error[E0308]: mismatched types --> $DIR/issue-16338.rs:7:9 | LL | let Slice { data: data, len: len } = "foo"; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ----- this expression has type `str` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ----- this expression has type `&str` | | | expected `str`, found struct `Slice` | diff --git a/src/test/ui/mismatched_types/E0409.stderr b/src/test/ui/mismatched_types/E0409.stderr index 098fd74a39da6..2306fb352738f 100644 --- a/src/test/ui/mismatched_types/E0409.stderr +++ b/src/test/ui/mismatched_types/E0409.stderr @@ -9,6 +9,8 @@ LL | (0, ref y) | (y, 0) => {} error[E0308]: mismatched types --> $DIR/E0409.rs:5:23 | +LL | match x { + | - this expression has type `({integer}, {integer})` LL | (0, ref y) | (y, 0) => {} | ^ expected `&{integer}`, found integer diff --git a/src/test/ui/or-patterns/already-bound-name.stderr b/src/test/ui/or-patterns/already-bound-name.stderr index 360699a873938..948c91370d0d4 100644 --- a/src/test/ui/or-patterns/already-bound-name.stderr +++ b/src/test/ui/or-patterns/already-bound-name.stderr @@ -94,7 +94,9 @@ error[E0308]: mismatched types --> $DIR/already-bound-name.rs:33:31 | LL | let B(A(a, _) | B(a)) | A(a, A(a, _) | B(a)) = B(B(1)); - | ^ expected integer, found enum `E` + | ^ ------- this expression has type `E>` + | | + | expected integer, found enum `E` | = note: expected type `{integer}` found type `E<{integer}>` diff --git a/src/test/ui/or-patterns/inconsistent-modes.stderr b/src/test/ui/or-patterns/inconsistent-modes.stderr index 0a36ed5548e5b..80d914b8d236c 100644 --- a/src/test/ui/or-patterns/inconsistent-modes.stderr +++ b/src/test/ui/or-patterns/inconsistent-modes.stderr @@ -60,7 +60,9 @@ error[E0308]: mismatched types --> $DIR/inconsistent-modes.rs:13:25 | LL | let Ok(ref a) | Err(ref mut a): Result<&u8, &mut u8> = Ok(&0); - | ^^^^^^^^^ types differ in mutability + | ^^^^^^^^^ ------ this expression has type `std::result::Result<&u8, &mut u8>` + | | + | types differ in mutability | = note: expected type `&&u8` found type `&mut &mut u8` @@ -69,7 +71,9 @@ error[E0308]: mismatched types --> $DIR/inconsistent-modes.rs:16:31 | LL | let Ok((ref a, b)) | Err((ref mut a, ref b)) = Ok((0, &0)); - | ^^^^^^^^^ types differ in mutability + | ^^^^^^^^^ ----------- this expression has type `std::result::Result<({integer}, &{integer}), (_, _)>` + | | + | types differ in mutability | = note: expected type `&{integer}` found type `&mut _` diff --git a/src/test/ui/or-patterns/or-pattern-mismatch.stderr b/src/test/ui/or-patterns/or-pattern-mismatch.stderr index 253f3ef772525..bc288e0625075 100644 --- a/src/test/ui/or-patterns/or-pattern-mismatch.stderr +++ b/src/test/ui/or-patterns/or-pattern-mismatch.stderr @@ -2,7 +2,7 @@ error[E0308]: mismatched types --> $DIR/or-pattern-mismatch.rs:3:68 | LL | fn main() { match Blah::A(1, 1, 2) { Blah::A(_, x, y) | Blah::B(x, y) => { } } } - | ^ expected `usize`, found `isize` + | ---------------- this expression has type `Blah` ^ expected `usize`, found `isize` error: aborting due to previous error diff --git a/src/test/ui/parser/recover-range-pats.stderr b/src/test/ui/parser/recover-range-pats.stderr index 50a44192707f0..3fed64c191a8a 100644 --- a/src/test/ui/parser/recover-range-pats.stderr +++ b/src/test/ui/parser/recover-range-pats.stderr @@ -425,8 +425,9 @@ error[E0308]: mismatched types --> $DIR/recover-range-pats.rs:23:16 | LL | if let X.. .0 = 0 {} - | - ^^ expected integer, found floating-point number - | | + | - ^^ - this expression has type `u8` + | | | + | | expected integer, found floating-point number | this is of type `u8` error[E0029]: only char and numeric types are allowed in range patterns @@ -457,8 +458,9 @@ error[E0308]: mismatched types --> $DIR/recover-range-pats.rs:36:16 | LL | if let X..=.0 = 0 {} - | - ^^ expected integer, found floating-point number - | | + | - ^^ - this expression has type `u8` + | | | + | | expected integer, found floating-point number | this is of type `u8` error[E0029]: only char and numeric types are allowed in range patterns @@ -489,8 +491,9 @@ error[E0308]: mismatched types --> $DIR/recover-range-pats.rs:52:17 | LL | if let X... .0 = 0 {} - | - ^^ expected integer, found floating-point number - | | + | - ^^ - this expression has type `u8` + | | | + | | expected integer, found floating-point number | this is of type `u8` error[E0029]: only char and numeric types are allowed in range patterns diff --git a/src/test/ui/pattern/pat-struct-field-expr-has-type.stderr b/src/test/ui/pattern/pat-struct-field-expr-has-type.stderr index 7962c376a92a8..d57a8a0dbc181 100644 --- a/src/test/ui/pattern/pat-struct-field-expr-has-type.stderr +++ b/src/test/ui/pattern/pat-struct-field-expr-has-type.stderr @@ -2,7 +2,7 @@ error[E0308]: mismatched types --> $DIR/pat-struct-field-expr-has-type.rs:7:16 | LL | match (S { f: 42 }) { - | ------------- this expression has type `u8` + | ------------- this expression has type `S` LL | S { f: Ok(_) } => {} | ^^^^^ expected `u8`, found enum `std::result::Result` | diff --git a/src/test/ui/pattern/pattern-tyvar.stderr b/src/test/ui/pattern/pattern-tyvar.stderr index 1e671e8d8eff3..15425da69bcc4 100644 --- a/src/test/ui/pattern/pattern-tyvar.stderr +++ b/src/test/ui/pattern/pattern-tyvar.stderr @@ -2,7 +2,7 @@ error[E0308]: mismatched types --> $DIR/pattern-tyvar.rs:5:18 | LL | match t { - | - this expression has type `std::option::Option>` + | - this expression has type `Bar` LL | Bar::T1(_, Some::(x)) => { | ^^^^^^^^^^^^^^^^ expected struct `std::vec::Vec`, found `isize` | diff --git a/src/test/ui/resolve/resolve-inconsistent-binding-mode.stderr b/src/test/ui/resolve/resolve-inconsistent-binding-mode.stderr index 58455024d3827..61d1001ce9154 100644 --- a/src/test/ui/resolve/resolve-inconsistent-binding-mode.stderr +++ b/src/test/ui/resolve/resolve-inconsistent-binding-mode.stderr @@ -23,18 +23,24 @@ LL | Opts::A(ref mut i) | Opts::B(ref i) => {} error[E0308]: mismatched types --> $DIR/resolve-inconsistent-binding-mode.rs:7:32 | +LL | match x { + | - this expression has type `Opts` LL | Opts::A(ref i) | Opts::B(i) => {} | ^ expected `&isize`, found `isize` error[E0308]: mismatched types --> $DIR/resolve-inconsistent-binding-mode.rs:16:32 | +LL | match x { + | - this expression has type `Opts` LL | Opts::A(ref i) | Opts::B(i) => {} | ^ expected `&isize`, found `isize` error[E0308]: mismatched types --> $DIR/resolve-inconsistent-binding-mode.rs:25:36 | +LL | match x { + | - this expression has type `Opts` LL | Opts::A(ref mut i) | Opts::B(ref i) => {} | ^^^^^ types differ in mutability | diff --git a/src/test/ui/resolve/resolve-inconsistent-names.stderr b/src/test/ui/resolve/resolve-inconsistent-names.stderr index 271495012dab5..5c87f7c684f3b 100644 --- a/src/test/ui/resolve/resolve-inconsistent-names.stderr +++ b/src/test/ui/resolve/resolve-inconsistent-names.stderr @@ -86,6 +86,8 @@ LL | (CONST1, _) | (_, Const2) => () error[E0308]: mismatched types --> $DIR/resolve-inconsistent-names.rs:19:19 | +LL | match x { + | - this expression has type `(E, E)` LL | (A, B) | (ref B, c) | (c, A) => () | ^^^^^ expected enum `E`, found `&E` diff --git a/src/test/ui/rfc-2497-if-let-chains/disallowed-positions.stderr b/src/test/ui/rfc-2497-if-let-chains/disallowed-positions.stderr index a69011d745080..7170adca60dc3 100644 --- a/src/test/ui/rfc-2497-if-let-chains/disallowed-positions.stderr +++ b/src/test/ui/rfc-2497-if-let-chains/disallowed-positions.stderr @@ -697,7 +697,7 @@ error[E0308]: mismatched types --> $DIR/disallowed-positions.rs:86:12 | LL | if let Range { start: true, end } = t..&&false {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ - this expression has type `bool` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ - this expression has type `&&bool` | | | expected `bool`, found struct `std::ops::Range` | @@ -885,7 +885,7 @@ error[E0308]: mismatched types --> $DIR/disallowed-positions.rs:150:15 | LL | while let Range { start: true, end } = t..&&false {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ - this expression has type `bool` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ - this expression has type `&&bool` | | | expected `bool`, found struct `std::ops::Range` | From f2c6a19c0d9ad11620a6f617c1b851e98dad5cb2 Mon Sep 17 00:00:00 2001 From: Mazdak Farrokhzad Date: Mon, 30 Dec 2019 09:40:44 +0100 Subject: [PATCH 08/10] check_fn: simplify --- src/librustc_typeck/check/mod.rs | 74 ++++++++++++++++---------------- 1 file changed, 38 insertions(+), 36 deletions(-) diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index 583a0409fb9f4..41313ffbab6cf 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -1242,13 +1242,17 @@ fn check_fn<'a, 'tcx>( let mut fcx = FnCtxt::new(inherited, param_env, body.value.hir_id); *fcx.ps.borrow_mut() = UnsafetyState::function(fn_sig.unsafety, fn_id); + let tcx = fcx.tcx; + let sess = tcx.sess; + let hir = tcx.hir(); + let declared_ret_ty = fn_sig.output(); fcx.require_type_is_sized(declared_ret_ty, decl.output.span(), traits::SizedReturnType); let revealed_ret_ty = fcx.instantiate_opaque_types_from_value(fn_id, &declared_ret_ty, decl.output.span()); debug!("check_fn: declared_ret_ty: {}, revealed_ret_ty: {}", declared_ret_ty, revealed_ret_ty); fcx.ret_coercion = Some(RefCell::new(CoerceMany::new(revealed_ret_ty))); - fn_sig = fcx.tcx.mk_fn_sig( + fn_sig = tcx.mk_fn_sig( fn_sig.inputs().iter().cloned(), revealed_ret_ty, fn_sig.c_variadic, @@ -1258,7 +1262,7 @@ fn check_fn<'a, 'tcx>( let span = body.value.span; - fn_maybe_err(fcx.tcx, span, fn_sig.abi); + fn_maybe_err(tcx, span, fn_sig.abi); if body.generator_kind.is_some() && can_be_generator.is_some() { let yield_ty = fcx @@ -1267,23 +1271,23 @@ fn check_fn<'a, 'tcx>( fcx.yield_ty = Some(yield_ty); } - let outer_def_id = fcx.tcx.closure_base_def_id(fcx.tcx.hir().local_def_id(fn_id)); - let outer_hir_id = fcx.tcx.hir().as_local_hir_id(outer_def_id).unwrap(); + let outer_def_id = tcx.closure_base_def_id(hir.local_def_id(fn_id)); + let outer_hir_id = hir.as_local_hir_id(outer_def_id).unwrap(); GatherLocalsVisitor { fcx: &fcx, parent_id: outer_hir_id }.visit_body(body); // C-variadic fns also have a `VaList` input that's not listed in `fn_sig` // (as it's created inside the body itself, not passed in from outside). let maybe_va_list = if fn_sig.c_variadic { - let va_list_did = fcx.tcx.require_lang_item( + let va_list_did = tcx.require_lang_item( lang_items::VaListTypeLangItem, Some(body.params.last().unwrap().span), ); - let region = fcx.tcx.mk_region(ty::ReScope(region::Scope { + let region = tcx.mk_region(ty::ReScope(region::Scope { id: body.value.hir_id.local_id, data: region::ScopeData::CallSite, })); - Some(fcx.tcx.type_of(va_list_did).subst(fcx.tcx, &[region.into()])) + Some(tcx.type_of(va_list_did).subst(tcx, &[region.into()])) } else { None }; @@ -1297,7 +1301,7 @@ fn check_fn<'a, 'tcx>( // The check for a non-trivial pattern is a hack to avoid duplicate warnings // for simple cases like `fn foo(x: Trait)`, // where we would error once on the parameter as a whole, and once on the binding `x`. - if param.pat.simple_ident().is_none() && !fcx.tcx.features().unsized_locals { + if param.pat.simple_ident().is_none() && !tcx.features().unsized_locals { fcx.require_type_is_sized(param_ty, decl.output.span(), traits::SizedArgumentType); } @@ -1358,11 +1362,11 @@ fn check_fn<'a, 'tcx>( fcx.demand_suptype(span, revealed_ret_ty, actual_return_ty); // Check that the main return type implements the termination trait. - if let Some(term_id) = fcx.tcx.lang_items().termination() { - if let Some((def_id, EntryFnType::Main)) = fcx.tcx.entry_fn(LOCAL_CRATE) { - let main_id = fcx.tcx.hir().as_local_hir_id(def_id).unwrap(); + if let Some(term_id) = tcx.lang_items().termination() { + if let Some((def_id, EntryFnType::Main)) = tcx.entry_fn(LOCAL_CRATE) { + let main_id = hir.as_local_hir_id(def_id).unwrap(); if main_id == fn_id { - let substs = fcx.tcx.mk_substs_trait(declared_ret_ty, &[]); + let substs = tcx.mk_substs_trait(declared_ret_ty, &[]); let trait_ref = ty::TraitRef::new(term_id, substs); let return_ty_span = decl.output.span(); let cause = traits::ObligationCause::new( @@ -1381,15 +1385,15 @@ fn check_fn<'a, 'tcx>( } // Check that a function marked as `#[panic_handler]` has signature `fn(&PanicInfo) -> !` - if let Some(panic_impl_did) = fcx.tcx.lang_items().panic_impl() { - if panic_impl_did == fcx.tcx.hir().local_def_id(fn_id) { - if let Some(panic_info_did) = fcx.tcx.lang_items().panic_info() { + if let Some(panic_impl_did) = tcx.lang_items().panic_impl() { + if panic_impl_did == hir.local_def_id(fn_id) { + if let Some(panic_info_did) = tcx.lang_items().panic_info() { if declared_ret_ty.kind != ty::Never { - fcx.tcx.sess.span_err(decl.output.span(), "return type should be `!`"); + sess.span_err(decl.output.span(), "return type should be `!`"); } let inputs = fn_sig.inputs(); - let span = fcx.tcx.hir().span(fn_id); + let span = hir.span(fn_id); if inputs.len() == 1 { let arg_is_panic_info = match inputs[0].kind { ty::Ref(region, ty, mutbl) => match ty.kind { @@ -1404,38 +1408,36 @@ fn check_fn<'a, 'tcx>( }; if !arg_is_panic_info { - fcx.tcx - .sess - .span_err(decl.inputs[0].span, "argument should be `&PanicInfo`"); + sess.span_err(decl.inputs[0].span, "argument should be `&PanicInfo`"); } - if let Node::Item(item) = fcx.tcx.hir().get(fn_id) { + if let Node::Item(item) = hir.get(fn_id) { if let ItemKind::Fn(_, ref generics, _) = item.kind { if !generics.params.is_empty() { - fcx.tcx.sess.span_err(span, "should have no type parameters"); + sess.span_err(span, "should have no type parameters"); } } } } else { - let span = fcx.tcx.sess.source_map().def_span(span); - fcx.tcx.sess.span_err(span, "function should have one argument"); + let span = sess.source_map().def_span(span); + sess.span_err(span, "function should have one argument"); } } else { - fcx.tcx.sess.err("language item required, but not found: `panic_info`"); + sess.err("language item required, but not found: `panic_info`"); } } } // Check that a function marked as `#[alloc_error_handler]` has signature `fn(Layout) -> !` - if let Some(alloc_error_handler_did) = fcx.tcx.lang_items().oom() { - if alloc_error_handler_did == fcx.tcx.hir().local_def_id(fn_id) { - if let Some(alloc_layout_did) = fcx.tcx.lang_items().alloc_layout() { + if let Some(alloc_error_handler_did) = tcx.lang_items().oom() { + if alloc_error_handler_did == hir.local_def_id(fn_id) { + if let Some(alloc_layout_did) = tcx.lang_items().alloc_layout() { if declared_ret_ty.kind != ty::Never { - fcx.tcx.sess.span_err(decl.output.span(), "return type should be `!`"); + sess.span_err(decl.output.span(), "return type should be `!`"); } let inputs = fn_sig.inputs(); - let span = fcx.tcx.hir().span(fn_id); + let span = hir.span(fn_id); if inputs.len() == 1 { let arg_is_alloc_layout = match inputs[0].kind { ty::Adt(ref adt, _) => adt.did == alloc_layout_did, @@ -1443,13 +1445,13 @@ fn check_fn<'a, 'tcx>( }; if !arg_is_alloc_layout { - fcx.tcx.sess.span_err(decl.inputs[0].span, "argument should be `Layout`"); + sess.span_err(decl.inputs[0].span, "argument should be `Layout`"); } - if let Node::Item(item) = fcx.tcx.hir().get(fn_id) { + if let Node::Item(item) = hir.get(fn_id) { if let ItemKind::Fn(_, ref generics, _) = item.kind { if !generics.params.is_empty() { - fcx.tcx.sess.span_err( + sess.span_err( span, "`#[alloc_error_handler]` function should have no type \ parameters", @@ -1458,11 +1460,11 @@ fn check_fn<'a, 'tcx>( } } } else { - let span = fcx.tcx.sess.source_map().def_span(span); - fcx.tcx.sess.span_err(span, "function should have one argument"); + let span = sess.source_map().def_span(span); + sess.span_err(span, "function should have one argument"); } } else { - fcx.tcx.sess.err("language item required, but not found: `alloc_layout`"); + sess.err("language item required, but not found: `alloc_layout`"); } } } From f8d2cce0ce24981269e6994c332bff7f033b59e0 Mon Sep 17 00:00:00 2001 From: Mazdak Farrokhzad Date: Mon, 30 Dec 2019 11:39:13 +0100 Subject: [PATCH 09/10] Blame user type in pat type error. --- src/librustc/infer/error_reporting/mod.rs | 7 ++- src/librustc/traits/mod.rs | 8 ++- src/librustc/traits/structural_impls.rs | 4 +- src/librustc_typeck/check/_match.rs | 2 +- src/librustc_typeck/check/mod.rs | 21 ++++++-- src/librustc_typeck/check/pat.rs | 29 +++++++---- src/librustc_typeck/lib.rs | 1 + .../ui/or-patterns/inconsistent-modes.stderr | 2 +- .../ui/pattern/pat-type-err-formal-param.rs | 8 +++ .../pattern/pat-type-err-formal-param.stderr | 11 +++++ src/test/ui/pattern/pat-type-err-let-stmt.rs | 16 ++++++ .../ui/pattern/pat-type-err-let-stmt.stderr | 49 +++++++++++++++++++ 12 files changed, 138 insertions(+), 20 deletions(-) create mode 100644 src/test/ui/pattern/pat-type-err-formal-param.rs create mode 100644 src/test/ui/pattern/pat-type-err-formal-param.stderr create mode 100644 src/test/ui/pattern/pat-type-err-let-stmt.rs create mode 100644 src/test/ui/pattern/pat-type-err-let-stmt.stderr diff --git a/src/librustc/infer/error_reporting/mod.rs b/src/librustc/infer/error_reporting/mod.rs index 5c561a87b0547..7254bb52d7039 100644 --- a/src/librustc/infer/error_reporting/mod.rs +++ b/src/librustc/infer/error_reporting/mod.rs @@ -581,8 +581,8 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { exp_found: Option>>, ) { match cause.code { - ObligationCauseCode::Pattern { span, ty } => { - let ty = self.resolve_vars_if_possible(&ty); + ObligationCauseCode::Pattern { origin_expr: true, span: Some(span), root_ty } => { + let ty = self.resolve_vars_if_possible(&root_ty); if ty.is_suggestable() { // don't show type `_` err.span_label(span, format!("this expression has type `{}`", ty)); @@ -600,6 +600,9 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { } } } + ObligationCauseCode::Pattern { origin_expr: false, span: Some(span), .. } => { + err.span_label(span, "expected due to this"); + } ObligationCauseCode::MatchExpressionArm(box MatchExpressionArmCause { source, ref prior_arms, diff --git a/src/librustc/traits/mod.rs b/src/librustc/traits/mod.rs index 6142dc25f2228..f726a52946ed8 100644 --- a/src/librustc/traits/mod.rs +++ b/src/librustc/traits/mod.rs @@ -251,8 +251,12 @@ pub enum ObligationCauseCode<'tcx> { /// Type error arising from type checking a pattern against an expected type. Pattern { - span: Span, - ty: Ty<'tcx>, + /// The span of the scrutinee or type expression which caused the `root_ty` type. + span: Option, + /// The root expected type induced by a scrutinee or type expression. + root_ty: Ty<'tcx>, + /// Whether the `Span` came from an expression or a type expression. + origin_expr: bool, }, /// Constants in patterns must have `Structural` type. diff --git a/src/librustc/traits/structural_impls.rs b/src/librustc/traits/structural_impls.rs index cfc27438b50fd..7b14ada8469a9 100644 --- a/src/librustc/traits/structural_impls.rs +++ b/src/librustc/traits/structural_impls.rs @@ -521,7 +521,9 @@ impl<'a, 'tcx> Lift<'tcx> for traits::ObligationCauseCode<'a> { discrim_hir_id, }) }), - super::Pattern { span, ty } => tcx.lift(&ty).map(|ty| super::Pattern { span, ty }), + super::Pattern { span, root_ty, origin_expr } => { + tcx.lift(&root_ty).map(|root_ty| super::Pattern { span, root_ty, origin_expr }) + } super::IfExpression(box super::IfExpressionCause { then, outer, semicolon }) => { Some(super::IfExpression(box super::IfExpressionCause { then, outer, semicolon })) } diff --git a/src/librustc_typeck/check/_match.rs b/src/librustc_typeck/check/_match.rs index 0d7ddd0fc4819..e4cf54f629c59 100644 --- a/src/librustc_typeck/check/_match.rs +++ b/src/librustc_typeck/check/_match.rs @@ -61,7 +61,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { .map(|arm| { let mut all_pats_diverge = Diverges::WarnedAlways; self.diverges.set(Diverges::Maybe); - self.check_pat_top(&arm.pat, discrim_ty, Some(discrim.span)); + self.check_pat_top(&arm.pat, discrim_ty, Some(discrim.span), true); all_pats_diverge &= self.diverges.get(); // As discussed with @eddyb, this is for disabling unreachable_code diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index 41313ffbab6cf..2a1297966a94e 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -1293,9 +1293,11 @@ fn check_fn<'a, 'tcx>( }; // Add formal parameters. - for (param_ty, param) in fn_sig.inputs().iter().copied().chain(maybe_va_list).zip(body.params) { + let inputs_hir = hir.fn_decl_by_hir_id(fn_id).map(|decl| &decl.inputs); + let inputs_fn = fn_sig.inputs().iter().copied(); + for (idx, (param_ty, param)) in inputs_fn.chain(maybe_va_list).zip(body.params).enumerate() { // Check the pattern. - fcx.check_pat_top(¶m.pat, param_ty, None); + fcx.check_pat_top(¶m.pat, param_ty, try { inputs_hir?.get(idx)?.span }, false); // Check that argument is Sized. // The check for a non-trivial pattern is a hack to avoid duplicate warnings @@ -4276,16 +4278,27 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } } + /// Type check a `let` statement. pub fn check_decl_local(&self, local: &'tcx hir::Local<'tcx>) { + // Determine and write the type which we'll check the pattern against. let ty = self.local_ty(local.span, local.hir_id).decl_ty; self.write_ty(local.hir_id, ty); + // Type check the initializer. if let Some(ref init) = local.init { let init_ty = self.check_decl_initializer(local, &init); self.overwrite_local_ty_if_err(local, ty, init_ty); } - self.check_pat_top(&local.pat, ty, local.init.map(|init| init.span)); + // Does the expected pattern type originate from an expression and what is the span? + let (origin_expr, ty_span) = match (local.ty, local.init) { + (Some(ty), _) => (false, Some(ty.span)), // Bias towards the explicit user type. + (_, Some(init)) => (true, Some(init.span)), // No explicit type; so use the scrutinee. + _ => (false, None), // We have `let $pat;`, so the expected type is unconstrained. + }; + + // Type check the pattern. Override if necessary to avoid knock-on errors. + self.check_pat_top(&local.pat, ty, ty_span, origin_expr); let pat_ty = self.node_ty(local.pat.hir_id); self.overwrite_local_ty_if_err(local, ty, pat_ty); } @@ -4297,7 +4310,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ty: Ty<'tcx>, ) { if ty.references_error() { - // Override the types everywhere with `types.err` to avoid knock down errors. + // Override the types everywhere with `types.err` to avoid knock on errors. self.write_ty(local.hir_id, ty); self.write_ty(local.pat.hir_id, ty); let local_ty = LocalTy { decl_ty, revealed_ty: ty }; diff --git a/src/librustc_typeck/check/pat.rs b/src/librustc_typeck/check/pat.rs index a3ef41f0de5b5..7591189339603 100644 --- a/src/librustc_typeck/check/pat.rs +++ b/src/librustc_typeck/check/pat.rs @@ -37,9 +37,13 @@ https://doc.rust-lang.org/reference/types.html#trait-objects"; struct TopInfo<'tcx> { /// The `expected` type at the top level of type checking a pattern. expected: Ty<'tcx>, + /// Was the origin of the `span` from a scrutinee expression? + /// + /// Otherwise there is no scrutinee and it could be e.g. from the type of a formal parameter. + origin_expr: bool, /// The span giving rise to the `expected` type, if one could be provided. /// - /// This is the span of the scrutinee as in: + /// If `origin_expr` is `true`, then this is the span of the scrutinee as in: /// /// - `match scrutinee { ... }` /// - `let _ = scrutinee;` @@ -70,11 +74,8 @@ impl<'tcx> FnCtxt<'_, 'tcx> { actual: Ty<'tcx>, ti: TopInfo<'tcx>, ) -> Option> { - let cause = if let Some(span) = ti.span { - self.cause(cause_span, Pattern { span, ty: ti.expected }) - } else { - self.misc(cause_span) - }; + let code = Pattern { span: ti.span, root_ty: ti.expected, origin_expr: ti.origin_expr }; + let cause = self.cause(cause_span, code); self.demand_eqtype_with_origin(&cause, expected, actual) } @@ -92,11 +93,21 @@ impl<'tcx> FnCtxt<'_, 'tcx> { impl<'a, 'tcx> FnCtxt<'a, 'tcx> { /// Type check the given top level pattern against the `expected` type. /// - /// If a `Some(span)` is provided, then the `span` represents the scrutinee's span. + /// If a `Some(span)` is provided and `origin_expr` holds, + /// then the `span` represents the scrutinee's span. /// The scrutinee is found in e.g. `match scrutinee { ... }` and `let pat = scrutinee;`. - pub fn check_pat_top(&self, pat: &'tcx Pat<'tcx>, expected: Ty<'tcx>, span: Option) { + /// + /// Otherwise, `Some(span)` represents the span of a type expression + /// which originated the `expected` type. + pub fn check_pat_top( + &self, + pat: &'tcx Pat<'tcx>, + expected: Ty<'tcx>, + span: Option, + origin_expr: bool, + ) { let def_bm = BindingMode::BindByValue(hir::Mutability::Not); - self.check_pat(pat, expected, def_bm, TopInfo { expected, span }); + self.check_pat(pat, expected, def_bm, TopInfo { expected, origin_expr, span }); } /// Type check the given `pat` against the `expected` type diff --git a/src/librustc_typeck/lib.rs b/src/librustc_typeck/lib.rs index d9b7e98ea75c3..f06fe1e4bf211 100644 --- a/src/librustc_typeck/lib.rs +++ b/src/librustc_typeck/lib.rs @@ -65,6 +65,7 @@ This API is completely unstable and subject to change. #![feature(in_band_lifetimes)] #![feature(nll)] #![feature(slice_patterns)] +#![feature(try_blocks)] #![feature(never_type)] #![recursion_limit = "256"] diff --git a/src/test/ui/or-patterns/inconsistent-modes.stderr b/src/test/ui/or-patterns/inconsistent-modes.stderr index 80d914b8d236c..7c1638ff94d0f 100644 --- a/src/test/ui/or-patterns/inconsistent-modes.stderr +++ b/src/test/ui/or-patterns/inconsistent-modes.stderr @@ -60,7 +60,7 @@ error[E0308]: mismatched types --> $DIR/inconsistent-modes.rs:13:25 | LL | let Ok(ref a) | Err(ref mut a): Result<&u8, &mut u8> = Ok(&0); - | ^^^^^^^^^ ------ this expression has type `std::result::Result<&u8, &mut u8>` + | ^^^^^^^^^ -------------------- expected due to this | | | types differ in mutability | diff --git a/src/test/ui/pattern/pat-type-err-formal-param.rs b/src/test/ui/pattern/pat-type-err-formal-param.rs new file mode 100644 index 0000000000000..54336b3492321 --- /dev/null +++ b/src/test/ui/pattern/pat-type-err-formal-param.rs @@ -0,0 +1,8 @@ +// Test the `.span_label(..)` to the type when there's a +// type error in a pattern due to a the formal parameter. + +fn main() {} + +struct Tuple(u8); + +fn foo(Tuple(_): String) {} //~ ERROR mismatched types diff --git a/src/test/ui/pattern/pat-type-err-formal-param.stderr b/src/test/ui/pattern/pat-type-err-formal-param.stderr new file mode 100644 index 0000000000000..2d7eb62faef2b --- /dev/null +++ b/src/test/ui/pattern/pat-type-err-formal-param.stderr @@ -0,0 +1,11 @@ +error[E0308]: mismatched types + --> $DIR/pat-type-err-formal-param.rs:8:8 + | +LL | fn foo(Tuple(_): String) {} + | ^^^^^^^^ ------ expected due to this + | | + | expected struct `std::string::String`, found struct `Tuple` + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0308`. diff --git a/src/test/ui/pattern/pat-type-err-let-stmt.rs b/src/test/ui/pattern/pat-type-err-let-stmt.rs new file mode 100644 index 0000000000000..6e9850b655cb9 --- /dev/null +++ b/src/test/ui/pattern/pat-type-err-let-stmt.rs @@ -0,0 +1,16 @@ +// Test the `.span_label` to the type / scrutinee +// when there's a type error in checking a pattern. + +fn main() { + // We want to point at the `Option`. + let Ok(0): Option = 42u8; + //~^ ERROR mismatched types + //~| ERROR mismatched types + + // We want to point at the `Option`. + let Ok(0): Option; + //~^ ERROR mismatched types + + // We want to point at the scrutinee. + let Ok(0) = 42u8; //~ ERROR mismatched types +} diff --git a/src/test/ui/pattern/pat-type-err-let-stmt.stderr b/src/test/ui/pattern/pat-type-err-let-stmt.stderr new file mode 100644 index 0000000000000..d75fa3f247c45 --- /dev/null +++ b/src/test/ui/pattern/pat-type-err-let-stmt.stderr @@ -0,0 +1,49 @@ +error[E0308]: mismatched types + --> $DIR/pat-type-err-let-stmt.rs:6:29 + | +LL | let Ok(0): Option = 42u8; + | ---------- ^^^^ + | | | + | | expected enum `std::option::Option`, found `u8` + | | help: try using a variant of the expected enum: `Some(42u8)` + | expected due to this + | + = note: expected enum `std::option::Option` + found type `u8` + +error[E0308]: mismatched types + --> $DIR/pat-type-err-let-stmt.rs:6:9 + | +LL | let Ok(0): Option = 42u8; + | ^^^^^ ---------- expected due to this + | | + | expected enum `std::option::Option`, found enum `std::result::Result` + | + = note: expected enum `std::option::Option` + found enum `std::result::Result<_, _>` + +error[E0308]: mismatched types + --> $DIR/pat-type-err-let-stmt.rs:11:9 + | +LL | let Ok(0): Option; + | ^^^^^ ---------- expected due to this + | | + | expected enum `std::option::Option`, found enum `std::result::Result` + | + = note: expected enum `std::option::Option` + found enum `std::result::Result<_, _>` + +error[E0308]: mismatched types + --> $DIR/pat-type-err-let-stmt.rs:15:9 + | +LL | let Ok(0) = 42u8; + | ^^^^^ ---- this expression has type `u8` + | | + | expected `u8`, found enum `std::result::Result` + | + = note: expected type `u8` + found enum `std::result::Result<_, _>` + +error: aborting due to 4 previous errors + +For more information about this error, try `rustc --explain E0308`. From 63dc0e41dbf6d939741238a7c71bf5a63ae3ce55 Mon Sep 17 00:00:00 2001 From: Mazdak Farrokhzad Date: Mon, 30 Dec 2019 12:48:48 +0100 Subject: [PATCH 10/10] discriminant -> scrutinee --- src/librustc/infer/error_reporting/mod.rs | 10 +++--- src/librustc/traits/mod.rs | 2 +- src/librustc/traits/structural_impls.rs | 4 +-- src/librustc_typeck/check/_match.rs | 38 +++++++++++------------ 4 files changed, 27 insertions(+), 27 deletions(-) diff --git a/src/librustc/infer/error_reporting/mod.rs b/src/librustc/infer/error_reporting/mod.rs index 7254bb52d7039..b3a79c0883358 100644 --- a/src/librustc/infer/error_reporting/mod.rs +++ b/src/librustc/infer/error_reporting/mod.rs @@ -607,7 +607,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { source, ref prior_arms, last_ty, - discrim_hir_id, + scrut_hir_id, .. }) => match source { hir::MatchSource::IfLetDesugar { .. } => { @@ -616,16 +616,16 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { } hir::MatchSource::TryDesugar => { if let Some(ty::error::ExpectedFound { expected, .. }) = exp_found { - let discrim_expr = self.tcx.hir().expect_expr(discrim_hir_id); - let discrim_ty = if let hir::ExprKind::Call(_, args) = &discrim_expr.kind { + let scrut_expr = self.tcx.hir().expect_expr(scrut_hir_id); + let scrut_ty = if let hir::ExprKind::Call(_, args) = &scrut_expr.kind { let arg_expr = args.first().expect("try desugaring call w/out arg"); self.in_progress_tables .and_then(|tables| tables.borrow().expr_ty_opt(arg_expr)) } else { - bug!("try desugaring w/out call expr as discriminant"); + bug!("try desugaring w/out call expr as scrutinee"); }; - match discrim_ty { + match scrut_ty { Some(ty) if expected == ty => { let source_map = self.tcx.sess.source_map(); err.span_suggestion( diff --git a/src/librustc/traits/mod.rs b/src/librustc/traits/mod.rs index f726a52946ed8..fe373e02e10f3 100644 --- a/src/librustc/traits/mod.rs +++ b/src/librustc/traits/mod.rs @@ -315,7 +315,7 @@ pub struct MatchExpressionArmCause<'tcx> { pub source: hir::MatchSource, pub prior_arms: Vec, pub last_ty: Ty<'tcx>, - pub discrim_hir_id: hir::HirId, + pub scrut_hir_id: hir::HirId, } #[derive(Clone, Debug, PartialEq, Eq, Hash)] diff --git a/src/librustc/traits/structural_impls.rs b/src/librustc/traits/structural_impls.rs index 7b14ada8469a9..c439f20d64002 100644 --- a/src/librustc/traits/structural_impls.rs +++ b/src/librustc/traits/structural_impls.rs @@ -511,14 +511,14 @@ impl<'a, 'tcx> Lift<'tcx> for traits::ObligationCauseCode<'a> { source, ref prior_arms, last_ty, - discrim_hir_id, + scrut_hir_id, }) => tcx.lift(&last_ty).map(|last_ty| { super::MatchExpressionArm(box super::MatchExpressionArmCause { arm_span, source, prior_arms: prior_arms.clone(), last_ty, - discrim_hir_id, + scrut_hir_id, }) }), super::Pattern { span, root_ty, origin_expr } => { diff --git a/src/librustc_typeck/check/_match.rs b/src/librustc_typeck/check/_match.rs index e4cf54f629c59..841dd226b4058 100644 --- a/src/librustc_typeck/check/_match.rs +++ b/src/librustc_typeck/check/_match.rs @@ -11,7 +11,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { pub fn check_match( &self, expr: &'tcx hir::Expr<'tcx>, - discrim: &'tcx hir::Expr<'tcx>, + scrut: &'tcx hir::Expr<'tcx>, arms: &'tcx [hir::Arm<'tcx>], expected: Expectation<'tcx>, match_src: hir::MatchSource, @@ -27,7 +27,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { }; // Type check the descriminant and get its type. - let discrim_ty = if force_scrutinee_bool { + let scrut_ty = if force_scrutinee_bool { // Here we want to ensure: // // 1. That default match bindings are *not* accepted in the condition of an @@ -36,9 +36,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // 2. By expecting `bool` for `expr` we get nice diagnostics for e.g. `if x = y { .. }`. // // FIXME(60707): Consider removing hack with principled solution. - self.check_expr_has_type_or_error(discrim, self.tcx.types.bool, |_| {}) + self.check_expr_has_type_or_error(scrut, self.tcx.types.bool, |_| {}) } else { - self.demand_discriminant_type(arms, discrim) + self.demand_scrutinee_type(arms, scrut) }; // If there are no arms, that is a diverging match; a special case. @@ -51,7 +51,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // Otherwise, we have to union together the types that the // arms produce and so forth. - let discrim_diverges = self.diverges.get(); + let scrut_diverges = self.diverges.get(); self.diverges.set(Diverges::Maybe); // rust-lang/rust#55810: Typecheck patterns first (via eager @@ -61,7 +61,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { .map(|arm| { let mut all_pats_diverge = Diverges::WarnedAlways; self.diverges.set(Diverges::Maybe); - self.check_pat_top(&arm.pat, discrim_ty, Some(discrim.span), true); + self.check_pat_top(&arm.pat, scrut_ty, Some(scrut.span), true); all_pats_diverge &= self.diverges.get(); // As discussed with @eddyb, this is for disabling unreachable_code @@ -157,7 +157,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { source: match_src, prior_arms: other_arms.clone(), last_ty: prior_arm_ty.unwrap(), - discrim_hir_id: discrim.hir_id, + scrut_hir_id: scrut.hir_id, }), ), }; @@ -186,8 +186,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { }; } - // We won't diverge unless the discriminant or all arms diverge. - self.diverges.set(discrim_diverges | all_arms_diverge); + // We won't diverge unless the scrutinee or all arms diverge. + self.diverges.set(scrut_diverges | all_arms_diverge); coercion.complete(self) } @@ -388,14 +388,14 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ) } - fn demand_discriminant_type( + fn demand_scrutinee_type( &self, arms: &'tcx [hir::Arm<'tcx>], - discrim: &'tcx hir::Expr<'tcx>, + scrut: &'tcx hir::Expr<'tcx>, ) -> Ty<'tcx> { // Not entirely obvious: if matches may create ref bindings, we want to - // use the *precise* type of the discriminant, *not* some supertype, as - // the "discriminant type" (issue #23116). + // use the *precise* type of the scrutinee, *not* some supertype, as + // the "scrutinee type" (issue #23116). // // arielb1 [writes here in this comment thread][c] that there // is certainly *some* potential danger, e.g., for an example @@ -454,17 +454,17 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { }); if let Some(m) = contains_ref_bindings { - self.check_expr_with_needs(discrim, Needs::maybe_mut_place(m)) + self.check_expr_with_needs(scrut, Needs::maybe_mut_place(m)) } else { // ...but otherwise we want to use any supertype of the - // discriminant. This is sort of a workaround, see note (*) in + // scrutinee. This is sort of a workaround, see note (*) in // `check_pat` for some details. - let discrim_ty = self.next_ty_var(TypeVariableOrigin { + let scrut_ty = self.next_ty_var(TypeVariableOrigin { kind: TypeVariableOriginKind::TypeInference, - span: discrim.span, + span: scrut.span, }); - self.check_expr_has_type_or_error(discrim, discrim_ty, |_| {}); - discrim_ty + self.check_expr_has_type_or_error(scrut, scrut_ty, |_| {}); + scrut_ty } } }