Skip to content

Commit bf68227

Browse files
committed
labelify the check_match errors
1 parent 8a4641b commit bf68227

20 files changed

+145
-138
lines changed

src/librustc_const_eval/check_match.rs

+75-65
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ use rustc::ty;
3131
use std::cmp::Ordering;
3232
use std::fmt;
3333
use std::iter::{FromIterator, IntoIterator, repeat};
34+
use std::mem;
3435

3536
use rustc::hir;
3637
use rustc::hir::{Pat, PatKind};
@@ -214,19 +215,8 @@ fn check_expr(cx: &mut MatchCheckCtxt, ex: &hir::Expr) {
214215
// Finally, check if the whole match expression is exhaustive.
215216
// Check for empty enum, because is_useful only works on inhabited types.
216217
let pat_ty = cx.tcx.node_id_to_type(scrut.id);
217-
if inlined_arms.is_empty() {
218-
if !pat_ty.is_empty(cx.tcx) {
219-
// We know the type is inhabited, so this must be wrong
220-
let mut err = struct_span_err!(cx.tcx.sess, ex.span, E0002,
221-
"non-exhaustive patterns: type {} is non-empty",
222-
pat_ty);
223-
span_help!(&mut err, ex.span,
224-
"Please ensure that all possible cases are being handled; \
225-
possibly adding wildcards or more match arms.");
226-
err.emit();
227-
}
228-
// If the type *is* empty, it's vacuously exhaustive
229-
return;
218+
if inlined_arms.is_empty() && pat_ty.is_empty(cx.tcx) {
219+
return
230220
}
231221

232222
let matrix: Matrix = inlined_arms
@@ -235,12 +225,7 @@ fn check_expr(cx: &mut MatchCheckCtxt, ex: &hir::Expr) {
235225
.flat_map(|arm| &arm.0)
236226
.map(|pat| vec![wrap_pat(cx, &pat)])
237227
.collect();
238-
let match_span = Span {
239-
lo: ex.span.lo,
240-
hi: scrut.span.hi,
241-
expn_id: ex.span.expn_id
242-
};
243-
check_exhaustive(cx, match_span, &matrix, source);
228+
check_exhaustive(cx, ex.span, &matrix, source);
244229
},
245230
_ => ()
246231
}
@@ -316,7 +301,10 @@ fn check_arms(cx: &MatchCheckCtxt,
316301
let &(ref first_arm_pats, _) = &arms[0];
317302
let first_pat = &first_arm_pats[0];
318303
let span = first_pat.span;
319-
span_err!(cx.tcx.sess, span, E0162, "irrefutable if-let pattern");
304+
struct_span_err!(
305+
cx.tcx.sess, span, E0162, "irrefutable if-let pattern")
306+
.span_label(span, &"this pattern always applies")
307+
.emit();
320308
printed_if_let_err = true;
321309
}
322310
},
@@ -326,7 +314,10 @@ fn check_arms(cx: &MatchCheckCtxt,
326314
let &(ref first_arm_pats, _) = &arms[0];
327315
let first_pat = &first_arm_pats[0];
328316
let span = first_pat.span;
329-
span_err!(cx.tcx.sess, span, E0165, "irrefutable while-let pattern");
317+
struct_span_err!(
318+
cx.tcx.sess, span, E0165, "irrefutable while-let pattern")
319+
.span_label(span, &"this pattern always applies")
320+
.emit();
330321
},
331322

332323
hir::MatchSource::ForLoopDesugar => {
@@ -338,17 +329,17 @@ fn check_arms(cx: &MatchCheckCtxt,
338329
},
339330

340331
hir::MatchSource::Normal => {
341-
let mut err = struct_span_err!(cx.tcx.sess, pat.span, E0001,
342-
"unreachable pattern");
343-
err.span_label(pat.span, &format!("this is an unreachable pattern"));
332+
let mut diag = struct_span_err!(cx.tcx.sess, pat.span, E0001,
333+
"unreachable pattern");
334+
diag.span_label(pat.span, &"this pattern cannot be reached");
344335
// if we had a catchall pattern, hint at that
345336
for row in &seen.0 {
346337
if pat_is_catchall(&cx.tcx.def_map.borrow(), row[0].0) {
347-
span_note!(err, row[0].0.span,
348-
"this pattern matches any value");
338+
diag.span_label(row[0].0.span,
339+
&"this pattern matches any value");
349340
}
350341
}
351-
err.emit();
342+
diag.emit();
352343
},
353344

354345
hir::MatchSource::TryDesugar => {
@@ -407,10 +398,18 @@ fn check_exhaustive<'a, 'tcx>(cx: &MatchCheckCtxt<'a, 'tcx>,
407398
},
408399
_ => bug!(),
409400
};
410-
span_err!(cx.tcx.sess, sp, E0297,
411-
"refutable pattern in `for` loop binding: \
412-
`{}` not covered",
413-
pat_to_string(witness));
401+
let pat = matrix.0[0][0].0;
402+
let span = match pat.node {
403+
hir::PatKind::TupleStruct(_, ref subpats, _) => subpats.get(0),
404+
_ => None
405+
}.unwrap_or_else(|| {
406+
span_bug!(pat.span, "bad for-loop desugaring {:?}", pat);
407+
}).span;
408+
struct_span_err!(cx.tcx.sess, span, E0297,
409+
"refutable pattern in `for` loop binding")
410+
.span_label(span, &format!("`{}` not covered",
411+
pat_to_string(witness)))
412+
.emit();
414413
},
415414
_ => {
416415
let pattern_strings: Vec<_> = witnesses.iter().map(|w| {
@@ -429,15 +428,10 @@ fn check_exhaustive<'a, 'tcx>(cx: &MatchCheckCtxt<'a, 'tcx>,
429428
format!("`{}` and {} more", head.join("`, `"), tail.len())
430429
}
431430
};
432-
433-
let label_text = match pattern_strings.len(){
434-
1 => format!("pattern {} not covered", joined_patterns),
435-
_ => format!("patterns {} not covered", joined_patterns)
436-
};
437431
struct_span_err!(cx.tcx.sess, sp, E0004,
438-
"non-exhaustive patterns: {} not covered",
439-
joined_patterns
440-
).span_label(sp, &label_text).emit();
432+
"non-exhaustive patterns")
433+
.span_label(sp, &format!("{} not covered", joined_patterns))
434+
.emit();
441435
},
442436
}
443437
}
@@ -520,8 +514,11 @@ impl<'a, 'tcx> Folder for StaticInliner<'a, 'tcx> {
520514
}
521515
} else {
522516
self.failed = true;
523-
span_err!(self.tcx.sess, pat.span, E0158,
524-
"statics cannot be referenced in patterns");
517+
struct_span_err!(
518+
self.tcx.sess, pat.span, E0158,
519+
"unresolvable constant in pattern")
520+
.span_label(pat.span, &"unresolvable constant here")
521+
.emit();
525522
pat
526523
}
527524
}
@@ -1075,11 +1072,11 @@ fn check_irrefutable(cx: &MatchCheckCtxt, pat: &Pat, is_fn_arg: bool) {
10751072
};
10761073

10771074
is_refutable(cx, pat, |uncovered_pat| {
1078-
span_err!(cx.tcx.sess, pat.span, E0005,
1079-
"refutable pattern in {}: `{}` not covered",
1080-
origin,
1081-
pat_to_string(uncovered_pat),
1082-
);
1075+
struct_span_err!(cx.tcx.sess, pat.span, E0005,
1076+
"refutable pattern in {}", origin)
1077+
.span_label(pat.span, &format!(
1078+
"`{}` not covered here", pat_to_string(uncovered_pat)))
1079+
.emit();
10831080
});
10841081
}
10851082

@@ -1111,16 +1108,20 @@ fn check_legality_of_move_bindings(cx: &MatchCheckCtxt,
11111108
// check legality of moving out of the enum
11121109

11131110
// x @ Foo(..) is legal, but x @ Foo(y) isn't.
1114-
if sub.map_or(false, |p| pat_contains_bindings(&p)) {
1115-
span_err!(cx.tcx.sess, p.span, E0007, "cannot bind by-move with sub-bindings");
1111+
let mut diag = if sub.map_or(false, |p| pat_contains_bindings(&p)) {
1112+
struct_span_err!(cx.tcx.sess, p.span, E0007, "cannot bind by-move with sub-bindings")
11161113
} else if has_guard {
1117-
span_err!(cx.tcx.sess, p.span, E0008, "cannot bind by-move into a pattern guard");
1114+
struct_span_err!(cx.tcx.sess, p.span, E0008, "cannot bind by-move into a pattern guard")
11181115
} else if by_ref_span.is_some() {
1119-
let mut err = struct_span_err!(cx.tcx.sess, p.span, E0009,
1120-
"cannot bind by-move and by-ref in the same pattern");
1121-
span_note!(&mut err, by_ref_span.unwrap(), "by-ref binding occurs here");
1122-
err.emit();
1123-
}
1116+
let mut diag = struct_span_err!(cx.tcx.sess, p.span, E0009,
1117+
"cannot bind by-move and by-ref in the same pattern");
1118+
diag.span_label(by_ref_span.unwrap(), &"by-ref binding occurs here");
1119+
diag
1120+
} else {
1121+
return
1122+
};
1123+
diag.span_label(p.span, &"invalid by-move binding here");
1124+
diag.emit();
11241125
};
11251126

11261127
for pat in pats {
@@ -1171,8 +1172,10 @@ impl<'a, 'gcx, 'tcx> Delegate<'tcx> for MutationChecker<'a, 'gcx> {
11711172
_: LoanCause) {
11721173
match kind {
11731174
MutBorrow => {
1174-
span_err!(self.cx.tcx.sess, span, E0301,
1175-
"cannot mutably borrow in a pattern guard")
1175+
struct_span_err!(self.cx.tcx.sess, span, E0301,
1176+
"cannot mutably borrow in a pattern guard")
1177+
.span_label(span, &"bad mutable borrow here")
1178+
.emit();
11761179
}
11771180
ImmBorrow | UniqueImmBorrow => {}
11781181
}
@@ -1181,7 +1184,10 @@ impl<'a, 'gcx, 'tcx> Delegate<'tcx> for MutationChecker<'a, 'gcx> {
11811184
fn mutate(&mut self, _: NodeId, span: Span, _: cmt, mode: MutateMode) {
11821185
match mode {
11831186
MutateMode::JustWrite | MutateMode::WriteAndRead => {
1184-
span_err!(self.cx.tcx.sess, span, E0302, "cannot assign in a pattern guard")
1187+
struct_span_err!(
1188+
self.cx.tcx.sess, span, E0302, "cannot assign in a pattern guard")
1189+
.span_label(span, &"bad assignment here")
1190+
.emit();
11851191
}
11861192
MutateMode::Init => {}
11871193
}
@@ -1192,28 +1198,32 @@ impl<'a, 'gcx, 'tcx> Delegate<'tcx> for MutationChecker<'a, 'gcx> {
11921198
/// because of the way rvalues are handled in the borrow check. (See issue
11931199
/// #14587.)
11941200
fn check_legality_of_bindings_in_at_patterns(cx: &MatchCheckCtxt, pat: &Pat) {
1195-
AtBindingPatternVisitor { cx: cx, bindings_allowed: true }.visit_pat(pat);
1201+
AtBindingPatternVisitor { cx: cx, containing_binding: None }.visit_pat(pat);
11961202
}
11971203

11981204
struct AtBindingPatternVisitor<'a, 'b:'a, 'tcx:'b> {
11991205
cx: &'a MatchCheckCtxt<'b, 'tcx>,
1200-
bindings_allowed: bool
1206+
containing_binding: Option<Span>,
12011207
}
12021208

12031209
impl<'a, 'b, 'tcx, 'v> Visitor<'v> for AtBindingPatternVisitor<'a, 'b, 'tcx> {
12041210
fn visit_pat(&mut self, pat: &Pat) {
12051211
match pat.node {
12061212
PatKind::Binding(_, _, ref subpat) => {
1207-
if !self.bindings_allowed {
1208-
span_err!(self.cx.tcx.sess, pat.span, E0303,
1209-
"pattern bindings are not allowed after an `@`");
1213+
if let Some(containing_binding) = self.containing_binding {
1214+
struct_span_err!(
1215+
self.cx.tcx.sess, pat.span, E0303,
1216+
"nested pattern bindings are invalid")
1217+
.span_label(pat.span, &"invalid nested binding here")
1218+
.span_label(containing_binding, &"within this binding")
1219+
.emit();
12101220
}
12111221

12121222
if subpat.is_some() {
1213-
let bindings_were_allowed = self.bindings_allowed;
1214-
self.bindings_allowed = false;
1223+
let containing_binding = mem::replace(
1224+
&mut self.containing_binding, Some(pat.span));
12151225
intravisit::walk_pat(self, pat);
1216-
self.bindings_allowed = bindings_were_allowed;
1226+
self.containing_binding = containing_binding;
12171227
}
12181228
}
12191229
_ => intravisit::walk_pat(self, pat),

src/librustc_const_eval/diagnostics.rs

+1-31
Original file line numberDiff line numberDiff line change
@@ -40,37 +40,6 @@ Ensure the ordering of the match arm is correct and remove any superfluous
4040
arms.
4141
"##,
4242

43-
E0002: r##"
44-
This error indicates that an empty match expression is invalid because the type
45-
it is matching on is non-empty (there exist values of this type). In safe code
46-
it is impossible to create an instance of an empty type, so empty match
47-
expressions are almost never desired. This error is typically fixed by adding
48-
one or more cases to the match expression.
49-
50-
An example of an empty type is `enum Empty { }`. So, the following will work:
51-
52-
```
53-
enum Empty {}
54-
55-
fn foo(x: Empty) {
56-
match x {
57-
// empty
58-
}
59-
}
60-
```
61-
62-
However, this won't:
63-
64-
```compile_fail
65-
fn foo(x: Option<String>) {
66-
match x {
67-
// empty
68-
}
69-
}
70-
```
71-
"##,
72-
73-
7443
E0003: r##"
7544
Not-a-Number (NaN) values cannot be compared for equality and hence can never
7645
match the input to a match expression. So, the following will not compile:
@@ -594,6 +563,7 @@ let x = [0i32; 2];
594563

595564

596565
register_diagnostics! {
566+
// E0002, // duplicated from E0001
597567
E0298, // cannot compare constants
598568
// E0299, // mismatched types between arms
599569
// E0471, // constant evaluation error (in pattern)

src/test/compile-fail/E0002.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -11,5 +11,5 @@
1111
fn main() {
1212
let x = Some(1);
1313

14-
match x { } //~ ERROR E0002
14+
match x { } //~ ERROR E0004
1515
}

src/test/compile-fail/bind-by-move-neither-can-live-while-the-other-survives-2.rs

+1
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ fn main() {
2020
let x = Some((X { x: () }, X { x: () }));
2121
match x {
2222
Some((ref _y, _z)) => { }, //~ ERROR cannot bind by-move and by-ref in the same pattern
23+
//~| invalid by-move binding here
2324
None => panic!()
2425
}
2526
}

src/test/compile-fail/bind-by-move-neither-can-live-while-the-other-survives-3.rs

+1
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ fn main() {
2323
match x {
2424
double_option::some2(ref _y, _z) => { },
2525
//~^ ERROR cannot bind by-move and by-ref in the same pattern
26+
//~| invalid by-move binding here
2627
double_option::none2 => panic!()
2728
}
2829
}

src/test/compile-fail/bind-by-move-neither-can-live-while-the-other-survives-4.rs

+1
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ fn main() {
2020
let x = Some((X { x: () }, X { x: () }));
2121
match x {
2222
Some((_y, ref _z)) => { }, //~ ERROR cannot bind by-move and by-ref in the same pattern
23+
//~| invalid by-move binding here
2324
None => panic!()
2425
}
2526
}

src/test/compile-fail/bind-by-move-no-guards.rs

+1
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ fn main() {
1717
match x {
1818
Some(z) if z.recv().unwrap() => { panic!() },
1919
//~^ ERROR cannot bind by-move into a pattern guard
20+
//~| invalid by-move binding here
2021
Some(z) => { assert!(!z.recv().unwrap()); },
2122
None => panic!()
2223
}

src/test/compile-fail/issue-15129.rs

+2-1
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,8 @@ pub enum V {
2020

2121
fn main() {
2222
match (T::T1(()), V::V2(true)) {
23-
//~^ ERROR non-exhaustive patterns: `(T1(()), V2(_))` not covered
23+
//~^ ERROR non-exhaustive patterns
24+
//~| `(T1(()), V2(_))` not covered
2425
(T::T1(()), V::V1(i)) => (),
2526
(T::T2(()), V::V2(b)) => ()
2627
}

src/test/compile-fail/issue-15381.rs

+2-1
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,8 @@ fn main() {
1414
let values: Vec<u8> = vec![1,2,3,4,5,6,7,8];
1515

1616
for &[x,y,z] in values.chunks(3).filter(|&xs| xs.len() == 3) {
17-
//~^ ERROR refutable pattern in `for` loop binding: `&[]` not covered
17+
//~^ ERROR refutable pattern in `for` loop binding
18+
//~| `&[]` not covered
1819
println!("y={}", y);
1920
}
2021
}

src/test/compile-fail/issue-2111.rs

+2-1
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,8 @@
1010

1111
fn foo(a: Option<usize>, b: Option<usize>) {
1212
match (a,b) {
13-
//~^ ERROR: non-exhaustive patterns: `(None, None)` not covered
13+
//~^ ERROR: non-exhaustive patterns
14+
//~| `(None, None)` not covered
1415
(Some(a), Some(b)) if a == b => { }
1516
(Some(_), None) |
1617
(None, Some(_)) => { }

src/test/compile-fail/issue-30240.rs

+4-2
Original file line numberDiff line numberDiff line change
@@ -9,11 +9,13 @@
99
// except according to those terms.
1010

1111
fn main() {
12-
match "world" { //~ ERROR non-exhaustive patterns: `&_`
12+
match "world" { //~ ERROR non-exhaustive patterns
13+
//~| `&_` not covered
1314
"hello" => {}
1415
}
1516

16-
match "world" { //~ ERROR non-exhaustive patterns: `&_`
17+
match "world" { //~ ERROR non-exhaustive patterns
18+
//~| `&_` not covered
1719
ref _x if false => {}
1820
"hello" => {}
1921
"hello" => {} //~ ERROR unreachable pattern

0 commit comments

Comments
 (0)