Skip to content

Commit

Permalink
Add a machine-applicable suggestion to "unreachable pattern"
Browse files Browse the repository at this point in the history
  • Loading branch information
Nadrieril committed Aug 14, 2024
1 parent 0f442e2 commit 10ae774
Show file tree
Hide file tree
Showing 47 changed files with 1,166 additions and 269 deletions.
1 change: 1 addition & 0 deletions compiler/rustc_mir_build/messages.ftl
Original file line number Diff line number Diff line change
Expand Up @@ -335,6 +335,7 @@ mir_build_unreachable_pattern = unreachable pattern
.unreachable_covered_by_catchall = matches any value
.unreachable_covered_by_one = matches all the values already
.unreachable_covered_by_many = these patterns collectively make the last one unreachable
.suggestion = remove the match arm
mir_build_unsafe_fn_safe_body = an unsafe function restricts its caller, but its body is safe by default
mir_build_unsafe_not_inherited = items do not inherit unsafety from separate enclosing items
Expand Down
2 changes: 2 additions & 0 deletions compiler/rustc_mir_build/src/errors.rs
Original file line number Diff line number Diff line change
Expand Up @@ -594,6 +594,8 @@ pub(crate) struct UnreachablePattern<'tcx> {
pub(crate) covered_by_one: Option<Span>,
#[note(mir_build_unreachable_covered_by_many)]
pub(crate) covered_by_many: Option<MultiSpan>,
#[suggestion(code = "", applicability = "machine-applicable")]
pub(crate) suggest_remove: Option<Span>,
}

#[derive(Subdiagnostic)]
Expand Down
37 changes: 31 additions & 6 deletions compiler/rustc_mir_build/src/thir/pattern/check_match.rs
Original file line number Diff line number Diff line change
Expand Up @@ -413,7 +413,7 @@ impl<'p, 'tcx> MatchVisitor<'p, 'tcx> {
// Emit lints in the order in which they occur in the file.
redundant_subpats.sort_unstable_by_key(|(pat, _)| pat.data().span);
for (pat, explanation) in redundant_subpats {
report_unreachable_pattern(cx, arm.arm_data, pat, &explanation)
report_unreachable_pattern(cx, arm.arm_data, pat, &explanation, None)
}
}
}
Expand Down Expand Up @@ -474,7 +474,11 @@ impl<'p, 'tcx> MatchVisitor<'p, 'tcx> {
hir::MatchSource::ForLoopDesugar
| hir::MatchSource::Postfix
| hir::MatchSource::Normal
| hir::MatchSource::FormatArgs => report_arm_reachability(&cx, &report),
| hir::MatchSource::FormatArgs => {
let suggest_removing_if_unreachable =
matches!(source, hir::MatchSource::Postfix | hir::MatchSource::Normal);
report_arm_reachability(&cx, &report, suggest_removing_if_unreachable);
}
// Unreachable patterns in try and await expressions occur when one of
// the arms are an uninhabited type. Which is OK.
hir::MatchSource::AwaitDesugar | hir::MatchSource::TryDesugar(_) => {}
Expand Down Expand Up @@ -612,7 +616,8 @@ impl<'p, 'tcx> MatchVisitor<'p, 'tcx> {
refutability: RefutableFlag,
scrut: Option<&Expr<'tcx>>,
) -> Result<(PatCtxt<'p, 'tcx>, UsefulnessReport<'p, 'tcx>), ErrorGuaranteed> {
let cx = self.new_cx(refutability, None, scrut, pat.span);
let pat_span = pat.span;
let cx = self.new_cx(refutability, None, scrut, pat_span);
let pat = self.lower_pattern(&cx, pat)?;
let arms = [MatchArm { pat, arm_data: self.lint_level, has_guard: false }];
let report = self.analyze_patterns(&cx, &arms, pat.ty().inner())?;
Expand All @@ -626,7 +631,7 @@ impl<'p, 'tcx> MatchVisitor<'p, 'tcx> {
) -> Result<RefutableFlag, ErrorGuaranteed> {
let (cx, report) = self.analyze_binding(pat, Refutable, scrut)?;
// Report if the pattern is unreachable, which can only occur when the type is uninhabited.
report_arm_reachability(&cx, &report);
report_arm_reachability(&cx, &report, false);
// If the list of witnesses is empty, the match is exhaustive, i.e. the `if let` pattern is
// irrefutable.
Ok(if report.non_exhaustiveness_witnesses.is_empty() { Irrefutable } else { Refutable })
Expand Down Expand Up @@ -916,6 +921,7 @@ fn report_unreachable_pattern<'p, 'tcx>(
hir_id: HirId,
pat: &DeconstructedPat<'p, 'tcx>,
explanation: &RedundancyExplanation<'p, 'tcx>,
suggest_remove: Option<Span>,
) {
let pat_span = pat.data().span;
let mut lint = UnreachablePattern {
Expand All @@ -924,6 +930,7 @@ fn report_unreachable_pattern<'p, 'tcx>(
covered_by_catchall: None,
covered_by_one: None,
covered_by_many: None,
suggest_remove,
};
match explanation.covered_by.as_slice() {
[] => {
Expand Down Expand Up @@ -964,10 +971,28 @@ fn report_unreachable_pattern<'p, 'tcx>(
}

/// Report unreachable arms, if any.
fn report_arm_reachability<'p, 'tcx>(cx: &PatCtxt<'p, 'tcx>, report: &UsefulnessReport<'p, 'tcx>) {
fn report_arm_reachability<'p, 'tcx>(
cx: &PatCtxt<'p, 'tcx>,
report: &UsefulnessReport<'p, 'tcx>,
is_match_arm: bool,
) {
let sm = cx.tcx.sess.source_map();
for (arm, is_useful) in report.arm_usefulness.iter() {
if let Usefulness::Redundant(explanation) = is_useful {
report_unreachable_pattern(cx, arm.arm_data, arm.pat, explanation)
let hir_id = arm.arm_data;
let arm_span = cx.tcx.hir().span(hir_id);
let suggest_remove = if is_match_arm {
// If the arm is followed by a comma, extend the span to include it.
let with_whitespace = sm.span_extend_while_whitespace(arm_span);
if let Some(comma) = sm.span_look_ahead(with_whitespace, ",", Some(1)) {
Some(arm_span.to(comma))
} else {
Some(arm_span)
}
} else {
None
};
report_unreachable_pattern(cx, hir_id, arm.pat, explanation, suggest_remove)
}
}
}
Expand Down
1 change: 1 addition & 0 deletions compiler/rustc_pattern_analysis/src/rustc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -921,6 +921,7 @@ impl<'p, 'tcx: 'p> PatCx for RustcPatCtxt<'p, 'tcx> {
type Error = ErrorGuaranteed;
type VariantIdx = VariantIdx;
type StrLit = Const<'tcx>;
// The `HirId` is used for lints, the `Span` is the span of the arm.
type ArmData = HirId;
type PatData = &'p Pat<'tcx>;

Expand Down
5 changes: 4 additions & 1 deletion tests/ui/consts/packed_pattern.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,10 @@ warning: unreachable pattern
LL | Foo { field: (5, 6, 7, 8) } => {},
| --------------------------- matches all the values already
LL | FOO => unreachable!(),
| ^^^ unreachable pattern
| ^^^-------------------
| |
| unreachable pattern
| help: remove the match arm
|
= note: `#[warn(unreachable_patterns)]` on by default

Expand Down
5 changes: 4 additions & 1 deletion tests/ui/consts/packed_pattern2.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,10 @@ warning: unreachable pattern
LL | Bar { a: Foo { field: (5, 6) } } => {},
| -------------------------------- matches all the values already
LL | FOO => unreachable!(),
| ^^^ unreachable pattern
| ^^^-------------------
| |
| unreachable pattern
| help: remove the match arm
|
= note: `#[warn(unreachable_patterns)]` on by default

Expand Down
5 changes: 4 additions & 1 deletion tests/ui/error-codes/E0001.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,10 @@ error: unreachable pattern
--> $DIR/E0001.rs:8:9
|
LL | _ => {/* ... */}
| ^ unreachable pattern
| ^---------------
| |
| unreachable pattern
| help: remove the match arm
|
note: these patterns collectively make the last one unreachable
--> $DIR/E0001.rs:8:9
Expand Down
5 changes: 4 additions & 1 deletion tests/ui/lint/issue-30302.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,10 @@ LL | Nil => true,
| --- matches any value
LL |
LL | _ => false
| ^ unreachable pattern
| ^---------
| |
| unreachable pattern
| help: remove the match arm
|
note: the lint level is defined here
--> $DIR/issue-30302.rs:4:9
Expand Down
55 changes: 44 additions & 11 deletions tests/ui/or-patterns/exhaustiveness-unreachable-pattern.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,10 @@ error: unreachable pattern
LL | (1 | 2,) => {}
| -------- matches all the values already
LL | (1,) => {}
| ^^^^ unreachable pattern
| ^^^^------
| |
| unreachable pattern
| help: remove the match arm
|
note: the lint level is defined here
--> $DIR/exhaustiveness-unreachable-pattern.rs:1:9
Expand All @@ -18,13 +21,19 @@ error: unreachable pattern
LL | (1 | 2,) => {}
| -------- matches all the values already
LL | (2,) => {}
| ^^^^ unreachable pattern
| ^^^^------
| |
| unreachable pattern
| help: remove the match arm

error: unreachable pattern
--> $DIR/exhaustiveness-unreachable-pattern.rs:19:9
|
LL | (1 | 2,) => {}
| ^^^^^^^^ unreachable pattern
| ^^^^^^^^------
| |
| unreachable pattern
| help: remove the match arm
|
note: these patterns collectively make the last one unreachable
--> $DIR/exhaustiveness-unreachable-pattern.rs:19:9
Expand All @@ -42,7 +51,10 @@ error: unreachable pattern
LL | (1 | 2, 3 | 4) => {}
| -------------- matches all the values already
LL | (1, 3) => {}
| ^^^^^^ unreachable pattern
| ^^^^^^------
| |
| unreachable pattern
| help: remove the match arm

error: unreachable pattern
--> $DIR/exhaustiveness-unreachable-pattern.rs:25:9
Expand All @@ -51,7 +63,10 @@ LL | (1 | 2, 3 | 4) => {}
| -------------- matches all the values already
LL | (1, 3) => {}
LL | (1, 4) => {}
| ^^^^^^ unreachable pattern
| ^^^^^^------
| |
| unreachable pattern
| help: remove the match arm

error: unreachable pattern
--> $DIR/exhaustiveness-unreachable-pattern.rs:26:9
Expand All @@ -60,7 +75,10 @@ LL | (1 | 2, 3 | 4) => {}
| -------------- matches all the values already
...
LL | (2, 4) => {}
| ^^^^^^ unreachable pattern
| ^^^^^^------
| |
| unreachable pattern
| help: remove the match arm

error: unreachable pattern
--> $DIR/exhaustiveness-unreachable-pattern.rs:27:9
Expand All @@ -69,13 +87,19 @@ LL | (1 | 2, 3 | 4) => {}
| -------------- matches all the values already
...
LL | (2 | 1, 4) => {}
| ^^^^^^^^^^ unreachable pattern
| ^^^^^^^^^^------
| |
| unreachable pattern
| help: remove the match arm

error: unreachable pattern
--> $DIR/exhaustiveness-unreachable-pattern.rs:29:9
|
LL | (1, 4 | 5) => {}
| ^^^^^^^^^^ unreachable pattern
| ^^^^^^^^^^------
| |
| unreachable pattern
| help: remove the match arm
|
note: these patterns collectively make the last one unreachable
--> $DIR/exhaustiveness-unreachable-pattern.rs:29:9
Expand All @@ -102,7 +126,10 @@ error: unreachable pattern
LL | (None | Some(1 | 2),) => {}
| --------------------- matches all the values already
LL | (Some(1),) => {}
| ^^^^^^^^^^ unreachable pattern
| ^^^^^^^^^^------
| |
| unreachable pattern
| help: remove the match arm

error: unreachable pattern
--> $DIR/exhaustiveness-unreachable-pattern.rs:43:9
Expand All @@ -111,15 +138,21 @@ LL | (None | Some(1 | 2),) => {}
| --------------------- matches all the values already
LL | (Some(1),) => {}
LL | (None,) => {}
| ^^^^^^^ unreachable pattern
| ^^^^^^^------
| |
| unreachable pattern
| help: remove the match arm

error: unreachable pattern
--> $DIR/exhaustiveness-unreachable-pattern.rs:48:9
|
LL | ((1 | 2,) | (3 | 4,),) => {}
| ---------------------- matches all the values already
LL | ((1..=4,),) => {}
| ^^^^^^^^^^^ unreachable pattern
| ^^^^^^^^^^^------
| |
| unreachable pattern
| help: remove the match arm

error: unreachable pattern
--> $DIR/exhaustiveness-unreachable-pattern.rs:53:14
Expand Down
5 changes: 4 additions & 1 deletion tests/ui/pattern/issue-14221.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,10 @@ LL | A => "A",
| - matches any value
LL |
LL | B => "B",
| ^ unreachable pattern
| ^--------
| |
| unreachable pattern
| help: remove the match arm
|
note: the lint level is defined here
--> $DIR/issue-14221.rs:1:9
Expand Down
Loading

0 comments on commit 10ae774

Please sign in to comment.