//! This is enough to compute reachability: a pattern in a `match` expression is reachable iff it
//! is useful w.r.t. the patterns above it:
//! ```rust
+//! # fn foo(x: Option<i32>) {
//! match x {
-//! Some(_) => ...,
-//! None => ..., // reachable: `None` is matched by this but not the branch above
-//! Some(0) => ..., // unreachable: all the values this matches are already matched by
-//! // `Some(_)` above
+//! Some(_) => {},
+//! None => {}, // reachable: `None` is matched by this but not the branch above
+//! Some(0) => {}, // unreachable: all the values this matches are already matched by
+//! // `Some(_)` above
//! }
+//! # }
//! ```
//!
//! This is also enough to compute exhaustiveness: a match is exhaustive iff the wildcard `_`
//! pattern is _not_ useful w.r.t. the patterns in the match. The values returned by `usefulness`
//! are used to tell the user which values are missing.
-//! ```rust
+//! ```compile_fail,E0004
+//! # fn foo(x: Option<i32>) {
//! match x {
-//! Some(0) => ...,
-//! None => ...,
+//! Some(0) => {},
+//! None => {},
//! // not exhaustive: `_` is useful because it matches `Some(1)`
//! }
+//! # }
//! ```
//!
//! The entrypoint of this file is the [`compute_match_usefulness`] function, which computes
//! say from knowing only the first constructor of our candidate value.
//!
//! Let's take the following example:
-//! ```
+//! ```compile_fail,E0004
+//! # enum Enum { Variant1(()), Variant2(Option<bool>, u32)}
+//! # fn foo(x: Enum) {
//! match x {
//! Enum::Variant1(_) => {} // `p1`
//! Enum::Variant2(None, 0) => {} // `p2`
//! Enum::Variant2(Some(_), 0) => {} // `q`
//! }
+//! # }
//! ```
//!
//! We can easily see that if our candidate value `v` starts with `Variant1` it will not match `q`.
//! and `v1`. In fact, such a `v` will be a witness of usefulness of `q` exactly when the tuple
//! `(v0, v1)` is a witness of usefulness of `q'` in the following reduced match:
//!
-//! ```
+//! ```compile_fail,E0004
+//! # fn foo(x: (Option<bool>, u32)) {
//! match x {
//! (None, 0) => {} // `p2'`
//! (Some(_), 0) => {} // `q'`
//! }
+//! # }
//! ```
//!
//! This motivates a new step in computing usefulness, that we call _specialization_.
//! like a stack. We note a pattern-stack simply with `[p_1 ... p_n]`.
//! Here's a sequence of specializations of a list of pattern-stacks, to illustrate what's
//! happening:
-//! ```
+//! ```ignore (illustrative)
//! [Enum::Variant1(_)]
//! [Enum::Variant2(None, 0)]
//! [Enum::Variant2(Some(_), 0)]
//! - We return the concatenation of all the witnesses found, if any.
//!
//! Example:
-//! ```
+//! ```ignore (illustrative)
//! [Some(true)] // p_1
//! [None] // p_2
//! [Some(_)] // q
///
/// For example, if we are constructing a witness for the match against
///
-/// ```
+/// ```compile_fail,E0004
+/// # #![feature(type_ascription)]
/// struct Pair(Option<(u32, u32)>, bool);
-///
+/// # fn foo(p: Pair) {
/// match (p: Pair) {
/// Pair(None, _) => {}
/// Pair(_, false) => {}
/// }
+/// # }
/// ```
///
/// We'll perform the following steps:
/// `is_under_guard` is used to inform if the pattern has a guard. If it
/// has one it must not be inserted into the matrix. This shouldn't be
/// relied on for soundness.
-#[instrument(
- level = "debug",
- skip(cx, matrix, witness_preference, hir_id, is_under_guard, is_top_level)
-)]
+#[instrument(level = "debug", skip(cx, matrix, hir_id))]
fn is_useful<'p, 'tcx>(
cx: &MatchCheckCtxt<'p, 'tcx>,
matrix: &Matrix<'p, 'tcx>,
let ty = v.head().ty();
let is_non_exhaustive = cx.is_foreign_non_exhaustive_enum(ty);
+ debug!("v.head: {:?}, v.span: {:?}", v.head(), v.head().span());
let pcx = PatCtxt { cx, ty, span: v.head().span(), is_top_level, is_non_exhaustive };
// If the first pattern is an or-pattern, expand it.
// We try each or-pattern branch in turn.
let mut matrix = matrix.clone();
for v in v.expand_or_pat() {
+ debug!(?v);
let usefulness = ensure_sufficient_stack(|| {
is_useful(cx, &matrix, &v, witness_preference, hir_id, is_under_guard, false)
});
+ debug!(?usefulness);
ret.extend(usefulness);
// If pattern has a guard don't add it to the matrix.
if !is_under_guard {
}
} else {
let v_ctor = v.head().ctor();
+ debug!(?v_ctor);
if let Constructor::IntRange(ctor_range) = &v_ctor {
// Lint on likely incorrect range patterns (#63987)
ctor_range.lint_overlapping_range_endpoints(
}
/// The arm of a match expression.
-#[derive(Clone, Copy)]
+#[derive(Clone, Copy, Debug)]
crate struct MatchArm<'p, 'tcx> {
/// The pattern must have been lowered through `check_match::MatchVisitor::lower_pattern`.
crate pat: &'p DeconstructedPat<'p, 'tcx>,
///
/// Note: the input patterns must have been lowered through
/// `check_match::MatchVisitor::lower_pattern`.
+#[instrument(skip(cx, arms), level = "debug")]
crate fn compute_match_usefulness<'p, 'tcx>(
cx: &MatchCheckCtxt<'p, 'tcx>,
arms: &[MatchArm<'p, 'tcx>],
.iter()
.copied()
.map(|arm| {
+ debug!(?arm);
let v = PatStack::from_pattern(arm.pat);
is_useful(cx, &matrix, &v, RealArm, arm.hir_id, arm.has_guard, true);
if !arm.has_guard {