Explain why a given pattern is considered unreachable
This commit is contained in:
parent
c4d6a4a7e4
commit
64ac2b8082
49 changed files with 1291 additions and 271 deletions
|
@ -327,7 +327,10 @@ mir_build_union_pattern = cannot use unions in constant patterns
|
|||
|
||||
mir_build_unreachable_pattern = unreachable pattern
|
||||
.label = unreachable pattern
|
||||
.catchall_label = matches any value
|
||||
.unreachable_matches_no_values = this pattern matches no values because `{$ty}` is uninhabited
|
||||
.unreachable_covered_by_catchall = matches any value
|
||||
.unreachable_covered_by_one = matches all the values already
|
||||
.unreachable_covered_by_many = matches some of the same values
|
||||
|
||||
mir_build_unsafe_fn_safe_body = an unsafe function restricts its caller, but its body is safe by default
|
||||
mir_build_unsafe_not_inherited = items do not inherit unsafety from separate enclosing items
|
||||
|
|
|
@ -582,11 +582,37 @@ pub(crate) struct NonConstPath {
|
|||
|
||||
#[derive(LintDiagnostic)]
|
||||
#[diag(mir_build_unreachable_pattern)]
|
||||
pub(crate) struct UnreachablePattern {
|
||||
pub(crate) struct UnreachablePattern<'tcx> {
|
||||
#[label]
|
||||
pub(crate) span: Option<Span>,
|
||||
#[label(mir_build_catchall_label)]
|
||||
pub(crate) catchall: Option<Span>,
|
||||
#[subdiagnostic]
|
||||
pub(crate) matches_no_values: Option<UnreachableMatchesNoValues<'tcx>>,
|
||||
#[label(mir_build_unreachable_covered_by_catchall)]
|
||||
pub(crate) covered_by_catchall: Option<Span>,
|
||||
#[label(mir_build_unreachable_covered_by_one)]
|
||||
pub(crate) covered_by_one: Option<Span>,
|
||||
#[subdiagnostic]
|
||||
pub(crate) covered_by_many: Option<UnreachableCoveredByMany>,
|
||||
}
|
||||
|
||||
#[derive(Subdiagnostic)]
|
||||
#[note(mir_build_unreachable_matches_no_values)]
|
||||
pub(crate) struct UnreachableMatchesNoValues<'tcx> {
|
||||
pub(crate) ty: Ty<'tcx>,
|
||||
}
|
||||
|
||||
pub(crate) struct UnreachableCoveredByMany(pub(crate) Vec<Span>);
|
||||
|
||||
impl Subdiagnostic for UnreachableCoveredByMany {
|
||||
fn add_to_diag_with<G: EmissionGuarantee, F: SubdiagMessageOp<G>>(
|
||||
self,
|
||||
diag: &mut Diag<'_, G>,
|
||||
_f: &F,
|
||||
) {
|
||||
for span in self.0 {
|
||||
diag.span_label(span, fluent::mir_build_unreachable_covered_by_many);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
|
|
|
@ -16,8 +16,8 @@ use rustc_middle::ty::print::with_no_trimmed_paths;
|
|||
use rustc_middle::ty::{self, AdtDef, Ty, TyCtxt};
|
||||
use rustc_pattern_analysis::errors::Uncovered;
|
||||
use rustc_pattern_analysis::rustc::{
|
||||
Constructor, DeconstructedPat, MatchArm, RevealedTy, RustcPatCtxt as PatCtxt, Usefulness,
|
||||
UsefulnessReport, WitnessPat,
|
||||
Constructor, DeconstructedPat, MatchArm, RedundancyExplanation, RevealedTy,
|
||||
RustcPatCtxt as PatCtxt, Usefulness, UsefulnessReport, WitnessPat,
|
||||
};
|
||||
use rustc_session::lint::builtin::{
|
||||
BINDINGS_WITH_VARIANT_NAME, IRREFUTABLE_LET_PATTERNS, UNREACHABLE_PATTERNS,
|
||||
|
@ -409,9 +409,9 @@ impl<'p, 'tcx> MatchVisitor<'p, 'tcx> {
|
|||
{
|
||||
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().span);
|
||||
for pat in redundant_subpats {
|
||||
report_unreachable_pattern(cx, arm.arm_data, pat.data().span, None)
|
||||
redundant_subpats.sort_unstable_by_key(|(pat, _)| pat.data().span);
|
||||
for (pat, explanation) in redundant_subpats {
|
||||
report_unreachable_pattern(cx, arm.arm_data, pat, &explanation)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -910,26 +910,52 @@ fn report_irrefutable_let_patterns(
|
|||
fn report_unreachable_pattern<'p, 'tcx>(
|
||||
cx: &PatCtxt<'p, 'tcx>,
|
||||
hir_id: HirId,
|
||||
span: Span,
|
||||
catchall: Option<Span>,
|
||||
pat: &DeconstructedPat<'p, 'tcx>,
|
||||
explanation: &RedundancyExplanation<'p, 'tcx>,
|
||||
) {
|
||||
cx.tcx.emit_node_span_lint(
|
||||
UNREACHABLE_PATTERNS,
|
||||
hir_id,
|
||||
span,
|
||||
UnreachablePattern { span: if catchall.is_some() { Some(span) } else { None }, catchall },
|
||||
);
|
||||
let pat_span = pat.data().span;
|
||||
let mut lint = UnreachablePattern {
|
||||
span: Some(pat_span),
|
||||
matches_no_values: None,
|
||||
covered_by_catchall: None,
|
||||
covered_by_one: None,
|
||||
covered_by_many: None,
|
||||
};
|
||||
match explanation.covered_by.as_slice() {
|
||||
[] => {
|
||||
// Empty pattern; we report the uninhabited type that caused the emptiness.
|
||||
lint.span = None; // Don't label the pattern itself
|
||||
pat.walk(&mut |subpat| {
|
||||
let ty = **subpat.ty();
|
||||
if cx.is_uninhabited(ty) {
|
||||
lint.matches_no_values = Some(UnreachableMatchesNoValues { ty });
|
||||
false // No need to dig further.
|
||||
} else if matches!(subpat.ctor(), Constructor::Ref | Constructor::UnionField) {
|
||||
false // Don't explore further since they are not by-value.
|
||||
} else {
|
||||
true
|
||||
}
|
||||
});
|
||||
}
|
||||
[covering_pat] if pat_is_catchall(covering_pat) => {
|
||||
lint.covered_by_catchall = Some(covering_pat.data().span);
|
||||
}
|
||||
[covering_pat] => {
|
||||
lint.covered_by_one = Some(covering_pat.data().span);
|
||||
}
|
||||
covering_pats => {
|
||||
let covering_spans = covering_pats.iter().map(|p| p.data().span).collect();
|
||||
lint.covered_by_many = Some(UnreachableCoveredByMany(covering_spans));
|
||||
}
|
||||
}
|
||||
cx.tcx.emit_node_span_lint(UNREACHABLE_PATTERNS, hir_id, pat_span, lint);
|
||||
}
|
||||
|
||||
/// Report unreachable arms, if any.
|
||||
fn report_arm_reachability<'p, 'tcx>(cx: &PatCtxt<'p, 'tcx>, report: &UsefulnessReport<'p, 'tcx>) {
|
||||
let mut catchall = None;
|
||||
for (arm, is_useful) in report.arm_usefulness.iter() {
|
||||
if matches!(is_useful, Usefulness::Redundant) {
|
||||
report_unreachable_pattern(cx, arm.arm_data, arm.pat.data().span, catchall)
|
||||
}
|
||||
if !arm.has_guard && catchall.is_none() && pat_is_catchall(arm.pat) {
|
||||
catchall = Some(arm.pat.data().span);
|
||||
if let Usefulness::Redundant(explanation) = is_useful {
|
||||
report_unreachable_pattern(cx, arm.arm_data, arm.pat, explanation)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue