]> git.proxmox.com Git - rustc.git/blobdiff - compiler/rustc_mir_build/src/thir/pattern/usefulness.rs
New upstream version 1.62.1+dfsg1
[rustc.git] / compiler / rustc_mir_build / src / thir / pattern / usefulness.rs
index 15bb5adf8ba19a2768836a0a11ce5f8397cc9f82..4e96cfd9bbd501191157dc7f64a3fc8ae456dd3c 100644 (file)
 //! 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
@@ -659,13 +668,15 @@ enum ArmType {
 ///
 /// 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:
@@ -765,10 +776,7 @@ fn lint_non_exhaustive_omitted_patterns<'p, 'tcx>(
 /// `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>,
@@ -800,6 +808,7 @@ fn is_useful<'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.
@@ -809,9 +818,11 @@ fn is_useful<'p, 'tcx>(
         // 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 {
@@ -822,6 +833,7 @@ fn is_useful<'p, 'tcx>(
         }
     } 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(
@@ -895,7 +907,7 @@ fn is_useful<'p, 'tcx>(
 }
 
 /// 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>,
@@ -928,6 +940,7 @@ crate struct UsefulnessReport<'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>],
@@ -939,6 +952,7 @@ crate fn compute_match_usefulness<'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 {