1
1
use rustc_pattern_analysis:: errors:: Uncovered ;
2
2
use rustc_pattern_analysis:: rustc:: {
3
- Constructor , DeconstructedPat , RustcMatchCheckCtxt as MatchCheckCtxt , Usefulness ,
3
+ Constructor , DeconstructedPat , MatchArm , RustcMatchCheckCtxt as MatchCheckCtxt , Usefulness ,
4
4
UsefulnessReport , WitnessPat ,
5
5
} ;
6
- use rustc_pattern_analysis:: { analyze_match, MatchArm } ;
7
6
8
7
use crate :: errors:: * ;
9
8
@@ -390,6 +389,34 @@ impl<'p, 'tcx> MatchVisitor<'p, 'tcx> {
390
389
}
391
390
}
392
391
392
+ fn analyze_patterns (
393
+ & mut self ,
394
+ cx : & MatchCheckCtxt < ' p , ' tcx > ,
395
+ arms : & [ MatchArm < ' p , ' tcx > ] ,
396
+ scrut_ty : Ty < ' tcx > ,
397
+ ) -> Result < UsefulnessReport < ' p , ' tcx > , ErrorGuaranteed > {
398
+ let report =
399
+ rustc_pattern_analysis:: analyze_match ( & cx, & arms, scrut_ty) . map_err ( |err| {
400
+ self . error = Err ( err) ;
401
+ err
402
+ } ) ?;
403
+
404
+ // Warn unreachable subpatterns.
405
+ for ( arm, is_useful) in report. arm_usefulness . iter ( ) {
406
+ if let Usefulness :: Useful ( redundant_subpats) = is_useful
407
+ && !redundant_subpats. is_empty ( )
408
+ {
409
+ let mut redundant_subpats = redundant_subpats. clone ( ) ;
410
+ // Emit lints in the order in which they occur in the file.
411
+ redundant_subpats. sort_unstable_by_key ( |pat| pat. data ( ) . unwrap ( ) . span ) ;
412
+ for pat in redundant_subpats {
413
+ report_unreachable_pattern ( cx, arm. arm_data , pat. data ( ) . unwrap ( ) . span , None )
414
+ }
415
+ }
416
+ }
417
+ Ok ( report)
418
+ }
419
+
393
420
#[ instrument( level = "trace" , skip( self ) ) ]
394
421
fn check_let ( & mut self , pat : & ' p Pat < ' tcx > , scrutinee : Option < ExprId > , span : Span ) {
395
422
assert ! ( self . let_source != LetSource :: None ) ;
@@ -435,14 +462,7 @@ impl<'p, 'tcx> MatchVisitor<'p, 'tcx> {
435
462
}
436
463
}
437
464
438
- let scrut_ty = scrut. ty ;
439
- let report = match analyze_match ( & cx, & tarms, scrut_ty) {
440
- Ok ( report) => report,
441
- Err ( err) => {
442
- self . error = Err ( err) ;
443
- return ;
444
- }
445
- } ;
465
+ let Ok ( report) = self . analyze_patterns ( & cx, & tarms, scrut. ty ) else { return } ;
446
466
447
467
match source {
448
468
// Don't report arm reachability of desugared `match $iter.into_iter() { iter => .. }`
@@ -474,7 +494,7 @@ impl<'p, 'tcx> MatchVisitor<'p, 'tcx> {
474
494
) ;
475
495
} else {
476
496
self . error = Err ( report_non_exhaustive_match (
477
- & cx, self . thir , scrut_ty , scrut. span , witnesses, arms, expr_span,
497
+ & cx, self . thir , scrut . ty , scrut. span , witnesses, arms, expr_span,
478
498
) ) ;
479
499
}
480
500
}
@@ -556,7 +576,7 @@ impl<'p, 'tcx> MatchVisitor<'p, 'tcx> {
556
576
let cx = self . new_cx ( refutability, None , scrut, pat. span ) ;
557
577
let pat = self . lower_pattern ( & cx, pat) ?;
558
578
let arms = [ MatchArm { pat, arm_data : self . lint_level , has_guard : false } ] ;
559
- let report = analyze_match ( & cx, & arms, pat. ty ( ) . inner ( ) ) ?;
579
+ let report = self . analyze_patterns ( & cx, & arms, pat. ty ( ) . inner ( ) ) ?;
560
580
Ok ( ( cx, report) )
561
581
}
562
582
@@ -567,7 +587,6 @@ impl<'p, 'tcx> MatchVisitor<'p, 'tcx> {
567
587
) -> Result < RefutableFlag , ErrorGuaranteed > {
568
588
let ( cx, report) = self . analyze_binding ( pat, Refutable , scrut) ?;
569
589
// Report if the pattern is unreachable, which can only occur when the type is uninhabited.
570
- // This also reports unreachable sub-patterns.
571
590
report_arm_reachability ( & cx, & report) ;
572
591
// If the list of witnesses is empty, the match is exhaustive, i.e. the `if let` pattern is
573
592
// irrefutable.
@@ -850,39 +869,30 @@ fn report_irrefutable_let_patterns(
850
869
}
851
870
}
852
871
872
+ /// Report unreachable arms, if any.
873
+ fn report_unreachable_pattern < ' p , ' tcx > (
874
+ cx : & MatchCheckCtxt < ' p , ' tcx > ,
875
+ hir_id : HirId ,
876
+ span : Span ,
877
+ catchall : Option < Span > ,
878
+ ) {
879
+ cx. tcx . emit_spanned_lint (
880
+ UNREACHABLE_PATTERNS ,
881
+ hir_id,
882
+ span,
883
+ UnreachablePattern { span : if catchall. is_some ( ) { Some ( span) } else { None } , catchall } ,
884
+ ) ;
885
+ }
886
+
853
887
/// Report unreachable arms, if any.
854
888
fn report_arm_reachability < ' p , ' tcx > (
855
889
cx : & MatchCheckCtxt < ' p , ' tcx > ,
856
890
report : & UsefulnessReport < ' p , ' tcx > ,
857
891
) {
858
- let report_unreachable_pattern = |span, hir_id, catchall : Option < Span > | {
859
- cx. tcx . emit_spanned_lint (
860
- UNREACHABLE_PATTERNS ,
861
- hir_id,
862
- span,
863
- UnreachablePattern {
864
- span : if catchall. is_some ( ) { Some ( span) } else { None } ,
865
- catchall,
866
- } ,
867
- ) ;
868
- } ;
869
-
870
892
let mut catchall = None ;
871
893
for ( arm, is_useful) in report. arm_usefulness . iter ( ) {
872
- match is_useful {
873
- Usefulness :: Redundant => {
874
- report_unreachable_pattern ( arm. pat . data ( ) . unwrap ( ) . span , arm. arm_data , catchall)
875
- }
876
- Usefulness :: Useful ( redundant_subpats) if redundant_subpats. is_empty ( ) => { }
877
- // The arm is reachable, but contains redundant subpatterns (from or-patterns).
878
- Usefulness :: Useful ( redundant_subpats) => {
879
- let mut redundant_subpats = redundant_subpats. clone ( ) ;
880
- // Emit lints in the order in which they occur in the file.
881
- redundant_subpats. sort_unstable_by_key ( |pat| pat. data ( ) . unwrap ( ) . span ) ;
882
- for pat in redundant_subpats {
883
- report_unreachable_pattern ( pat. data ( ) . unwrap ( ) . span , arm. arm_data , None ) ;
884
- }
885
- }
894
+ if matches ! ( is_useful, Usefulness :: Redundant ) {
895
+ report_unreachable_pattern ( cx, arm. arm_data , arm. pat . data ( ) . unwrap ( ) . span , catchall)
886
896
}
887
897
if !arm. has_guard && catchall. is_none ( ) && pat_is_catchall ( arm. pat ) {
888
898
catchall = Some ( arm. pat . data ( ) . unwrap ( ) . span ) ;
0 commit comments