1
1
use super :: usefulness:: {
2
- compute_match_usefulness, expand_pattern, is_wildcard, MatchArm , MatchCheckCtxt , Reachability ,
3
- UsefulnessReport ,
2
+ compute_match_usefulness, expand_pattern, is_wildcard, MatchArm , MatchCheckCtxt ,
3
+ NonExhaustiveReachable , Reachability , UsefulnessReport ,
4
4
} ;
5
5
use super :: { PatCtxt , PatternError } ;
6
6
@@ -14,8 +14,8 @@ use rustc_hir::intravisit::{self, NestedVisitorMap, Visitor};
14
14
use rustc_hir:: { HirId , Pat } ;
15
15
use rustc_middle:: thir:: PatKind ;
16
16
use rustc_middle:: ty:: { self , Ty , TyCtxt } ;
17
- use rustc_session:: lint:: builtin:: BINDINGS_WITH_VARIANT_NAME ;
18
17
use rustc_session:: lint:: builtin:: { IRREFUTABLE_LET_PATTERNS , UNREACHABLE_PATTERNS } ;
18
+ use rustc_session:: lint:: { builtin:: BINDINGS_WITH_VARIANT_NAME , Level } ;
19
19
use rustc_session:: parse:: feature_err;
20
20
use rustc_session:: Session ;
21
21
use rustc_span:: { sym, Span } ;
@@ -74,6 +74,7 @@ impl<'tcx> Visitor<'tcx> for MatchVisitor<'_, 'tcx> {
74
74
} ;
75
75
self . check_irrefutable ( & loc. pat , msg, sp) ;
76
76
self . check_patterns ( & loc. pat ) ;
77
+ check_for_reachable_patterns_in_non_exhaustive ( self , & loc. pat , loc. hir_id ) ;
77
78
}
78
79
79
80
fn visit_param ( & mut self , param : & ' tcx hir:: Param < ' tcx > ) {
@@ -121,7 +122,7 @@ impl PatCtxt<'_, '_> {
121
122
}
122
123
123
124
impl < ' tcx > MatchVisitor < ' _ , ' tcx > {
124
- fn check_patterns ( & mut self , pat : & Pat < ' _ > ) {
125
+ fn check_patterns ( & mut self , pat : & ' tcx Pat < ' _ > ) {
125
126
pat. walk_always ( |pat| check_borrow_conflicts_in_at_patterns ( self , pat) ) ;
126
127
if !self . tcx . features ( ) . bindings_after_at {
127
128
check_legality_of_bindings_in_at_patterns ( self , pat) ;
@@ -183,9 +184,10 @@ impl<'tcx> MatchVisitor<'_, 'tcx> {
183
184
184
185
let arms: Vec < _ > = arms
185
186
. iter ( )
186
- . map ( |hir:: Arm { pat, guard, .. } | MatchArm {
187
+ . map ( |hir:: Arm { pat, guard, hir_id , .. } | MatchArm {
187
188
pat : self . lower_pattern ( & mut cx, pat, & mut have_errors) . 0 ,
188
189
hir_id : pat. hir_id ,
190
+ arm_hir_id : Some ( * hir_id) ,
189
191
has_guard : guard. is_some ( ) ,
190
192
} )
191
193
. collect ( ) ;
@@ -206,16 +208,24 @@ impl<'tcx> MatchVisitor<'_, 'tcx> {
206
208
// since an empty matrix can occur when there are arms, if those arms all have guards.
207
209
let is_empty_match = arms. is_empty ( ) ;
208
210
let witnesses = report. non_exhaustiveness_witnesses ;
211
+ let reachable = report. reachable ;
209
212
if !witnesses. is_empty ( ) {
210
- non_exhaustive_match ( & cx, scrut_ty, scrut. span , witnesses, is_empty_match) ;
213
+ if let NonExhaustiveReachable :: Lint { wildcard_span : Some ( sp) , level : Some ( level) } =
214
+ reachable
215
+ {
216
+ non_exhaustive_reachable_match ( & cx, scrut_ty, scrut. span , sp, witnesses, level) ;
217
+ } else {
218
+ non_exhaustive_match ( & cx, scrut_ty, scrut. span , witnesses, is_empty_match) ;
219
+ }
211
220
}
212
221
}
213
222
214
223
fn check_irrefutable ( & self , pat : & ' tcx Pat < ' tcx > , origin : & str , sp : Option < Span > ) {
215
224
let mut cx = self . new_cx ( pat. hir_id ) ;
216
225
217
226
let ( pattern, pattern_ty) = self . lower_pattern ( & mut cx, pat, & mut false ) ;
218
- let arms = vec ! [ MatchArm { pat: pattern, hir_id: pat. hir_id, has_guard: false } ] ;
227
+ let arms =
228
+ vec ! [ MatchArm { pat: pattern, hir_id: pat. hir_id, arm_hir_id: None , has_guard: false } ] ;
219
229
let report = compute_match_usefulness ( & cx, & arms, pat. hir_id , pattern_ty) ;
220
230
221
231
// Note: we ignore whether the pattern is unreachable (i.e. whether the type is empty). We
@@ -343,6 +353,37 @@ fn check_for_bindings_named_same_as_variants(cx: &MatchVisitor<'_, '_>, pat: &Pa
343
353
} ) ;
344
354
}
345
355
356
+ fn check_for_reachable_patterns_in_non_exhaustive < ' p , ' tcx > (
357
+ cx : & MatchVisitor < ' p , ' tcx > ,
358
+ pat : & ' tcx Pat < ' tcx > ,
359
+ attr_hir_id : HirId ,
360
+ ) {
361
+ if let hir:: PatKind :: Struct ( _, _fields @ [ _, ..] , true ) = & pat. kind {
362
+ if let ty:: Adt ( def, _) = cx. typeck_results . pat_ty ( pat) . kind ( ) {
363
+ if let Some ( var) = def. variants . iter ( ) . next ( ) {
364
+ if var. is_field_list_non_exhaustive ( ) && !def. did . is_local ( ) {
365
+ let mut mcx = cx. new_cx ( pat. hir_id ) ;
366
+
367
+ let ( pattern, pattern_ty) = cx. lower_pattern ( & mut mcx, pat, & mut false ) ;
368
+ let arms = vec ! [ MatchArm {
369
+ pat: pattern,
370
+ hir_id: pat. hir_id,
371
+ arm_hir_id: Some ( attr_hir_id) ,
372
+ has_guard: false ,
373
+ } ] ;
374
+ let report = compute_match_usefulness ( & mcx, & arms, pat. hir_id , pattern_ty) ;
375
+ println ! ( "{:?}" , report) ;
376
+ // let missing = get_missing_fields(fields, &var.fields);
377
+ // if !missing.is_empty() {
378
+ // let last = fields.last().unwrap().span;
379
+ // lint(cx, pat.span, last, missing)
380
+ // }
381
+ }
382
+ }
383
+ }
384
+ }
385
+ }
386
+
346
387
/// Checks for common cases of "catchall" patterns that may not be intended as such.
347
388
fn pat_is_catchall ( pat : & super :: Pat < ' _ > ) -> bool {
348
389
use PatKind :: * ;
@@ -400,7 +441,7 @@ fn check_if_let_guard<'p, 'tcx>(
400
441
pat : & ' p super :: Pat < ' tcx > ,
401
442
pat_id : HirId ,
402
443
) {
403
- let arms = [ MatchArm { pat, hir_id : pat_id, has_guard : false } ] ;
444
+ let arms = [ MatchArm { pat, hir_id : pat_id, arm_hir_id : None , has_guard : false } ] ;
404
445
let report = compute_match_usefulness ( & cx, & arms, pat_id, pat. ty ) ;
405
446
report_arm_reachability ( & cx, & report, hir:: MatchSource :: IfLetGuardDesugar ) ;
406
447
@@ -502,6 +543,10 @@ fn non_exhaustive_match<'p, 'tcx>(
502
543
_ => false ,
503
544
} ;
504
545
546
+ if is_variant_list_non_exhaustive {
547
+ println ! ( "{:?}" , witnesses) ;
548
+ }
549
+
505
550
adt_defined_here ( cx, & mut err, scrut_ty, & witnesses) ;
506
551
err. help (
507
552
"ensure that all possible cases are being handled, \
@@ -538,6 +583,38 @@ fn non_exhaustive_match<'p, 'tcx>(
538
583
err. emit ( ) ;
539
584
}
540
585
586
+ /// Report that a match of a non_exhaustive type marked with `reachable_patterns` is not
587
+ /// exhaustive enough.
588
+ fn non_exhaustive_reachable_match < ' p , ' tcx > (
589
+ cx : & MatchCheckCtxt < ' p , ' tcx > ,
590
+ scrut_ty : Ty < ' tcx > ,
591
+ sp : Span ,
592
+ _wild_sp : Span ,
593
+ witnesses : Vec < super :: Pat < ' tcx > > ,
594
+ _level : Level ,
595
+ ) {
596
+ let joined_patterns = joined_uncovered_patterns ( & witnesses) ;
597
+
598
+ let mut warn = cx
599
+ . tcx
600
+ . sess
601
+ . struct_span_err ( sp, & format ! ( "reachable-patterns: {} not covered" , joined_patterns) ) ;
602
+ warn. span_label ( sp, pattern_not_covered_label ( & witnesses, & joined_patterns) ) ;
603
+
604
+ // IS THIS HELPFUL
605
+ // adt_defined_here(cx, &mut warn, scrut_ty, &witnesses);
606
+
607
+ warn. help (
608
+ "ensure that all possible cases are being handled by adding the suggested match arms" ,
609
+ ) ;
610
+ warn. note ( & format ! (
611
+ "the matched value is of type `{}` and the wildcard has the `reachable_patterns` attribute" ,
612
+ scrut_ty,
613
+ ) ) ;
614
+
615
+ warn. emit ( ) ;
616
+ }
617
+
541
618
fn joined_uncovered_patterns ( witnesses : & [ super :: Pat < ' _ > ] ) -> String {
542
619
const LIMIT : usize = 3 ;
543
620
match witnesses {
0 commit comments