From 1d33717583c34bb09fcef236884774ae082cc1fd Mon Sep 17 00:00:00 2001 From: Mazdak Farrokhzad Date: Tue, 25 Feb 2020 05:30:43 +0100 Subject: [PATCH] improve or-pattern type consistency diagnostics --- src/librustc_typeck/check/pat.rs | 17 +- src/test/ui/mismatched_types/E0409.stderr | 6 +- .../ui/or-patterns/already-bound-name.stderr | 8 +- .../ui/or-patterns/inconsistent-modes.stderr | 16 +- .../or-patterns-binding-type-mismatch.stderr | 158 +++++++++++++----- .../resolve-inconsistent-binding-mode.stderr | 17 +- .../resolve/resolve-inconsistent-names.stderr | 6 +- 7 files changed, 170 insertions(+), 58 deletions(-) diff --git a/src/librustc_typeck/check/pat.rs b/src/librustc_typeck/check/pat.rs index a4312e41ee87..a003c7c365dd 100644 --- a/src/librustc_typeck/check/pat.rs +++ b/src/librustc_typeck/check/pat.rs @@ -542,8 +542,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // 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, ti); + self.check_binding_alt_eq_ty(pat.span, var_id, local_ty, ti); } if let Some(p) = sub { @@ -553,6 +552,20 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { local_ty } + fn check_binding_alt_eq_ty(&self, span: Span, var_id: HirId, ty: Ty<'tcx>, ti: TopInfo<'tcx>) { + let var_ty = self.local_ty(span, var_id).decl_ty; + if let Some(mut err) = self.demand_eqtype_pat_diag(span, var_ty, ty, ti) { + let hir = self.tcx.hir(); + let var_ty = self.resolve_vars_with_obligations(var_ty); + let msg = format!("first introduced with type `{}` here", var_ty); + err.span_label(hir.span(var_id), msg); + let in_arm = hir.parent_iter(var_id).any(|(_, n)| matches!(n, hir::Node::Arm(..))); + let pre = if in_arm { "in the same arm, " } else { "" }; + err.note(&format!("{}a binding must have the same type in all alternatives", pre)); + err.emit(); + } + } + fn borrow_pat_suggestion( &self, err: &mut DiagnosticBuilder<'_>, diff --git a/src/test/ui/mismatched_types/E0409.stderr b/src/test/ui/mismatched_types/E0409.stderr index 2306fb352738..f5c8b02ae272 100644 --- a/src/test/ui/mismatched_types/E0409.stderr +++ b/src/test/ui/mismatched_types/E0409.stderr @@ -12,7 +12,11 @@ error[E0308]: mismatched types LL | match x { | - this expression has type `({integer}, {integer})` LL | (0, ref y) | (y, 0) => {} - | ^ expected `&{integer}`, found integer + | ----- ^ expected `&{integer}`, found integer + | | + | first introduced with type `&{integer}` here + | + = note: in the same arm, a binding must have the same type in all alternatives error: aborting due to 2 previous errors diff --git a/src/test/ui/or-patterns/already-bound-name.stderr b/src/test/ui/or-patterns/already-bound-name.stderr index 9924b0d7f72e..97933ca12294 100644 --- a/src/test/ui/or-patterns/already-bound-name.stderr +++ b/src/test/ui/or-patterns/already-bound-name.stderr @@ -86,12 +86,14 @@ error[E0308]: mismatched types --> $DIR/already-bound-name.rs:32:31 | LL | let B(A(a, _) | B(a)) | A(a, A(a, _) | B(a)) = B(B(1)); - | ^ ------- this expression has type `E>` - | | - | expected integer, found enum `E` + | - ^ ------- this expression has type `E>` + | | | + | | expected integer, found enum `E` + | first introduced with type `{integer}` here | = note: expected type `{integer}` found type `E<{integer}>` + = note: a binding must have the same type in all alternatives error: aborting due to 15 previous errors diff --git a/src/test/ui/or-patterns/inconsistent-modes.stderr b/src/test/ui/or-patterns/inconsistent-modes.stderr index c329f9059609..8c01e00bae35 100644 --- a/src/test/ui/or-patterns/inconsistent-modes.stderr +++ b/src/test/ui/or-patterns/inconsistent-modes.stderr @@ -52,23 +52,27 @@ error[E0308]: mismatched types --> $DIR/inconsistent-modes.rs:11:25 | LL | let Ok(ref a) | Err(ref mut a): Result<&u8, &mut u8> = Ok(&0); - | ^^^^^^^^^ -------------------- expected due to this - | | - | types differ in mutability + | ----- ^^^^^^^^^ -------------------- expected due to this + | | | + | | types differ in mutability + | first introduced with type `&&u8` here | = note: expected type `&&u8` found type `&mut &mut u8` + = note: a binding must have the same type in all alternatives error[E0308]: mismatched types --> $DIR/inconsistent-modes.rs:14:31 | LL | let Ok((ref a, b)) | Err((ref mut a, ref b)) = Ok((0, &0)); - | ^^^^^^^^^ ----------- this expression has type `std::result::Result<({integer}, &{integer}), (_, _)>` - | | - | types differ in mutability + | ----- ^^^^^^^^^ ----------- this expression has type `std::result::Result<({integer}, &{integer}), (_, _)>` + | | | + | | types differ in mutability + | first introduced with type `&{integer}` here | = note: expected type `&{integer}` found type `&mut _` + = note: a binding must have the same type in all alternatives error: aborting due to 9 previous errors diff --git a/src/test/ui/or-patterns/or-patterns-binding-type-mismatch.stderr b/src/test/ui/or-patterns/or-patterns-binding-type-mismatch.stderr index 5094f04b9204..d5e029d668d4 100644 --- a/src/test/ui/or-patterns/or-patterns-binding-type-mismatch.stderr +++ b/src/test/ui/or-patterns/or-patterns-binding-type-mismatch.stderr @@ -4,7 +4,11 @@ error[E0308]: mismatched types LL | match Blah::A(1, 1, 2) { | ---------------- this expression has type `main::Blah` LL | Blah::A(_, x, y) | Blah::B(x, y) => {} - | ^ expected `usize`, found `isize` + | - ^ expected `usize`, found `isize` + | | + | first introduced with type `usize` here + | + = note: in the same arm, a binding must have the same type in all alternatives error[E0308]: mismatched types --> $DIR/or-patterns-binding-type-mismatch.rs:17:44 @@ -12,7 +16,11 @@ error[E0308]: mismatched types LL | match Some(Blah::A(1, 1, 2)) { | ---------------------- this expression has type `std::option::Option` LL | Some(Blah::A(_, x, y) | Blah::B(x, y)) => {} - | ^ expected `usize`, found `isize` + | - ^ expected `usize`, found `isize` + | | + | first introduced with type `usize` here + | + = note: in the same arm, a binding must have the same type in all alternatives error[E0308]: mismatched types --> $DIR/or-patterns-binding-type-mismatch.rs:21:19 @@ -20,7 +28,11 @@ error[E0308]: mismatched types LL | match (0u8, 1u16) { | ----------- this expression has type `(u8, u16)` LL | (x, y) | (y, x) => {} - | ^ expected `u16`, found `u8` + | - ^ expected `u16`, found `u8` + | | + | first introduced with type `u16` here + | + = note: in the same arm, a binding must have the same type in all alternatives error[E0308]: mismatched types --> $DIR/or-patterns-binding-type-mismatch.rs:21:22 @@ -28,7 +40,11 @@ error[E0308]: mismatched types LL | match (0u8, 1u16) { | ----------- this expression has type `(u8, u16)` LL | (x, y) | (y, x) => {} - | ^ expected `u8`, found `u16` + | - ^ expected `u8`, found `u16` + | | + | first introduced with type `u8` here + | + = note: in the same arm, a binding must have the same type in all alternatives error[E0308]: mismatched types --> $DIR/or-patterns-binding-type-mismatch.rs:26:41 @@ -36,7 +52,11 @@ error[E0308]: mismatched types LL | match Some((0u8, Some((1u16, 2u32)))) { | ------------------------------- this expression has type `std::option::Option<(u8, std::option::Option<(u16, u32)>)>` LL | Some((x, Some((y, z)))) | Some((y, Some((x, z) | (z, x)))) => {} - | ^ expected `u16`, found `u8` + | - ^ expected `u16`, found `u8` + | | + | first introduced with type `u16` here + | + = note: in the same arm, a binding must have the same type in all alternatives error[E0308]: mismatched types --> $DIR/or-patterns-binding-type-mismatch.rs:26:50 @@ -44,7 +64,11 @@ error[E0308]: mismatched types LL | match Some((0u8, Some((1u16, 2u32)))) { | ------------------------------- this expression has type `std::option::Option<(u8, std::option::Option<(u16, u32)>)>` LL | Some((x, Some((y, z)))) | Some((y, Some((x, z) | (z, x)))) => {} - | ^ expected `u8`, found `u16` + | - ^ expected `u8`, found `u16` + | | + | first introduced with type `u8` here + | + = note: in the same arm, a binding must have the same type in all alternatives error[E0308]: mismatched types --> $DIR/or-patterns-binding-type-mismatch.rs:26:59 @@ -52,7 +76,11 @@ error[E0308]: mismatched types LL | match Some((0u8, Some((1u16, 2u32)))) { | ------------------------------- this expression has type `std::option::Option<(u8, std::option::Option<(u16, u32)>)>` LL | Some((x, Some((y, z)))) | Some((y, Some((x, z) | (z, x)))) => {} - | ^ expected `u32`, found `u16` + | - ^ expected `u32`, found `u16` + | | + | first introduced with type `u32` here + | + = note: in the same arm, a binding must have the same type in all alternatives error[E0308]: mismatched types --> $DIR/or-patterns-binding-type-mismatch.rs:26:62 @@ -60,123 +88,169 @@ error[E0308]: mismatched types LL | match Some((0u8, Some((1u16, 2u32)))) { | ------------------------------- this expression has type `std::option::Option<(u8, std::option::Option<(u16, u32)>)>` LL | Some((x, Some((y, z)))) | Some((y, Some((x, z) | (z, x)))) => {} - | ^ expected `u8`, found `u32` + | - first introduced with type `u8` here ^ expected `u8`, found `u32` + | + = note: in the same arm, a binding must have the same type in all alternatives error[E0308]: mismatched types --> $DIR/or-patterns-binding-type-mismatch.rs:34:42 | LL | if let Blah::A(_, x, y) | Blah::B(x, y) = Blah::A(1, 1, 2) { - | ^ ---------------- this expression has type `main::Blah` - | | - | expected `usize`, found `isize` + | - ^ ---------------- this expression has type `main::Blah` + | | | + | | expected `usize`, found `isize` + | first introduced with type `usize` here + | + = note: in the same arm, a binding must have the same type in all alternatives error[E0308]: mismatched types --> $DIR/or-patterns-binding-type-mismatch.rs:38:47 | LL | if let Some(Blah::A(_, x, y) | Blah::B(x, y)) = Some(Blah::A(1, 1, 2)) { - | ^ ---------------------- this expression has type `std::option::Option` - | | - | expected `usize`, found `isize` + | - ^ ---------------------- this expression has type `std::option::Option` + | | | + | | expected `usize`, found `isize` + | first introduced with type `usize` here + | + = note: in the same arm, a binding must have the same type in all alternatives error[E0308]: mismatched types --> $DIR/or-patterns-binding-type-mismatch.rs:42:22 | LL | if let (x, y) | (y, x) = (0u8, 1u16) { - | ^ ----------- this expression has type `(u8, u16)` - | | - | expected `u16`, found `u8` + | - ^ ----------- this expression has type `(u8, u16)` + | | | + | | expected `u16`, found `u8` + | first introduced with type `u16` here + | + = note: in the same arm, a binding must have the same type in all alternatives error[E0308]: mismatched types --> $DIR/or-patterns-binding-type-mismatch.rs:42:25 | LL | if let (x, y) | (y, x) = (0u8, 1u16) { - | ^ ----------- this expression has type `(u8, u16)` - | | - | expected `u8`, found `u16` + | - ^ ----------- this expression has type `(u8, u16)` + | | | + | | expected `u8`, found `u16` + | first introduced with type `u8` here + | + = note: in the same arm, a binding must have the same type in all alternatives error[E0308]: mismatched types --> $DIR/or-patterns-binding-type-mismatch.rs:47:44 | LL | if let Some((x, Some((y, z)))) | Some((y, Some((x, z) | (z, x)))) - | ^ expected `u16`, found `u8` + | - ^ expected `u16`, found `u8` + | | + | first introduced with type `u16` here ... LL | = Some((0u8, Some((1u16, 2u32)))) | ------------------------------- this expression has type `std::option::Option<(u8, std::option::Option<(u16, u32)>)>` + | + = note: in the same arm, a binding must have the same type in all alternatives error[E0308]: mismatched types --> $DIR/or-patterns-binding-type-mismatch.rs:47:53 | LL | if let Some((x, Some((y, z)))) | Some((y, Some((x, z) | (z, x)))) - | ^ expected `u8`, found `u16` + | - ^ expected `u8`, found `u16` + | | + | first introduced with type `u8` here ... LL | = Some((0u8, Some((1u16, 2u32)))) | ------------------------------- this expression has type `std::option::Option<(u8, std::option::Option<(u16, u32)>)>` + | + = note: in the same arm, a binding must have the same type in all alternatives error[E0308]: mismatched types --> $DIR/or-patterns-binding-type-mismatch.rs:47:62 | LL | if let Some((x, Some((y, z)))) | Some((y, Some((x, z) | (z, x)))) - | ^ expected `u32`, found `u16` + | - ^ expected `u32`, found `u16` + | | + | first introduced with type `u32` here ... LL | = Some((0u8, Some((1u16, 2u32)))) | ------------------------------- this expression has type `std::option::Option<(u8, std::option::Option<(u16, u32)>)>` + | + = note: in the same arm, a binding must have the same type in all alternatives error[E0308]: mismatched types --> $DIR/or-patterns-binding-type-mismatch.rs:47:65 | LL | if let Some((x, Some((y, z)))) | Some((y, Some((x, z) | (z, x)))) - | ^ expected `u8`, found `u32` + | - first introduced with type `u8` here ^ expected `u8`, found `u32` ... LL | = Some((0u8, Some((1u16, 2u32)))) | ------------------------------- this expression has type `std::option::Option<(u8, std::option::Option<(u16, u32)>)>` + | + = note: in the same arm, a binding must have the same type in all alternatives error[E0308]: mismatched types --> $DIR/or-patterns-binding-type-mismatch.rs:55:39 | LL | let Blah::A(_, x, y) | Blah::B(x, y) = Blah::A(1, 1, 2); - | ^ ---------------- this expression has type `main::Blah` - | | - | expected `usize`, found `isize` + | - ^ ---------------- this expression has type `main::Blah` + | | | + | | expected `usize`, found `isize` + | first introduced with type `usize` here + | + = note: a binding must have the same type in all alternatives error[E0308]: mismatched types --> $DIR/or-patterns-binding-type-mismatch.rs:58:19 | LL | let (x, y) | (y, x) = (0u8, 1u16); - | ^ ----------- this expression has type `(u8, u16)` - | | - | expected `u16`, found `u8` + | - ^ ----------- this expression has type `(u8, u16)` + | | | + | | expected `u16`, found `u8` + | first introduced with type `u16` here + | + = note: a binding must have the same type in all alternatives error[E0308]: mismatched types --> $DIR/or-patterns-binding-type-mismatch.rs:58:22 | LL | let (x, y) | (y, x) = (0u8, 1u16); - | ^ ----------- this expression has type `(u8, u16)` - | | - | expected `u8`, found `u16` + | - ^ ----------- this expression has type `(u8, u16)` + | | | + | | expected `u8`, found `u16` + | first introduced with type `u8` here + | + = note: a binding must have the same type in all alternatives error[E0308]: mismatched types --> $DIR/or-patterns-binding-type-mismatch.rs:62:42 | LL | fn f1((Blah::A(_, x, y) | Blah::B(x, y)): Blah) {} - | ^ ---- expected due to this - | | - | expected `usize`, found `isize` + | - ^ ---- expected due to this + | | | + | | expected `usize`, found `isize` + | first introduced with type `usize` here + | + = note: a binding must have the same type in all alternatives error[E0308]: mismatched types --> $DIR/or-patterns-binding-type-mismatch.rs:65:22 | LL | fn f2(((x, y) | (y, x)): (u8, u16)) {} - | ^ --------- expected due to this - | | - | expected `u16`, found `u8` + | - ^ --------- expected due to this + | | | + | | expected `u16`, found `u8` + | first introduced with type `u16` here + | + = note: a binding must have the same type in all alternatives error[E0308]: mismatched types --> $DIR/or-patterns-binding-type-mismatch.rs:65:25 | LL | fn f2(((x, y) | (y, x)): (u8, u16)) {} - | ^ --------- expected due to this - | | - | expected `u8`, found `u16` + | - ^ --------- expected due to this + | | | + | | expected `u8`, found `u16` + | first introduced with type `u8` here + | + = note: a binding must have the same type in all alternatives error: aborting due to 22 previous errors diff --git a/src/test/ui/resolve/resolve-inconsistent-binding-mode.stderr b/src/test/ui/resolve/resolve-inconsistent-binding-mode.stderr index 61d1001ce915..749ed131b204 100644 --- a/src/test/ui/resolve/resolve-inconsistent-binding-mode.stderr +++ b/src/test/ui/resolve/resolve-inconsistent-binding-mode.stderr @@ -26,7 +26,11 @@ error[E0308]: mismatched types LL | match x { | - this expression has type `Opts` LL | Opts::A(ref i) | Opts::B(i) => {} - | ^ expected `&isize`, found `isize` + | ----- ^ expected `&isize`, found `isize` + | | + | first introduced with type `&isize` here + | + = note: in the same arm, a binding must have the same type in all alternatives error[E0308]: mismatched types --> $DIR/resolve-inconsistent-binding-mode.rs:16:32 @@ -34,7 +38,11 @@ error[E0308]: mismatched types LL | match x { | - this expression has type `Opts` LL | Opts::A(ref i) | Opts::B(i) => {} - | ^ expected `&isize`, found `isize` + | ----- ^ expected `&isize`, found `isize` + | | + | first introduced with type `&isize` here + | + = note: in the same arm, a binding must have the same type in all alternatives error[E0308]: mismatched types --> $DIR/resolve-inconsistent-binding-mode.rs:25:36 @@ -42,10 +50,13 @@ error[E0308]: mismatched types LL | match x { | - this expression has type `Opts` LL | Opts::A(ref mut i) | Opts::B(ref i) => {} - | ^^^^^ types differ in mutability + | --------- ^^^^^ types differ in mutability + | | + | first introduced with type `&mut isize` here | = note: expected type `&mut isize` found type `&isize` + = note: in the same arm, a binding must have the same type in all alternatives error: aborting due to 6 previous errors diff --git a/src/test/ui/resolve/resolve-inconsistent-names.stderr b/src/test/ui/resolve/resolve-inconsistent-names.stderr index 5c87f7c684f3..1d3079c90baf 100644 --- a/src/test/ui/resolve/resolve-inconsistent-names.stderr +++ b/src/test/ui/resolve/resolve-inconsistent-names.stderr @@ -89,7 +89,11 @@ error[E0308]: mismatched types LL | match x { | - this expression has type `(E, E)` LL | (A, B) | (ref B, c) | (c, A) => () - | ^^^^^ expected enum `E`, found `&E` + | - ^^^^^ expected enum `E`, found `&E` + | | + | first introduced with type `E` here + | + = note: in the same arm, a binding must have the same type in all alternatives error: aborting due to 9 previous errors