Change:
Not much to comment about. The supposedly “unreachable” pattern is obviously reached. () Output: Errors: <!-- TRIAGEBOTSTART --<!-- TRIAGEBOTASSIGNSTART --This issue has been assigned to via . <!-- TRIAGEBOTASSIGNDATASTARTTRIAGEBOTASSIGNDATAEND --<!-- TRIAGEBOTASSIGNEND --<!-- TRIAGEBOTEND --
Looks like this was injected in 1.41.0, ostensibly in the exhaustiveness checking refactorings. To find out, let's cc ping cleanup cc
Hey Cleanup Crew ICE-breakers! This bug has been identified as a good "Cleanup ICE-breaking candidate". In case it's useful, here are some [instructions] for tackling these sorts of bugs. Maybe take a look? Thanks! <3 [instructions]: https://rustc-dev- cc
The relevant code is in : From the point of exhaustiveness checking this algorithm is correct, but not from a linting POV in the presence of guards. Previously, before the or-patterns reform, we merely interpreted each as a separate arm, so this was correctly handled from a linting perspective in the arm. Now however, the linting will happen in the arm, as according to , unaware of whether the arm , the pattern itself has an unreachable alternative. To fix this, presumably we have to propagate into , while being careful not to declare anything exhaustive which isn't for the soundness sensitive bits.
In case this is still relevant.. I went trying out and it gave me: regressed nightly: nightly-2019-12-04 regressed commit:
I'm going to assume we're ok with not detecting as redundant, otherwise we violate one of the assumptions of match checking, namely that variables and wildcards behave identically, and that's a whole other can of worms. Agreed. Specifically, what we want to avoid is adding to the matrix any pattern that is under a match guard. The code in does that correctly, but the or-pattern-handling code in doesn't. Once again I can't fix that myself right now, but I suspect it should be enough to disable this line: when we are under a match guard. So passing a bool to (recursively) should do the trick. (or anyone really) would you mind trying that ? :angel: Two more test cases to be sure we're doing it right:
With such clear instructions, this looks like a good issue for beginners! I'll add the labels.
Hi, I want to take this I understand the solution explained by but have one question regarding because it also calls . From what I gather it generates a wildcard pattern and check it isn't useful, so for this task I can treat it as having no guard right?
assign
Absolutely !
Thanks for tackling this. :) I think it would also be neat to add some comments on around what it means to pass in "yes it has a guard", specifically that it shouldn't be relied on for soundness (i.e. in ). Perhaps also consider an or some such for robustness (consider also turning into for stronger typing). Best of luck!
-- that seems like quite a reasonable tradeoff for what is a rare occurrence. :)
I don't think this is any more readable, or safe, than a . The variable name makes it very clear in the method, and we can comment the call site if that seems ambiguous.

Discussion:
/// 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). <ins> /// /// `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. </ins> crate fn is_useful<'p, 'tcx>( cx: &mut MatchCheckCtxt<'p, 'tcx>, matrix: &Matrix<'p, 'tcx>, v: &PatStack<'p, 'tcx>, witness_preference: WitnessPreference, hir_id: HirId, <ins> is_under_guard: bool, </ins> is_top_level: bool, ) -> Usefulness<'tcx, 'p> { let &Matrix(ref rows) = matrix;

let mut unreachable_pats = Vec::new(); let mut any_is_useful = false; for v in vs { <del> let res = is_useful(cx, &matrix, &v, witness_preference, hir_id, false); </del> <ins> let res = is_useful(cx, &matrix, &v, witness_preference, hir_id, is_under_guard, false); </ins> match res { Useful(pats) => { any_is_useful = true;

bug!("Encountered or-pat in `v` during exhaustiveness checking") } } <del> matrix.push(v); </del> <ins> // If pattern has a guard don't add it to the matrix if !is_under_guard { matrix.push(v); } </ins> } return if any_is_useful { Useful(unreachable_pats) } else { NotUseful }; }

Some(hir_id), ) .into_iter() <del> .map(|c| is_useful_specialized(cx, matrix, v, c, pcx.ty, witness_preference, hir_id)) </del> <ins> .map(|c| { is_useful_specialized( cx, matrix, v, c, pcx.ty, witness_preference, hir_id, is_under_guard, ) }) </ins> .find(|result| result.is_useful()) .unwrap_or(NotUseful) } else {

split_grouped_constructors(cx.tcx, cx.param_env, pcx, all_ctors, matrix, DUMMY_SP, None) .into_iter() .map(|c| { <del> is_useful_specialized(cx, matrix, v, c, pcx.ty, witness_preference, hir_id) </del> <ins> is_useful_specialized( cx, matrix, v, c, pcx.ty, witness_preference, hir_id, is_under_guard, ) </ins> }) .find(|result| result.is_useful()) .unwrap_or(NotUseful) } else { let matrix = matrix.specialize_wildcard(); let v = v.to_tail(); <del> let usefulness = is_useful(cx, &matrix, &v, witness_preference, hir_id, false); </del> <ins> let usefulness = is_useful(cx, &matrix, &v, witness_preference, hir_id, is_under_guard, false); </ins> // In this case, there's at least one "free" // constructor that is only matched against by

lty: Ty<'tcx>, witness_preference: WitnessPreference, hir_id: HirId, <ins> is_under_guard: bool, </ins> ) -> Usefulness<'tcx, 'p> { debug!("is_useful_specialized({:#?}, {:#?}, {:?})", v, ctor, lty);

cx.pattern_arena.alloc_from_iter(ctor.wildcard_subpatterns(cx, lty)); let matrix = matrix.specialize_constructor(cx, &ctor, ctor_wild_subpatterns); v.specialize_constructor(cx, &ctor, ctor_wild_subpatterns) <del> .map(|v| is_useful(cx, &matrix, &v, witness_preference, hir_id, false)) </del> <ins> .map(|v| is_useful(cx, &matrix, &v, witness_preference, hir_id, is_under_guard, false)) </ins> .map(|u| u.apply_constructor(cx, &ctor, lty)) .unwrap_or(NotUseful) }

let mut catchall = None; for (arm_index, (pat, id, has_guard)) in arms.iter().copied().enumerate() { let v = PatStack::from_pattern(pat); <del> match is_useful(cx, &seen, &v, LeaveOutWitness, id, true) { </del> <ins> match is_useful(cx, &seen, &v, LeaveOutWitness, id, has_guard, true) { </ins> NotUseful => { match source { hir::MatchSource::IfDesugar { .. } | hir::MatchSource::WhileDesugar => bug!(),

) -> Result<(), Vec<super::Pat<'tcx>>> { let wild_pattern = cx.pattern_arena.alloc(super::Pat::wildcard_from_ty(ty)); let v = PatStack::from_pattern(wild_pattern); <del> match is_useful(cx, matrix, &v, ConstructWitness, hir_id, true) { </del> <ins> // false is given for `is_under_guard` argument due to the wildcard // pattern not having a guard match is_useful(cx, matrix, &v, ConstructWitness, hir_id, false, true) { </ins> NotUseful => Ok(()), // This is good, wildcard pattern isn't reachable. UsefulWithWitness(pats) => Err(if pats.is_empty() { bug!("Exhaustiveness check returned no witnesses")

<ins> // check-pass #![deny(unreachable_patterns)] #![feature(or_patterns)] fn main() { match (3,42) { (a,_) | (_,a) if a > 10 => {println!("{}", a)} _ => () } match Some((3,42)) { Some((a, _)) | Some((_, a)) if a > 10 => {println!("{}", a)} _ => () } match Some((3,42)) { Some((a, _) | (_, a)) if a > 10 => {println!("{}", a)} _ => () } } </ins>