improve or-pattern type consistency diagnostics

This commit is contained in:
Mazdak Farrokhzad 2020-02-25 05:30:43 +01:00
parent e58496c371
commit 1d33717583
7 changed files with 170 additions and 58 deletions

View file

@ -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<'_>,

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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