Show the guard exhaustivity note only when it's the guards alone that cause non-exhaustiveness

Only show the "match arms with guards don't count towards exhaustivity"
note when removing all guards would make the match exhaustive. Previously,
this note was shown whenever all arms had guards, even if the patterns
themselves were insufficient to cover all valid values of a type.

Re-run the exhaustiveness analysis with guards stripped to determine
whether the guards are actually the cause of non-exhaustiveness. This only happens
on an actual exhaustiveness error, so should not be a performance concern.
This commit is contained in:
Jacob Adam
2026-04-07 10:04:24 +01:00
parent 49b6ac01d6
commit b400f22c7b
@@ -532,6 +532,18 @@ fn check_match(
| hir::MatchSource::AwaitDesugar
| hir::MatchSource::FormatArgs => None,
};
// Check if the match would be exhaustive if all guards were removed.
// If so, we leave a note that guards don't count towards exhaustivity.
let would_be_exhaustive_without_guards = {
let any_arm_has_guard = tarms.iter().any(|arm| arm.has_guard);
any_arm_has_guard && {
let guardless_arms: Vec<_> =
tarms.iter().map(|arm| MatchArm { has_guard: false, ..*arm }).collect();
rustc_pattern_analysis::rustc::analyze_match(&cx, &guardless_arms, scrut.ty)
.is_ok_and(|report| report.non_exhaustiveness_witnesses.is_empty())
}
};
self.error = Err(report_non_exhaustive_match(
&cx,
self.thir,
@@ -540,6 +552,7 @@ fn check_match(
witnesses,
arms,
braces_span,
would_be_exhaustive_without_guards,
));
}
}
@@ -1154,6 +1167,7 @@ fn report_non_exhaustive_match<'p, 'tcx>(
witnesses: Vec<WitnessPat<'p, 'tcx>>,
arms: &[ArmId],
braces_span: Option<Span>,
would_be_exhaustive_without_guards: bool,
) -> ErrorGuaranteed {
let is_empty_match = arms.is_empty();
let non_empty_enum = match scrut_ty.kind() {
@@ -1364,8 +1378,7 @@ fn report_non_exhaustive_match<'p, 'tcx>(
},
);
let all_arms_have_guards = arms.iter().all(|arm_id| thir[*arm_id].guard.is_some());
if !is_empty_match && all_arms_have_guards {
if would_be_exhaustive_without_guards {
err.subdiagnostic(NonExhaustiveMatchAllArmsGuarded);
}
if let Some((span, sugg)) = suggestion {