Auto merge of #128034 - Nadrieril:explain-unreachable, r= · rust-lang/rust@49ee7bc (original) (raw)
`@@ -16,8 +16,8 @@ use rustc_middle::ty::print::with_no_trimmed_paths;
`
16
16
`use rustc_middle::ty::{self, AdtDef, Ty, TyCtxt};
`
17
17
`use rustc_pattern_analysis::errors::Uncovered;
`
18
18
`use rustc_pattern_analysis::rustc::{
`
19
``
`-
Constructor, DeconstructedPat, MatchArm, RustcPatCtxt as PatCtxt, Usefulness, UsefulnessReport,
`
20
``
`-
WitnessPat,
`
``
19
`+
Constructor, DeconstructedPat, MatchArm, RedundancyExplanation, RustcPatCtxt as PatCtxt,
`
``
20
`+
Usefulness, UsefulnessReport, WitnessPat,
`
21
21
`};
`
22
22
`use rustc_session::lint::builtin::{
`
23
23
`BINDINGS_WITH_VARIANT_NAME, IRREFUTABLE_LET_PATTERNS, UNREACHABLE_PATTERNS,
`
`@@ -391,12 +391,16 @@ impl<'p, 'tcx> MatchVisitor<'p, 'tcx> {
`
391
391
`) -> Result<UsefulnessReport<'p, 'tcx>, ErrorGuaranteed> {
`
392
392
`let pattern_complexity_limit =
`
393
393
`get_limit_size(cx.tcx.hir().krate_attrs(), cx.tcx.sess, sym::pattern_complexity);
`
394
``
`-
let report =
`
395
``
`-
rustc_pattern_analysis::analyze_match(&cx, &arms, scrut_ty, pattern_complexity_limit)
`
396
``
`-
.map_err(|err| {
`
397
``
`-
self.error = Err(err);
`
398
``
`-
err
`
399
``
`-
})?;
`
``
394
`+
let report = rustc_pattern_analysis::rustc::analyze_match(
`
``
395
`+
&cx,
`
``
396
`+
&arms,
`
``
397
`+
scrut_ty,
`
``
398
`+
pattern_complexity_limit,
`
``
399
`+
)
`
``
400
`+
.map_err(|err| {
`
``
401
`+
self.error = Err(err);
`
``
402
`+
err
`
``
403
`+
})?;
`
400
404
``
401
405
`// Warn unreachable subpatterns.
`
402
406
`for (arm, is_useful) in report.arm_usefulness.iter() {
`
`@@ -405,9 +409,9 @@ impl<'p, 'tcx> MatchVisitor<'p, 'tcx> {
`
405
409
`{
`
406
410
`let mut redundant_subpats = redundant_subpats.clone();
`
407
411
`// Emit lints in the order in which they occur in the file.
`
408
``
`-
redundant_subpats.sort_unstable_by_key(|pat| pat.data().span);
`
409
``
`-
for pat in redundant_subpats {
`
410
``
`-
report_unreachable_pattern(cx, arm.arm_data, pat.data().span, None)
`
``
412
`+
redundant_subpats.sort_unstable_by_key(|(pat, _)| pat.data().span);
`
``
413
`+
for (pat, explanation) in redundant_subpats {
`
``
414
`+
report_unreachable_pattern(cx, arm.arm_data, pat, &explanation)
`
411
415
`}
`
412
416
`}
`
413
417
`}
`
`@@ -906,26 +910,52 @@ fn report_irrefutable_let_patterns(
`
906
910
`fn report_unreachable_pattern<'p, 'tcx>(
`
907
911
`cx: &PatCtxt<'p, 'tcx>,
`
908
912
`hir_id: HirId,
`
909
``
`-
span: Span,
`
910
``
`-
catchall: Option,
`
``
913
`+
pat: &DeconstructedPat<'p, 'tcx>,
`
``
914
`+
explanation: &RedundancyExplanation<'p, 'tcx>,
`
911
915
`) {
`
912
``
`-
cx.tcx.emit_node_span_lint(
`
913
``
`-
UNREACHABLE_PATTERNS,
`
914
``
`-
hir_id,
`
915
``
`-
span,
`
916
``
`-
UnreachablePattern { span: if catchall.is_some() { Some(span) } else { None }, catchall },
`
917
``
`-
);
`
``
916
`+
let pat_span = pat.data().span;
`
``
917
`+
let mut lint = UnreachablePattern {
`
``
918
`+
span: Some(pat_span),
`
``
919
`+
matches_no_values: None,
`
``
920
`+
covered_by_catchall: None,
`
``
921
`+
covered_by_one: None,
`
``
922
`+
covered_by_many: None,
`
``
923
`+
};
`
``
924
`+
match explanation.covered_by.as_slice() {
`
``
925
`+
[] => {
`
``
926
`+
// Empty pattern; we report the uninhabited type that caused the emptiness.
`
``
927
`+
lint.span = None; // Don't label the pattern itself
`
``
928
`+
pat.walk(&mut |subpat| {
`
``
929
`+
let ty = **subpat.ty();
`
``
930
`+
if cx.is_uninhabited(ty) {
`
``
931
`+
lint.matches_no_values = Some(UnreachableMatchesNoValues { ty });
`
``
932
`+
false // No need to dig further.
`
``
933
`+
} else if matches!(subpat.ctor(), Constructor::Ref | Constructor::UnionField) {
`
``
934
`+
false // Don't explore further since they are not by-value.
`
``
935
`+
} else {
`
``
936
`+
true
`
``
937
`+
}
`
``
938
`+
});
`
``
939
`+
}
`
``
940
`+
[covering_pat] if pat_is_catchall(covering_pat) => {
`
``
941
`+
lint.covered_by_catchall = Some(covering_pat.data().span);
`
``
942
`+
}
`
``
943
`+
[covering_pat] => {
`
``
944
`+
lint.covered_by_one = Some(covering_pat.data().span);
`
``
945
`+
}
`
``
946
`+
covering_pats => {
`
``
947
`+
let covering_spans = covering_pats.iter().map(|p| p.data().span).collect();
`
``
948
`+
lint.covered_by_many = Some(UnreachableCoveredByMany(covering_spans));
`
``
949
`+
}
`
``
950
`+
}
`
``
951
`+
cx.tcx.emit_node_span_lint(UNREACHABLE_PATTERNS, hir_id, pat_span, lint);
`
918
952
`}
`
919
953
``
920
954
`/// Report unreachable arms, if any.
`
921
955
`fn report_arm_reachability<'p, 'tcx>(cx: &PatCtxt<'p, 'tcx>, report: &UsefulnessReport<'p, 'tcx>) {
`
922
``
`-
let mut catchall = None;
`
923
956
`for (arm, is_useful) in report.arm_usefulness.iter() {
`
924
``
`-
if matches!(is_useful, Usefulness::Redundant) {
`
925
``
`-
report_unreachable_pattern(cx, arm.arm_data, arm.pat.data().span, catchall)
`
926
``
`-
}
`
927
``
`-
if !arm.has_guard && catchall.is_none() && pat_is_catchall(arm.pat) {
`
928
``
`-
catchall = Some(arm.pat.data().span);
`
``
957
`+
if let Usefulness::Redundant(explanation) = is_useful {
`
``
958
`+
report_unreachable_pattern(cx, arm.arm_data, arm.pat, explanation)
`
929
959
`}
`
930
960
`}
`
931
961
`}
`