Skip to content

Commit f9567d0

Browse files
committed
Auto merge of rust-lang#128991 - Nadrieril:rustfix-unreachable-pattern, r=compiler-errors
Add a machine-applicable suggestion to "unreachable pattern"
2 parents 4a47e8e + 1f69638 commit f9567d0

19 files changed

+502
-98
lines changed

compiler/rustc_mir_build/messages.ftl

+1
Original file line numberDiff line numberDiff line change
@@ -338,6 +338,7 @@ mir_build_unreachable_pattern = unreachable pattern
338338
.unreachable_covered_by_catchall = matches any value
339339
.unreachable_covered_by_one = matches all the relevant values
340340
.unreachable_covered_by_many = multiple earlier patterns match some of the same values
341+
.suggestion = remove the match arm
341342
342343
mir_build_unsafe_fn_safe_body = an unsafe function restricts its caller, but its body is safe by default
343344
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
@@ -598,6 +598,8 @@ pub(crate) struct UnreachablePattern<'tcx> {
598598
#[note(mir_build_unreachable_covered_by_many)]
599599
pub(crate) covered_by_many: Option<MultiSpan>,
600600
pub(crate) covered_by_many_n_more_count: usize,
601+
#[suggestion(code = "", applicability = "machine-applicable")]
602+
pub(crate) suggest_remove: Option<Span>,
601603
}
602604

603605
#[derive(Diagnostic)]

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

+30-5
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 is_match_arm =
479+
matches!(source, hir::MatchSource::Postfix | hir::MatchSource::Normal);
480+
report_arm_reachability(&cx, &report, is_match_arm);
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(_) => {}
@@ -626,7 +630,7 @@ impl<'p, 'tcx> MatchVisitor<'p, 'tcx> {
626630
) -> Result<RefutableFlag, ErrorGuaranteed> {
627631
let (cx, report) = self.analyze_binding(pat, Refutable, scrut)?;
628632
// Report if the pattern is unreachable, which can only occur when the type is uninhabited.
629-
report_arm_reachability(&cx, &report);
633+
report_arm_reachability(&cx, &report, false);
630634
// If the list of witnesses is empty, the match is exhaustive, i.e. the `if let` pattern is
631635
// irrefutable.
632636
Ok(if report.non_exhaustiveness_witnesses.is_empty() { Irrefutable } else { Refutable })
@@ -916,6 +920,7 @@ fn report_unreachable_pattern<'p, 'tcx>(
916920
hir_id: HirId,
917921
pat: &DeconstructedPat<'p, 'tcx>,
918922
explanation: &RedundancyExplanation<'p, 'tcx>,
923+
whole_arm_span: Option<Span>,
919924
) {
920925
static CAP_COVERED_BY_MANY: usize = 4;
921926
let pat_span = pat.data().span;
@@ -928,13 +933,15 @@ fn report_unreachable_pattern<'p, 'tcx>(
928933
covered_by_one: None,
929934
covered_by_many: None,
930935
covered_by_many_n_more_count: 0,
936+
suggest_remove: None,
931937
};
932938
match explanation.covered_by.as_slice() {
933939
[] => {
934940
// Empty pattern; we report the uninhabited type that caused the emptiness.
935941
lint.span = None; // Don't label the pattern itself
936942
lint.uninhabited_note = Some(()); // Give a link about empty types
937943
lint.matches_no_values = Some(pat_span);
944+
lint.suggest_remove = whole_arm_span; // Suggest to remove the match arm
938945
pat.walk(&mut |subpat| {
939946
let ty = **subpat.ty();
940947
if cx.is_uninhabited(ty) {
@@ -982,10 +989,28 @@ fn report_unreachable_pattern<'p, 'tcx>(
982989
}
983990

984991
/// Report unreachable arms, if any.
985-
fn report_arm_reachability<'p, 'tcx>(cx: &PatCtxt<'p, 'tcx>, report: &UsefulnessReport<'p, 'tcx>) {
992+
fn report_arm_reachability<'p, 'tcx>(
993+
cx: &PatCtxt<'p, 'tcx>,
994+
report: &UsefulnessReport<'p, 'tcx>,
995+
is_match_arm: bool,
996+
) {
997+
let sm = cx.tcx.sess.source_map();
986998
for (arm, is_useful) in report.arm_usefulness.iter() {
987999
if let Usefulness::Redundant(explanation) = is_useful {
988-
report_unreachable_pattern(cx, arm.arm_data, arm.pat, explanation)
1000+
let hir_id = arm.arm_data;
1001+
let arm_span = cx.tcx.hir().span(hir_id);
1002+
let whole_arm_span = if is_match_arm {
1003+
// If the arm is followed by a comma, extend the span to include it.
1004+
let with_whitespace = sm.span_extend_while_whitespace(arm_span);
1005+
if let Some(comma) = sm.span_look_ahead(with_whitespace, ",", Some(1)) {
1006+
Some(arm_span.to(comma))
1007+
} else {
1008+
Some(arm_span)
1009+
}
1010+
} else {
1011+
None
1012+
};
1013+
report_unreachable_pattern(cx, hir_id, arm.pat, explanation, whole_arm_span)
9891014
}
9901015
}
9911016
}

tests/ui/pattern/usefulness/empty-match-check-notes.exhaustive_patterns.stderr

+16-4
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,10 @@ error: unreachable pattern
22
--> $DIR/empty-match-check-notes.rs:17:9
33
|
44
LL | _ => {}
5-
| ^ matches no values because `EmptyEnum` is uninhabited
5+
| ^------
6+
| |
7+
| matches no values because `EmptyEnum` is uninhabited
8+
| help: remove the match arm
69
|
710
= note: to learn more about uninhabited types, see https://doc.rust-lang.org/nomicon/exotic-sizes.html#empty-types
811
note: the lint level is defined here
@@ -15,23 +18,32 @@ error: unreachable pattern
1518
--> $DIR/empty-match-check-notes.rs:22:9
1619
|
1720
LL | _ if false => {}
18-
| ^ matches no values because `EmptyEnum` is uninhabited
21+
| ^---------------
22+
| |
23+
| matches no values because `EmptyEnum` is uninhabited
24+
| help: remove the match arm
1925
|
2026
= note: to learn more about uninhabited types, see https://doc.rust-lang.org/nomicon/exotic-sizes.html#empty-types
2127

2228
error: unreachable pattern
2329
--> $DIR/empty-match-check-notes.rs:31:9
2430
|
2531
LL | _ => {}
26-
| ^ matches no values because `EmptyForeignEnum` is uninhabited
32+
| ^------
33+
| |
34+
| matches no values because `EmptyForeignEnum` is uninhabited
35+
| help: remove the match arm
2736
|
2837
= note: to learn more about uninhabited types, see https://doc.rust-lang.org/nomicon/exotic-sizes.html#empty-types
2938

3039
error: unreachable pattern
3140
--> $DIR/empty-match-check-notes.rs:36:9
3241
|
3342
LL | _ if false => {}
34-
| ^ matches no values because `EmptyForeignEnum` is uninhabited
43+
| ^---------------
44+
| |
45+
| matches no values because `EmptyForeignEnum` is uninhabited
46+
| help: remove the match arm
3547
|
3648
= note: to learn more about uninhabited types, see https://doc.rust-lang.org/nomicon/exotic-sizes.html#empty-types
3749

tests/ui/pattern/usefulness/empty-match-check-notes.normal.stderr

+16-4
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,10 @@ error: unreachable pattern
22
--> $DIR/empty-match-check-notes.rs:17:9
33
|
44
LL | _ => {}
5-
| ^ matches no values because `EmptyEnum` is uninhabited
5+
| ^------
6+
| |
7+
| matches no values because `EmptyEnum` is uninhabited
8+
| help: remove the match arm
69
|
710
= note: to learn more about uninhabited types, see https://doc.rust-lang.org/nomicon/exotic-sizes.html#empty-types
811
note: the lint level is defined here
@@ -15,23 +18,32 @@ error: unreachable pattern
1518
--> $DIR/empty-match-check-notes.rs:22:9
1619
|
1720
LL | _ if false => {}
18-
| ^ matches no values because `EmptyEnum` is uninhabited
21+
| ^---------------
22+
| |
23+
| matches no values because `EmptyEnum` is uninhabited
24+
| help: remove the match arm
1925
|
2026
= note: to learn more about uninhabited types, see https://doc.rust-lang.org/nomicon/exotic-sizes.html#empty-types
2127

2228
error: unreachable pattern
2329
--> $DIR/empty-match-check-notes.rs:31:9
2430
|
2531
LL | _ => {}
26-
| ^ matches no values because `EmptyForeignEnum` is uninhabited
32+
| ^------
33+
| |
34+
| matches no values because `EmptyForeignEnum` is uninhabited
35+
| help: remove the match arm
2736
|
2837
= note: to learn more about uninhabited types, see https://doc.rust-lang.org/nomicon/exotic-sizes.html#empty-types
2938

3039
error: unreachable pattern
3140
--> $DIR/empty-match-check-notes.rs:36:9
3241
|
3342
LL | _ if false => {}
34-
| ^ matches no values because `EmptyForeignEnum` is uninhabited
43+
| ^---------------
44+
| |
45+
| matches no values because `EmptyForeignEnum` is uninhabited
46+
| help: remove the match arm
3547
|
3648
= note: to learn more about uninhabited types, see https://doc.rust-lang.org/nomicon/exotic-sizes.html#empty-types
3749

0 commit comments

Comments
 (0)