11use super :: _match:: Usefulness :: * ;
2- use super :: _match:: WitnessPreference :: * ;
3- use super :: _match:: { expand_pattern, is_useful, MatchCheckCtxt , Matrix , PatStack } ;
2+ use super :: _match:: {
3+ compute_match_usefulness, expand_pattern, MatchArm , MatchCheckCtxt , UsefulnessReport ,
4+ } ;
45use super :: { PatCtxt , PatKind , PatternError } ;
56
67use rustc_arena:: TypedArena ;
@@ -169,39 +170,50 @@ impl<'tcx> MatchVisitor<'_, 'tcx> {
169170
170171 let mut have_errors = false ;
171172
172- let inlined_arms : Vec < _ > = arms
173+ let arms : Vec < _ > = arms
173174 . iter ( )
174- . map ( |hir:: Arm { pat, guard, .. } | {
175- ( self . lower_pattern ( & mut cx, pat, & mut have_errors) . 0 , pat. hir_id , guard. is_some ( ) )
175+ . map ( |hir:: Arm { pat, guard, .. } | MatchArm {
176+ pat : self . lower_pattern ( & mut cx, pat, & mut have_errors) . 0 ,
177+ hir_id : pat. hir_id ,
178+ has_guard : guard. is_some ( ) ,
176179 } )
177180 . collect ( ) ;
178181
179- // Bail out early if inlining failed.
182+ // Bail out early if lowering failed.
180183 if have_errors {
181184 return ;
182185 }
183186
184- // Fourth, check for unreachable arms.
185- let matrix = check_arms ( & mut cx, & inlined_arms, source) ;
187+ let scrut_ty = self . typeck_results . expr_ty_adjusted ( scrut) ;
188+ let report = compute_match_usefulness ( & cx, & arms, scrut. hir_id , scrut_ty) ;
189+
190+ // Report unreachable arms.
191+ report_arm_reachability ( & cx, & report, source) ;
186192
187- // Fifth, check if the match is exhaustive.
193+ // Check if the match is exhaustive.
188194 // Note: An empty match isn't the same as an empty matrix for diagnostics purposes,
189195 // since an empty matrix can occur when there are arms, if those arms all have guards.
190- let scrut_ty = self . typeck_results . expr_ty_adjusted ( scrut) ;
191- let is_empty_match = inlined_arms. is_empty ( ) ;
192- check_exhaustive ( & mut cx, scrut_ty, scrut. span , & matrix, scrut. hir_id , is_empty_match) ;
196+ let is_empty_match = arms. is_empty ( ) ;
197+ let witnesses = report. non_exhaustiveness_witnesses ;
198+ if !witnesses. is_empty ( ) {
199+ non_exhaustive_match ( & cx, scrut_ty, scrut. span , witnesses, is_empty_match) ;
200+ }
193201 }
194202
195203 fn check_irrefutable ( & self , pat : & ' tcx Pat < ' tcx > , origin : & str , sp : Option < Span > ) {
196204 let mut cx = self . new_cx ( pat. hir_id ) ;
197205
198206 let ( pattern, pattern_ty) = self . lower_pattern ( & mut cx, pat, & mut false ) ;
199- let pats: Matrix < ' _ , ' _ > = vec ! [ PatStack :: from_pattern( pattern) ] . into_iter ( ) . collect ( ) ;
200-
201- let witnesses = match check_not_useful ( & mut cx, pattern_ty, & pats, pat. hir_id ) {
202- Ok ( _) => return ,
203- Err ( err) => err,
204- } ;
207+ let arms = vec ! [ MatchArm { pat: pattern, hir_id: pat. hir_id, has_guard: false } ] ;
208+ let report = compute_match_usefulness ( & cx, & arms, pat. hir_id , pattern_ty) ;
209+
210+ // Note: we ignore whether the pattern is unreachable (i.e. whether the type is empty). We
211+ // only care about exhaustiveness here.
212+ let witnesses = report. non_exhaustiveness_witnesses ;
213+ if witnesses. is_empty ( ) {
214+ // The pattern is irrefutable.
215+ return ;
216+ }
205217
206218 let joined_patterns = joined_uncovered_patterns ( & witnesses) ;
207219 let mut err = struct_span_err ! (
@@ -354,17 +366,15 @@ fn irrefutable_let_pattern(tcx: TyCtxt<'_>, span: Span, id: HirId, source: hir::
354366 } ) ;
355367}
356368
357- /// Check for unreachable patterns .
358- fn check_arms < ' p , ' tcx > (
359- cx : & mut MatchCheckCtxt < ' p , ' tcx > ,
360- arms : & [ ( & ' p super :: Pat < ' tcx > , HirId , bool ) ] ,
369+ /// Report unreachable arms, if any .
370+ fn report_arm_reachability < ' p , ' tcx > (
371+ cx : & MatchCheckCtxt < ' p , ' tcx > ,
372+ report : & UsefulnessReport < ' p , ' tcx > ,
361373 source : hir:: MatchSource ,
362- ) -> Matrix < ' p , ' tcx > {
363- let mut seen = Matrix :: empty ( ) ;
374+ ) {
364375 let mut catchall = None ;
365- for ( arm_index, ( pat, id, has_guard) ) in arms. iter ( ) . copied ( ) . enumerate ( ) {
366- let v = PatStack :: from_pattern ( pat) ;
367- match is_useful ( cx, & seen, & v, LeaveOutWitness , id, has_guard, true ) {
376+ for ( arm_index, ( arm, is_useful) ) in report. arm_usefulness . iter ( ) . enumerate ( ) {
377+ match is_useful {
368378 NotUseful => {
369379 match source {
370380 hir:: MatchSource :: IfDesugar { .. } | hir:: MatchSource :: WhileDesugar => bug ! ( ) ,
@@ -373,15 +383,15 @@ fn check_arms<'p, 'tcx>(
373383 // Check which arm we're on.
374384 match arm_index {
375385 // The arm with the user-specified pattern.
376- 0 => unreachable_pattern ( cx. tcx , pat. span , id , None ) ,
386+ 0 => unreachable_pattern ( cx. tcx , arm . pat . span , arm . hir_id , None ) ,
377387 // The arm with the wildcard pattern.
378- 1 => irrefutable_let_pattern ( cx. tcx , pat. span , id , source) ,
388+ 1 => irrefutable_let_pattern ( cx. tcx , arm . pat . span , arm . hir_id , source) ,
379389 _ => bug ! ( ) ,
380390 }
381391 }
382392
383393 hir:: MatchSource :: ForLoopDesugar | hir:: MatchSource :: Normal => {
384- unreachable_pattern ( cx. tcx , pat. span , id , catchall) ;
394+ unreachable_pattern ( cx. tcx , arm . pat . span , arm . hir_id , catchall) ;
385395 }
386396
387397 // Unreachable patterns in try and await expressions occur when one of
@@ -392,60 +402,29 @@ fn check_arms<'p, 'tcx>(
392402 Useful ( unreachables) if unreachables. is_empty ( ) => { }
393403 // The arm is reachable, but contains unreachable subpatterns (from or-patterns).
394404 Useful ( unreachables) => {
395- let mut unreachables: Vec < _ > = unreachables. into_iter ( ) . flatten ( ) . collect ( ) ;
405+ let mut unreachables: Vec < _ > = unreachables. iter ( ) . flatten ( ) . copied ( ) . collect ( ) ;
396406 // Emit lints in the order in which they occur in the file.
397407 unreachables. sort_unstable ( ) ;
398408 for span in unreachables {
399- unreachable_pattern ( cx. tcx , span, id , None ) ;
409+ unreachable_pattern ( cx. tcx , span, arm . hir_id , None ) ;
400410 }
401411 }
402412 UsefulWithWitness ( _) => bug ! ( ) ,
403413 }
404- if !has_guard {
405- seen. push ( v) ;
406- if catchall. is_none ( ) && pat_is_catchall ( pat) {
407- catchall = Some ( pat. span ) ;
408- }
414+ if !arm. has_guard && catchall. is_none ( ) && pat_is_catchall ( arm. pat ) {
415+ catchall = Some ( arm. pat . span ) ;
409416 }
410417 }
411- seen
412418}
413419
414- fn check_not_useful < ' p , ' tcx > (
415- cx : & mut MatchCheckCtxt < ' p , ' tcx > ,
416- ty : Ty < ' tcx > ,
417- matrix : & Matrix < ' p , ' tcx > ,
418- hir_id : HirId ,
419- ) -> Result < ( ) , Vec < super :: Pat < ' tcx > > > {
420- let wild_pattern = cx. pattern_arena . alloc ( super :: Pat :: wildcard_from_ty ( ty) ) ;
421- let v = PatStack :: from_pattern ( wild_pattern) ;
422-
423- // false is given for `is_under_guard` argument due to the wildcard
424- // pattern not having a guard
425- match is_useful ( cx, matrix, & v, ConstructWitness , hir_id, false , true ) {
426- NotUseful => Ok ( ( ) ) , // This is good, wildcard pattern isn't reachable.
427- UsefulWithWitness ( pats) => Err ( if pats. is_empty ( ) {
428- bug ! ( "Exhaustiveness check returned no witnesses" )
429- } else {
430- pats. into_iter ( ) . map ( |w| w. single_pattern ( ) ) . collect ( )
431- } ) ,
432- Useful ( _) => bug ! ( ) ,
433- }
434- }
435-
436- fn check_exhaustive < ' p , ' tcx > (
437- cx : & mut MatchCheckCtxt < ' p , ' tcx > ,
420+ /// Report that a match is not exhaustive.
421+ fn non_exhaustive_match < ' p , ' tcx > (
422+ cx : & MatchCheckCtxt < ' p , ' tcx > ,
438423 scrut_ty : Ty < ' tcx > ,
439424 sp : Span ,
440- matrix : & Matrix < ' p , ' tcx > ,
441- hir_id : HirId ,
425+ witnesses : Vec < super :: Pat < ' tcx > > ,
442426 is_empty_match : bool ,
443427) {
444- let witnesses = match check_not_useful ( cx, scrut_ty, matrix, hir_id) {
445- Ok ( _) => return ,
446- Err ( err) => err,
447- } ;
448-
449428 let non_empty_enum = match scrut_ty. kind ( ) {
450429 ty:: Adt ( def, _) => def. is_enum ( ) && !def. variants . is_empty ( ) ,
451430 _ => false ,
0 commit comments