1
1
use 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
+ } ;
4
5
use super :: { PatCtxt , PatKind , PatternError } ;
5
6
6
7
use rustc_arena:: TypedArena ;
@@ -169,39 +170,50 @@ impl<'tcx> MatchVisitor<'_, 'tcx> {
169
170
170
171
let mut have_errors = false ;
171
172
172
- let inlined_arms : Vec < _ > = arms
173
+ let arms : Vec < _ > = arms
173
174
. 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 ( ) ,
176
179
} )
177
180
. collect ( ) ;
178
181
179
- // Bail out early if inlining failed.
182
+ // Bail out early if lowering failed.
180
183
if have_errors {
181
184
return ;
182
185
}
183
186
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) ;
186
192
187
- // Fifth, check if the match is exhaustive.
193
+ // Check if the match is exhaustive.
188
194
// Note: An empty match isn't the same as an empty matrix for diagnostics purposes,
189
195
// 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
+ }
193
201
}
194
202
195
203
fn check_irrefutable ( & self , pat : & ' tcx Pat < ' tcx > , origin : & str , sp : Option < Span > ) {
196
204
let mut cx = self . new_cx ( pat. hir_id ) ;
197
205
198
206
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
+ }
205
217
206
218
let joined_patterns = joined_uncovered_patterns ( & witnesses) ;
207
219
let mut err = struct_span_err ! (
@@ -354,17 +366,15 @@ fn irrefutable_let_pattern(tcx: TyCtxt<'_>, span: Span, id: HirId, source: hir::
354
366
} ) ;
355
367
}
356
368
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 > ,
361
373
source : hir:: MatchSource ,
362
- ) -> Matrix < ' p , ' tcx > {
363
- let mut seen = Matrix :: empty ( ) ;
374
+ ) {
364
375
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 {
368
378
NotUseful => {
369
379
match source {
370
380
hir:: MatchSource :: IfDesugar { .. } | hir:: MatchSource :: WhileDesugar => bug ! ( ) ,
@@ -373,15 +383,15 @@ fn check_arms<'p, 'tcx>(
373
383
// Check which arm we're on.
374
384
match arm_index {
375
385
// 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 ) ,
377
387
// 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) ,
379
389
_ => bug ! ( ) ,
380
390
}
381
391
}
382
392
383
393
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) ;
385
395
}
386
396
387
397
// Unreachable patterns in try and await expressions occur when one of
@@ -392,60 +402,29 @@ fn check_arms<'p, 'tcx>(
392
402
Useful ( unreachables) if unreachables. is_empty ( ) => { }
393
403
// The arm is reachable, but contains unreachable subpatterns (from or-patterns).
394
404
Useful ( unreachables) => {
395
- let mut unreachables: Vec < _ > = unreachables. into_iter ( ) . flatten ( ) . collect ( ) ;
405
+ let mut unreachables: Vec < _ > = unreachables. iter ( ) . flatten ( ) . copied ( ) . collect ( ) ;
396
406
// Emit lints in the order in which they occur in the file.
397
407
unreachables. sort_unstable ( ) ;
398
408
for span in unreachables {
399
- unreachable_pattern ( cx. tcx , span, id , None ) ;
409
+ unreachable_pattern ( cx. tcx , span, arm . hir_id , None ) ;
400
410
}
401
411
}
402
412
UsefulWithWitness ( _) => bug ! ( ) ,
403
413
}
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 ) ;
409
416
}
410
417
}
411
- seen
412
418
}
413
419
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 > ,
438
423
scrut_ty : Ty < ' tcx > ,
439
424
sp : Span ,
440
- matrix : & Matrix < ' p , ' tcx > ,
441
- hir_id : HirId ,
425
+ witnesses : Vec < super :: Pat < ' tcx > > ,
442
426
is_empty_match : bool ,
443
427
) {
444
- let witnesses = match check_not_useful ( cx, scrut_ty, matrix, hir_id) {
445
- Ok ( _) => return ,
446
- Err ( err) => err,
447
- } ;
448
-
449
428
let non_empty_enum = match scrut_ty. kind ( ) {
450
429
ty:: Adt ( def, _) => def. is_enum ( ) && !def. variants . is_empty ( ) ,
451
430
_ => false ,
0 commit comments