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
Next Next commit
Shorten e0004 description
  • Loading branch information
mejrs committed Mar 12, 2023
commit 3ddfeeb1ebbefd4171afe47cb1ee2c5d83a33361
9 changes: 5 additions & 4 deletions compiler/rustc_mir_build/messages.ftl
Original file line number Diff line number Diff line change
Expand Up @@ -176,10 +176,10 @@ mir_build_unused_unsafe = unnecessary `unsafe` block
mir_build_unused_unsafe_enclosing_block_label = because it's nested under this `unsafe` block
mir_build_unused_unsafe_enclosing_fn_label = because it's nested under this `unsafe` fn

mir_build_non_exhaustive_patterns_type_not_empty = non-exhaustive patterns: type `{$ty}` is non-empty
mir_build_non_exhaustive_patterns_type_not_empty = non-exhaustive patterns: type `{$scrut_ty}` is non-empty
.def_note = `{$peeled_ty}` defined here
.type_note = the matched value is of type `{$ty}`
.non_exhaustive_type_note = the matched value is of type `{$ty}`, which is marked as non-exhaustive
.type_note = the matched value is of type `{$scrut_ty}`
.non_exhaustive_type_note = the matched value is of type `{$scrut_ty}`, which is marked as non-exhaustive
.reference_note = references are always considered inhabited
.suggestion = ensure that all possible cases are being handled by adding a match arm with a wildcard pattern as shown
.help = ensure that all possible cases are being handled by adding a match arm with a wildcard pattern
Expand Down Expand Up @@ -375,8 +375,9 @@ mir_build_suggest_let_else = you might want to use `let else` to handle the {$co

mir_build_suggest_attempted_int_lit = alternatively, you could prepend the pattern with an underscore to define a new named variable; identifiers cannot begin with digits


mir_build_rustc_box_attribute_error = `#[rustc_box]` attribute used incorrectly
.attributes = no other attributes may be applied
.not_box = `#[rustc_box]` may only be applied to a `Box::new()` call
.missing_box = `#[rustc_box]` requires the `owned_box` lang item

mir_build_non_exhaustive_pattern = match is non-exhaustive
18 changes: 12 additions & 6 deletions compiler/rustc_mir_build/src/errors.rs
Original file line number Diff line number Diff line change
Expand Up @@ -352,7 +352,7 @@ pub(crate) struct NonExhaustivePatternsTypeNotEmpty<'p, 'tcx, 'm> {
pub cx: &'m MatchCheckCtxt<'p, 'tcx>,
pub expr_span: Span,
pub span: Span,
pub ty: Ty<'tcx>,
pub scrut_ty: Ty<'tcx>,
}

impl<'a> IntoDiagnostic<'a> for NonExhaustivePatternsTypeNotEmpty<'_, '_, '_> {
Expand All @@ -363,8 +363,8 @@ impl<'a> IntoDiagnostic<'a> for NonExhaustivePatternsTypeNotEmpty<'_, '_, '_> {
error_code!(E0004),
);

let peeled_ty = self.ty.peel_refs();
diag.set_arg("ty", self.ty);
let peeled_ty = self.scrut_ty.peel_refs();
diag.set_arg("scrut_ty", self.scrut_ty);
diag.set_arg("peeled_ty", peeled_ty);

if let ty::Adt(def, _) = peeled_ty.kind() {
Expand All @@ -384,7 +384,7 @@ impl<'a> IntoDiagnostic<'a> for NonExhaustivePatternsTypeNotEmpty<'_, '_, '_> {
diag.span_note(span, fluent::mir_build_def_note);
}

let is_variant_list_non_exhaustive = match self.ty.kind() {
let is_variant_list_non_exhaustive = match self.scrut_ty.kind() {
ty::Adt(def, _) if def.is_variant_list_non_exhaustive() && !def.did().is_local() => {
true
}
Expand All @@ -397,7 +397,7 @@ impl<'a> IntoDiagnostic<'a> for NonExhaustivePatternsTypeNotEmpty<'_, '_, '_> {
diag.note(fluent::mir_build_type_note);
}

if let ty::Ref(_, sub_ty, _) = self.ty.kind() {
if let ty::Ref(_, sub_ty, _) = self.scrut_ty.kind() {
if !sub_ty.is_inhabited_from(self.cx.tcx, self.cx.module, self.cx.param_env) {
diag.note(fluent::mir_build_reference_note);
}
Expand Down Expand Up @@ -760,7 +760,7 @@ impl<'tcx> Uncovered<'tcx> {
pub fn new<'p>(
span: Span,
cx: &MatchCheckCtxt<'p, 'tcx>,
witnesses: Vec<DeconstructedPat<'p, 'tcx>>,
witnesses: &[DeconstructedPat<'p, 'tcx>],
) -> Self {
let witness_1 = witnesses.get(0).unwrap().to_pat(cx);
Self {
Expand Down Expand Up @@ -906,4 +906,10 @@ pub enum RustcBoxAttrReason {
NotBoxNew,
#[note(mir_build_missing_box)]
MissingBox,
#[diag(mir_build_non_exhaustive_pattern, code = "E0004")]
pub(crate) struct NonExhaustivePatterns<'tcx> {
#[primary_span]
pub span: Span,
#[subdiagnostic]
pub uncovered: Uncovered<'tcx>,
}
96 changes: 23 additions & 73 deletions compiler/rustc_mir_build/src/thir/pattern/check_match.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,12 @@ use super::usefulness::{
};
use super::{PatCtxt, PatternError};

use crate::errors::*;
use crate::errors::{self, *};

use hir::{ExprKind, PatKind};
use rustc_arena::TypedArena;
use rustc_ast::{LitKind, Mutability};
use rustc_errors::{
struct_span_err, Applicability, Diagnostic, DiagnosticBuilder, ErrorGuaranteed, MultiSpan,
};
use rustc_errors::{Applicability, Diagnostic, MultiSpan};
use rustc_hir as hir;
use rustc_hir::def::*;
use rustc_hir::def_id::DefId;
Expand All @@ -23,7 +21,6 @@ use rustc_middle::ty::{self, AdtDef, Ty, TyCtxt};
use rustc_session::lint::builtin::{
BINDINGS_WITH_VARIANT_NAME, IRREFUTABLE_LET_PATTERNS, UNREACHABLE_PATTERNS,
};
use rustc_session::Session;
use rustc_span::source_map::Spanned;
use rustc_span::{BytePos, Span};

Expand All @@ -43,14 +40,6 @@ pub(crate) fn check_match(tcx: TyCtxt<'_>, def_id: DefId) {
visitor.visit_body(tcx.hir().body(body_id));
}

fn create_e0004(
sess: &Session,
sp: Span,
error_message: String,
) -> DiagnosticBuilder<'_, ErrorGuaranteed> {
struct_span_err!(sess, sp, E0004, "{}", &error_message)
}

#[derive(PartialEq)]
enum RefutableFlag {
Irrefutable,
Expand Down Expand Up @@ -458,7 +447,7 @@ impl<'p, 'tcx> MatchVisitor<'_, 'p, 'tcx> {
self.tcx.sess.emit_err(PatternNotCovered {
span: pat.span,
origin,
uncovered: Uncovered::new(pat.span, &cx, witnesses),
uncovered: Uncovered::new(pat.span, &cx, &witnesses),
inform,
interpreted_as_const,
_p: (),
Expand Down Expand Up @@ -605,7 +594,7 @@ fn report_arm_reachability<'p, 'tcx>(
fn non_exhaustive_match<'p, 'tcx>(
cx: &MatchCheckCtxt<'p, 'tcx>,
scrut_ty: Ty<'tcx>,
sp: Span,
span: Span,
witnesses: Vec<DeconstructedPat<'p, 'tcx>>,
arms: &[hir::Arm<'tcx>],
expr_span: Span,
Expand All @@ -617,38 +606,27 @@ fn non_exhaustive_match<'p, 'tcx>(
};
// In the case of an empty match, replace the '`_` not covered' diagnostic with something more
// informative.
let mut err;
let pattern;
let patterns_len;
if is_empty_match && !non_empty_enum {
cx.tcx.sess.emit_err(NonExhaustivePatternsTypeNotEmpty {
cx,
expr_span,
span: sp,
ty: scrut_ty,
});
cx.tcx.sess.emit_err(NonExhaustivePatternsTypeNotEmpty { cx, expr_span, span, scrut_ty });
return;
}

let patterns_len = witnesses.len();
let pattern = if witnesses.len() < 4 {
witnesses
.iter()
.map(|witness| witness.to_pat(cx).to_string())
.collect::<Vec<String>>()
.join(" | ")
} else {
// FIXME: migration of this diagnostic will require list support
let joined_patterns = joined_uncovered_patterns(cx, &witnesses);
err = create_e0004(
cx.tcx.sess,
sp,
format!("non-exhaustive patterns: {} not covered", joined_patterns),
);
err.span_label(sp, pattern_not_covered_label(&witnesses, &joined_patterns));
patterns_len = witnesses.len();
pattern = if witnesses.len() < 4 {
witnesses
.iter()
.map(|witness| witness.to_pat(cx).to_string())
.collect::<Vec<String>>()
.join(" | ")
} else {
"_".to_string()
};
"_".to_string()
};

let mut err = cx.tcx.sess.create_err(errors::NonExhaustivePatterns {
span,
uncovered: Uncovered::new(span, &cx, &witnesses),
});

let is_variant_list_non_exhaustive = match scrut_ty.kind() {
ty::Adt(def, _) if def.is_variant_list_non_exhaustive() && !def.did().is_local() => true,
_ => false,
Expand Down Expand Up @@ -687,15 +665,15 @@ fn non_exhaustive_match<'p, 'tcx>(
let mut suggestion = None;
let sm = cx.tcx.sess.source_map();
match arms {
[] if sp.eq_ctxt(expr_span) => {
[] if span.eq_ctxt(expr_span) => {
// Get the span for the empty match body `{}`.
let (indentation, more) = if let Some(snippet) = sm.indentation_before(sp) {
let (indentation, more) = if let Some(snippet) = sm.indentation_before(span) {
(format!("\n{}", snippet), " ")
} else {
(" ".to_string(), "")
};
suggestion = Some((
sp.shrink_to_hi().with_hi(expr_span.hi()),
span.shrink_to_hi().with_hi(expr_span.hi()),
format!(
" {{{indentation}{more}{pattern} => todo!(),{indentation}}}",
indentation = indentation,
Expand Down Expand Up @@ -776,34 +754,6 @@ fn non_exhaustive_match<'p, 'tcx>(
err.emit();
}

pub(crate) fn joined_uncovered_patterns<'p, 'tcx>(
cx: &MatchCheckCtxt<'p, 'tcx>,
witnesses: &[DeconstructedPat<'p, 'tcx>],
) -> String {
const LIMIT: usize = 3;
let pat_to_str = |pat: &DeconstructedPat<'p, 'tcx>| pat.to_pat(cx).to_string();
match witnesses {
[] => bug!(),
[witness] => format!("`{}`", witness.to_pat(cx)),
[head @ .., tail] if head.len() < LIMIT => {
let head: Vec<_> = head.iter().map(pat_to_str).collect();
format!("`{}` and `{}`", head.join("`, `"), tail.to_pat(cx))
}
_ => {
let (head, tail) = witnesses.split_at(LIMIT);
let head: Vec<_> = head.iter().map(pat_to_str).collect();
format!("`{}` and {} more", head.join("`, `"), tail.len())
}
}
}

pub(crate) fn pattern_not_covered_label(
witnesses: &[DeconstructedPat<'_, '_>],
joined_patterns: &str,
) -> String {
format!("pattern{} {} not covered", rustc_errors::pluralize!(witnesses.len()), joined_patterns)
}

/// Point at the definition of non-covered `enum` variants.
fn adt_defined_here<'p, 'tcx>(
cx: &MatchCheckCtxt<'p, 'tcx>,
Expand Down
2 changes: 1 addition & 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,7 @@ fn is_useful<'p, 'tcx>(
pcx.span,
NonExhaustiveOmittedPattern {
scrut_ty: pcx.ty,
uncovered: Uncovered::new(pcx.span, pcx.cx, patterns),
uncovered: Uncovered::new(pcx.span, pcx.cx, &patterns),
},
);
}
Expand Down
4 changes: 2 additions & 2 deletions tests/ui/closures/2229_closure_analysis/match/issue-88331.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ impl Opcode {

pub fn example1(msg_type: Opcode) -> impl FnMut(&[u8]) {
move |i| match msg_type {
//~^ ERROR: non-exhaustive patterns: `Opcode(0_u8)` and `Opcode(2_u8..=u8::MAX)` not covered
//~^ ERROR: match is non-exhaustive
Opcode::OP1 => unimplemented!(),
}
}
Expand All @@ -25,7 +25,7 @@ impl Opcode2 {
pub fn example2(msg_type: Opcode2) -> impl FnMut(&[u8]) {

move |i| match msg_type {
//~^ ERROR: non-exhaustive patterns: `Opcode2(Opcode(0_u8))` and `Opcode2(Opcode(2_u8..=u8::MAX))` not covered
//~^ ERROR: match is non-exhaustive
Opcode2::OP2=> unimplemented!(),
}
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
error[E0004]: non-exhaustive patterns: `Opcode(0_u8)` and `Opcode(2_u8..=u8::MAX)` not covered
error[E0004]: match is non-exhaustive
--> $DIR/issue-88331.rs:11:20
|
LL | move |i| match msg_type {
Expand All @@ -16,7 +16,7 @@ LL ~ Opcode::OP1 => unimplemented!(),
LL ~ Opcode(0_u8) | Opcode(2_u8..=u8::MAX) => todo!(),
|

error[E0004]: non-exhaustive patterns: `Opcode2(Opcode(0_u8))` and `Opcode2(Opcode(2_u8..=u8::MAX))` not covered
error[E0004]: match is non-exhaustive
--> $DIR/issue-88331.rs:27:20
|
LL | move |i| match msg_type {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ fn main() {
let _a = || { match l1 { L1::A => (), L1::B => () } };
// (except if the match is already non-exhaustive)
let _b = || { match l1 { L1::A => () } };
//~^ ERROR: non-exhaustive patterns: `L1::B` not covered [E0004]
//~^ ERROR match is non-exhaustive [E0004]

// l2 should not be captured as it is a non-exhaustive SingleVariant
// defined in this crate
Expand All @@ -37,7 +37,7 @@ fn main() {
let _d = || { match e1 {} };
//~^ ERROR: non-exhaustive patterns: type `E1` is non-empty [E0004]
let _e = || { match e2 { E2::A => (), E2::B => () } };
//~^ ERROR: non-exhaustive patterns: `_` not covered [E0004]
//~^ ERROR match is non-exhaustive [E0004]
let _f = || { match e2 { E2::A => (), E2::B => (), _ => () } };

// e3 should be captured as it is a non-exhaustive SingleVariant
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
error[E0004]: non-exhaustive patterns: `L1::B` not covered
error[E0004]: match is non-exhaustive
--> $DIR/non-exhaustive-match.rs:26:25
|
LL | let _b = || { match l1 { L1::A => () } };
Expand Down Expand Up @@ -34,7 +34,7 @@ LL + _ => todo!(),
LL ~ } };
|

error[E0004]: non-exhaustive patterns: `_` not covered
error[E0004]: match is non-exhaustive
--> $DIR/non-exhaustive-match.rs:39:25
|
LL | let _e = || { match e2 { E2::A => (), E2::B => () } };
Expand Down
2 changes: 1 addition & 1 deletion tests/ui/consts/const_in_pattern/incomplete-slice.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ const E_SL: &[E] = &[E::A];

fn main() {
match &[][..] {
//~^ ERROR non-exhaustive patterns: `&_` not covered [E0004]
//~^ ERROR match is non-exhaustive [E0004]
E_SL => {}
//~^ WARN to use a constant of type `E` in a pattern, `E` must be annotated with `#[derive(PartialEq, Eq)]`
//~| WARN this was previously accepted by the compiler but is being phased out
Expand Down
2 changes: 1 addition & 1 deletion tests/ui/consts/const_in_pattern/incomplete-slice.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ LL | E_SL => {}
= note: for more information, see issue #62411 <https://github.com/rust-lang/rust/issues/62411>
= note: `#[warn(indirect_structural_match)]` on by default

error[E0004]: non-exhaustive patterns: `&_` not covered
error[E0004]: match is non-exhaustive
--> $DIR/incomplete-slice.rs:9:11
|
LL | match &[][..] {
Expand Down
2 changes: 1 addition & 1 deletion tests/ui/error-codes/E0004-2.stderr
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
error[E0004]: non-exhaustive patterns: `None` and `Some(_)` not covered
error[E0004]: match is non-exhaustive
--> $DIR/E0004-2.rs:4:11
|
LL | match x { }
Expand Down
2 changes: 1 addition & 1 deletion tests/ui/error-codes/E0004.stderr
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
error[E0004]: non-exhaustive patterns: `Terminator::HastaLaVistaBaby` not covered
error[E0004]: match is non-exhaustive
--> $DIR/E0004.rs:9:11
|
LL | match x {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ fn main() {
Foo::A => {}
Foo::B => {}
}
//~^^^^ ERROR non-exhaustive patterns: `Foo::C` not covered
//~^^^^ ERROR match is non-exhaustive

match Foo::A {
Foo::A => {}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -99,7 +99,7 @@ LL | #[warn(non_exhaustive_omitted_patterns)]
= note: see issue #89554 <https://github.com/rust-lang/rust/issues/89554> for more information
= help: add `#![feature(non_exhaustive_omitted_patterns_lint)]` to the crate attributes to enable

error[E0004]: non-exhaustive patterns: `Foo::C` not covered
error[E0004]: match is non-exhaustive
--> $DIR/feature-gate-non_exhaustive_omitted_patterns_lint.rs:20:11
|
LL | match Foo::A {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
fn main() {
match 0usize {
//~^ ERROR non-exhaustive patterns: `_` not covered
//~^ ERROR match is non-exhaustive
//~| NOTE pattern `_` not covered
//~| NOTE the matched value is of type `usize`
//~| NOTE `usize` does not have a fixed maximum value
0..=usize::MAX => {}
}

match 0isize {
//~^ ERROR non-exhaustive patterns: `_` not covered
//~^ ERROR match is non-exhaustive
//~| NOTE pattern `_` not covered
//~| NOTE the matched value is of type `isize`
//~| NOTE `isize` does not have a fixed maximum value
Expand Down
Loading