Auto merge of #117611 - Nadrieril:linear-pass-take-4, r=cjgillot

Rewrite exhaustiveness in one pass

This is at least my 4th attempt at this in as many years x) Previous attempts were all too complicated or too slow. But we're finally here!

The previous version of the exhaustiveness algorithm computed reachability for each arm then exhaustiveness of the whole match. Since each of these steps does roughly the same things, this rewrites the algorithm to do them all in one go. I also think this makes things much simpler.

I also rewrote the documentation of the algorithm in depth. Hopefully it's up-to-date and easier to follow now. Plz comment if anything's unclear.

r? `@oli-obk` I think you're one of the rare other people to understand the exhaustiveness algorithm?

cc `@varkor` I know you're not active anymore, but if you feel like having a look you might enjoy this :D

Fixes https://github.com/rust-lang/rust/issues/79307
This commit is contained in:
bors 2023-11-26 00:14:14 +00:00
commit ee80c8d0a8
18 changed files with 1380 additions and 1088 deletions

View File

@ -279,8 +279,10 @@ impl<'thir, 'p, 'tcx> MatchVisitor<'thir, 'p, 'tcx> {
} else {
// Check the pattern for some things unrelated to exhaustiveness.
let refutable = if cx.refutable { Refutable } else { Irrefutable };
pat.walk_always(|pat| check_borrow_conflicts_in_at_patterns(self, pat));
pat.walk_always(|pat| check_for_bindings_named_same_as_variants(self, pat, refutable));
pat.walk_always(|pat| {
check_borrow_conflicts_in_at_patterns(self, pat);
check_for_bindings_named_same_as_variants(self, pat, refutable);
});
Ok(cx.pattern_arena.alloc(DeconstructedPat::from_pat(cx, pat)))
}
}
@ -289,6 +291,7 @@ impl<'thir, 'p, 'tcx> MatchVisitor<'thir, 'p, 'tcx> {
&self,
refutability: RefutableFlag,
match_span: Option<Span>,
scrut_span: Span,
) -> MatchCheckCtxt<'p, 'tcx> {
let refutable = match refutability {
Irrefutable => false,
@ -299,7 +302,9 @@ impl<'thir, 'p, 'tcx> MatchVisitor<'thir, 'p, 'tcx> {
param_env: self.param_env,
module: self.tcx.parent_module(self.lint_level).to_def_id(),
pattern_arena: self.pattern_arena,
match_lint_level: self.lint_level,
match_span,
scrut_span,
refutable,
}
}
@ -330,7 +335,8 @@ impl<'thir, 'p, 'tcx> MatchVisitor<'thir, 'p, 'tcx> {
source: hir::MatchSource,
expr_span: Span,
) {
let cx = self.new_cx(Refutable, Some(expr_span));
let scrut = &self.thir[scrut];
let cx = self.new_cx(Refutable, Some(expr_span), scrut.span);
let mut tarms = Vec::with_capacity(arms.len());
for &arm in arms {
@ -346,9 +352,8 @@ impl<'thir, 'p, 'tcx> MatchVisitor<'thir, 'p, 'tcx> {
}
}
let scrut = &self.thir[scrut];
let scrut_ty = scrut.ty;
let report = compute_match_usefulness(&cx, &tarms, self.lint_level, scrut_ty, scrut.span);
let report = compute_match_usefulness(&cx, &tarms, scrut_ty);
match source {
// Don't report arm reachability of desugared `match $iter.into_iter() { iter => .. }`
@ -453,10 +458,10 @@ impl<'thir, 'p, 'tcx> MatchVisitor<'thir, 'p, 'tcx> {
pat: &Pat<'tcx>,
refutability: RefutableFlag,
) -> Result<(MatchCheckCtxt<'p, 'tcx>, UsefulnessReport<'p, 'tcx>), ErrorGuaranteed> {
let cx = self.new_cx(refutability, None);
let cx = self.new_cx(refutability, None, pat.span);
let pat = self.lower_pattern(&cx, pat)?;
let arms = [MatchArm { pat, hir_id: self.lint_level, has_guard: false }];
let report = compute_match_usefulness(&cx, &arms, self.lint_level, pat.ty(), pat.span());
let report = compute_match_usefulness(&cx, &arms, pat.ty());
Ok((cx, report))
}

View File

@ -1,46 +1,88 @@
//! [`super::usefulness`] explains most of what is happening in this file. As explained there,
//! values and patterns are made from constructors applied to fields. This file defines a
//! `Constructor` enum, a `Fields` struct, and various operations to manipulate them and convert
//! them from/to patterns.
//! As explained in [`super::usefulness`], values and patterns are made from constructors applied to
//! fields. This file defines a `Constructor` enum, a `Fields` struct, and various operations to
//! manipulate them and convert them from/to patterns.
//!
//! There's one idea that is not detailed in [`super::usefulness`] because the details are not
//! needed there: _constructor splitting_.
//! There are two important bits of core logic in this file: constructor inclusion and constructor
//! splitting. Constructor inclusion, i.e. whether a constructor is included in/covered by another,
//! is straightforward and defined in [`Constructor::is_covered_by`].
//!
//! # Constructor splitting
//! Constructor splitting is mentioned in [`super::usefulness`] but not detailed. We describe it
//! precisely here.
//!
//! The idea is as follows: given a constructor `c` and a matrix, we want to specialize in turn
//! with all the value constructors that are covered by `c`, and compute usefulness for each.
//! Instead of listing all those constructors (which is intractable), we group those value
//! constructors together as much as possible. Example:
//!
//! # Constructor grouping and splitting
//!
//! As explained in the corresponding section in [`super::usefulness`], to make usefulness tractable
//! we need to group together constructors that have the same effect when they are used to
//! specialize the matrix.
//!
//! Example:
//! ```compile_fail,E0004
//! match (0, false) {
//! (0 ..=100, true) => {} // `p_1`
//! (50..=150, false) => {} // `p_2`
//! (0 ..=200, _) => {} // `q`
//! (0 ..=100, true) => {}
//! (50..=150, false) => {}
//! (0 ..=200, _) => {}
//! }
//! ```
//!
//! The naive approach would try all numbers in the range `0..=200`. But we can be a lot more
//! clever: `0` and `1` for example will match the exact same rows, and return equivalent
//! witnesses. In fact all of `0..50` would. We can thus restrict our exploration to 4
//! constructors: `0..50`, `50..=100`, `101..=150` and `151..=200`. That is enough and infinitely
//! more tractable.
//! In this example we can restrict specialization to 5 cases: `0..50`, `50..=100`, `101..=150`,
//! `151..=200` and `200..`.
//!
//! We capture this idea in a function `split(p_1 ... p_n, c)` which returns a list of constructors
//! `c'` covered by `c`. Given such a `c'`, we require that all value ctors `c''` covered by `c'`
//! return an equivalent set of witnesses after specializing and computing usefulness.
//! In the example above, witnesses for specializing by `c''` covered by `0..50` will only differ
//! in their first element.
//! In [`super::usefulness`], we had said that `specialize` only takes value-only constructors. We
//! now relax this restriction: we allow `specialize` to take constructors like `0..50` as long as
//! we're careful to only do that with constructors that make sense. For example, `specialize(0..50,
//! (0..=100, true))` is sensible, but `specialize(50..=200, (0..=100, true))` is not.
//!
//! We usually also ask that the `c'` together cover all of the original `c`. However we allow
//! skipping some constructors as long as it doesn't change whether the resulting list of witnesses
//! is empty of not. We use this in the wildcard `_` case.
//! Constructor splitting looks at the constructors in the first column of the matrix and constructs
//! such a sensible set of constructors. Formally, we want to find a smallest disjoint set of
//! constructors:
//! - Whose union covers the whole type, and
//! - That have no non-trivial intersection with any of the constructors in the column (i.e. they're
//! each either disjoint with or covered by any given column constructor).
//!
//! Splitting is implemented in the [`Constructor::split`] function. We don't do splitting for
//! or-patterns; instead we just try the alternatives one-by-one. For details on splitting
//! wildcards, see [`Constructor::split`]; for integer ranges, see
//! [`IntRange::split`]; for slices, see [`Slice::split`].
//! We compute this in two steps: first [`ConstructorSet::for_ty`] determines the set of all
//! possible constructors for the type. Then [`ConstructorSet::split`] looks at the column of
//! constructors and splits the set into groups accordingly. The precise invariants of
//! [`ConstructorSet::split`] is described in [`SplitConstructorSet`].
//!
//! Constructor splitting has two interesting special cases: integer range splitting (see
//! [`IntRange::split`]) and slice splitting (see [`Slice::split`]).
//!
//!
//! # The `Missing` constructor
//!
//! We detail a special case of constructor splitting that is a bit subtle. Take the following:
//!
//! ```
//! enum Direction { North, South, East, West }
//! # let wind = (Direction::North, 0u8);
//! match wind {
//! (Direction::North, 50..) => {}
//! (_, _) => {}
//! }
//! ```
//!
//! Here we expect constructor splitting to output two cases: `North`, and "everything else". This
//! "everything else" is represented by [`Constructor::Missing`]. Unlike other constructors, it's a
//! bit contextual: to know the exact list of constructors it represents we have to look at the
//! column. In practice however we don't need to, because by construction it only matches rows that
//! have wildcards. This is how this constructor is special: the only constructor that covers it is
//! `Wildcard`.
//!
//! The only place where we care about which constructors `Missing` represents is in diagnostics
//! (see `super::usefulness::WitnessMatrix::apply_constructor`).
//!
//! We choose whether to specialize with `Missing` in
//! `super::usefulness::compute_exhaustiveness_and_reachability`.
//!
//!
//!
//! ## Opaque patterns
//!
//! Some patterns, such as constants that are not allowed to be matched structurally, cannot be
//! inspected, which we handle with `Constructor::Opaque`. Since we know nothing of these patterns,
//! we assume they never cover each other. In order to respect the invariants of
//! [`SplitConstructorSet`], we give each `Opaque` constructor a unique id so we can recognize it.
use std::cell::Cell;
use std::cmp::{self, max, min, Ordering};
@ -617,6 +659,18 @@ impl Slice {
}
}
/// A globally unique id to distinguish `Opaque` patterns.
#[derive(Clone, Debug, PartialEq, Eq)]
pub(super) struct OpaqueId(u32);
impl OpaqueId {
fn new() -> Self {
use std::sync::atomic::{AtomicU32, Ordering};
static OPAQUE_ID: AtomicU32 = AtomicU32::new(0);
OpaqueId(OPAQUE_ID.fetch_add(1, Ordering::SeqCst))
}
}
/// A value can be decomposed into a constructor applied to some fields. This struct represents
/// the constructor. See also `Fields`.
///
@ -626,8 +680,8 @@ impl Slice {
/// `Fields`.
#[derive(Clone, Debug, PartialEq)]
pub(super) enum Constructor<'tcx> {
/// The constructor for patterns that have a single constructor, like tuples, struct patterns
/// and fixed-length arrays.
/// The constructor for patterns that have a single constructor, like tuples, struct patterns,
/// and references. Fixed-length arrays are treated separately with `Slice`.
Single,
/// Enum variants.
Variant(VariantIdx),
@ -642,10 +696,12 @@ pub(super) enum Constructor<'tcx> {
Str(mir::Const<'tcx>),
/// Array and slice patterns.
Slice(Slice),
/// Constants that must not be matched structurally. They are treated as black
/// boxes for the purposes of exhaustiveness: we must not inspect them, and they
/// don't count towards making a match exhaustive.
Opaque,
/// Constants that must not be matched structurally. They are treated as black boxes for the
/// purposes of exhaustiveness: we must not inspect them, and they don't count towards making a
/// match exhaustive.
/// Carries an id that must be unique within a match. We need this to ensure the invariants of
/// [`SplitConstructorSet`].
Opaque(OpaqueId),
/// Or-pattern.
Or,
/// Wildcard pattern.
@ -657,12 +713,15 @@ pub(super) enum Constructor<'tcx> {
/// We use this for variants behind an unstable gate as well as
/// `#[doc(hidden)]` ones.
Hidden,
/// Fake extra constructor for constructors that are not seen in the matrix, as explained in the
/// code for [`Constructor::split`].
/// Fake extra constructor for constructors that are not seen in the matrix, as explained at the
/// top of the file.
Missing,
}
impl<'tcx> Constructor<'tcx> {
pub(super) fn is_wildcard(&self) -> bool {
matches!(self, Wildcard)
}
pub(super) fn is_non_exhaustive(&self) -> bool {
matches!(self, NonExhaustive)
}
@ -728,7 +787,7 @@ impl<'tcx> Constructor<'tcx> {
| F32Range(..)
| F64Range(..)
| Str(..)
| Opaque
| Opaque(..)
| NonExhaustive
| Hidden
| Missing { .. }
@ -737,109 +796,23 @@ impl<'tcx> Constructor<'tcx> {
}
}
/// Some constructors (namely `Wildcard`, `IntRange` and `Slice`) actually stand for a set of
/// actual constructors (like variants, integers or fixed-sized slices). When specializing for
/// these constructors, we want to be specialising for the actual underlying constructors.
/// Naively, we would simply return the list of constructors they correspond to. We instead are
/// more clever: if there are constructors that we know will behave the same w.r.t. the current
/// matrix, we keep them grouped. For example, all slices of a sufficiently large length will
/// either be all useful or all non-useful with a given matrix.
///
/// See the branches for details on how the splitting is done.
///
/// This function may discard some irrelevant constructors if this preserves behavior. Eg. for
/// the `_` case, we ignore the constructors already present in the column, unless all of them
/// are.
pub(super) fn split<'a>(
&self,
pcx: &PatCtxt<'_, '_, 'tcx>,
ctors: impl Iterator<Item = &'a Constructor<'tcx>> + Clone,
) -> SmallVec<[Self; 1]>
where
'tcx: 'a,
{
match self {
Wildcard => {
let split_set = ConstructorSet::for_ty(pcx.cx, pcx.ty).split(pcx, ctors);
if !split_set.missing.is_empty() {
// We are splitting a wildcard in order to compute its usefulness. Some constructors are
// not present in the column. The first thing we note is that specializing with any of
// the missing constructors would select exactly the rows with wildcards. Moreover, they
// would all return equivalent results. We can therefore group them all into a
// fictitious `Missing` constructor.
//
// As an important optimization, this function will skip all the present constructors.
// This is correct because specializing with any of the present constructors would
// select a strict superset of the wildcard rows, and thus would only find witnesses
// already found with the `Missing` constructor.
// This does mean that diagnostics are incomplete: in
// ```
// match x {
// Some(true) => {}
// }
// ```
// we report `None` as missing but not `Some(false)`.
//
// When all the constructors are missing we can equivalently return the `Wildcard`
// constructor on its own. The difference between `Wildcard` and `Missing` will then
// only be in diagnostics.
// If some constructors are missing, we typically want to report those constructors,
// e.g.:
// ```
// enum Direction { N, S, E, W }
// let Direction::N = ...;
// ```
// we can report 3 witnesses: `S`, `E`, and `W`.
//
// However, if the user didn't actually specify a constructor
// in this arm, e.g., in
// ```
// let x: (Direction, Direction, bool) = ...;
// let (_, _, false) = x;
// ```
// we don't want to show all 16 possible witnesses `(<direction-1>, <direction-2>,
// true)` - we are satisfied with `(_, _, true)`. So if all constructors are missing we
// prefer to report just a wildcard `_`.
//
// The exception is: if we are at the top-level, for example in an empty match, we
// usually prefer to report the full list of constructors.
let all_missing = split_set.present.is_empty();
let report_when_all_missing =
pcx.is_top_level && !IntRange::is_integral(pcx.ty);
let ctor =
if all_missing && !report_when_all_missing { Wildcard } else { Missing };
smallvec![ctor]
} else {
split_set.present
}
}
// Fast-track if the range is trivial.
IntRange(this_range) if !this_range.is_singleton() => {
let column_ranges = ctors.filter_map(|ctor| ctor.as_int_range()).cloned();
this_range.split(column_ranges).map(|(_, range)| IntRange(range)).collect()
}
Slice(this_slice @ Slice { kind: VarLen(..), .. }) => {
let column_slices = ctors.filter_map(|c| c.as_slice());
this_slice.split(column_slices).map(|(_, slice)| Slice(slice)).collect()
}
// Any other constructor can be used unchanged.
_ => smallvec![self.clone()],
}
}
/// Returns whether `self` is covered by `other`, i.e. whether `self` is a subset of `other`.
/// For the simple cases, this is simply checking for equality. For the "grouped" constructors,
/// this checks for inclusion.
// We inline because this has a single call site in `Matrix::specialize_constructor`.
#[inline]
pub(super) fn is_covered_by<'p>(&self, pcx: &PatCtxt<'_, 'p, 'tcx>, other: &Self) -> bool {
// This must be kept in sync with `is_covered_by_any`.
match (self, other) {
(Wildcard, _) => {
span_bug!(
pcx.cx.scrut_span,
"Constructor splitting should not have returned `Wildcard`"
)
}
// Wildcards cover anything
(_, Wildcard) => true,
// Only a wildcard pattern can match these special constructors.
(Wildcard | Missing { .. } | NonExhaustive | Hidden, _) => false,
(Missing { .. } | NonExhaustive | Hidden, _) => false,
(Single, Single) => true,
(Variant(self_id), Variant(other_id)) => self_id == other_id,
@ -869,11 +842,13 @@ impl<'tcx> Constructor<'tcx> {
}
(Slice(self_slice), Slice(other_slice)) => self_slice.is_covered_by(*other_slice),
// We are trying to inspect an opaque constant. Thus we skip the row.
(Opaque, _) | (_, Opaque) => false,
// Opaque constructors don't interact with anything unless they come from the
// syntactically identical pattern.
(Opaque(self_id), Opaque(other_id)) => self_id == other_id,
(Opaque(..), _) | (_, Opaque(..)) => false,
_ => span_bug!(
pcx.span,
pcx.cx.scrut_span,
"trying to compare incompatible constructors {:?} and {:?}",
self,
other
@ -917,16 +892,20 @@ pub(super) enum ConstructorSet {
/// `present` is morally the set of constructors present in the column, and `missing` is the set of
/// constructors that exist in the type but are not present in the column.
///
/// More formally, they respect the following constraints:
/// - the union of `present` and `missing` covers the whole type
/// - `present` and `missing` are disjoint
/// - neither contains wildcards
/// - each constructor in `present` is covered by some non-wildcard constructor in the column
/// - together, the constructors in `present` cover all the non-wildcard constructor in the column
/// - non-wildcards in the column do no cover anything in `missing`
/// - constructors in `present` and `missing` are split for the column; in other words, they are
/// either fully included in or disjoint from each constructor in the column. This avoids
/// non-trivial intersections like between `0..10` and `5..15`.
/// More formally, if we discard wildcards from the column, this respects the following constraints:
/// 1. the union of `present` and `missing` covers the whole type
/// 2. each constructor in `present` is covered by something in the column
/// 3. no constructor in `missing` is covered by anything in the column
/// 4. each constructor in the column is equal to the union of one or more constructors in `present`
/// 5. `missing` does not contain empty constructors (see discussion about emptiness at the top of
/// the file);
/// 6. constructors in `present` and `missing` are split for the column; in other words, they are
/// either fully included in or fully disjoint from each constructor in the column. In other
/// words, there are no non-trivial intersections like between `0..10` and `5..15`.
///
/// We must be particularly careful with weird constructors like `Opaque`: they're not formally part
/// of the `ConstructorSet` for the type, yet if we forgot to include them in `present` we would be
/// ignoring any row with `Opaque`s in the algorithm. Hence the importance of point 4.
#[derive(Debug)]
pub(super) struct SplitConstructorSet<'tcx> {
pub(super) present: SmallVec<[Constructor<'tcx>; 1]>,
@ -934,6 +913,7 @@ pub(super) struct SplitConstructorSet<'tcx> {
}
impl ConstructorSet {
/// Creates a set that represents all the constructors of `ty`.
#[instrument(level = "debug", skip(cx), ret)]
pub(super) fn for_ty<'p, 'tcx>(cx: &MatchCheckCtxt<'p, 'tcx>, ty: Ty<'tcx>) -> Self {
let make_range = |start, end| {
@ -1069,9 +1049,10 @@ impl ConstructorSet {
}
}
/// This is the core logical operation of exhaustiveness checking. This analyzes a column a
/// constructors to 1/ determine which constructors of the type (if any) are missing; 2/ split
/// constructors to handle non-trivial intersections e.g. on ranges or slices.
/// This analyzes a column of constructors to 1/ determine which constructors of the type (if
/// any) are missing; 2/ split constructors to handle non-trivial intersections e.g. on ranges
/// or slices. This can get subtle; see [`SplitConstructorSet`] for details of this operation
/// and its invariants.
#[instrument(level = "debug", skip(self, pcx, ctors), ret)]
pub(super) fn split<'a, 'tcx>(
&self,
@ -1083,18 +1064,26 @@ impl ConstructorSet {
{
let mut present: SmallVec<[_; 1]> = SmallVec::new();
let mut missing = Vec::new();
// Constructors in `ctors`, except wildcards.
let mut seen = ctors.filter(|c| !(matches!(c, Opaque | Wildcard)));
// Constructors in `ctors`, except wildcards and opaques.
let mut seen = Vec::new();
for ctor in ctors.cloned() {
if let Constructor::Opaque(..) = ctor {
present.push(ctor);
} else if !ctor.is_wildcard() {
seen.push(ctor);
}
}
match self {
ConstructorSet::Single => {
if seen.next().is_none() {
if seen.is_empty() {
missing.push(Single);
} else {
present.push(Single);
}
}
ConstructorSet::Variants { visible_variants, hidden_variants, non_exhaustive } => {
let seen_set: FxHashSet<_> = seen.map(|c| c.as_variant().unwrap()).collect();
let seen_set: FxHashSet<_> = seen.iter().map(|c| c.as_variant().unwrap()).collect();
let mut skipped_a_hidden_variant = false;
for variant in visible_variants {
@ -1125,7 +1114,7 @@ impl ConstructorSet {
ConstructorSet::Bool => {
let mut seen_false = false;
let mut seen_true = false;
for b in seen.map(|ctor| ctor.as_bool().unwrap()) {
for b in seen.iter().map(|ctor| ctor.as_bool().unwrap()) {
if b {
seen_true = true;
} else {
@ -1145,7 +1134,7 @@ impl ConstructorSet {
}
ConstructorSet::Integers { range_1, range_2 } => {
let seen_ranges: Vec<_> =
seen.map(|ctor| ctor.as_int_range().unwrap().clone()).collect();
seen.iter().map(|ctor| ctor.as_int_range().unwrap().clone()).collect();
for (seen, splitted_range) in range_1.split(seen_ranges.iter().cloned()) {
match seen {
Presence::Unseen => missing.push(IntRange(splitted_range)),
@ -1162,7 +1151,7 @@ impl ConstructorSet {
}
}
&ConstructorSet::Slice(array_len) => {
let seen_slices = seen.map(|c| c.as_slice().unwrap());
let seen_slices = seen.iter().map(|c| c.as_slice().unwrap());
let base_slice = Slice::new(array_len, VarLen(0, 0));
for (seen, splitted_slice) in base_slice.split(seen_slices) {
let ctor = Slice(splitted_slice);
@ -1178,7 +1167,7 @@ impl ConstructorSet {
// unreachable if length != 0.
// We still gather the seen constructors in `present`, but the only slice that can
// go in `missing` is `[]`.
let seen_slices = seen.map(|c| c.as_slice().unwrap());
let seen_slices = seen.iter().map(|c| c.as_slice().unwrap());
let base_slice = Slice::new(None, VarLen(0, 0));
for (seen, splitted_slice) in base_slice.split(seen_slices) {
let ctor = Slice(splitted_slice);
@ -1194,7 +1183,7 @@ impl ConstructorSet {
ConstructorSet::Unlistable => {
// Since we can't list constructors, we take the ones in the column. This might list
// some constructors several times but there's not much we can do.
present.extend(seen.cloned());
present.extend(seen);
missing.push(NonExhaustive);
}
// If `exhaustive_patterns` is disabled and our scrutinee is an empty type, we cannot
@ -1210,19 +1199,6 @@ impl ConstructorSet {
SplitConstructorSet { present, missing }
}
/// Compute the set of constructors missing from this column.
/// This is only used for reporting to the user.
pub(super) fn compute_missing<'a, 'tcx>(
&self,
pcx: &PatCtxt<'_, '_, 'tcx>,
ctors: impl Iterator<Item = &'a Constructor<'tcx>> + Clone,
) -> Vec<Constructor<'tcx>>
where
'tcx: 'a,
{
self.split(pcx, ctors).missing
}
}
/// A value can be decomposed into a constructor applied to some fields. This struct represents
@ -1273,9 +1249,8 @@ impl<'p, 'tcx> Fields<'p, 'tcx> {
fn wildcards_from_tys(
cx: &MatchCheckCtxt<'p, 'tcx>,
tys: impl IntoIterator<Item = Ty<'tcx>>,
span: Span,
) -> Self {
Fields::from_iter(cx, tys.into_iter().map(|ty| DeconstructedPat::wildcard(ty, span)))
Fields::from_iter(cx, tys.into_iter().map(|ty| DeconstructedPat::wildcard(ty, DUMMY_SP)))
}
// In the cases of either a `#[non_exhaustive]` field list or a non-public field, we hide
@ -1311,18 +1286,18 @@ impl<'p, 'tcx> Fields<'p, 'tcx> {
pub(super) fn wildcards(pcx: &PatCtxt<'_, 'p, 'tcx>, constructor: &Constructor<'tcx>) -> Self {
let ret = match constructor {
Single | Variant(_) => match pcx.ty.kind() {
ty::Tuple(fs) => Fields::wildcards_from_tys(pcx.cx, fs.iter(), pcx.span),
ty::Ref(_, rty, _) => Fields::wildcards_from_tys(pcx.cx, once(*rty), pcx.span),
ty::Tuple(fs) => Fields::wildcards_from_tys(pcx.cx, fs.iter()),
ty::Ref(_, rty, _) => Fields::wildcards_from_tys(pcx.cx, once(*rty)),
ty::Adt(adt, args) => {
if adt.is_box() {
// The only legal patterns of type `Box` (outside `std`) are `_` and box
// patterns. If we're here we can assume this is a box pattern.
Fields::wildcards_from_tys(pcx.cx, once(args.type_at(0)), pcx.span)
Fields::wildcards_from_tys(pcx.cx, once(args.type_at(0)))
} else {
let variant = &adt.variant(constructor.variant_index_for_adt(*adt));
let tys = Fields::list_variant_nonhidden_fields(pcx.cx, pcx.ty, variant)
.map(|(_, ty)| ty);
Fields::wildcards_from_tys(pcx.cx, tys, pcx.span)
Fields::wildcards_from_tys(pcx.cx, tys)
}
}
_ => bug!("Unexpected type for `Single` constructor: {:?}", pcx),
@ -1330,7 +1305,7 @@ impl<'p, 'tcx> Fields<'p, 'tcx> {
Slice(slice) => match *pcx.ty.kind() {
ty::Slice(ty) | ty::Array(ty, _) => {
let arity = slice.arity();
Fields::wildcards_from_tys(pcx.cx, (0..arity).map(|_| ty), pcx.span)
Fields::wildcards_from_tys(pcx.cx, (0..arity).map(|_| ty))
}
_ => bug!("bad slice pattern {:?} {:?}", constructor, pcx),
},
@ -1339,7 +1314,7 @@ impl<'p, 'tcx> Fields<'p, 'tcx> {
| F32Range(..)
| F64Range(..)
| Str(..)
| Opaque
| Opaque(..)
| NonExhaustive
| Hidden
| Missing { .. }
@ -1388,6 +1363,8 @@ impl<'p, 'tcx> DeconstructedPat<'p, 'tcx> {
DeconstructedPat { ctor, fields, ty, span, reachable: Cell::new(false) }
}
/// Note: the input patterns must have been lowered through
/// `super::check_match::MatchVisitor::lower_pattern`.
pub(crate) fn from_pat(cx: &MatchCheckCtxt<'p, 'tcx>, pat: &Pat<'tcx>) -> Self {
let mkpat = |pat| DeconstructedPat::from_pat(cx, pat);
let ctor;
@ -1470,14 +1447,14 @@ impl<'p, 'tcx> DeconstructedPat<'p, 'tcx> {
ty::Bool => {
ctor = match value.try_eval_bool(cx.tcx, cx.param_env) {
Some(b) => Bool(b),
None => Opaque,
None => Opaque(OpaqueId::new()),
};
fields = Fields::empty();
}
ty::Char | ty::Int(_) | ty::Uint(_) => {
ctor = match value.try_eval_bits(cx.tcx, cx.param_env) {
Some(bits) => IntRange(IntRange::from_bits(cx.tcx, pat.ty, bits)),
None => Opaque,
None => Opaque(OpaqueId::new()),
};
fields = Fields::empty();
}
@ -1488,7 +1465,7 @@ impl<'p, 'tcx> DeconstructedPat<'p, 'tcx> {
let value = rustc_apfloat::ieee::Single::from_bits(bits);
F32Range(value, value, RangeEnd::Included)
}
None => Opaque,
None => Opaque(OpaqueId::new()),
};
fields = Fields::empty();
}
@ -1499,7 +1476,7 @@ impl<'p, 'tcx> DeconstructedPat<'p, 'tcx> {
let value = rustc_apfloat::ieee::Double::from_bits(bits);
F64Range(value, value, RangeEnd::Included)
}
None => Opaque,
None => Opaque(OpaqueId::new()),
};
fields = Fields::empty();
}
@ -1520,7 +1497,7 @@ impl<'p, 'tcx> DeconstructedPat<'p, 'tcx> {
// into the corresponding `Pat`s by `const_to_pat`. Constants that remain are
// opaque.
_ => {
ctor = Opaque;
ctor = Opaque(OpaqueId::new());
fields = Fields::empty();
}
}
@ -1581,7 +1558,7 @@ impl<'p, 'tcx> DeconstructedPat<'p, 'tcx> {
fields = Fields::from_iter(cx, pats.into_iter().map(mkpat));
}
PatKind::Error(_) => {
ctor = Opaque;
ctor = Opaque(OpaqueId::new());
fields = Fields::empty();
}
}
@ -1591,6 +1568,7 @@ impl<'p, 'tcx> DeconstructedPat<'p, 'tcx> {
pub(super) fn is_or_pat(&self) -> bool {
matches!(self.ctor, Or)
}
/// Expand this (possibly-nested) or-pattern into its alternatives.
pub(super) fn flatten_or_pat(&'p self) -> SmallVec<[&'p Self; 1]> {
if self.is_or_pat() {
self.iter_fields().flat_map(|p| p.flatten_or_pat()).collect()
@ -1646,7 +1624,7 @@ impl<'p, 'tcx> DeconstructedPat<'p, 'tcx> {
let wildcard: &_ = pcx
.cx
.pattern_arena
.alloc(DeconstructedPat::wildcard(inner_ty, pcx.span));
.alloc(DeconstructedPat::wildcard(inner_ty, DUMMY_SP));
let extra_wildcards = other_slice.arity() - self_slice.arity();
let extra_wildcards = (0..extra_wildcards).map(|_| wildcard);
prefix.iter().chain(extra_wildcards).chain(suffix).collect()
@ -1663,7 +1641,17 @@ impl<'p, 'tcx> DeconstructedPat<'p, 'tcx> {
self.reachable.set(true)
}
pub(super) fn is_reachable(&self) -> bool {
self.reachable.get()
if self.reachable.get() {
true
} else if self.is_or_pat() && self.iter_fields().any(|f| f.is_reachable()) {
// We always expand or patterns in the matrix, so we will never see the actual
// or-pattern (the one with constructor `Or`) in the column. As such, it will not be
// marked as reachable itself, only its children will. We recover this information here.
self.set_reachable();
true
} else {
false
}
}
/// Report the spans of subpatterns that were not reachable, if any.
@ -1672,7 +1660,6 @@ impl<'p, 'tcx> DeconstructedPat<'p, 'tcx> {
self.collect_unreachable_spans(&mut spans);
spans
}
fn collect_unreachable_spans(&self, spans: &mut Vec<Span>) {
// We don't look at subpatterns if we already reported the whole pattern as unreachable.
if !self.is_reachable() {
@ -1768,7 +1755,7 @@ impl<'p, 'tcx> fmt::Debug for DeconstructedPat<'p, 'tcx> {
F32Range(lo, hi, end) => write!(f, "{lo}{end}{hi}"),
F64Range(lo, hi, end) => write!(f, "{lo}{end}{hi}"),
Str(value) => write!(f, "{value}"),
Opaque => write!(f, "<constant pattern>"),
Opaque(..) => write!(f, "<constant pattern>"),
Or => {
for pat in self.iter_fields() {
write!(f, "{}{:?}", start_or_continue(" | "), pat)?;
@ -1898,7 +1885,7 @@ impl<'tcx> WitnessPat<'tcx> {
"trying to convert a `Missing` constructor into a `Pat`; this is probably a bug,
`Missing` should have been processed in `apply_constructors`"
),
F32Range(..) | F64Range(..) | Opaque | Or => {
F32Range(..) | F64Range(..) | Opaque(..) | Or => {
bug!("can't convert to pattern: {:?}", self)
}
};

File diff suppressed because it is too large Load Diff

View File

@ -35,6 +35,17 @@ fn main() {
((0, 0) | (1, 0),) => {}
_ => {}
}
match ((0, 0),) {
// Note how the second one would be redundant without the guard.
((x, y) | (y, x),) if x == 0 => {}
_ => {}
}
match 0 {
// We don't warn the second one as redundant in general because of cases like the one above.
// We could technically do it if there are no bindings.
0 | 0 if 0 == 0 => {}
_ => {}
}
// This one caused ICE https://github.com/rust-lang/rust/issues/117378
match (0u8, 0) {

View File

@ -1,6 +1,7 @@
#![deny(unreachable_patterns)]
// We wrap patterns in a tuple because top-level or-patterns were special-cased.
#[rustfmt::skip]
fn main() {
match (0u8,) {
(1 | 2,) => {}
@ -73,6 +74,11 @@ fn main() {
| 0] => {} //~ ERROR unreachable
_ => {}
}
match (true, 0) {
(true, 0 | 0) => {} //~ ERROR unreachable
(_, 0 | 0) => {} //~ ERROR unreachable
_ => {}
}
match &[][..] {
[0] => {}
[0, _] => {}
@ -149,4 +155,8 @@ fn main() {
| true, //~ ERROR unreachable
false | true) => {}
}
match (true, true) {
(x, y)
| (y, x) => {} //~ ERROR unreachable
}
}

View File

@ -1,5 +1,5 @@
error: unreachable pattern
--> $DIR/exhaustiveness-unreachable-pattern.rs:7:9
--> $DIR/exhaustiveness-unreachable-pattern.rs:8:9
|
LL | (1,) => {}
| ^^^^
@ -11,128 +11,140 @@ LL | #![deny(unreachable_patterns)]
| ^^^^^^^^^^^^^^^^^^^^
error: unreachable pattern
--> $DIR/exhaustiveness-unreachable-pattern.rs:12:9
--> $DIR/exhaustiveness-unreachable-pattern.rs:13:9
|
LL | (2,) => {}
| ^^^^
error: unreachable pattern
--> $DIR/exhaustiveness-unreachable-pattern.rs:18:9
--> $DIR/exhaustiveness-unreachable-pattern.rs:19:9
|
LL | (1 | 2,) => {}
| ^^^^^^^^
error: unreachable pattern
--> $DIR/exhaustiveness-unreachable-pattern.rs:23:9
--> $DIR/exhaustiveness-unreachable-pattern.rs:24:9
|
LL | (1, 3) => {}
| ^^^^^^
error: unreachable pattern
--> $DIR/exhaustiveness-unreachable-pattern.rs:24:9
--> $DIR/exhaustiveness-unreachable-pattern.rs:25:9
|
LL | (1, 4) => {}
| ^^^^^^
error: unreachable pattern
--> $DIR/exhaustiveness-unreachable-pattern.rs:25:9
--> $DIR/exhaustiveness-unreachable-pattern.rs:26:9
|
LL | (2, 4) => {}
| ^^^^^^
error: unreachable pattern
--> $DIR/exhaustiveness-unreachable-pattern.rs:26:9
--> $DIR/exhaustiveness-unreachable-pattern.rs:27:9
|
LL | (2 | 1, 4) => {}
| ^^^^^^^^^^
error: unreachable pattern
--> $DIR/exhaustiveness-unreachable-pattern.rs:28:9
--> $DIR/exhaustiveness-unreachable-pattern.rs:29:9
|
LL | (1, 4 | 5) => {}
| ^^^^^^^^^^
error: unreachable pattern
--> $DIR/exhaustiveness-unreachable-pattern.rs:36:9
--> $DIR/exhaustiveness-unreachable-pattern.rs:37:9
|
LL | (Some(1),) => {}
| ^^^^^^^^^^
error: unreachable pattern
--> $DIR/exhaustiveness-unreachable-pattern.rs:37:9
--> $DIR/exhaustiveness-unreachable-pattern.rs:38:9
|
LL | (None,) => {}
| ^^^^^^^
error: unreachable pattern
--> $DIR/exhaustiveness-unreachable-pattern.rs:42:9
--> $DIR/exhaustiveness-unreachable-pattern.rs:43:9
|
LL | ((1..=4,),) => {}
| ^^^^^^^^^^^
error: unreachable pattern
--> $DIR/exhaustiveness-unreachable-pattern.rs:47:14
--> $DIR/exhaustiveness-unreachable-pattern.rs:48:14
|
LL | (1 | 1,) => {}
| ^
error: unreachable pattern
--> $DIR/exhaustiveness-unreachable-pattern.rs:51:19
--> $DIR/exhaustiveness-unreachable-pattern.rs:52:19
|
LL | (0 | 1) | 1 => {}
| ^
error: unreachable pattern
--> $DIR/exhaustiveness-unreachable-pattern.rs:57:14
--> $DIR/exhaustiveness-unreachable-pattern.rs:58:14
|
LL | 0 | (0 | 0) => {}
| ^
error: unreachable pattern
--> $DIR/exhaustiveness-unreachable-pattern.rs:57:18
--> $DIR/exhaustiveness-unreachable-pattern.rs:58:18
|
LL | 0 | (0 | 0) => {}
| ^
error: unreachable pattern
--> $DIR/exhaustiveness-unreachable-pattern.rs:65:13
--> $DIR/exhaustiveness-unreachable-pattern.rs:66:13
|
LL | / Some(
LL | | 0 | 0) => {}
| |______________________^
error: unreachable pattern
--> $DIR/exhaustiveness-unreachable-pattern.rs:71:15
--> $DIR/exhaustiveness-unreachable-pattern.rs:72:15
|
LL | | 0
| ^
error: unreachable pattern
--> $DIR/exhaustiveness-unreachable-pattern.rs:73:15
--> $DIR/exhaustiveness-unreachable-pattern.rs:74:15
|
LL | | 0] => {}
| ^
error: unreachable pattern
--> $DIR/exhaustiveness-unreachable-pattern.rs:81:10
--> $DIR/exhaustiveness-unreachable-pattern.rs:78:20
|
LL | (true, 0 | 0) => {}
| ^
error: unreachable pattern
--> $DIR/exhaustiveness-unreachable-pattern.rs:79:17
|
LL | (_, 0 | 0) => {}
| ^
error: unreachable pattern
--> $DIR/exhaustiveness-unreachable-pattern.rs:87:10
|
LL | [1
| ^
error: unreachable pattern
--> $DIR/exhaustiveness-unreachable-pattern.rs:93:10
--> $DIR/exhaustiveness-unreachable-pattern.rs:99:10
|
LL | [true
| ^^^^
error: unreachable pattern
--> $DIR/exhaustiveness-unreachable-pattern.rs:100:36
--> $DIR/exhaustiveness-unreachable-pattern.rs:106:36
|
LL | (true | false, None | Some(true
| ^^^^
error: unreachable pattern
--> $DIR/exhaustiveness-unreachable-pattern.rs:105:14
--> $DIR/exhaustiveness-unreachable-pattern.rs:111:14
|
LL | (true
| ^^^^
@ -143,28 +155,34 @@ LL | (true | false, None | Some(t_or_f!())) => {}
= note: this error originates in the macro `t_or_f` (in Nightly builds, run with -Z macro-backtrace for more info)
error: unreachable pattern
--> $DIR/exhaustiveness-unreachable-pattern.rs:116:14
--> $DIR/exhaustiveness-unreachable-pattern.rs:122:14
|
LL | Some(0
| ^
error: unreachable pattern
--> $DIR/exhaustiveness-unreachable-pattern.rs:135:19
--> $DIR/exhaustiveness-unreachable-pattern.rs:141:19
|
LL | | false) => {}
| ^^^^^
error: unreachable pattern
--> $DIR/exhaustiveness-unreachable-pattern.rs:143:15
--> $DIR/exhaustiveness-unreachable-pattern.rs:149:15
|
LL | | true) => {}
| ^^^^
error: unreachable pattern
--> $DIR/exhaustiveness-unreachable-pattern.rs:149:15
--> $DIR/exhaustiveness-unreachable-pattern.rs:155:15
|
LL | | true,
| ^^^^
error: aborting due to 26 previous errors
error: unreachable pattern
--> $DIR/exhaustiveness-unreachable-pattern.rs:160:15
|
LL | | (y, x) => {}
| ^^^^^^
error: aborting due to 29 previous errors

View File

@ -1,5 +1,5 @@
error[E0004]: non-exhaustive patterns: type `usize` is non-empty
--> $DIR/pointer-sized-int.rs:54:11
--> $DIR/pointer-sized-int.rs:59:11
|
LL | match 7usize {}
| ^^^^^^

View File

@ -9,7 +9,7 @@ LL | match 0usize {
= help: add `#![feature(precise_pointer_size_matching)]` to the crate attributes to enable precise `usize` matching
help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
|
LL ~ 0 ..= usize::MAX => {},
LL ~ 0..=usize::MAX => {},
LL + usize::MAX.. => todo!()
|
@ -24,12 +24,12 @@ LL | match 0isize {
= help: add `#![feature(precise_pointer_size_matching)]` to the crate attributes to enable precise `isize` matching
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 ~ isize::MIN ..= isize::MAX => {},
LL ~ isize::MIN..=isize::MAX => {},
LL + ..isize::MIN | isize::MAX.. => todo!()
|
error[E0004]: non-exhaustive patterns: `usize::MAX..` not covered
--> $DIR/pointer-sized-int.rs:25:8
--> $DIR/pointer-sized-int.rs:24:8
|
LL | m!(0usize, 0..=usize::MAX);
| ^^^^^^ pattern `usize::MAX..` not covered
@ -43,7 +43,7 @@ LL | match $s { $($t)+ => {}, usize::MAX.. => todo!() }
| +++++++++++++++++++++++++
error[E0004]: non-exhaustive patterns: `usize::MAX..` not covered
--> $DIR/pointer-sized-int.rs:27:8
--> $DIR/pointer-sized-int.rs:26:8
|
LL | m!(0usize, 0..5 | 5..=usize::MAX);
| ^^^^^^ pattern `usize::MAX..` not covered
@ -57,7 +57,7 @@ LL | match $s { $($t)+ => {}, usize::MAX.. => todo!() }
| +++++++++++++++++++++++++
error[E0004]: non-exhaustive patterns: `usize::MAX..` not covered
--> $DIR/pointer-sized-int.rs:29:8
--> $DIR/pointer-sized-int.rs:28:8
|
LL | m!(0usize, 0..usize::MAX | usize::MAX);
| ^^^^^^ pattern `usize::MAX..` not covered
@ -71,7 +71,7 @@ LL | match $s { $($t)+ => {}, usize::MAX.. => todo!() }
| +++++++++++++++++++++++++
error[E0004]: non-exhaustive patterns: `(usize::MAX.., _)` not covered
--> $DIR/pointer-sized-int.rs:31:8
--> $DIR/pointer-sized-int.rs:30:8
|
LL | m!((0usize, true), (0..5, true) | (5..=usize::MAX, true) | (0..=usize::MAX, false));
| ^^^^^^^^^^^^^^ pattern `(usize::MAX.., _)` not covered
@ -85,7 +85,7 @@ LL | match $s { $($t)+ => {}, (usize::MAX.., _) => todo!() }
| ++++++++++++++++++++++++++++++
error[E0004]: non-exhaustive patterns: `..isize::MIN` and `isize::MAX..` not covered
--> $DIR/pointer-sized-int.rs:36:8
--> $DIR/pointer-sized-int.rs:39:8
|
LL | m!(0isize, isize::MIN..=isize::MAX);
| ^^^^^^ patterns `..isize::MIN` and `isize::MAX..` not covered
@ -99,7 +99,7 @@ LL | match $s { $($t)+ => {}, ..isize::MIN | isize::MAX.. => todo!() }
| ++++++++++++++++++++++++++++++++++++++++
error[E0004]: non-exhaustive patterns: `..isize::MIN` and `isize::MAX..` not covered
--> $DIR/pointer-sized-int.rs:38:8
--> $DIR/pointer-sized-int.rs:41:8
|
LL | m!(0isize, isize::MIN..5 | 5..=isize::MAX);
| ^^^^^^ patterns `..isize::MIN` and `isize::MAX..` not covered
@ -113,7 +113,21 @@ LL | match $s { $($t)+ => {}, ..isize::MIN | isize::MAX.. => todo!() }
| ++++++++++++++++++++++++++++++++++++++++
error[E0004]: non-exhaustive patterns: `..isize::MIN` and `isize::MAX..` not covered
--> $DIR/pointer-sized-int.rs:40:8
--> $DIR/pointer-sized-int.rs:43:8
|
LL | m!(0isize, isize::MIN..=-1 | 0 | 1..=isize::MAX);
| ^^^^^^ patterns `..isize::MIN` and `isize::MAX..` not covered
|
= note: the matched value is of type `isize`
= note: `isize` does not have fixed minimum and maximum values, so half-open ranges are necessary to match exhaustively
= help: add `#![feature(precise_pointer_size_matching)]` to the crate attributes to enable precise `isize` matching
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 | match $s { $($t)+ => {}, ..isize::MIN | isize::MAX.. => todo!() }
| ++++++++++++++++++++++++++++++++++++++++
error[E0004]: non-exhaustive patterns: `..isize::MIN` and `isize::MAX..` not covered
--> $DIR/pointer-sized-int.rs:45:8
|
LL | m!(0isize, isize::MIN..isize::MAX | isize::MAX);
| ^^^^^^ patterns `..isize::MIN` and `isize::MAX..` not covered
@ -127,10 +141,10 @@ LL | match $s { $($t)+ => {}, ..isize::MIN | isize::MAX.. => todo!() }
| ++++++++++++++++++++++++++++++++++++++++
error[E0004]: non-exhaustive patterns: `(..isize::MIN, _)` and `(isize::MAX.., _)` not covered
--> $DIR/pointer-sized-int.rs:42:8
--> $DIR/pointer-sized-int.rs:48:9
|
LL | m!((0isize, true), (isize::MIN..5, true)
| ^^^^^^^^^^^^^^ patterns `(..isize::MIN, _)` and `(isize::MAX.., _)` not covered
LL | (0isize, true),
| ^^^^^^^^^^^^^^ patterns `(..isize::MIN, _)` and `(isize::MAX.., _)` not covered
|
= note: the matched value is of type `(isize, bool)`
= note: `isize` does not have fixed minimum and maximum values, so half-open ranges are necessary to match exhaustively
@ -140,23 +154,8 @@ help: ensure that all possible cases are being handled by adding a match arm wit
LL | match $s { $($t)+ => {}, (..isize::MIN, _) | (isize::MAX.., _) => todo!() }
| ++++++++++++++++++++++++++++++++++++++++++++++++++
error[E0004]: non-exhaustive patterns: `..isize::MIN` and `isize::MAX..` not covered
--> $DIR/pointer-sized-int.rs:47:11
|
LL | match 0isize {
| ^^^^^^ patterns `..isize::MIN` and `isize::MAX..` not covered
|
= note: the matched value is of type `isize`
= note: `isize` does not have fixed minimum and maximum values, so half-open ranges are necessary to match exhaustively
= help: add `#![feature(precise_pointer_size_matching)]` to the crate attributes to enable precise `isize` matching
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 ~ 1 ..= isize::MAX => {},
LL + ..isize::MIN | isize::MAX.. => todo!()
|
error[E0004]: non-exhaustive patterns: type `usize` is non-empty
--> $DIR/pointer-sized-int.rs:54:11
--> $DIR/pointer-sized-int.rs:59:11
|
LL | match 7usize {}
| ^^^^^^

View File

@ -13,15 +13,14 @@ macro_rules! m {
fn main() {
match 0usize {
//[deny]~^ ERROR non-exhaustive patterns
0 ..= usize::MAX => {}
0..=usize::MAX => {}
}
match 0isize {
//[deny]~^ ERROR non-exhaustive patterns
isize::MIN ..= isize::MAX => {}
isize::MIN..=isize::MAX => {}
}
m!(0usize, 0..);
m!(0usize, 0..=usize::MAX);
//[deny]~^ ERROR non-exhaustive patterns
m!(0usize, 0..5 | 5..=usize::MAX);
@ -30,26 +29,32 @@ fn main() {
//[deny]~^ ERROR non-exhaustive patterns
m!((0usize, true), (0..5, true) | (5..=usize::MAX, true) | (0..=usize::MAX, false));
//[deny]~^ ERROR non-exhaustive patterns
m!(0usize, 0..);
m!(0usize, 0..5 | 5..);
m!(0usize, ..5 | 5..);
m!((0usize, true), (0..5, true) | (5.., true) | (0.., false));
m!(0usize, 0..=usize::MAX | usize::MAX..);
m!(0isize, ..0 | 0..);
m!(0isize, isize::MIN..=isize::MAX);
//[deny]~^ ERROR non-exhaustive patterns
m!(0isize, isize::MIN..5 | 5..=isize::MAX);
//[deny]~^ ERROR non-exhaustive patterns
m!(0isize, isize::MIN..=-1 | 0 | 1..=isize::MAX);
//[deny]~^ ERROR non-exhaustive patterns
m!(0isize, isize::MIN..isize::MAX | isize::MAX);
//[deny]~^ ERROR non-exhaustive patterns
m!((0isize, true), (isize::MIN..5, true)
| (5..=isize::MAX, true) | (isize::MIN..=isize::MAX, false));
//[deny]~^^ ERROR non-exhaustive patterns
m!(0isize, ..=isize::MIN | isize::MIN..=isize::MAX | isize::MAX..);
m!(
(0isize, true),
(isize::MIN..5, true) | (5..=isize::MAX, true) | (isize::MIN..=isize::MAX, false)
);
//[deny]~^^^ ERROR non-exhaustive patterns
match 0isize {
//[deny]~^ ERROR non-exhaustive patterns
isize::MIN ..= -1 => {}
0 => {}
1 ..= isize::MAX => {}
}
m!(0isize, ..0 | 0..);
m!(0isize, ..5 | 5..);
m!((0isize, true), (..5, true)
| (5.., true) | (..0 | 0.., false));
m!(0isize, ..=isize::MIN | isize::MIN..=isize::MAX | isize::MAX..);
match 7usize {}
//~^ ERROR non-exhaustive patterns

View File

@ -9,9 +9,10 @@ macro_rules! m {
$t2 => {}
_ => {}
}
}
};
}
#[rustfmt::skip]
fn main() {
m!(0u8, 42, 41);
m!(0u8, 42, 42); //~ ERROR unreachable pattern
@ -85,7 +86,7 @@ fn main() {
match 'a' {
'\u{0}'..='\u{D7FF}' => {},
'\u{E000}'..='\u{10_FFFF}' => {},
'\u{D7FF}'..='\u{E000}' => {}, // FIXME should be unreachable
'\u{D7FF}'..='\u{E000}' => {}, //~ ERROR unreachable pattern
}
match (0u8, true) {

View File

@ -1,5 +1,5 @@
error: unreachable pattern
--> $DIR/reachability.rs:17:17
--> $DIR/reachability.rs:18:17
|
LL | m!(0u8, 42, 42);
| ^^
@ -11,127 +11,127 @@ LL | #![deny(unreachable_patterns)]
| ^^^^^^^^^^^^^^^^^^^^
error: unreachable pattern
--> $DIR/reachability.rs:21:22
--> $DIR/reachability.rs:22:22
|
LL | m!(0u8, 20..=30, 20);
| ^^
error: unreachable pattern
--> $DIR/reachability.rs:22:22
--> $DIR/reachability.rs:23:22
|
LL | m!(0u8, 20..=30, 21);
| ^^
error: unreachable pattern
--> $DIR/reachability.rs:23:22
--> $DIR/reachability.rs:24:22
|
LL | m!(0u8, 20..=30, 25);
| ^^
error: unreachable pattern
--> $DIR/reachability.rs:24:22
--> $DIR/reachability.rs:25:22
|
LL | m!(0u8, 20..=30, 29);
| ^^
error: unreachable pattern
--> $DIR/reachability.rs:25:22
--> $DIR/reachability.rs:26:22
|
LL | m!(0u8, 20..=30, 30);
| ^^
error: unreachable pattern
--> $DIR/reachability.rs:28:21
--> $DIR/reachability.rs:29:21
|
LL | m!(0u8, 20..30, 20);
| ^^
error: unreachable pattern
--> $DIR/reachability.rs:29:21
--> $DIR/reachability.rs:30:21
|
LL | m!(0u8, 20..30, 21);
| ^^
error: unreachable pattern
--> $DIR/reachability.rs:30:21
--> $DIR/reachability.rs:31:21
|
LL | m!(0u8, 20..30, 25);
| ^^
error: unreachable pattern
--> $DIR/reachability.rs:31:21
--> $DIR/reachability.rs:32:21
|
LL | m!(0u8, 20..30, 29);
| ^^
error: unreachable pattern
--> $DIR/reachability.rs:35:22
--> $DIR/reachability.rs:36:22
|
LL | m!(0u8, 20..=30, 20..=30);
| ^^^^^^^
error: unreachable pattern
--> $DIR/reachability.rs:36:22
--> $DIR/reachability.rs:37:22
|
LL | m!(0u8, 20.. 30, 20.. 30);
| ^^^^^^^
error: unreachable pattern
--> $DIR/reachability.rs:37:22
--> $DIR/reachability.rs:38:22
|
LL | m!(0u8, 20..=30, 20.. 30);
| ^^^^^^^
error: unreachable pattern
--> $DIR/reachability.rs:39:22
--> $DIR/reachability.rs:40:22
|
LL | m!(0u8, 20..=30, 21..=30);
| ^^^^^^^
error: unreachable pattern
--> $DIR/reachability.rs:40:22
--> $DIR/reachability.rs:41:22
|
LL | m!(0u8, 20..=30, 20..=29);
| ^^^^^^^
error: unreachable pattern
--> $DIR/reachability.rs:42:24
--> $DIR/reachability.rs:43:24
|
LL | m!('a', 'A'..='z', 'a'..='z');
| ^^^^^^^^^
error: unreachable pattern
--> $DIR/reachability.rs:49:9
--> $DIR/reachability.rs:50:9
|
LL | 5..=8 => {},
| ^^^^^
error: unreachable pattern
--> $DIR/reachability.rs:55:9
--> $DIR/reachability.rs:56:9
|
LL | 5..15 => {},
| ^^^^^
error: unreachable pattern
--> $DIR/reachability.rs:62:9
--> $DIR/reachability.rs:63:9
|
LL | 5..25 => {},
| ^^^^^
error: unreachable pattern
--> $DIR/reachability.rs:70:9
--> $DIR/reachability.rs:71:9
|
LL | 5..25 => {},
| ^^^^^
error: unreachable pattern
--> $DIR/reachability.rs:76:9
--> $DIR/reachability.rs:77:9
|
LL | 5..15 => {},
| ^^^^^
error: unreachable pattern
--> $DIR/reachability.rs:83:9
--> $DIR/reachability.rs:84:9
|
LL | _ => {},
| - matches any value
@ -139,16 +139,22 @@ LL | '\u{D7FF}'..='\u{E000}' => {},
| ^^^^^^^^^^^^^^^^^^^^^^^ unreachable pattern
error: unreachable pattern
--> $DIR/reachability.rs:104:9
--> $DIR/reachability.rs:89:9
|
LL | '\u{D7FF}'..='\u{E000}' => {},
| ^^^^^^^^^^^^^^^^^^^^^^^
error: unreachable pattern
--> $DIR/reachability.rs:105:9
|
LL | &FOO => {}
| ^^^^
error: unreachable pattern
--> $DIR/reachability.rs:105:9
--> $DIR/reachability.rs:106:9
|
LL | BAR => {}
| ^^^
error: aborting due to 24 previous errors
error: aborting due to 25 previous errors

View File

@ -31,7 +31,7 @@ fn main() {
//~^ ERROR non-exhaustive patterns
//~| NOTE the matched value is of type
//~| NOTE match arms with guards don't count towards exhaustivity
//~| NOTE pattern `box _` not covered
//~| NOTE pattern `box ElementKind::HTMLImageElement(_)` not covered
//~| NOTE `Box<ElementKind>` defined here
box ElementKind::HTMLImageElement(ref d) if d.image.is_some() => true,
},

View File

@ -1,8 +1,8 @@
error[E0004]: non-exhaustive patterns: `box _` not covered
error[E0004]: non-exhaustive patterns: `box ElementKind::HTMLImageElement(_)` not covered
--> $DIR/issue-3601.rs:30:44
|
LL | box NodeKind::Element(ed) => match ed.kind {
| ^^^^^^^ pattern `box _` not covered
| ^^^^^^^ pattern `box ElementKind::HTMLImageElement(_)` not covered
|
note: `Box<ElementKind>` defined here
--> $SRC_DIR/alloc/src/boxed.rs:LL:COL
@ -11,7 +11,7 @@ note: `Box<ElementKind>` defined here
help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
|
LL ~ box ElementKind::HTMLImageElement(ref d) if d.image.is_some() => true,
LL ~ box _ => todo!(),
LL ~ box ElementKind::HTMLImageElement(_) => todo!(),
|
error: aborting due to 1 previous error

View File

@ -10,18 +10,18 @@ help: ensure that all possible cases are being handled by adding a match arm wit
LL | match 0 { 1 => (), i32::MIN..=0_i32 | 2_i32..=i32::MAX => todo!() }
| ++++++++++++++++++++++++++++++++++++++++++++++++
error[E0004]: non-exhaustive patterns: `_` not covered
error[E0004]: non-exhaustive patterns: `i32::MIN..=-1_i32` and `1_i32..=i32::MAX` not covered
--> $DIR/match-non-exhaustive.rs:3:11
|
LL | match 0 { 0 if false => () }
| ^ pattern `_` not covered
| ^ patterns `i32::MIN..=-1_i32` and `1_i32..=i32::MAX` not covered
|
= note: the matched value is of type `i32`
= note: match arms with guards don't count towards exhaustivity
help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
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 | match 0 { 0 if false => (), _ => todo!() }
| ++++++++++++++
LL | match 0 { 0 if false => (), i32::MIN..=-1_i32 | 1_i32..=i32::MAX => todo!() }
| +++++++++++++++++++++++++++++++++++++++++++++++++
error: aborting due to 2 previous errors

View File

@ -43,6 +43,10 @@ fn main() {
//~^ ERROR `&[_, ..]` not covered
[] => {}
}
match s {
//~^ ERROR `&[]` and `&[_, ..]` not covered
[..] if false => {}
}
match s {
//~^ ERROR `&[_, _, ..]` not covered
[] => {}

View File

@ -89,9 +89,23 @@ LL ~ [] => {},
LL + &[_, ..] => todo!()
|
error[E0004]: non-exhaustive patterns: `&[_, _, ..]` not covered
error[E0004]: non-exhaustive patterns: `&[]` and `&[_, ..]` not covered
--> $DIR/slice-patterns-exhaustiveness.rs:46:11
|
LL | match s {
| ^ patterns `&[]` and `&[_, ..]` not covered
|
= note: the matched value is of type `&[bool]`
= note: match arms with guards don't count towards exhaustivity
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 ~ [..] if false => {},
LL + &[] | &[_, ..] => todo!()
|
error[E0004]: non-exhaustive patterns: `&[_, _, ..]` not covered
--> $DIR/slice-patterns-exhaustiveness.rs:50:11
|
LL | match s {
| ^ pattern `&[_, _, ..]` not covered
|
@ -103,7 +117,7 @@ LL + &[_, _, ..] => todo!()
|
error[E0004]: non-exhaustive patterns: `&[false, ..]` not covered
--> $DIR/slice-patterns-exhaustiveness.rs:51:11
--> $DIR/slice-patterns-exhaustiveness.rs:55:11
|
LL | match s {
| ^ pattern `&[false, ..]` not covered
@ -116,7 +130,7 @@ LL + &[false, ..] => todo!()
|
error[E0004]: non-exhaustive patterns: `&[false, _, ..]` not covered
--> $DIR/slice-patterns-exhaustiveness.rs:56:11
--> $DIR/slice-patterns-exhaustiveness.rs:60:11
|
LL | match s {
| ^ pattern `&[false, _, ..]` not covered
@ -129,7 +143,7 @@ LL + &[false, _, ..] => todo!()
|
error[E0004]: non-exhaustive patterns: `&[_, .., false]` not covered
--> $DIR/slice-patterns-exhaustiveness.rs:62:11
--> $DIR/slice-patterns-exhaustiveness.rs:66:11
|
LL | match s {
| ^ pattern `&[_, .., false]` not covered
@ -142,7 +156,7 @@ LL + &[_, .., false] => todo!()
|
error[E0004]: non-exhaustive patterns: `&[_, _, .., true]` not covered
--> $DIR/slice-patterns-exhaustiveness.rs:69:11
--> $DIR/slice-patterns-exhaustiveness.rs:73:11
|
LL | match s {
| ^ pattern `&[_, _, .., true]` not covered
@ -155,7 +169,7 @@ LL + &[_, _, .., true] => todo!()
|
error[E0004]: non-exhaustive patterns: `&[true, _, .., _]` not covered
--> $DIR/slice-patterns-exhaustiveness.rs:76:11
--> $DIR/slice-patterns-exhaustiveness.rs:80:11
|
LL | match s {
| ^ pattern `&[true, _, .., _]` not covered
@ -168,7 +182,7 @@ LL + &[true, _, .., _] => todo!()
|
error[E0004]: non-exhaustive patterns: `&[]` and `&[_, _, ..]` not covered
--> $DIR/slice-patterns-exhaustiveness.rs:85:11
--> $DIR/slice-patterns-exhaustiveness.rs:89:11
|
LL | match s {
| ^ patterns `&[]` and `&[_, _, ..]` not covered
@ -181,7 +195,7 @@ LL + &[] | &[_, _, ..] => todo!()
|
error[E0004]: non-exhaustive patterns: `&[]` and `&[_, _, ..]` not covered
--> $DIR/slice-patterns-exhaustiveness.rs:89:11
--> $DIR/slice-patterns-exhaustiveness.rs:93:11
|
LL | match s {
| ^ patterns `&[]` and `&[_, _, ..]` not covered
@ -194,7 +208,7 @@ LL + &[] | &[_, _, ..] => todo!()
|
error[E0004]: non-exhaustive patterns: `&[]` and `&[_, _, ..]` not covered
--> $DIR/slice-patterns-exhaustiveness.rs:93:11
--> $DIR/slice-patterns-exhaustiveness.rs:97:11
|
LL | match s {
| ^ patterns `&[]` and `&[_, _, ..]` not covered
@ -207,7 +221,7 @@ LL + &[] | &[_, _, ..] => todo!()
|
error[E0004]: non-exhaustive patterns: `&[]` and `&[_, _, ..]` not covered
--> $DIR/slice-patterns-exhaustiveness.rs:98:11
--> $DIR/slice-patterns-exhaustiveness.rs:102:11
|
LL | match s {
| ^ patterns `&[]` and `&[_, _, ..]` not covered
@ -220,7 +234,7 @@ LL + &[] | &[_, _, ..] => todo!()
|
error[E0004]: non-exhaustive patterns: `&[_, _, ..]` not covered
--> $DIR/slice-patterns-exhaustiveness.rs:103:11
--> $DIR/slice-patterns-exhaustiveness.rs:107:11
|
LL | match s {
| ^ pattern `&[_, _, ..]` not covered
@ -233,7 +247,7 @@ LL + &[_, _, ..] => todo!()
|
error[E0004]: non-exhaustive patterns: `&[false]` not covered
--> $DIR/slice-patterns-exhaustiveness.rs:108:11
--> $DIR/slice-patterns-exhaustiveness.rs:112:11
|
LL | match s {
| ^ pattern `&[false]` not covered
@ -246,7 +260,7 @@ LL + &[false] => todo!()
|
error[E0004]: non-exhaustive patterns: `&[false]` not covered
--> $DIR/slice-patterns-exhaustiveness.rs:121:11
--> $DIR/slice-patterns-exhaustiveness.rs:125:11
|
LL | match s1 {
| ^^ pattern `&[false]` not covered
@ -258,6 +272,6 @@ LL ~ CONST1 => {},
LL + &[false] => todo!()
|
error: aborting due to 20 previous errors
error: aborting due to 21 previous errors
For more information about this error, try `rustc --explain E0004`.

View File

@ -1,6 +1,7 @@
// Test that the `non_exhaustive_omitted_patterns` lint is triggered correctly.
#![feature(non_exhaustive_omitted_patterns_lint, unstable_test_feature)]
#![deny(unreachable_patterns)]
// aux-build:enums.rs
extern crate enums;
@ -31,11 +32,21 @@ pub enum Bar {
C,
}
fn no_lint() {
let non_enum = NonExhaustiveEnum::Unit;
// Ok: without the attribute
match non_enum {
NonExhaustiveEnum::Unit => {}
NonExhaustiveEnum::Tuple(_) => {}
_ => {}
}
}
#[deny(non_exhaustive_omitted_patterns)]
fn main() {
let enumeration = Bar::A;
// Ok: this is a crate local non_exhaustive enum
#[deny(non_exhaustive_omitted_patterns)]
match enumeration {
Bar::A => {}
Bar::B => {}
@ -44,14 +55,13 @@ fn main() {
let non_enum = NonExhaustiveEnum::Unit;
// Ok: without the attribute
#[allow(non_exhaustive_omitted_patterns)]
match non_enum {
NonExhaustiveEnum::Unit => {}
NonExhaustiveEnum::Tuple(_) => {}
_ => {}
}
#[deny(non_exhaustive_omitted_patterns)]
match non_enum {
//~^ some variants are not matched explicitly
NonExhaustiveEnum::Unit => {}
@ -59,7 +69,6 @@ fn main() {
_ => {}
}
#[deny(non_exhaustive_omitted_patterns)]
match non_enum {
//~^ some variants are not matched explicitly
NonExhaustiveEnum::Unit | NonExhaustiveEnum::Struct { .. } => {}
@ -68,7 +77,6 @@ fn main() {
let x = 5;
// We ignore the guard.
#[deny(non_exhaustive_omitted_patterns)]
match non_enum {
NonExhaustiveEnum::Unit if x > 10 => {}
NonExhaustiveEnum::Tuple(_) => {}
@ -76,14 +84,12 @@ fn main() {
_ => {}
}
#[deny(non_exhaustive_omitted_patterns)]
match (non_enum, true) {
(NonExhaustiveEnum::Unit, true) => {}
(NonExhaustiveEnum::Tuple(_), false) => {}
(NonExhaustiveEnum::Struct { .. }, false) => {}
_ => {}
}
#[deny(non_exhaustive_omitted_patterns)]
match (non_enum, true) {
//~^ some variants are not matched explicitly
(NonExhaustiveEnum::Unit, true) => {}
@ -91,14 +97,12 @@ fn main() {
_ => {}
}
#[deny(non_exhaustive_omitted_patterns)]
match (true, non_enum) {
(true, NonExhaustiveEnum::Unit) => {}
(false, NonExhaustiveEnum::Tuple(_)) => {}
(false, NonExhaustiveEnum::Struct { .. }) => {}
_ => {}
}
#[deny(non_exhaustive_omitted_patterns)]
match (true, non_enum) {
//~^ some variants are not matched explicitly
(true, NonExhaustiveEnum::Unit) => {}
@ -106,7 +110,6 @@ fn main() {
_ => {}
}
#[deny(non_exhaustive_omitted_patterns)]
match Some(non_enum) {
//~^ some variants are not matched explicitly
Some(NonExhaustiveEnum::Unit) => {}
@ -116,7 +119,6 @@ fn main() {
// Ok: all covered and not `unreachable-patterns`
#[deny(unreachable_patterns)]
#[deny(non_exhaustive_omitted_patterns)]
match non_enum {
NonExhaustiveEnum::Unit => {}
NonExhaustiveEnum::Tuple(_) => {}
@ -124,7 +126,6 @@ fn main() {
_ => {}
}
#[deny(non_exhaustive_omitted_patterns)]
match NestedNonExhaustive::B {
//~^ some variants are not matched explicitly
NestedNonExhaustive::A(NonExhaustiveEnum::Unit) => {}
@ -133,54 +134,53 @@ fn main() {
_ => {}
}
#[warn(non_exhaustive_omitted_patterns)]
match VariantNonExhaustive::Baz(1, 2) {
VariantNonExhaustive::Baz(_, _) => {}
VariantNonExhaustive::Bar { x, .. } => {}
}
//~^^ some fields are not explicitly listed
#[warn(non_exhaustive_omitted_patterns)]
let FunctionalRecord { first_field, second_field, .. } = FunctionalRecord::default();
//~^ some fields are not explicitly listed
// Ok: this is local
#[warn(non_exhaustive_omitted_patterns)]
let Foo { a, b, .. } = Foo::default();
#[warn(non_exhaustive_omitted_patterns)]
let NestedStruct { bar: NormalStruct { first_field, .. }, .. } = NestedStruct::default();
//~^ some fields are not explicitly listed
//~^^ some fields are not explicitly listed
// Ok: this tests https://github.com/rust-lang/rust/issues/89382
#[warn(non_exhaustive_omitted_patterns)]
let MixedVisFields { a, b, .. } = MixedVisFields::default();
// Ok: this only has 1 variant
#[deny(non_exhaustive_omitted_patterns)]
match NonExhaustiveSingleVariant::A(true) {
NonExhaustiveSingleVariant::A(true) => {}
_ => {}
}
// We can't catch the case below, so for consistency we don't catch this one either.
#[deny(non_exhaustive_omitted_patterns)]
match NonExhaustiveSingleVariant::A(true) {
_ => {}
}
// We can't catch this case, because this would require digging fully through all the values of
// any type we encounter. We need to be able to only consider present constructors.
#[deny(non_exhaustive_omitted_patterns)]
match &NonExhaustiveSingleVariant::A(true) {
_ => {}
}
match Some(NonExhaustiveSingleVariant::A(true)) {
Some(_) => {}
None => {}
}
match Some(&NonExhaustiveSingleVariant::A(true)) {
Some(_) => {}
None => {}
}
// Ok: we don't lint on `if let` expressions
#[deny(non_exhaustive_omitted_patterns)]
if let NonExhaustiveEnum::Tuple(_) = non_enum {}
#[deny(non_exhaustive_omitted_patterns)]
match UnstableEnum::Stable {
//~^ some variants are not matched explicitly
UnstableEnum::Stable => {}
@ -189,7 +189,6 @@ fn main() {
}
// Ok: the feature is on and all variants are matched
#[deny(non_exhaustive_omitted_patterns)]
match UnstableEnum::Stable {
UnstableEnum::Stable => {}
UnstableEnum::Stable2 => {}
@ -198,52 +197,66 @@ fn main() {
}
// Ok: the feature is on and both variants are matched
#[deny(non_exhaustive_omitted_patterns)]
match OnlyUnstableEnum::Unstable {
OnlyUnstableEnum::Unstable => {}
OnlyUnstableEnum::Unstable2 => {}
_ => {}
}
#[deny(non_exhaustive_omitted_patterns)]
match OnlyUnstableEnum::Unstable {
//~^ some variants are not matched explicitly
OnlyUnstableEnum::Unstable => {}
_ => {}
}
#[warn(non_exhaustive_omitted_patterns)]
let OnlyUnstableStruct { unstable, .. } = OnlyUnstableStruct::new();
//~^ some fields are not explicitly listed
// OK: both unstable fields are matched with feature on
#[warn(non_exhaustive_omitted_patterns)]
let OnlyUnstableStruct { unstable, unstable2, .. } = OnlyUnstableStruct::new();
#[warn(non_exhaustive_omitted_patterns)]
let UnstableStruct { stable, stable2, .. } = UnstableStruct::default();
//~^ some fields are not explicitly listed
// OK: both unstable and stable fields are matched with feature on
#[warn(non_exhaustive_omitted_patterns)]
let UnstableStruct { stable, stable2, unstable, .. } = UnstableStruct::default();
// Ok: local bindings are allowed
#[deny(non_exhaustive_omitted_patterns)]
let local = NonExhaustiveEnum::Unit;
// Ok: missing patterns will be blocked by the pattern being refutable
#[deny(non_exhaustive_omitted_patterns)]
let local_refutable @ NonExhaustiveEnum::Unit = NonExhaustiveEnum::Unit;
//~^ refutable pattern in local binding
#[deny(non_exhaustive_omitted_patterns)]
// Check that matching on a reference results in a correct diagnostic
match &non_enum {
//~^ some variants are not matched explicitly
//~| pattern `&NonExhaustiveEnum::Struct { .. }` not covered
NonExhaustiveEnum::Unit => {}
NonExhaustiveEnum::Tuple(_) => {}
_ => {}
}
match (true, &non_enum) {
//~^ some variants are not matched explicitly
//~| patterns `(_, &NonExhaustiveEnum::Tuple(_))` and `(_, &NonExhaustiveEnum::Struct { .. })` not covered
(true, NonExhaustiveEnum::Unit) => {}
_ => {}
}
match (&non_enum, true) {
//~^ some variants are not matched explicitly
//~| patterns `(&NonExhaustiveEnum::Tuple(_), _)` and `(&NonExhaustiveEnum::Struct { .. }, _)` not covered
(NonExhaustiveEnum::Unit, true) => {}
_ => {}
}
match Some(&non_enum) {
//~^ some variants are not matched explicitly
//~| pattern `Some(&NonExhaustiveEnum::Struct { .. })` not covered
Some(NonExhaustiveEnum::Unit | NonExhaustiveEnum::Tuple(_)) => {}
_ => {}
}
}
#[deny(non_exhaustive_omitted_patterns)]

View File

@ -1,4 +1,4 @@
warning: some fields are not explicitly listed
error: some fields are not explicitly listed
--> $DIR/omitted-patterns.rs:139:9
|
LL | VariantNonExhaustive::Bar { x, .. } => {}
@ -7,41 +7,31 @@ LL | VariantNonExhaustive::Bar { x, .. } => {}
= help: ensure that all fields are mentioned explicitly by adding the suggested fields
= note: the pattern is of type `VariantNonExhaustive` and the `non_exhaustive_omitted_patterns` attribute was found
note: the lint level is defined here
--> $DIR/omitted-patterns.rs:136:12
--> $DIR/omitted-patterns.rs:45:8
|
LL | #[warn(non_exhaustive_omitted_patterns)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
LL | #[deny(non_exhaustive_omitted_patterns)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
warning: some fields are not explicitly listed
--> $DIR/omitted-patterns.rs:144:9
error: some fields are not explicitly listed
--> $DIR/omitted-patterns.rs:143:9
|
LL | let FunctionalRecord { first_field, second_field, .. } = FunctionalRecord::default();
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ field `third_field` not listed
|
= help: ensure that all fields are mentioned explicitly by adding the suggested fields
= note: the pattern is of type `FunctionalRecord` and the `non_exhaustive_omitted_patterns` attribute was found
note: the lint level is defined here
--> $DIR/omitted-patterns.rs:143:12
|
LL | #[warn(non_exhaustive_omitted_patterns)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
warning: some fields are not explicitly listed
--> $DIR/omitted-patterns.rs:152:29
error: some fields are not explicitly listed
--> $DIR/omitted-patterns.rs:149:29
|
LL | let NestedStruct { bar: NormalStruct { first_field, .. }, .. } = NestedStruct::default();
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ field `second_field` not listed
|
= help: ensure that all fields are mentioned explicitly by adding the suggested fields
= note: the pattern is of type `NormalStruct` and the `non_exhaustive_omitted_patterns` attribute was found
note: the lint level is defined here
--> $DIR/omitted-patterns.rs:151:12
|
LL | #[warn(non_exhaustive_omitted_patterns)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
warning: some fields are not explicitly listed
--> $DIR/omitted-patterns.rs:152:9
error: some fields are not explicitly listed
--> $DIR/omitted-patterns.rs:149:9
|
LL | let NestedStruct { bar: NormalStruct { first_field, .. }, .. } = NestedStruct::default();
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ field `foo` not listed
@ -49,117 +39,77 @@ LL | let NestedStruct { bar: NormalStruct { first_field, .. }, .. } = Nested
= help: ensure that all fields are mentioned explicitly by adding the suggested fields
= note: the pattern is of type `NestedStruct` and the `non_exhaustive_omitted_patterns` attribute was found
warning: some fields are not explicitly listed
--> $DIR/omitted-patterns.rs:216:9
error: some fields are not explicitly listed
--> $DIR/omitted-patterns.rs:212:9
|
LL | let OnlyUnstableStruct { unstable, .. } = OnlyUnstableStruct::new();
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ field `unstable2` not listed
|
= help: ensure that all fields are mentioned explicitly by adding the suggested fields
= note: the pattern is of type `OnlyUnstableStruct` and the `non_exhaustive_omitted_patterns` attribute was found
note: the lint level is defined here
--> $DIR/omitted-patterns.rs:215:12
|
LL | #[warn(non_exhaustive_omitted_patterns)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
warning: some fields are not explicitly listed
--> $DIR/omitted-patterns.rs:224:9
error: some fields are not explicitly listed
--> $DIR/omitted-patterns.rs:218:9
|
LL | let UnstableStruct { stable, stable2, .. } = UnstableStruct::default();
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ field `unstable` not listed
|
= help: ensure that all fields are mentioned explicitly by adding the suggested fields
= note: the pattern is of type `UnstableStruct` and the `non_exhaustive_omitted_patterns` attribute was found
note: the lint level is defined here
--> $DIR/omitted-patterns.rs:223:12
|
LL | #[warn(non_exhaustive_omitted_patterns)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: some variants are not matched explicitly
--> $DIR/omitted-patterns.rs:55:11
--> $DIR/omitted-patterns.rs:65:11
|
LL | match non_enum {
| ^^^^^^^^ pattern `NonExhaustiveEnum::Struct { .. }` not covered
|
= help: ensure that all variants are matched explicitly by adding the suggested match arms
= note: the matched value is of type `NonExhaustiveEnum` and the `non_exhaustive_omitted_patterns` attribute was found
note: the lint level is defined here
--> $DIR/omitted-patterns.rs:54:12
|
LL | #[deny(non_exhaustive_omitted_patterns)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: some variants are not matched explicitly
--> $DIR/omitted-patterns.rs:63:11
--> $DIR/omitted-patterns.rs:72:11
|
LL | match non_enum {
| ^^^^^^^^ pattern `NonExhaustiveEnum::Tuple(_)` not covered
|
= help: ensure that all variants are matched explicitly by adding the suggested match arms
= note: the matched value is of type `NonExhaustiveEnum` and the `non_exhaustive_omitted_patterns` attribute was found
note: the lint level is defined here
--> $DIR/omitted-patterns.rs:62:12
|
LL | #[deny(non_exhaustive_omitted_patterns)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: some variants are not matched explicitly
--> $DIR/omitted-patterns.rs:87:11
--> $DIR/omitted-patterns.rs:93:11
|
LL | match (non_enum, true) {
| ^^^^^^^^^^^^^^^^ pattern `(NonExhaustiveEnum::Struct { .. }, _)` not covered
|
= help: ensure that all variants are matched explicitly by adding the suggested match arms
= note: the matched value is of type `(NonExhaustiveEnum, bool)` and the `non_exhaustive_omitted_patterns` attribute was found
note: the lint level is defined here
--> $DIR/omitted-patterns.rs:86:12
|
LL | #[deny(non_exhaustive_omitted_patterns)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: some variants are not matched explicitly
--> $DIR/omitted-patterns.rs:102:11
--> $DIR/omitted-patterns.rs:106:11
|
LL | match (true, non_enum) {
| ^^^^^^^^^^^^^^^^ pattern `(_, NonExhaustiveEnum::Struct { .. })` not covered
|
= help: ensure that all variants are matched explicitly by adding the suggested match arms
= note: the matched value is of type `(bool, NonExhaustiveEnum)` and the `non_exhaustive_omitted_patterns` attribute was found
note: the lint level is defined here
--> $DIR/omitted-patterns.rs:101:12
|
LL | #[deny(non_exhaustive_omitted_patterns)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: some variants are not matched explicitly
--> $DIR/omitted-patterns.rs:110:11
--> $DIR/omitted-patterns.rs:113:11
|
LL | match Some(non_enum) {
| ^^^^^^^^^^^^^^ pattern `Some(NonExhaustiveEnum::Struct { .. })` not covered
|
= help: ensure that all variants are matched explicitly by adding the suggested match arms
= note: the matched value is of type `Option<NonExhaustiveEnum>` and the `non_exhaustive_omitted_patterns` attribute was found
note: the lint level is defined here
--> $DIR/omitted-patterns.rs:109:12
|
LL | #[deny(non_exhaustive_omitted_patterns)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: some variants are not matched explicitly
--> $DIR/omitted-patterns.rs:128:11
--> $DIR/omitted-patterns.rs:129:11
|
LL | match NestedNonExhaustive::B {
| ^^^^^^^^^^^^^^^^^^^^^^ patterns `NestedNonExhaustive::C`, `NestedNonExhaustive::A(NonExhaustiveEnum::Tuple(_))` and `NestedNonExhaustive::A(NonExhaustiveEnum::Struct { .. })` not covered
|
= help: ensure that all variants are matched explicitly by adding the suggested match arms
= note: the matched value is of type `NestedNonExhaustive` and the `non_exhaustive_omitted_patterns` attribute was found
note: the lint level is defined here
--> $DIR/omitted-patterns.rs:127:12
|
LL | #[deny(non_exhaustive_omitted_patterns)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: some variants are not matched explicitly
--> $DIR/omitted-patterns.rs:184:11
@ -169,28 +119,18 @@ LL | match UnstableEnum::Stable {
|
= help: ensure that all variants are matched explicitly by adding the suggested match arms
= note: the matched value is of type `UnstableEnum` and the `non_exhaustive_omitted_patterns` attribute was found
note: the lint level is defined here
--> $DIR/omitted-patterns.rs:183:12
|
LL | #[deny(non_exhaustive_omitted_patterns)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: some variants are not matched explicitly
--> $DIR/omitted-patterns.rs:209:11
--> $DIR/omitted-patterns.rs:206:11
|
LL | match OnlyUnstableEnum::Unstable {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^ pattern `OnlyUnstableEnum::Unstable2` not covered
|
= help: ensure that all variants are matched explicitly by adding the suggested match arms
= note: the matched value is of type `OnlyUnstableEnum` and the `non_exhaustive_omitted_patterns` attribute was found
note: the lint level is defined here
--> $DIR/omitted-patterns.rs:208:12
|
LL | #[deny(non_exhaustive_omitted_patterns)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error[E0005]: refutable pattern in local binding
--> $DIR/omitted-patterns.rs:237:9
--> $DIR/omitted-patterns.rs:228:9
|
LL | let local_refutable @ NonExhaustiveEnum::Unit = NonExhaustiveEnum::Unit;
| ^^^^^^^^^^^^^^^ pattern `_` not covered
@ -204,19 +144,41 @@ LL | let local_refutable @ NonExhaustiveEnum::Unit = NonExhaustiveEnum::Unit
| ++++++++++++++++
error: some variants are not matched explicitly
--> $DIR/omitted-patterns.rs:241:11
--> $DIR/omitted-patterns.rs:232:11
|
LL | match &non_enum {
| ^^^^^^^^^ pattern `&NonExhaustiveEnum::Struct { .. }` not covered
|
= help: ensure that all variants are matched explicitly by adding the suggested match arms
= note: the matched value is of type `&NonExhaustiveEnum` and the `non_exhaustive_omitted_patterns` attribute was found
note: the lint level is defined here
--> $DIR/omitted-patterns.rs:240:12
|
LL | #[deny(non_exhaustive_omitted_patterns)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: aborting due to 10 previous errors; 6 warnings emitted
error: some variants are not matched explicitly
--> $DIR/omitted-patterns.rs:240:11
|
LL | match (true, &non_enum) {
| ^^^^^^^^^^^^^^^^^ patterns `(_, &NonExhaustiveEnum::Tuple(_))` and `(_, &NonExhaustiveEnum::Struct { .. })` not covered
|
= help: ensure that all variants are matched explicitly by adding the suggested match arms
= note: the matched value is of type `(bool, &NonExhaustiveEnum)` and the `non_exhaustive_omitted_patterns` attribute was found
error: some variants are not matched explicitly
--> $DIR/omitted-patterns.rs:247:11
|
LL | match (&non_enum, true) {
| ^^^^^^^^^^^^^^^^^ patterns `(&NonExhaustiveEnum::Tuple(_), _)` and `(&NonExhaustiveEnum::Struct { .. }, _)` not covered
|
= help: ensure that all variants are matched explicitly by adding the suggested match arms
= note: the matched value is of type `(&NonExhaustiveEnum, bool)` and the `non_exhaustive_omitted_patterns` attribute was found
error: some variants are not matched explicitly
--> $DIR/omitted-patterns.rs:254:11
|
LL | match Some(&non_enum) {
| ^^^^^^^^^^^^^^^ pattern `Some(&NonExhaustiveEnum::Struct { .. })` not covered
|
= help: ensure that all variants are matched explicitly by adding the suggested match arms
= note: the matched value is of type `Option<&NonExhaustiveEnum>` and the `non_exhaustive_omitted_patterns` attribute was found
error: aborting due to 19 previous errors
For more information about this error, try `rustc --explain E0005`.