Skip to content

Commit

Permalink
Point at const when intended binding fall-through pattern is a const
Browse files Browse the repository at this point in the history
```
error[E0004]: non-exhaustive patterns: `i32::MIN..=3_i32` and `5_i32..=i32::MAX` not covered
  --> $DIR/intended-binding-pattern-is-const.rs:2:11
   |
LL |     match 1 {
   |           ^ patterns `i32::MIN..=3_i32` and `5_i32..=i32::MAX` not covered
LL |         x => {}
   |         - this pattern doesn't introduce a new catch-all binding, but rather pattern matches against the value of constant `x`
   |
   = note: the matched value is of type `i32`
note: constant `x` defined here
  --> $DIR/intended-binding-pattern-is-const.rs:7:5
   |
LL |     const x: i32 = 4;
   |     ^^^^^^^^^^^^
help: if you meant to introduce a binding, use a different name
   |
LL |         x_var => {}
   |          ++++
help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern, a match arm with multiple or-patterns as shown, or multiple match arms
   |
LL |         x => {}, i32::MIN..=3_i32 | 5_i32..=i32::MAX => todo!()
   |                ++++++++++++++++++++++++++++++++++++++++++++++++
```
  • Loading branch information
estebank committed Nov 7, 2024
1 parent 3a25296 commit f7179b8
Show file tree
Hide file tree
Showing 3 changed files with 62 additions and 4 deletions.
29 changes: 25 additions & 4 deletions compiler/rustc_mir_build/src/thir/pattern/check_match.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1116,13 +1116,13 @@ fn report_non_exhaustive_match<'p, 'tcx>(
if ty.is_ptr_sized_integral() {
if ty.inner() == cx.tcx.types.usize {
err.note(format!(
"`{ty}` does not have a fixed maximum value, so half-open ranges are necessary to match \
exhaustively",
"`{ty}` does not have a fixed maximum value, so half-open ranges are \
necessary to match exhaustively",
));
} else if ty.inner() == cx.tcx.types.isize {
err.note(format!(
"`{ty}` does not have fixed minimum and maximum values, so half-open ranges are necessary to match \
exhaustively",
"`{ty}` does not have fixed minimum and maximum values, so half-open \
ranges are necessary to match exhaustively",
));
}
} else if ty.inner() == cx.tcx.types.str_ {
Expand All @@ -1143,6 +1143,27 @@ fn report_non_exhaustive_match<'p, 'tcx>(
}
}

for &arm in arms {
let arm = &thir.arms[arm];
if let PatKind::Constant { opt_def: Some(def_id), .. } = arm.pattern.kind {
let const_name = cx.tcx.item_name(def_id);
err.span_label(
arm.pattern.span,
format!(
"this pattern doesn't introduce a new catch-all binding, but rather pattern \
matches against the value of constant `{const_name}`",
),
);
err.span_note(cx.tcx.def_span(def_id), format!("constant `{const_name}` defined here"));
err.span_suggestion_verbose(
arm.pattern.span.shrink_to_hi(),
"if you meant to introduce a binding, use a different name",
"_var".to_string(),
Applicability::MaybeIncorrect,
);
}
}

// Whether we suggest the actual missing patterns or `_`.
let suggest_the_witnesses = witnesses.len() < 4;
let suggested_arm = if suggest_the_witnesses {
Expand Down
10 changes: 10 additions & 0 deletions tests/ui/match/intended-binding-pattern-is-const.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
fn main() {
match 1 { //~ ERROR non-exhaustive patterns
//~^ patterns `i32::MIN..=3_i32` and `5_i32..=i32::MAX` not covered
//~| the matched value is of type `i32`
x => {} //~ this pattern doesn't introduce a new catch-all binding
//~^ HELP ensure that all possible cases are being handled
//~| HELP if you meant to introduce a binding, use a different name
}
const x: i32 = 4; //~ NOTE constant `x` defined here
}
27 changes: 27 additions & 0 deletions tests/ui/match/intended-binding-pattern-is-const.stderr
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
error[E0004]: non-exhaustive patterns: `i32::MIN..=3_i32` and `5_i32..=i32::MAX` not covered
--> $DIR/intended-binding-pattern-is-const.rs:2:11
|
LL | match 1 {
| ^ patterns `i32::MIN..=3_i32` and `5_i32..=i32::MAX` not covered
...
LL | x => {}
| - this pattern doesn't introduce a new catch-all binding, but rather pattern matches against the value of constant `x`
|
= note: the matched value is of type `i32`
note: constant `x` defined here
--> $DIR/intended-binding-pattern-is-const.rs:9:5
|
LL | const x: i32 = 4;
| ^^^^^^^^^^^^
help: if you meant to introduce a binding, use a different name
|
LL | x_var => {}
| ++++
help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern, a match arm with multiple or-patterns as shown, or multiple match arms
|
LL | x => {}, i32::MIN..=3_i32 | 5_i32..=i32::MAX => todo!()
| ++++++++++++++++++++++++++++++++++++++++++++++++

error: aborting due to 1 previous error

For more information about this error, try `rustc --explain E0004`.

0 comments on commit f7179b8

Please sign in to comment.