mirror of
https://github.com/rust-lang/rust.git
synced 2024-11-25 16:24:46 +00:00
Consistently warn unreachable subpatterns
This commit is contained in:
parent
753680afe8
commit
0a9bb97229
@ -391,10 +391,26 @@ impl<'p, 'tcx> MatchVisitor<'p, 'tcx> {
|
||||
arms: &[MatchArm<'p, 'tcx>],
|
||||
scrut_ty: Ty<'tcx>,
|
||||
) -> Result<UsefulnessReport<'p, 'tcx>, ErrorGuaranteed> {
|
||||
rustc_pattern_analysis::analyze_match(&cx, &arms, scrut_ty).map_err(|err| {
|
||||
self.error = Err(err);
|
||||
err
|
||||
})
|
||||
let report =
|
||||
rustc_pattern_analysis::analyze_match(&cx, &arms, scrut_ty).map_err(|err| {
|
||||
self.error = Err(err);
|
||||
err
|
||||
})?;
|
||||
|
||||
// Warn unreachable subpatterns.
|
||||
for (arm, is_useful) in report.arm_usefulness.iter() {
|
||||
if let Usefulness::Useful(redundant_subpats) = is_useful
|
||||
&& !redundant_subpats.is_empty()
|
||||
{
|
||||
let mut redundant_subpats = redundant_subpats.clone();
|
||||
// Emit lints in the order in which they occur in the file.
|
||||
redundant_subpats.sort_unstable_by_key(|pat| pat.data().unwrap().span);
|
||||
for pat in redundant_subpats {
|
||||
report_unreachable_pattern(cx, arm.arm_data, pat.data().unwrap().span, None)
|
||||
}
|
||||
}
|
||||
}
|
||||
Ok(report)
|
||||
}
|
||||
|
||||
#[instrument(level = "trace", skip(self))]
|
||||
@ -567,7 +583,6 @@ 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.
|
||||
// This also reports unreachable sub-patterns.
|
||||
report_arm_reachability(&cx, &report);
|
||||
// If the list of witnesses is empty, the match is exhaustive, i.e. the `if let` pattern is
|
||||
// irrefutable.
|
||||
@ -837,39 +852,30 @@ fn report_irrefutable_let_patterns(
|
||||
}
|
||||
}
|
||||
|
||||
/// Report unreachable arms, if any.
|
||||
fn report_unreachable_pattern<'p, 'tcx>(
|
||||
cx: &MatchCheckCtxt<'p, 'tcx>,
|
||||
hir_id: HirId,
|
||||
span: Span,
|
||||
catchall: Option<Span>,
|
||||
) {
|
||||
cx.tcx.emit_spanned_lint(
|
||||
UNREACHABLE_PATTERNS,
|
||||
hir_id,
|
||||
span,
|
||||
UnreachablePattern { span: if catchall.is_some() { Some(span) } else { None }, catchall },
|
||||
);
|
||||
}
|
||||
|
||||
/// Report unreachable arms, if any.
|
||||
fn report_arm_reachability<'p, 'tcx>(
|
||||
cx: &MatchCheckCtxt<'p, 'tcx>,
|
||||
report: &UsefulnessReport<'p, 'tcx>,
|
||||
) {
|
||||
let report_unreachable_pattern = |span, hir_id, catchall: Option<Span>| {
|
||||
cx.tcx.emit_spanned_lint(
|
||||
UNREACHABLE_PATTERNS,
|
||||
hir_id,
|
||||
span,
|
||||
UnreachablePattern {
|
||||
span: if catchall.is_some() { Some(span) } else { None },
|
||||
catchall,
|
||||
},
|
||||
);
|
||||
};
|
||||
|
||||
let mut catchall = None;
|
||||
for (arm, is_useful) in report.arm_usefulness.iter() {
|
||||
match is_useful {
|
||||
Usefulness::Redundant => {
|
||||
report_unreachable_pattern(arm.pat.data().unwrap().span, arm.arm_data, catchall)
|
||||
}
|
||||
Usefulness::Useful(redundant_subpats) if redundant_subpats.is_empty() => {}
|
||||
// The arm is reachable, but contains redundant subpatterns (from or-patterns).
|
||||
Usefulness::Useful(redundant_subpats) => {
|
||||
let mut redundant_subpats = redundant_subpats.clone();
|
||||
// Emit lints in the order in which they occur in the file.
|
||||
redundant_subpats.sort_unstable_by_key(|pat| pat.data().unwrap().span);
|
||||
for pat in redundant_subpats {
|
||||
report_unreachable_pattern(pat.data().unwrap().span, arm.arm_data, None);
|
||||
}
|
||||
}
|
||||
if matches!(is_useful, Usefulness::Redundant) {
|
||||
report_unreachable_pattern(cx, arm.arm_data, arm.pat.data().unwrap().span, catchall)
|
||||
}
|
||||
if !arm.has_guard && catchall.is_none() && pat_is_catchall(arm.pat) {
|
||||
catchall = Some(arm.pat.data().unwrap().span);
|
||||
|
@ -162,12 +162,14 @@ fn main() {
|
||||
}
|
||||
|
||||
fn unreachable_in_param((_ | (_, _)): (bool, bool)) {}
|
||||
//~^ ERROR unreachable
|
||||
|
||||
fn unreachable_in_binding() {
|
||||
let bool_pair = (true, true);
|
||||
let bool_option = Some(true);
|
||||
|
||||
let (_ | (_, _)) = bool_pair;
|
||||
//~^ ERROR unreachable
|
||||
for (_ | (_, _)) in [bool_pair] {}
|
||||
//~^ ERROR unreachable
|
||||
|
||||
|
@ -184,29 +184,41 @@ error: unreachable pattern
|
||||
LL | | (y, x) => {}
|
||||
| ^^^^^^
|
||||
|
||||
error: unreachable pattern
|
||||
--> $DIR/exhaustiveness-unreachable-pattern.rs:164:30
|
||||
|
|
||||
LL | fn unreachable_in_param((_ | (_, _)): (bool, bool)) {}
|
||||
| ^^^^^^
|
||||
|
||||
error: unreachable pattern
|
||||
--> $DIR/exhaustiveness-unreachable-pattern.rs:171:14
|
||||
|
|
||||
LL | let (_ | (_, _)) = bool_pair;
|
||||
| ^^^^^^
|
||||
|
||||
error: unreachable pattern
|
||||
--> $DIR/exhaustiveness-unreachable-pattern.rs:173:14
|
||||
|
|
||||
LL | for (_ | (_, _)) in [bool_pair] {}
|
||||
| ^^^^^^
|
||||
|
||||
error: unreachable pattern
|
||||
--> $DIR/exhaustiveness-unreachable-pattern.rs:174:20
|
||||
--> $DIR/exhaustiveness-unreachable-pattern.rs:176:20
|
||||
|
|
||||
LL | let (Some(_) | Some(true)) = bool_option else { return };
|
||||
| ^^^^^^^^^^
|
||||
|
||||
error: unreachable pattern
|
||||
--> $DIR/exhaustiveness-unreachable-pattern.rs:176:22
|
||||
--> $DIR/exhaustiveness-unreachable-pattern.rs:178:22
|
||||
|
|
||||
LL | if let Some(_) | Some(true) = bool_option {}
|
||||
| ^^^^^^^^^^
|
||||
|
||||
error: unreachable pattern
|
||||
--> $DIR/exhaustiveness-unreachable-pattern.rs:178:25
|
||||
--> $DIR/exhaustiveness-unreachable-pattern.rs:180:25
|
||||
|
|
||||
LL | while let Some(_) | Some(true) = bool_option {}
|
||||
| ^^^^^^^^^^
|
||||
|
||||
error: aborting due to 33 previous errors
|
||||
error: aborting due to 35 previous errors
|
||||
|
||||
|
@ -11,22 +11,34 @@ LL | #![deny(unreachable_patterns)]
|
||||
| ^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: unreachable pattern
|
||||
--> $DIR/unreachable.rs:21:12
|
||||
--> $DIR/unreachable.rs:20:19
|
||||
|
|
||||
LL | let (Ok(_x) | Err(!)) = res_void;
|
||||
| ^^^^^^
|
||||
|
||||
error: unreachable pattern
|
||||
--> $DIR/unreachable.rs:22:12
|
||||
|
|
||||
LL | if let Err(!) = res_void {}
|
||||
| ^^^^^^
|
||||
|
||||
error: unreachable pattern
|
||||
--> $DIR/unreachable.rs:23:24
|
||||
--> $DIR/unreachable.rs:24:24
|
||||
|
|
||||
LL | if let (Ok(true) | Err(!)) = res_void {}
|
||||
| ^^^^^^
|
||||
|
||||
error: unreachable pattern
|
||||
--> $DIR/unreachable.rs:25:23
|
||||
--> $DIR/unreachable.rs:26:23
|
||||
|
|
||||
LL | for (Ok(mut _x) | Err(!)) in [res_void] {}
|
||||
| ^^^^^^
|
||||
|
||||
error: aborting due to 4 previous errors
|
||||
error: unreachable pattern
|
||||
--> $DIR/unreachable.rs:30:18
|
||||
|
|
||||
LL | fn foo((Ok(_x) | Err(!)): Result<bool, Void>) {}
|
||||
| ^^^^^^
|
||||
|
||||
error: aborting due to 6 previous errors
|
||||
|
||||
|
@ -18,6 +18,7 @@ fn main() {
|
||||
//[exh_pats]~^ ERROR unreachable
|
||||
}
|
||||
let (Ok(_x) | Err(!)) = res_void;
|
||||
//[exh_pats]~^ ERROR unreachable
|
||||
if let Err(!) = res_void {}
|
||||
//[exh_pats]~^ ERROR unreachable
|
||||
if let (Ok(true) | Err(!)) = res_void {}
|
||||
@ -27,3 +28,4 @@ fn main() {
|
||||
}
|
||||
|
||||
fn foo((Ok(_x) | Err(!)): Result<bool, Void>) {}
|
||||
//[exh_pats]~^ ERROR unreachable
|
||||
|
@ -1,4 +1,5 @@
|
||||
// run-pass
|
||||
#![allow(unreachable_patterns)]
|
||||
|
||||
#[derive(Copy, Clone)]
|
||||
#[allow(dead_code)]
|
||||
|
Loading…
Reference in New Issue
Block a user