Skip to content

Commit aa12554

Browse files
committed
Auto merge of #116042 - Nadrieril:linear-pass-take-2, r=<try>
[Experiment] Rewrite exhaustiveness in one pass Arm reachability checking does a quadratic amount of work: for each arm we check if it is reachable given the arms above it. This feels wasteful since we often end up re-exploring the same cases when we check for exhaustiveness. This PR is an attempt to check reachability at the same time as exhaustiveness. This opens the door to a bunch of code simplifications I'm very excited about. The main question is whether I can get actual performance gains out of this. I had started the experiment in #111720 but I can't reopen it. r? `@ghost`
2 parents f73d376 + b5728f1 commit aa12554

21 files changed

+1272
-1041
lines changed

compiler/rustc_lint_defs/src/builtin.rs

+12-11
Original file line numberDiff line numberDiff line change
@@ -3915,8 +3915,10 @@ declare_lint! {
39153915
}
39163916

39173917
declare_lint! {
3918-
/// The `non_exhaustive_omitted_patterns` lint detects when a wildcard (`_` or `..`) in a
3919-
/// pattern for a `#[non_exhaustive]` struct or enum is reachable.
3918+
/// The `non_exhaustive_omitted_patterns` lint detects when some variants or fields of a
3919+
/// `#[non_exhaustive]` struct or enum are not mentioned explicitly in a pattern. This allows
3920+
/// downstream crates to be warned when new variants or fields are added to the upstream struct
3921+
/// or enum.
39203922
///
39213923
/// ### Example
39223924
///
@@ -3930,9 +3932,9 @@ declare_lint! {
39303932
///
39313933
/// // in crate B
39323934
/// #![feature(non_exhaustive_omitted_patterns_lint)]
3935+
/// #[warn(non_exhaustive_omitted_patterns)]
39333936
/// match Bar::A {
39343937
/// Bar::A => {},
3935-
/// #[warn(non_exhaustive_omitted_patterns)]
39363938
/// _ => {},
39373939
/// }
39383940
/// ```
@@ -3943,8 +3945,8 @@ declare_lint! {
39433945
/// warning: reachable patterns not covered of non exhaustive enum
39443946
/// --> $DIR/reachable-patterns.rs:70:9
39453947
/// |
3946-
/// LL | _ => {}
3947-
/// | ^ pattern `B` not covered
3948+
/// LL | match Bar::A {
3949+
/// | ^ pattern `Bar::B` not covered
39483950
/// |
39493951
/// note: the lint level is defined here
39503952
/// --> $DIR/reachable-patterns.rs:69:16
@@ -3957,12 +3959,11 @@ declare_lint! {
39573959
///
39583960
/// ### Explanation
39593961
///
3960-
/// Structs and enums tagged with `#[non_exhaustive]` force the user to add a
3961-
/// (potentially redundant) wildcard when pattern-matching, to allow for future
3962-
/// addition of fields or variants. The `non_exhaustive_omitted_patterns` lint
3963-
/// detects when such a wildcard happens to actually catch some fields/variants.
3964-
/// In other words, when the match without the wildcard would not be exhaustive.
3965-
/// This lets the user be informed if new fields/variants were added.
3962+
/// Structs and enums tagged with `#[non_exhaustive]` force the user to add a (potentially
3963+
/// redundant) wildcard when pattern-matching, to allow for future addition of fields or
3964+
/// variants. The `non_exhaustive_omitted_patterns` lint detects when such a wildcard happens to
3965+
/// actually catch some fields/variants. This lets the user be informed if new fields/variants
3966+
/// were added.
39663967
pub NON_EXHAUSTIVE_OMITTED_PATTERNS,
39673968
Allow,
39683969
"detect when patterns of types marked `non_exhaustive` are missed",

compiler/rustc_mir_build/src/thir/pattern/check_match.rs

+4-3
Original file line numberDiff line numberDiff line change
@@ -269,7 +269,7 @@ impl<'p, 'tcx> MatchVisitor<'_, 'p, 'tcx> {
269269

270270
let scrut = &self.thir[scrut];
271271
let scrut_ty = scrut.ty;
272-
let report = compute_match_usefulness(&cx, &tarms, self.lint_level, scrut_ty);
272+
let report = compute_match_usefulness(&cx, &tarms, self.lint_level, scrut_ty, scrut.span);
273273

274274
match source {
275275
// Don't report arm reachability of desugared `match $iter.into_iter() { iter => .. }`
@@ -431,7 +431,8 @@ impl<'p, 'tcx> MatchVisitor<'_, 'p, 'tcx> {
431431
let pattern = self.lower_pattern(&mut cx, pat);
432432
let pattern_ty = pattern.ty();
433433
let arm = MatchArm { pat: pattern, hir_id: self.lint_level, has_guard: false };
434-
let report = compute_match_usefulness(&cx, &[arm], self.lint_level, pattern_ty);
434+
let report =
435+
compute_match_usefulness(&cx, &[arm], self.lint_level, pattern_ty, pattern.span());
435436

436437
// Note: we ignore whether the pattern is unreachable (i.e. whether the type is empty). We
437438
// only care about exhaustiveness here.
@@ -622,7 +623,7 @@ fn is_let_irrefutable<'p, 'tcx>(
622623
pat: &'p DeconstructedPat<'p, 'tcx>,
623624
) -> bool {
624625
let arms = [MatchArm { pat, hir_id: pat_id, has_guard: false }];
625-
let report = compute_match_usefulness(&cx, &arms, pat_id, pat.ty());
626+
let report = compute_match_usefulness(&cx, &arms, pat_id, pat.ty(), pat.span());
626627

627628
// Report if the pattern is unreachable, which can only occur when the type is uninhabited.
628629
// This also reports unreachable sub-patterns though, so we can't just replace it with an

0 commit comments

Comments
 (0)