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

`}

`