11use rustc_pattern_analysis:: errors:: Uncovered ;
22use rustc_pattern_analysis:: rustc:: {
3- Constructor , DeconstructedPat , RustcMatchCheckCtxt as MatchCheckCtxt , Usefulness ,
3+ Constructor , DeconstructedPat , MatchArm , RustcMatchCheckCtxt as MatchCheckCtxt , Usefulness ,
44 UsefulnessReport , WitnessPat ,
55} ;
6- use rustc_pattern_analysis:: { analyze_match, MatchArm } ;
76
87use crate :: errors:: * ;
98
@@ -390,6 +389,34 @@ impl<'p, 'tcx> MatchVisitor<'p, 'tcx> {
390389 }
391390 }
392391
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+
393420 #[ instrument( level = "trace" , skip( self ) ) ]
394421 fn check_let ( & mut self , pat : & ' p Pat < ' tcx > , scrutinee : Option < ExprId > , span : Span ) {
395422 assert ! ( self . let_source != LetSource :: None ) ;
@@ -435,14 +462,7 @@ impl<'p, 'tcx> MatchVisitor<'p, 'tcx> {
435462 }
436463 }
437464
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 } ;
446466
447467 match source {
448468 // Don't report arm reachability of desugared `match $iter.into_iter() { iter => .. }`
@@ -474,7 +494,7 @@ impl<'p, 'tcx> MatchVisitor<'p, 'tcx> {
474494 ) ;
475495 } else {
476496 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,
478498 ) ) ;
479499 }
480500 }
@@ -556,7 +576,7 @@ impl<'p, 'tcx> MatchVisitor<'p, 'tcx> {
556576 let cx = self . new_cx ( refutability, None , scrut, pat. span ) ;
557577 let pat = self . lower_pattern ( & cx, pat) ?;
558578 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 ( ) ) ?;
560580 Ok ( ( cx, report) )
561581 }
562582
@@ -567,7 +587,6 @@ impl<'p, 'tcx> MatchVisitor<'p, 'tcx> {
567587 ) -> Result < RefutableFlag , ErrorGuaranteed > {
568588 let ( cx, report) = self . analyze_binding ( pat, Refutable , scrut) ?;
569589 // Report if the pattern is unreachable, which can only occur when the type is uninhabited.
570- // This also reports unreachable sub-patterns.
571590 report_arm_reachability ( & cx, & report) ;
572591 // If the list of witnesses is empty, the match is exhaustive, i.e. the `if let` pattern is
573592 // irrefutable.
@@ -850,39 +869,30 @@ fn report_irrefutable_let_patterns(
850869 }
851870}
852871
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+
853887/// Report unreachable arms, if any.
854888fn report_arm_reachability < ' p , ' tcx > (
855889 cx : & MatchCheckCtxt < ' p , ' tcx > ,
856890 report : & UsefulnessReport < ' p , ' tcx > ,
857891) {
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-
870892 let mut catchall = None ;
871893 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)
886896 }
887897 if !arm. has_guard && catchall. is_none ( ) && pat_is_catchall ( arm. pat ) {
888898 catchall = Some ( arm. pat . data ( ) . unwrap ( ) . span ) ;
0 commit comments