Skip to content

Commit 10ae774

Browse files
committed
Add a machine-applicable suggestion to "unreachable pattern"
1 parent 0f442e2 commit 10ae774

Some content is hidden

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

47 files changed

+1166
-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
@@ -594,6 +594,8 @@ pub(crate) struct UnreachablePattern<'tcx> {
594594
pub(crate) covered_by_one: Option<Span>,
595595
#[note(mir_build_unreachable_covered_by_many)]
596596
pub(crate) covered_by_many: Option<MultiSpan>,
597+
#[suggestion(code = "", applicability = "machine-applicable")]
598+
pub(crate) suggest_remove: Option<Span>,
597599
}
598600

599601
#[derive(Subdiagnostic)]

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

+31-6
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, pat, &explanation, None)
417417
}
418418
}
419419
}
@@ -474,7 +474,11 @@ impl<'p, 'tcx> MatchVisitor<'p, 'tcx> {
474474
hir::MatchSource::ForLoopDesugar
475475
| hir::MatchSource::Postfix
476476
| hir::MatchSource::Normal
477-
| hir::MatchSource::FormatArgs => report_arm_reachability(&cx, &report),
477+
| hir::MatchSource::FormatArgs => {
478+
let suggest_removing_if_unreachable =
479+
matches!(source, hir::MatchSource::Postfix | hir::MatchSource::Normal);
480+
report_arm_reachability(&cx, &report, suggest_removing_if_unreachable);
481+
}
478482
// Unreachable patterns in try and await expressions occur when one of
479483
// the arms are an uninhabited type. Which is OK.
480484
hir::MatchSource::AwaitDesugar | hir::MatchSource::TryDesugar(_) => {}
@@ -612,7 +616,8 @@ impl<'p, 'tcx> MatchVisitor<'p, 'tcx> {
612616
refutability: RefutableFlag,
613617
scrut: Option<&Expr<'tcx>>,
614618
) -> Result<(PatCtxt<'p, 'tcx>, UsefulnessReport<'p, 'tcx>), ErrorGuaranteed> {
615-
let cx = self.new_cx(refutability, None, scrut, pat.span);
619+
let pat_span = pat.span;
620+
let cx = self.new_cx(refutability, None, scrut, pat_span);
616621
let pat = self.lower_pattern(&cx, pat)?;
617622
let arms = [MatchArm { pat, arm_data: self.lint_level, has_guard: false }];
618623
let report = self.analyze_patterns(&cx, &arms, pat.ty().inner())?;
@@ -626,7 +631,7 @@ impl<'p, 'tcx> MatchVisitor<'p, 'tcx> {
626631
) -> Result<RefutableFlag, ErrorGuaranteed> {
627632
let (cx, report) = self.analyze_binding(pat, Refutable, scrut)?;
628633
// Report if the pattern is unreachable, which can only occur when the type is uninhabited.
629-
report_arm_reachability(&cx, &report);
634+
report_arm_reachability(&cx, &report, false);
630635
// If the list of witnesses is empty, the match is exhaustive, i.e. the `if let` pattern is
631636
// irrefutable.
632637
Ok(if report.non_exhaustiveness_witnesses.is_empty() { Irrefutable } else { Refutable })
@@ -916,6 +921,7 @@ fn report_unreachable_pattern<'p, 'tcx>(
916921
hir_id: HirId,
917922
pat: &DeconstructedPat<'p, 'tcx>,
918923
explanation: &RedundancyExplanation<'p, 'tcx>,
924+
suggest_remove: Option<Span>,
919925
) {
920926
let pat_span = pat.data().span;
921927
let mut lint = UnreachablePattern {
@@ -924,6 +930,7 @@ fn report_unreachable_pattern<'p, 'tcx>(
924930
covered_by_catchall: None,
925931
covered_by_one: None,
926932
covered_by_many: None,
933+
suggest_remove,
927934
};
928935
match explanation.covered_by.as_slice() {
929936
[] => {
@@ -964,10 +971,28 @@ fn report_unreachable_pattern<'p, 'tcx>(
964971
}
965972

966973
/// Report unreachable arms, if any.
967-
fn report_arm_reachability<'p, 'tcx>(cx: &PatCtxt<'p, 'tcx>, report: &UsefulnessReport<'p, 'tcx>) {
974+
fn report_arm_reachability<'p, 'tcx>(
975+
cx: &PatCtxt<'p, 'tcx>,
976+
report: &UsefulnessReport<'p, 'tcx>,
977+
is_match_arm: bool,
978+
) {
979+
let sm = cx.tcx.sess.source_map();
968980
for (arm, is_useful) in report.arm_usefulness.iter() {
969981
if let Usefulness::Redundant(explanation) = is_useful {
970-
report_unreachable_pattern(cx, arm.arm_data, arm.pat, explanation)
982+
let hir_id = arm.arm_data;
983+
let arm_span = cx.tcx.hir().span(hir_id);
984+
let suggest_remove = if is_match_arm {
985+
// If the arm is followed by a comma, extend the span to include it.
986+
let with_whitespace = sm.span_extend_while_whitespace(arm_span);
987+
if let Some(comma) = sm.span_look_ahead(with_whitespace, ",", Some(1)) {
988+
Some(arm_span.to(comma))
989+
} else {
990+
Some(arm_span)
991+
}
992+
} else {
993+
None
994+
};
995+
report_unreachable_pattern(cx, hir_id, arm.pat, explanation, suggest_remove)
971996
}
972997
}
973998
}

compiler/rustc_pattern_analysis/src/rustc.rs

+1
Original file line numberDiff line numberDiff line change
@@ -921,6 +921,7 @@ impl<'p, 'tcx: 'p> PatCx for RustcPatCtxt<'p, 'tcx> {
921921
type Error = ErrorGuaranteed;
922922
type VariantIdx = VariantIdx;
923923
type StrLit = Const<'tcx>;
924+
// The `HirId` is used for lints, the `Span` is the span of the arm.
924925
type ArmData = HirId;
925926
type PatData = &'p Pat<'tcx>;
926927

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/error-codes/E0001.stderr

+4-1
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,10 @@ error: unreachable pattern
22
--> $DIR/E0001.rs:8:9
33
|
44
LL | _ => {/* ... */}
5-
| ^ unreachable pattern
5+
| ^---------------
6+
| |
7+
| unreachable pattern
8+
| help: remove the match arm
69
|
710
note: these patterns collectively make the last one unreachable
811
--> $DIR/E0001.rs:8:9

tests/ui/lint/issue-30302.stderr

+4-1
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,10 @@ LL | Nil => true,
1313
| --- matches any value
1414
LL |
1515
LL | _ => false
16-
| ^ unreachable pattern
16+
| ^---------
17+
| |
18+
| unreachable pattern
19+
| help: remove the match arm
1720
|
1821
note: the lint level is defined here
1922
--> $DIR/issue-30302.rs:4:9

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)