fn is_useful<'p, 'tcx>(
    cx: &MatchCheckCtxt<'p, 'tcx>,
    matrix: &Matrix<'p, 'tcx>,
    v: &PatStack<'p, 'tcx>,
    witness_preference: WitnessPreference,
    hir_id: HirId,
    is_under_guard: bool,
    is_top_level: bool,
) -> Usefulness<'tcx> {
    let Matrix { patterns: rows, .. } = matrix;
    debug!("is_useful({:#?}, {:#?})", matrix, v);

    // The base case. We are pattern-matching on () and the return value is
    // based on whether our matrix has a row or not.
    // NOTE: This could potentially be optimized by checking rows.is_empty()
    // first and then, if v is non-empty, the return value is based on whether
    // the type of the tuple we're checking is inhabited or not.
    if v.is_empty() {
        return if rows.is_empty() {
            Usefulness::new_useful(witness_preference)
        } else {
            NotUseful
        };
    };

    assert!(rows.iter().all(|r| r.len() == v.len()));

    // If the first pattern is an or-pattern, expand it.
    if let Some(vs) = v.expand_or_pat() {
        // We expand the or pattern, trying each of its branches in turn and keeping careful track
        // of possible unreachable sub-branches.
        //
        // If two branches have detected some unreachable sub-branches, we need to be careful. If
        // they were detected in columns that are not the current one, we want to keep only the
        // sub-branches that were unreachable in _all_ branches. Eg. in the following, the last
        // `true` is unreachable in the second branch of the first or-pattern, but not otherwise.
        // Therefore we don't want to lint that it is unreachable.
        //
        // ```
        // match (true, true) {
        //     (true, true) => {}
        //     (false | true, false | true) => {}
        // }
        // ```
        // If however the sub-branches come from the current column, they come from the inside of
        // the current or-pattern, and we want to keep them all. Eg. in the following, we _do_ want
        // to lint that the last `false` is unreachable.
        // ```
        // match None {
        //     Some(false) => {}
        //     None | Some(true | false) => {}
        // }
        // ```

        let mut matrix = matrix.clone();
        // We keep track of sub-branches separately depending on whether they come from this column
        // or from others.
        let mut unreachables_this_column: FxHashSet<Span> = FxHashSet::default();
        let mut unreachables_other_columns: Vec<FxHashSet<Span>> = Vec::default();
        // Whether at least one branch is reachable.
        let mut any_is_useful = false;

        for v in vs {
            let res = is_useful(cx, &matrix, &v, witness_preference, hir_id, is_under_guard, false);
            match res {
                Useful(unreachables) => {
                    if let Some((this_column, other_columns)) = unreachables.split_last() {
                        // We keep the union of unreachables found in the first column.
                        unreachables_this_column.extend(this_column);
                        // We keep the intersection of unreachables found in other columns.
                        if unreachables_other_columns.is_empty() {
                            unreachables_other_columns = other_columns.to_vec();
                        } else {
                            unreachables_other_columns = unreachables_other_columns
                                .into_iter()
                                .zip(other_columns)
                                .map(|(x, y)| x.intersection(&y).copied().collect())
                                .collect();
                        }
                    }
                    any_is_useful = true;
                }
                NotUseful => {
                    unreachables_this_column.insert(v.head().span);
                }
                UsefulWithWitness(_) => bug!(
                    "encountered or-pat in the expansion of `_` during exhaustiveness checking"
                ),
            }

            // If pattern has a guard don't add it to the matrix.
            if !is_under_guard {
                // We push the already-seen patterns into the matrix in order to detect redundant
                // branches like `Some(_) | Some(0)`.
                matrix.push(v);
            }
        }

        return if any_is_useful {
            let mut unreachables = if unreachables_other_columns.is_empty() {
                let n_columns = v.len();
                (0..n_columns - 1).map(|_| FxHashSet::default()).collect()
            } else {
                unreachables_other_columns
            };
            unreachables.push(unreachables_this_column);
            Useful(unreachables)
        } else {
            NotUseful
        };
    }

    // FIXME(Nadrieril): Hack to work around type normalization issues (see #72476).
    let ty = matrix.heads().next().map(|r| r.ty).unwrap_or(v.head().ty);
    let pcx = PatCtxt { cx, matrix, ty, span: v.head().span, is_top_level };

    debug!("is_useful_expand_first_col: ty={:#?}, expanding {:#?}", pcx.ty, v.head());

    let ret = v
        .head_ctor(cx)
        .split(pcx, Some(hir_id))
        .into_iter()
        .map(|ctor| {
            // We cache the result of `Fields::wildcards` because it is used a lot.
            let ctor_wild_subpatterns = Fields::wildcards(pcx, &ctor);
            let matrix = pcx.matrix.specialize_constructor(pcx, &ctor, &ctor_wild_subpatterns);
            let v = v.pop_head_constructor(&ctor_wild_subpatterns);
            let usefulness =
                is_useful(pcx.cx, &matrix, &v, witness_preference, hir_id, is_under_guard, false);
            usefulness.apply_constructor(pcx, &ctor, &ctor_wild_subpatterns)
        })
        .find(|result| result.is_useful())
        .unwrap_or(NotUseful);
    debug!("is_useful::returns({:#?}, {:#?}) = {:?}", matrix, v, ret);
    ret
}
/// Algorithm from <http://moscova.inria.fr/~maranget/papers/warn/index.html>.
/// The algorithm from the paper has been modified to correctly handle empty
/// types. The changes are:
///   (0) We don't exit early if the pattern matrix has zero rows. We just
///       continue to recurse over columns.
///   (1) all_constructors will only return constructors that are statically
///       possible. E.g., it will only return `Ok` for `Result<T, !>`.
///
/// This finds whether a (row) vector `v` of patterns is 'useful' in relation
/// to a set of such vectors `m` - this is defined as there being a set of
/// inputs that will match `v` but not any of the sets in `m`.
///
/// All the patterns at each column of the `matrix ++ v` matrix must have the same type.
///
/// This is used both for reachability checking (if a pattern isn't useful in
/// relation to preceding patterns, it is not reachable) and exhaustiveness
/// checking (if a wildcard pattern is useful in relation to a matrix, the
/// matrix isn't exhaustive).
///
/// `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.
Algorithm from .
The algorithm from the paper has been modified to correctly handle empty
types. The changes are:
(0) We don't exit early if the pattern matrix has zero rows. We just
continue to recurse over columns.
(1) all_constructors will only return constructors that are statically
possible. E.g., it will only return `Ok` for `Result`.



All the patterns at each column of the `matrix ++ v` matrix must have the same type.

This is used both for reachability checking (if a pattern isn't useful in
relation to preceding patterns, it is not reachable) and exhaustiveness
checking (if a wildcard pattern is useful in relation to a matrix, the
matrix isn't exhaustive).

`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.
Algorithm from . The algorithm from the paper has been modified to correctly handle empty types . The changes are : ( 0 ) We don ' t exit early if the pattern matrix has zero rows . We just continue to recurse over columns . ( 1 ) all_constructors will only return constructors that are statically possible . E . g . it will only return ` Ok ` for ` Result ` . All the patterns at each column of the ` matrix ++ v ` matrix must have the same type . This is used both for reachability checking ( if a pattern isn ' t useful in relation to preceding patterns it is not reachable ) and exhaustiveness checking ( if a wildcard pattern is useful in relation to a matrix the matrix isn ' t exhaustive ) . ` 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 .
fn is_useful<'p, 'tcx>(
    cx: &MatchCheckCtxt<'p, 'tcx>,
    matrix: &Matrix<'p, 'tcx>,
    v: &PatStack<'p, 'tcx>,
    witness_preference: WitnessPreference,
    hir_id: HirId,
    is_under_guard: bool,
    is_top_level: bool,
) -> Usefulness<'tcx> {
    let Matrix { patterns: rows, .. } = matrix;
    debug!("is_useful({:#?}, {:#?})", matrix, v);
    // The base case. We are pattern-matching on () and the return value is
    // based on whether our matrix has a row or not.
    // NOTE: This could potentially be optimized by checking rows.is_empty()
    // first and then, if v is non-empty, the return value is based on whether
    // the type of the tuple we're checking is inhabited or not.
    if v.is_empty() {
        return if rows.is_empty() {
            Usefulness::new_useful(witness_preference)
        } else {
            NotUseful
        };
    };
    assert!(rows.iter().all(|r| r.len() == v.len()));
    // If the first pattern is an or-pattern, expand it.
    if let Some(vs) = v.expand_or_pat() {
        // We expand the or pattern, trying each of its branches in turn and keeping careful track
        // of possible unreachable sub-branches.
        //
        // If two branches have detected some unreachable sub-branches, we need to be careful. If
        // they were detected in columns that are not the current one, we want to keep only the
        // sub-branches that were unreachable in _all_ branches. Eg. in the following, the last
        // `true` is unreachable in the second branch of the first or-pattern, but not otherwise.
        // Therefore we don't want to lint that it is unreachable.
        //
        // ```
        // match (true, true) {
        //     (true, true) => {}
        //     (false | true, false | true) => {}
        // }
        // ```
        // If however the sub-branches come from the current column, they come from the inside of
        // the current or-pattern, and we want to keep them all. Eg. in the following, we _do_ want
        // to lint that the last `false` is unreachable.
        // ```
        // match None {
        //     Some(false) => {}
        //     None | Some(true | false) => {}
        // }
        // ```
        let mut matrix = matrix.clone();
        // We keep track of sub-branches separately depending on whether they come from this column
        // or from others.
        let mut unreachables_this_column: FxHashSet<Span> = FxHashSet::default();
        let mut unreachables_other_columns: Vec<FxHashSet<Span>> = Vec::default();
        // Whether at least one branch is reachable.
        let mut any_is_useful = false;
        for v in vs {
            let res = is_useful(cx, &matrix, &v, witness_preference, hir_id, is_under_guard, false);
            match res {
                Useful(unreachables) => {
                    if let Some((this_column, other_columns)) = unreachables.split_last() {
                        // We keep the union of unreachables found in the first column.
                        unreachables_this_column.extend(this_column);
                        // We keep the intersection of unreachables found in other columns.
                        if unreachables_other_columns.is_empty() {
                            unreachables_other_columns = other_columns.to_vec();
                        } else {
                            unreachables_other_columns = unreachables_other_columns
                                .into_iter()
                                .zip(other_columns)
                                .map(|(x, y)| x.intersection(&y).copied().collect())
                                .collect();
                        }
                    }
                    any_is_useful = true;
                }
                NotUseful => {
                    unreachables_this_column.insert(v.head().span);
                }
                UsefulWithWitness(_) => bug!(
                    "encountered or-pat in the expansion of `_` during exhaustiveness checking"
                ),
            }
            // If pattern has a guard don't add it to the matrix.
            if !is_under_guard {
                // We push the already-seen patterns into the matrix in order to detect redundant
                // branches like `Some(_) | Some(0)`.
                matrix.push(v);
            }
        }
        return if any_is_useful {
            let mut unreachables = if unreachables_other_columns.is_empty() {
                let n_columns = v.len();
                (0..n_columns - 1).map(|_| FxHashSet::default()).collect()
            } else {
                unreachables_other_columns
            };
            unreachables.push(unreachables_this_column);
            Useful(unreachables)
        } else {
            NotUseful
        };
    }
    // FIXME(Nadrieril): Hack to work around type normalization issues (see #72476).
    let ty = matrix.heads().next().map(|r| r.ty).unwrap_or(v.head().ty);
    let pcx = PatCtxt { cx, matrix, ty, span: v.head().span, is_top_level };
    debug!("is_useful_expand_first_col: ty={:#?}, expanding {:#?}", pcx.ty, v.head());
    let ret = v
        .head_ctor(cx)
        .split(pcx, Some(hir_id))
        .into_iter()
        .map(|ctor| {
            // We cache the result of `Fields::wildcards` because it is used a lot.
            let ctor_wild_subpatterns = Fields::wildcards(pcx, &ctor);
            let matrix = pcx.matrix.specialize_constructor(pcx, &ctor, &ctor_wild_subpatterns);
            let v = v.pop_head_constructor(&ctor_wild_subpatterns);
            let usefulness =
                is_useful(pcx.cx, &matrix, &v, witness_preference, hir_id, is_under_guard, false);
            usefulness.apply_constructor(pcx, &ctor, &ctor_wild_subpatterns)
        })
        .find(|result| result.is_useful())
        .unwrap_or(NotUseful);
    debug!("is_useful::returns({:#?}, {:#?}) = {:?}", matrix, v, ret);
    ret
}
fn is_useful < ' p , ' tcx > ( cx : & MatchCheckCtxt < ' p , ' tcx > , matrix : & Matrix < ' p , ' tcx > , v : & PatStack < ' p , ' tcx > , witness_preference : WitnessPreference , hir_id : HirId , is_under_guard : bool , is_top_level : bool , ) -> Usefulness < ' tcx > { let Matrix { patterns : rows , .. } = matrix ; debug ! ( " " matrix v ) ; // The base case. We are pattern-matching on () and the return value is // based on whether our matrix has a row or not. // NOTE: This could potentially be optimized by checking rows.is_empty() // first and then, if v is non-empty, the return value is based on whether // the type of the tuple we're checking is inhabited or not. if v . is_empty ( ) { return if rows . is_empty ( ) { Usefulness :: new_useful ( witness_preference ) } else { NotUseful } ; } ; assert ! ( rows iter ( ) all ( r r len ( ) v len ( ) ) ) ; // If the first pattern is an or-pattern, expand it. if let Some ( vs ) = v . expand_or_pat ( ) { // We expand the or pattern, trying each of its branches in turn and keeping careful track // of possible unreachable sub-branches. // // If two branches have detected some unreachable sub-branches, we need to be careful. If // they were detected in columns that are not the current one, we want to keep only the // sub-branches that were unreachable in _all_ branches. Eg. in the following, the last // `true` is unreachable in the second branch of the first or-pattern, but not otherwise. // Therefore we don't want to lint that it is unreachable. // // ``` // match (true, true) { //     (true, true) => {} //     (false | true, false | true) => {} // } // ``` // If however the sub-branches come from the current column, they come from the inside of // the current or-pattern, and we want to keep them all. Eg. in the following, we _do_ want // to lint that the last `false` is unreachable. // ``` // match None { //     Some(false) => {} //     None | Some(true | false) => {} // } // ``` let mut matrix = matrix . clone ( ) ; // We keep track of sub-branches separately depending on whether they come from this column // or from others. let mut unreachables_this_column : FxHashSet < Span > = FxHashSet :: default ( ) ; let mut unreachables_other_columns : Vec < FxHashSet < Span > > = Vec :: default ( ) ; // Whether at least one branch is reachable. let mut any_is_useful = false ; for v in vs { let res = is_useful ( cx , & matrix , & v , witness_preference , hir_id , is_under_guard , false ) ; match res { Useful ( unreachables ) => { if let Some ( ( this_column , other_columns ) ) = unreachables . split_last ( ) { // We keep the union of unreachables found in the first column. unreachables_this_column . extend ( this_column ) ; // We keep the intersection of unreachables found in other columns. if unreachables_other_columns . is_empty ( ) { unreachables_other_columns = other_columns . to_vec ( ) ; } else { unreachables_other_columns = unreachables_other_columns . into_iter ( ) . zip ( other_columns ) . map ( | ( x , y ) | x . intersection ( & y ) . copied ( ) . collect ( ) ) . collect ( ) ; } } any_is_useful = true ; } NotUseful => { unreachables_this_column . insert ( v . head ( ) . span ) ; } UsefulWithWitness ( _ ) => bug ! ( " " ) , } // If pattern has a guard don't add it to the matrix. if ! is_under_guard { // We push the already-seen patterns into the matrix in order to detect redundant // branches like `Some(_) | Some(0)`. matrix . push ( v ) ; } } return if any_is_useful { let mut unreachables = if unreachables_other_columns . is_empty ( ) { let n_columns = v . len ( ) ; ( 0 .. n_columns - 1 ) . map ( | _ | FxHashSet :: default ( ) ) . collect ( ) } else { unreachables_other_columns } ; unreachables . push ( unreachables_this_column ) ; Useful ( unreachables ) } else { NotUseful } ; } // FIXME(Nadrieril): Hack to work around type normalization issues (see #72476). let ty = matrix . heads ( ) . next ( ) . map ( | r | r . ty ) . unwrap_or ( v . head ( ) . ty ) ; let pcx = PatCtxt { cx , matrix , ty , span : v . head ( ) . span , is_top_level } ; debug ! ( " " pcx ty v head ( ) ) ; let ret = v . head_ctor ( cx ) . split ( pcx , Some ( hir_id ) ) . into_iter ( ) . map ( | ctor | { // We cache the result of `Fields::wildcards` because it is used a lot. let ctor_wild_subpatterns = Fields :: wildcards ( pcx , & ctor ) ; let matrix = pcx . matrix . specialize_constructor ( pcx , & ctor , & ctor_wild_subpatterns ) ; let v = v . pop_head_constructor ( & ctor_wild_subpatterns ) ; let usefulness = is_useful ( pcx . cx , & matrix , & v , witness_preference , hir_id , is_under_guard , false ) ; usefulness . apply_constructor ( pcx , & ctor , & ctor_wild_subpatterns ) } ) . find ( | result | result . is_useful ( ) ) . unwrap_or ( NotUseful ) ; debug ! ( " " matrix v ret ) ; ret }
Algorithm from <http://moscova.inria.fr/~maranget/papers/warn/index.html>.
Algorithm from <http : // moscova . inria . fr / ~maranget / papers / warn / index . html > .
cx
&MatchCheckCtxt<'p, 'tcx>
matrix
&Matrix<'p, 'tcx>
v
&PatStack<'p, 'tcx>
witness_preference
WitnessPreference
hir_id
HirId
is_under_guard
bool
is_top_level
bool
cx
&MatchCheckCtxt<'p, 'tcx>
matrix
&Matrix<'p, 'tcx>
v
&PatStack<'p, 'tcx>
witness_preference
WitnessPreference
hir_id
HirId
is_under_guard
bool
is_top_level
bool