about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--src/librustc_typeck/check/pat.rs17
-rw-r--r--src/test/ui/mismatched_types/E0409.stderr6
-rw-r--r--src/test/ui/or-patterns/already-bound-name.stderr8
-rw-r--r--src/test/ui/or-patterns/inconsistent-modes.stderr16
-rw-r--r--src/test/ui/or-patterns/or-patterns-binding-type-mismatch.stderr158
-rw-r--r--src/test/ui/resolve/resolve-inconsistent-binding-mode.stderr17
-rw-r--r--src/test/ui/resolve/resolve-inconsistent-names.stderr6
7 files changed, 170 insertions, 58 deletions
diff --git a/src/librustc_typeck/check/pat.rs b/src/librustc_typeck/check/pat.rs
index a4312e41ee8..a003c7c365d 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 2306fb35273..f5c8b02ae27 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 9924b0d7f72..97933ca1229 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<E<{integer}>>`
-   |                               |
-   |                               expected integer, found enum `E`
+   |             -                 ^                    ------- this expression has type `E<E<{integer}>>`
+   |             |                 |
+   |             |                 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 c329f905960..8c01e00bae3 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 5094f04b920..d5e029d668d 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<main::Blah>`
 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<main::Blah>`
-   |                                               |
-   |                                               expected `usize`, found `isize`
+   |                               -               ^     ---------------------- this expression has type `std::option::Option<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: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 61d1001ce91..749ed131b20 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 5c87f7c684f..1d3079c90ba 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