Skip to content

Commit c507758

Browse files
committed
Add a machine-applicable suggestion to "unreachable pattern"
1 parent 8291d68 commit c507758

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

43 files changed

+1154
-269
lines changed

compiler/rustc_mir_build/messages.ftl

+1
Original file line numberDiff line numberDiff line change
@@ -335,6 +335,7 @@ mir_build_unreachable_pattern = unreachable pattern
335335
.unreachable_covered_by_catchall = matches any value
336336
.unreachable_covered_by_one = matches all the values already
337337
.unreachable_covered_by_many = these patterns collectively make the last one unreachable
338+
.suggestion = remove the match arm
338339
339340
mir_build_unsafe_fn_safe_body = an unsafe function restricts its caller, but its body is safe by default
340341
mir_build_unsafe_not_inherited = items do not inherit unsafety from separate enclosing items

compiler/rustc_mir_build/src/errors.rs

+2
Original file line numberDiff line numberDiff line change
@@ -595,6 +595,8 @@ pub(crate) struct UnreachablePattern<'tcx> {
595595
pub(crate) covered_by_one: Option<Span>,
596596
#[note(mir_build_unreachable_covered_by_many)]
597597
pub(crate) covered_by_many: Option<MultiSpan>,
598+
#[suggestion(code = "", applicability = "machine-applicable")]
599+
pub(crate) suggest_remove: Option<Span>,
598600
}
599601

600602
#[derive(Subdiagnostic)]

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

+36-9
Original file line numberDiff line numberDiff line change
@@ -413,7 +413,7 @@ impl<'p, 'tcx> MatchVisitor<'p, 'tcx> {
413413
// Emit lints in the order in which they occur in the file.
414414
redundant_subpats.sort_unstable_by_key(|(pat, _)| pat.data().span);
415415
for (pat, explanation) in redundant_subpats {
416-
report_unreachable_pattern(cx, arm.arm_data, pat, &explanation)
416+
report_unreachable_pattern(cx, arm.arm_data.0, pat, &explanation, None)
417417
}
418418
}
419419
}
@@ -455,8 +455,11 @@ impl<'p, 'tcx> MatchVisitor<'p, 'tcx> {
455455
let arm = &self.thir.arms[arm];
456456
let got_error = self.with_lint_level(arm.lint_level, |this| {
457457
let Ok(pat) = this.lower_pattern(&cx, &arm.pattern) else { return true };
458-
let arm =
459-
MatchArm { pat, arm_data: this.lint_level, has_guard: arm.guard.is_some() };
458+
let arm = MatchArm {
459+
pat,
460+
arm_data: (this.lint_level, arm.span),
461+
has_guard: arm.guard.is_some(),
462+
};
460463
tarms.push(arm);
461464
false
462465
});
@@ -474,7 +477,11 @@ impl<'p, 'tcx> MatchVisitor<'p, 'tcx> {
474477
hir::MatchSource::ForLoopDesugar
475478
| hir::MatchSource::Postfix
476479
| hir::MatchSource::Normal
477-
| hir::MatchSource::FormatArgs => report_arm_reachability(&cx, &report),
480+
| hir::MatchSource::FormatArgs => {
481+
let suggest_removing_if_unreachable =
482+
matches!(source, hir::MatchSource::Postfix | hir::MatchSource::Normal);
483+
report_arm_reachability(&cx, &report, suggest_removing_if_unreachable);
484+
}
478485
// Unreachable patterns in try and await expressions occur when one of
479486
// the arms are an uninhabited type. Which is OK.
480487
hir::MatchSource::AwaitDesugar | hir::MatchSource::TryDesugar(_) => {}
@@ -610,9 +617,10 @@ impl<'p, 'tcx> MatchVisitor<'p, 'tcx> {
610617
refutability: RefutableFlag,
611618
scrut: Option<&Expr<'tcx>>,
612619
) -> Result<(PatCtxt<'p, 'tcx>, UsefulnessReport<'p, 'tcx>), ErrorGuaranteed> {
613-
let cx = self.new_cx(refutability, None, scrut, pat.span);
620+
let pat_span = pat.span;
621+
let cx = self.new_cx(refutability, None, scrut, pat_span);
614622
let pat = self.lower_pattern(&cx, pat)?;
615-
let arms = [MatchArm { pat, arm_data: self.lint_level, has_guard: false }];
623+
let arms = [MatchArm { pat, arm_data: (self.lint_level, pat_span), has_guard: false }];
616624
let report = self.analyze_patterns(&cx, &arms, pat.ty().inner())?;
617625
Ok((cx, report))
618626
}
@@ -624,7 +632,7 @@ impl<'p, 'tcx> MatchVisitor<'p, 'tcx> {
624632
) -> Result<RefutableFlag, ErrorGuaranteed> {
625633
let (cx, report) = self.analyze_binding(pat, Refutable, scrut)?;
626634
// Report if the pattern is unreachable, which can only occur when the type is uninhabited.
627-
report_arm_reachability(&cx, &report);
635+
report_arm_reachability(&cx, &report, false);
628636
// If the list of witnesses is empty, the match is exhaustive, i.e. the `if let` pattern is
629637
// irrefutable.
630638
Ok(if report.non_exhaustiveness_witnesses.is_empty() { Irrefutable } else { Refutable })
@@ -912,6 +920,7 @@ fn report_unreachable_pattern<'p, 'tcx>(
912920
hir_id: HirId,
913921
pat: &DeconstructedPat<'p, 'tcx>,
914922
explanation: &RedundancyExplanation<'p, 'tcx>,
923+
suggest_remove: Option<Span>,
915924
) {
916925
let pat_span = pat.data().span;
917926
let mut lint = UnreachablePattern {
@@ -920,6 +929,7 @@ fn report_unreachable_pattern<'p, 'tcx>(
920929
covered_by_catchall: None,
921930
covered_by_one: None,
922931
covered_by_many: None,
932+
suggest_remove,
923933
};
924934
match explanation.covered_by.as_slice() {
925935
[] => {
@@ -960,10 +970,27 @@ fn report_unreachable_pattern<'p, 'tcx>(
960970
}
961971

962972
/// Report unreachable arms, if any.
963-
fn report_arm_reachability<'p, 'tcx>(cx: &PatCtxt<'p, 'tcx>, report: &UsefulnessReport<'p, 'tcx>) {
973+
fn report_arm_reachability<'p, 'tcx>(
974+
cx: &PatCtxt<'p, 'tcx>,
975+
report: &UsefulnessReport<'p, 'tcx>,
976+
suggest_removing_if_unreachable: bool,
977+
) {
978+
let sm = cx.tcx.sess.source_map();
964979
for (arm, is_useful) in report.arm_usefulness.iter() {
965980
if let Usefulness::Redundant(explanation) = is_useful {
966-
report_unreachable_pattern(cx, arm.arm_data, arm.pat, explanation)
981+
let (hid_id, arm_span) = arm.arm_data;
982+
let suggest_remove = if suggest_removing_if_unreachable {
983+
// If the arm is followed by a comma, extend the span to include it.
984+
let with_whitespace = sm.span_extend_while_whitespace(arm_span);
985+
if let Some(comma) = sm.span_look_ahead(with_whitespace, ",", Some(1)) {
986+
Some(arm_span.to(comma))
987+
} else {
988+
Some(arm_span)
989+
}
990+
} else {
991+
None
992+
};
993+
report_unreachable_pattern(cx, hid_id, arm.pat, explanation, suggest_remove)
967994
}
968995
}
969996
}

compiler/rustc_pattern_analysis/src/lints.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -89,7 +89,7 @@ pub(crate) fn lint_nonexhaustive_missing_variants<'p, 'tcx>(
8989
// usage of the lint.
9090
for arm in arms {
9191
let (lint_level, lint_level_source) =
92-
rcx.tcx.lint_level_at_node(NON_EXHAUSTIVE_OMITTED_PATTERNS, arm.arm_data);
92+
rcx.tcx.lint_level_at_node(NON_EXHAUSTIVE_OMITTED_PATTERNS, arm.arm_data.0);
9393
if !matches!(lint_level, rustc_session::lint::Level::Allow) {
9494
let decorator = NonExhaustiveOmittedPatternLintOnArm {
9595
lint_span: lint_level_source.span(),

compiler/rustc_pattern_analysis/src/rustc.rs

+2-1
Original file line numberDiff line numberDiff line change
@@ -917,7 +917,8 @@ impl<'p, 'tcx: 'p> PatCx for RustcPatCtxt<'p, 'tcx> {
917917
type Error = ErrorGuaranteed;
918918
type VariantIdx = VariantIdx;
919919
type StrLit = Const<'tcx>;
920-
type ArmData = HirId;
920+
// The `HirId` is used for lints, the `Span` is the span of the arm.
921+
type ArmData = (HirId, Span);
921922
type PatData = &'p Pat<'tcx>;
922923

923924
fn is_exhaustive_patterns_feature_on(&self) -> bool {

tests/ui/consts/packed_pattern.stderr

+4-1
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,10 @@ warning: unreachable pattern
44
LL | Foo { field: (5, 6, 7, 8) } => {},
55
| --------------------------- matches all the values already
66
LL | FOO => unreachable!(),
7-
| ^^^ unreachable pattern
7+
| ^^^-------------------
8+
| |
9+
| unreachable pattern
10+
| help: remove the match arm
811
|
912
= note: `#[warn(unreachable_patterns)]` on by default
1013

tests/ui/consts/packed_pattern2.stderr

+4-1
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,10 @@ warning: unreachable pattern
44
LL | Bar { a: Foo { field: (5, 6) } } => {},
55
| -------------------------------- matches all the values already
66
LL | FOO => unreachable!(),
7-
| ^^^ unreachable pattern
7+
| ^^^-------------------
8+
| |
9+
| unreachable pattern
10+
| help: remove the match arm
811
|
912
= note: `#[warn(unreachable_patterns)]` on by default
1013

tests/ui/or-patterns/exhaustiveness-unreachable-pattern.stderr

+44-11
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,10 @@ error: unreachable pattern
44
LL | (1 | 2,) => {}
55
| -------- matches all the values already
66
LL | (1,) => {}
7-
| ^^^^ unreachable pattern
7+
| ^^^^------
8+
| |
9+
| unreachable pattern
10+
| help: remove the match arm
811
|
912
note: the lint level is defined here
1013
--> $DIR/exhaustiveness-unreachable-pattern.rs:1:9
@@ -18,13 +21,19 @@ error: unreachable pattern
1821
LL | (1 | 2,) => {}
1922
| -------- matches all the values already
2023
LL | (2,) => {}
21-
| ^^^^ unreachable pattern
24+
| ^^^^------
25+
| |
26+
| unreachable pattern
27+
| help: remove the match arm
2228

2329
error: unreachable pattern
2430
--> $DIR/exhaustiveness-unreachable-pattern.rs:19:9
2531
|
2632
LL | (1 | 2,) => {}
27-
| ^^^^^^^^ unreachable pattern
33+
| ^^^^^^^^------
34+
| |
35+
| unreachable pattern
36+
| help: remove the match arm
2837
|
2938
note: these patterns collectively make the last one unreachable
3039
--> $DIR/exhaustiveness-unreachable-pattern.rs:19:9
@@ -42,7 +51,10 @@ error: unreachable pattern
4251
LL | (1 | 2, 3 | 4) => {}
4352
| -------------- matches all the values already
4453
LL | (1, 3) => {}
45-
| ^^^^^^ unreachable pattern
54+
| ^^^^^^------
55+
| |
56+
| unreachable pattern
57+
| help: remove the match arm
4658

4759
error: unreachable pattern
4860
--> $DIR/exhaustiveness-unreachable-pattern.rs:25:9
@@ -51,7 +63,10 @@ LL | (1 | 2, 3 | 4) => {}
5163
| -------------- matches all the values already
5264
LL | (1, 3) => {}
5365
LL | (1, 4) => {}
54-
| ^^^^^^ unreachable pattern
66+
| ^^^^^^------
67+
| |
68+
| unreachable pattern
69+
| help: remove the match arm
5570

5671
error: unreachable pattern
5772
--> $DIR/exhaustiveness-unreachable-pattern.rs:26:9
@@ -60,7 +75,10 @@ LL | (1 | 2, 3 | 4) => {}
6075
| -------------- matches all the values already
6176
...
6277
LL | (2, 4) => {}
63-
| ^^^^^^ unreachable pattern
78+
| ^^^^^^------
79+
| |
80+
| unreachable pattern
81+
| help: remove the match arm
6482

6583
error: unreachable pattern
6684
--> $DIR/exhaustiveness-unreachable-pattern.rs:27:9
@@ -69,13 +87,19 @@ LL | (1 | 2, 3 | 4) => {}
6987
| -------------- matches all the values already
7088
...
7189
LL | (2 | 1, 4) => {}
72-
| ^^^^^^^^^^ unreachable pattern
90+
| ^^^^^^^^^^------
91+
| |
92+
| unreachable pattern
93+
| help: remove the match arm
7394

7495
error: unreachable pattern
7596
--> $DIR/exhaustiveness-unreachable-pattern.rs:29:9
7697
|
7798
LL | (1, 4 | 5) => {}
78-
| ^^^^^^^^^^ unreachable pattern
99+
| ^^^^^^^^^^------
100+
| |
101+
| unreachable pattern
102+
| help: remove the match arm
79103
|
80104
note: these patterns collectively make the last one unreachable
81105
--> $DIR/exhaustiveness-unreachable-pattern.rs:29:9
@@ -102,7 +126,10 @@ error: unreachable pattern
102126
LL | (None | Some(1 | 2),) => {}
103127
| --------------------- matches all the values already
104128
LL | (Some(1),) => {}
105-
| ^^^^^^^^^^ unreachable pattern
129+
| ^^^^^^^^^^------
130+
| |
131+
| unreachable pattern
132+
| help: remove the match arm
106133

107134
error: unreachable pattern
108135
--> $DIR/exhaustiveness-unreachable-pattern.rs:43:9
@@ -111,15 +138,21 @@ LL | (None | Some(1 | 2),) => {}
111138
| --------------------- matches all the values already
112139
LL | (Some(1),) => {}
113140
LL | (None,) => {}
114-
| ^^^^^^^ unreachable pattern
141+
| ^^^^^^^------
142+
| |
143+
| unreachable pattern
144+
| help: remove the match arm
115145

116146
error: unreachable pattern
117147
--> $DIR/exhaustiveness-unreachable-pattern.rs:48:9
118148
|
119149
LL | ((1 | 2,) | (3 | 4,),) => {}
120150
| ---------------------- matches all the values already
121151
LL | ((1..=4,),) => {}
122-
| ^^^^^^^^^^^ unreachable pattern
152+
| ^^^^^^^^^^^------
153+
| |
154+
| unreachable pattern
155+
| help: remove the match arm
123156

124157
error: unreachable pattern
125158
--> $DIR/exhaustiveness-unreachable-pattern.rs:53:14

tests/ui/pattern/issue-14221.stderr

+4-1
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,10 @@ LL | A => "A",
1919
| - matches any value
2020
LL |
2121
LL | B => "B",
22-
| ^ unreachable pattern
22+
| ^--------
23+
| |
24+
| unreachable pattern
25+
| help: remove the match arm
2326
|
2427
note: the lint level is defined here
2528
--> $DIR/issue-14221.rs:1:9

0 commit comments

Comments
 (0)