Skip to content

Commit 1d33717

Browse files
committed
improve or-pattern type consistency diagnostics
1 parent e58496c commit 1d33717

File tree

7 files changed

+170
-58
lines changed

7 files changed

+170
-58
lines changed

src/librustc_typeck/check/pat.rs

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -542,8 +542,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
542542
// If there are multiple arms, make sure they all agree on
543543
// what the type of the binding `x` ought to be.
544544
if var_id != pat.hir_id {
545-
let vt = self.local_ty(pat.span, var_id).decl_ty;
546-
self.demand_eqtype_pat(pat.span, vt, local_ty, ti);
545+
self.check_binding_alt_eq_ty(pat.span, var_id, local_ty, ti);
547546
}
548547

549548
if let Some(p) = sub {
@@ -553,6 +552,20 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
553552
local_ty
554553
}
555554

555+
fn check_binding_alt_eq_ty(&self, span: Span, var_id: HirId, ty: Ty<'tcx>, ti: TopInfo<'tcx>) {
556+
let var_ty = self.local_ty(span, var_id).decl_ty;
557+
if let Some(mut err) = self.demand_eqtype_pat_diag(span, var_ty, ty, ti) {
558+
let hir = self.tcx.hir();
559+
let var_ty = self.resolve_vars_with_obligations(var_ty);
560+
let msg = format!("first introduced with type `{}` here", var_ty);
561+
err.span_label(hir.span(var_id), msg);
562+
let in_arm = hir.parent_iter(var_id).any(|(_, n)| matches!(n, hir::Node::Arm(..)));
563+
let pre = if in_arm { "in the same arm, " } else { "" };
564+
err.note(&format!("{}a binding must have the same type in all alternatives", pre));
565+
err.emit();
566+
}
567+
}
568+
556569
fn borrow_pat_suggestion(
557570
&self,
558571
err: &mut DiagnosticBuilder<'_>,

src/test/ui/mismatched_types/E0409.stderr

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,11 @@ error[E0308]: mismatched types
1212
LL | match x {
1313
| - this expression has type `({integer}, {integer})`
1414
LL | (0, ref y) | (y, 0) => {}
15-
| ^ expected `&{integer}`, found integer
15+
| ----- ^ expected `&{integer}`, found integer
16+
| |
17+
| first introduced with type `&{integer}` here
18+
|
19+
= note: in the same arm, a binding must have the same type in all alternatives
1620

1721
error: aborting due to 2 previous errors
1822

src/test/ui/or-patterns/already-bound-name.stderr

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -86,12 +86,14 @@ error[E0308]: mismatched types
8686
--> $DIR/already-bound-name.rs:32:31
8787
|
8888
LL | let B(A(a, _) | B(a)) | A(a, A(a, _) | B(a)) = B(B(1));
89-
| ^ ------- this expression has type `E<E<{integer}>>`
90-
| |
91-
| expected integer, found enum `E`
89+
| - ^ ------- this expression has type `E<E<{integer}>>`
90+
| | |
91+
| | expected integer, found enum `E`
92+
| first introduced with type `{integer}` here
9293
|
9394
= note: expected type `{integer}`
9495
found type `E<{integer}>`
96+
= note: a binding must have the same type in all alternatives
9597

9698
error: aborting due to 15 previous errors
9799

src/test/ui/or-patterns/inconsistent-modes.stderr

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -52,23 +52,27 @@ error[E0308]: mismatched types
5252
--> $DIR/inconsistent-modes.rs:11:25
5353
|
5454
LL | let Ok(ref a) | Err(ref mut a): Result<&u8, &mut u8> = Ok(&0);
55-
| ^^^^^^^^^ -------------------- expected due to this
56-
| |
57-
| types differ in mutability
55+
| ----- ^^^^^^^^^ -------------------- expected due to this
56+
| | |
57+
| | types differ in mutability
58+
| first introduced with type `&&u8` here
5859
|
5960
= note: expected type `&&u8`
6061
found type `&mut &mut u8`
62+
= note: a binding must have the same type in all alternatives
6163

6264
error[E0308]: mismatched types
6365
--> $DIR/inconsistent-modes.rs:14:31
6466
|
6567
LL | let Ok((ref a, b)) | Err((ref mut a, ref b)) = Ok((0, &0));
66-
| ^^^^^^^^^ ----------- this expression has type `std::result::Result<({integer}, &{integer}), (_, _)>`
67-
| |
68-
| types differ in mutability
68+
| ----- ^^^^^^^^^ ----------- this expression has type `std::result::Result<({integer}, &{integer}), (_, _)>`
69+
| | |
70+
| | types differ in mutability
71+
| first introduced with type `&{integer}` here
6972
|
7073
= note: expected type `&{integer}`
7174
found type `&mut _`
75+
= note: a binding must have the same type in all alternatives
7276

7377
error: aborting due to 9 previous errors
7478

src/test/ui/or-patterns/or-patterns-binding-type-mismatch.stderr

Lines changed: 116 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -4,179 +4,253 @@ error[E0308]: mismatched types
44
LL | match Blah::A(1, 1, 2) {
55
| ---------------- this expression has type `main::Blah`
66
LL | Blah::A(_, x, y) | Blah::B(x, y) => {}
7-
| ^ expected `usize`, found `isize`
7+
| - ^ expected `usize`, found `isize`
8+
| |
9+
| first introduced with type `usize` here
10+
|
11+
= note: in the same arm, a binding must have the same type in all alternatives
812

913
error[E0308]: mismatched types
1014
--> $DIR/or-patterns-binding-type-mismatch.rs:17:44
1115
|
1216
LL | match Some(Blah::A(1, 1, 2)) {
1317
| ---------------------- this expression has type `std::option::Option<main::Blah>`
1418
LL | Some(Blah::A(_, x, y) | Blah::B(x, y)) => {}
15-
| ^ expected `usize`, found `isize`
19+
| - ^ expected `usize`, found `isize`
20+
| |
21+
| first introduced with type `usize` here
22+
|
23+
= note: in the same arm, a binding must have the same type in all alternatives
1624

1725
error[E0308]: mismatched types
1826
--> $DIR/or-patterns-binding-type-mismatch.rs:21:19
1927
|
2028
LL | match (0u8, 1u16) {
2129
| ----------- this expression has type `(u8, u16)`
2230
LL | (x, y) | (y, x) => {}
23-
| ^ expected `u16`, found `u8`
31+
| - ^ expected `u16`, found `u8`
32+
| |
33+
| first introduced with type `u16` here
34+
|
35+
= note: in the same arm, a binding must have the same type in all alternatives
2436

2537
error[E0308]: mismatched types
2638
--> $DIR/or-patterns-binding-type-mismatch.rs:21:22
2739
|
2840
LL | match (0u8, 1u16) {
2941
| ----------- this expression has type `(u8, u16)`
3042
LL | (x, y) | (y, x) => {}
31-
| ^ expected `u8`, found `u16`
43+
| - ^ expected `u8`, found `u16`
44+
| |
45+
| first introduced with type `u8` here
46+
|
47+
= note: in the same arm, a binding must have the same type in all alternatives
3248

3349
error[E0308]: mismatched types
3450
--> $DIR/or-patterns-binding-type-mismatch.rs:26:41
3551
|
3652
LL | match Some((0u8, Some((1u16, 2u32)))) {
3753
| ------------------------------- this expression has type `std::option::Option<(u8, std::option::Option<(u16, u32)>)>`
3854
LL | Some((x, Some((y, z)))) | Some((y, Some((x, z) | (z, x)))) => {}
39-
| ^ expected `u16`, found `u8`
55+
| - ^ expected `u16`, found `u8`
56+
| |
57+
| first introduced with type `u16` here
58+
|
59+
= note: in the same arm, a binding must have the same type in all alternatives
4060

4161
error[E0308]: mismatched types
4262
--> $DIR/or-patterns-binding-type-mismatch.rs:26:50
4363
|
4464
LL | match Some((0u8, Some((1u16, 2u32)))) {
4565
| ------------------------------- this expression has type `std::option::Option<(u8, std::option::Option<(u16, u32)>)>`
4666
LL | Some((x, Some((y, z)))) | Some((y, Some((x, z) | (z, x)))) => {}
47-
| ^ expected `u8`, found `u16`
67+
| - ^ expected `u8`, found `u16`
68+
| |
69+
| first introduced with type `u8` here
70+
|
71+
= note: in the same arm, a binding must have the same type in all alternatives
4872

4973
error[E0308]: mismatched types
5074
--> $DIR/or-patterns-binding-type-mismatch.rs:26:59
5175
|
5276
LL | match Some((0u8, Some((1u16, 2u32)))) {
5377
| ------------------------------- this expression has type `std::option::Option<(u8, std::option::Option<(u16, u32)>)>`
5478
LL | Some((x, Some((y, z)))) | Some((y, Some((x, z) | (z, x)))) => {}
55-
| ^ expected `u32`, found `u16`
79+
| - ^ expected `u32`, found `u16`
80+
| |
81+
| first introduced with type `u32` here
82+
|
83+
= note: in the same arm, a binding must have the same type in all alternatives
5684

5785
error[E0308]: mismatched types
5886
--> $DIR/or-patterns-binding-type-mismatch.rs:26:62
5987
|
6088
LL | match Some((0u8, Some((1u16, 2u32)))) {
6189
| ------------------------------- this expression has type `std::option::Option<(u8, std::option::Option<(u16, u32)>)>`
6290
LL | Some((x, Some((y, z)))) | Some((y, Some((x, z) | (z, x)))) => {}
63-
| ^ expected `u8`, found `u32`
91+
| - first introduced with type `u8` here ^ expected `u8`, found `u32`
92+
|
93+
= note: in the same arm, a binding must have the same type in all alternatives
6494

6595
error[E0308]: mismatched types
6696
--> $DIR/or-patterns-binding-type-mismatch.rs:34:42
6797
|
6898
LL | if let Blah::A(_, x, y) | Blah::B(x, y) = Blah::A(1, 1, 2) {
69-
| ^ ---------------- this expression has type `main::Blah`
70-
| |
71-
| expected `usize`, found `isize`
99+
| - ^ ---------------- this expression has type `main::Blah`
100+
| | |
101+
| | expected `usize`, found `isize`
102+
| first introduced with type `usize` here
103+
|
104+
= note: in the same arm, a binding must have the same type in all alternatives
72105

73106
error[E0308]: mismatched types
74107
--> $DIR/or-patterns-binding-type-mismatch.rs:38:47
75108
|
76109
LL | if let Some(Blah::A(_, x, y) | Blah::B(x, y)) = Some(Blah::A(1, 1, 2)) {
77-
| ^ ---------------------- this expression has type `std::option::Option<main::Blah>`
78-
| |
79-
| expected `usize`, found `isize`
110+
| - ^ ---------------------- this expression has type `std::option::Option<main::Blah>`
111+
| | |
112+
| | expected `usize`, found `isize`
113+
| first introduced with type `usize` here
114+
|
115+
= note: in the same arm, a binding must have the same type in all alternatives
80116

81117
error[E0308]: mismatched types
82118
--> $DIR/or-patterns-binding-type-mismatch.rs:42:22
83119
|
84120
LL | if let (x, y) | (y, x) = (0u8, 1u16) {
85-
| ^ ----------- this expression has type `(u8, u16)`
86-
| |
87-
| expected `u16`, found `u8`
121+
| - ^ ----------- this expression has type `(u8, u16)`
122+
| | |
123+
| | expected `u16`, found `u8`
124+
| first introduced with type `u16` here
125+
|
126+
= note: in the same arm, a binding must have the same type in all alternatives
88127

89128
error[E0308]: mismatched types
90129
--> $DIR/or-patterns-binding-type-mismatch.rs:42:25
91130
|
92131
LL | if let (x, y) | (y, x) = (0u8, 1u16) {
93-
| ^ ----------- this expression has type `(u8, u16)`
94-
| |
95-
| expected `u8`, found `u16`
132+
| - ^ ----------- this expression has type `(u8, u16)`
133+
| | |
134+
| | expected `u8`, found `u16`
135+
| first introduced with type `u8` here
136+
|
137+
= note: in the same arm, a binding must have the same type in all alternatives
96138

97139
error[E0308]: mismatched types
98140
--> $DIR/or-patterns-binding-type-mismatch.rs:47:44
99141
|
100142
LL | if let Some((x, Some((y, z)))) | Some((y, Some((x, z) | (z, x))))
101-
| ^ expected `u16`, found `u8`
143+
| - ^ expected `u16`, found `u8`
144+
| |
145+
| first introduced with type `u16` here
102146
...
103147
LL | = Some((0u8, Some((1u16, 2u32))))
104148
| ------------------------------- this expression has type `std::option::Option<(u8, std::option::Option<(u16, u32)>)>`
149+
|
150+
= note: in the same arm, a binding must have the same type in all alternatives
105151

106152
error[E0308]: mismatched types
107153
--> $DIR/or-patterns-binding-type-mismatch.rs:47:53
108154
|
109155
LL | if let Some((x, Some((y, z)))) | Some((y, Some((x, z) | (z, x))))
110-
| ^ expected `u8`, found `u16`
156+
| - ^ expected `u8`, found `u16`
157+
| |
158+
| first introduced with type `u8` here
111159
...
112160
LL | = Some((0u8, Some((1u16, 2u32))))
113161
| ------------------------------- this expression has type `std::option::Option<(u8, std::option::Option<(u16, u32)>)>`
162+
|
163+
= note: in the same arm, a binding must have the same type in all alternatives
114164

115165
error[E0308]: mismatched types
116166
--> $DIR/or-patterns-binding-type-mismatch.rs:47:62
117167
|
118168
LL | if let Some((x, Some((y, z)))) | Some((y, Some((x, z) | (z, x))))
119-
| ^ expected `u32`, found `u16`
169+
| - ^ expected `u32`, found `u16`
170+
| |
171+
| first introduced with type `u32` here
120172
...
121173
LL | = Some((0u8, Some((1u16, 2u32))))
122174
| ------------------------------- this expression has type `std::option::Option<(u8, std::option::Option<(u16, u32)>)>`
175+
|
176+
= note: in the same arm, a binding must have the same type in all alternatives
123177

124178
error[E0308]: mismatched types
125179
--> $DIR/or-patterns-binding-type-mismatch.rs:47:65
126180
|
127181
LL | if let Some((x, Some((y, z)))) | Some((y, Some((x, z) | (z, x))))
128-
| ^ expected `u8`, found `u32`
182+
| - first introduced with type `u8` here ^ expected `u8`, found `u32`
129183
...
130184
LL | = Some((0u8, Some((1u16, 2u32))))
131185
| ------------------------------- this expression has type `std::option::Option<(u8, std::option::Option<(u16, u32)>)>`
186+
|
187+
= note: in the same arm, a binding must have the same type in all alternatives
132188

133189
error[E0308]: mismatched types
134190
--> $DIR/or-patterns-binding-type-mismatch.rs:55:39
135191
|
136192
LL | let Blah::A(_, x, y) | Blah::B(x, y) = Blah::A(1, 1, 2);
137-
| ^ ---------------- this expression has type `main::Blah`
138-
| |
139-
| expected `usize`, found `isize`
193+
| - ^ ---------------- this expression has type `main::Blah`
194+
| | |
195+
| | expected `usize`, found `isize`
196+
| first introduced with type `usize` here
197+
|
198+
= note: a binding must have the same type in all alternatives
140199

141200
error[E0308]: mismatched types
142201
--> $DIR/or-patterns-binding-type-mismatch.rs:58:19
143202
|
144203
LL | let (x, y) | (y, x) = (0u8, 1u16);
145-
| ^ ----------- this expression has type `(u8, u16)`
146-
| |
147-
| expected `u16`, found `u8`
204+
| - ^ ----------- this expression has type `(u8, u16)`
205+
| | |
206+
| | expected `u16`, found `u8`
207+
| first introduced with type `u16` here
208+
|
209+
= note: a binding must have the same type in all alternatives
148210

149211
error[E0308]: mismatched types
150212
--> $DIR/or-patterns-binding-type-mismatch.rs:58:22
151213
|
152214
LL | let (x, y) | (y, x) = (0u8, 1u16);
153-
| ^ ----------- this expression has type `(u8, u16)`
154-
| |
155-
| expected `u8`, found `u16`
215+
| - ^ ----------- this expression has type `(u8, u16)`
216+
| | |
217+
| | expected `u8`, found `u16`
218+
| first introduced with type `u8` here
219+
|
220+
= note: a binding must have the same type in all alternatives
156221

157222
error[E0308]: mismatched types
158223
--> $DIR/or-patterns-binding-type-mismatch.rs:62:42
159224
|
160225
LL | fn f1((Blah::A(_, x, y) | Blah::B(x, y)): Blah) {}
161-
| ^ ---- expected due to this
162-
| |
163-
| expected `usize`, found `isize`
226+
| - ^ ---- expected due to this
227+
| | |
228+
| | expected `usize`, found `isize`
229+
| first introduced with type `usize` here
230+
|
231+
= note: a binding must have the same type in all alternatives
164232

165233
error[E0308]: mismatched types
166234
--> $DIR/or-patterns-binding-type-mismatch.rs:65:22
167235
|
168236
LL | fn f2(((x, y) | (y, x)): (u8, u16)) {}
169-
| ^ --------- expected due to this
170-
| |
171-
| expected `u16`, found `u8`
237+
| - ^ --------- expected due to this
238+
| | |
239+
| | expected `u16`, found `u8`
240+
| first introduced with type `u16` here
241+
|
242+
= note: a binding must have the same type in all alternatives
172243

173244
error[E0308]: mismatched types
174245
--> $DIR/or-patterns-binding-type-mismatch.rs:65:25
175246
|
176247
LL | fn f2(((x, y) | (y, x)): (u8, u16)) {}
177-
| ^ --------- expected due to this
178-
| |
179-
| expected `u8`, found `u16`
248+
| - ^ --------- expected due to this
249+
| | |
250+
| | expected `u8`, found `u16`
251+
| first introduced with type `u8` here
252+
|
253+
= note: a binding must have the same type in all alternatives
180254

181255
error: aborting due to 22 previous errors
182256

0 commit comments

Comments
 (0)