Skip to content
Closed
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 3 additions & 5 deletions compiler/rustc_error_messages/locales/en-US/mir_build.ftl
Original file line number Diff line number Diff line change
Expand Up @@ -332,11 +332,9 @@ mir_build_non_exhaustive_omitted_pattern = some variants are not matched explici
.note = the matched value is of type `{$scrut_ty}` and the `non_exhaustive_omitted_patterns` attribute was found

mir_build_uncovered = {$count ->
[1] pattern `{$witness_1}`
[2] patterns `{$witness_1}` and `{$witness_2}`
[3] patterns `{$witness_1}`, `{$witness_2}` and `{$witness_3}`
*[other] patterns `{$witness_1}`, `{$witness_2}`, `{$witness_3}` and {$remainder} more
} not covered
[1] pattern
*[other] patterns
} {$witnesses} not covered

mir_build_pattern_not_covered = refutable pattern in {$origin}
.pattern_ty = the matched value is of type `{$pattern_ty}`
Expand Down
37 changes: 37 additions & 0 deletions compiler/rustc_errors/src/diagnostic_impls.rs
Original file line number Diff line number Diff line change
Expand Up @@ -256,3 +256,40 @@ impl IntoDiagnostic<'_, !> for TargetDataLayoutErrors<'_> {
}
}
}

/// Formats a Vec of DiagnosticArgValue
///
/// ""
/// "a"
/// "a and b"
/// "a, b and c"
/// "a, b, c and d"
/// "a, b, c and 2 more"
impl<T: IntoDiagnosticArg> IntoDiagnosticArg for Vec<T> {
fn into_diagnostic_arg(self) -> DiagnosticArgValue<'static> {
let mut args: Vec<Cow<'static, str>> = Vec::new();

for arg in self {
match arg.into_diagnostic_arg() {
DiagnosticArgValue::Str(s) => args.push(format!("`{s}`").into()),
DiagnosticArgValue::Number(i) => args.push(format!("`{i}`").into()),
DiagnosticArgValue::StrListSepByAnd(list) => {
for item in list {
args.push(format!("`{item}`").into());
}
}
}
}

// Avoid saying "and 1 more"
if args.len() > 4 {
args.truncate(3);

// FIXME(mejrs) This needs some form of translation
let more = format!("{} more", args.len() - 3).into();
args.push(more);
}

DiagnosticArgValue::StrListSepByAnd(args)
}
}
29 changes: 3 additions & 26 deletions compiler/rustc_mir_build/src/errors.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
use crate::thir::pattern::deconstruct_pat::DeconstructedPat;
use crate::thir::pattern::MatchCheckCtxt;
use rustc_errors::Handler;
use rustc_errors::{
Expand Down Expand Up @@ -723,31 +722,9 @@ pub(crate) struct NonExhaustiveOmittedPattern<'tcx> {
#[label(mir_build_uncovered)]
pub(crate) struct Uncovered<'tcx> {
#[primary_span]
span: Span,
count: usize,
witness_1: Pat<'tcx>,
witness_2: Pat<'tcx>,
witness_3: Pat<'tcx>,
remainder: usize,
}

impl<'tcx> Uncovered<'tcx> {
pub fn new<'p>(
span: Span,
cx: &MatchCheckCtxt<'p, 'tcx>,
witnesses: Vec<DeconstructedPat<'p, 'tcx>>,
) -> Self {
let witness_1 = witnesses.get(0).unwrap().to_pat(cx);
Self {
span,
count: witnesses.len(),
// Substitute dummy values if witnesses is smaller than 3. These will never be read.
witness_2: witnesses.get(1).map(|w| w.to_pat(cx)).unwrap_or_else(|| witness_1.clone()),
witness_3: witnesses.get(2).map(|w| w.to_pat(cx)).unwrap_or_else(|| witness_1.clone()),
witness_1,
remainder: witnesses.len().saturating_sub(3),
}
}
pub span: Span,
pub count: usize,
pub witnesses: Vec<Pat<'tcx>>,
}

#[derive(Diagnostic)]
Expand Down
5 changes: 4 additions & 1 deletion compiler/rustc_mir_build/src/thir/pattern/check_match.rs
Original file line number Diff line number Diff line change
Expand Up @@ -455,10 +455,13 @@ impl<'p, 'tcx> MatchVisitor<'_, 'p, 'tcx> {
AdtDefinedHere { adt_def_span, ty, variants }
};

let witnesses: Vec<_> = witnesses.into_iter().map(|w| w.to_pat(&cx)).collect();
let uncovered = Uncovered { span: pat.span, count: witnesses.len(), witnesses };

self.tcx.sess.emit_err(PatternNotCovered {
span: pat.span,
origin,
uncovered: Uncovered::new(pat.span, &cx, witnesses),
uncovered,
inform,
interpreted_as_const,
_p: (),
Expand Down
6 changes: 5 additions & 1 deletion compiler/rustc_mir_build/src/thir/pattern/usefulness.rs
Original file line number Diff line number Diff line change
Expand Up @@ -897,7 +897,11 @@ fn is_useful<'p, 'tcx>(
pcx.span,
NonExhaustiveOmittedPattern {
scrut_ty: pcx.ty,
uncovered: Uncovered::new(pcx.span, pcx.cx, patterns),
uncovered: {
let witnesses: Vec<_> =
patterns.into_iter().map(|w| w.to_pat(&pcx.cx)).collect();
Uncovered { span: pcx.span, count: witnesses.len(), witnesses }
},
},
);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -52,3 +52,19 @@ fn main() {
let mut mut_e4 = e4;
_h();
}

pub enum X {
A,
B,
C,
D,
E,
F,
G,
H,
}

pub fn many(x: X) {
match x {}
//~^ ERROR non-exhaustive patterns: `X::A`, `X::B`, `X::C` and 5 more not covered [E0004]
}
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,25 @@ help: ensure that all possible cases are being handled by adding a match arm wit
LL | let _e = || { match e2 { E2::A => (), E2::B => (), _ => todo!() } };
| ++++++++++++++

error[E0004]: non-exhaustive patterns: `X::A`, `X::B`, `X::C` and 5 more not covered
--> $DIR/non-exhaustive-match.rs:68:11
|
LL | match x {}
| ^ patterns `X::A`, `X::B`, `X::C` and 5 more not covered
|
note: `X` defined here
--> $DIR/non-exhaustive-match.rs:56:10
|
LL | pub enum X {
| ^
= note: the matched value is of type `X`
help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern as shown, or multiple match arms
|
LL ~ match x {
LL + _ => todo!(),
LL + }
|

error[E0505]: cannot move out of `e3` because it is borrowed
--> $DIR/non-exhaustive-match.rs:46:22
|
Expand All @@ -64,7 +83,7 @@ LL |
LL | _g();
| -- borrow later used here

error: aborting due to 4 previous errors
error: aborting due to 5 previous errors

Some errors have detailed explanations: E0004, E0505.
For more information about an error, try `rustc --explain E0004`.
2 changes: 1 addition & 1 deletion tests/ui/consts/const_let_refutable.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ error[E0005]: refutable pattern in function argument
--> $DIR/const_let_refutable.rs:3:16
|
LL | const fn slice(&[a, b]: &[i32]) -> i32 {
| ^^^^^^^ patterns `&[]`, `&[_]` and `&[_, _, _, ..]` not covered
| ^^^^^^^ patterns `&[]`, `&[_]`, and `&[_, _, _, ..]` not covered
|
= note: the matched value is of type `&[i32]`

Expand Down
2 changes: 1 addition & 1 deletion tests/ui/issues/issue-15381.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ fn main() {

for &[x,y,z] in values.chunks(3).filter(|&xs| xs.len() == 3) {
//~^ ERROR refutable pattern in `for` loop binding
//~| patterns `&[]`, `&[_]`, `&[_, _]` and 1 more not covered
//~| patterns `&[]`, `&[_]`, `&[_, _]`, and `&[_, _, _, _, ..]` not covered
println!("y={}", y);
}
}
2 changes: 1 addition & 1 deletion tests/ui/issues/issue-15381.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ error[E0005]: refutable pattern in `for` loop binding
--> $DIR/issue-15381.rs:4:9
|
LL | for &[x,y,z] in values.chunks(3).filter(|&xs| xs.len() == 3) {
| ^^^^^^^^ patterns `&[]`, `&[_]`, `&[_, _]` and 1 more not covered
| ^^^^^^^^ patterns `&[]`, `&[_]`, `&[_, _]`, and `&[_, _, _, _, ..]` not covered
|
= note: the matched value is of type `&[u8]`

Expand Down