1
+ use super :: deconstruct_pat:: { Constructor , DeconstructedPat } ;
1
2
use super :: usefulness:: {
2
- compute_match_usefulness, expand_pattern, is_wildcard, MatchArm , MatchCheckCtxt , Reachability ,
3
- UsefulnessReport ,
3
+ compute_match_usefulness, MatchArm , MatchCheckCtxt , Reachability , UsefulnessReport ,
4
4
} ;
5
5
use super :: { PatCtxt , PatternError } ;
6
6
@@ -12,26 +12,25 @@ use rustc_hir::def::*;
12
12
use rustc_hir:: def_id:: DefId ;
13
13
use rustc_hir:: intravisit:: { self , NestedVisitorMap , Visitor } ;
14
14
use rustc_hir:: { HirId , Pat } ;
15
- use rustc_middle:: thir:: PatKind ;
16
- use rustc_middle:: ty:: { self , Ty , TyCtxt } ;
15
+ use rustc_middle:: ty:: { self , AdtDef , Ty , TyCtxt } ;
17
16
use rustc_session:: lint:: builtin:: {
18
17
BINDINGS_WITH_VARIANT_NAME , IRREFUTABLE_LET_PATTERNS , UNREACHABLE_PATTERNS ,
19
18
} ;
20
19
use rustc_session:: Session ;
21
20
use rustc_span:: { DesugaringKind , ExpnKind , Span } ;
22
- use std:: slice;
23
21
24
22
crate fn check_match ( tcx : TyCtxt < ' _ > , def_id : DefId ) {
25
23
let body_id = match def_id. as_local ( ) {
26
24
None => return ,
27
25
Some ( id) => tcx. hir ( ) . body_owned_by ( tcx. hir ( ) . local_def_id_to_hir_id ( id) ) ,
28
26
} ;
29
27
28
+ let pattern_arena = TypedArena :: default ( ) ;
30
29
let mut visitor = MatchVisitor {
31
30
tcx,
32
31
typeck_results : tcx. typeck_body ( body_id) ,
33
32
param_env : tcx. param_env ( def_id) ,
34
- pattern_arena : TypedArena :: default ( ) ,
33
+ pattern_arena : & pattern_arena ,
35
34
} ;
36
35
visitor. visit_body ( tcx. hir ( ) . body ( body_id) ) ;
37
36
}
@@ -40,14 +39,14 @@ fn create_e0004(sess: &Session, sp: Span, error_message: String) -> DiagnosticBu
40
39
struct_span_err ! ( sess, sp, E0004 , "{}" , & error_message)
41
40
}
42
41
43
- struct MatchVisitor < ' a , ' tcx > {
42
+ struct MatchVisitor < ' a , ' p , ' tcx > {
44
43
tcx : TyCtxt < ' tcx > ,
45
44
typeck_results : & ' a ty:: TypeckResults < ' tcx > ,
46
45
param_env : ty:: ParamEnv < ' tcx > ,
47
- pattern_arena : TypedArena < super :: Pat < ' tcx > > ,
46
+ pattern_arena : & ' p TypedArena < DeconstructedPat < ' p , ' tcx > > ,
48
47
}
49
48
50
- impl < ' tcx > Visitor < ' tcx > for MatchVisitor < ' _ , ' tcx > {
49
+ impl < ' tcx > Visitor < ' tcx > for MatchVisitor < ' _ , ' _ , ' tcx > {
51
50
type Map = intravisit:: ErasedMap < ' tcx > ;
52
51
53
52
fn nested_visit_map ( & mut self ) -> NestedVisitorMap < Self :: Map > {
@@ -113,31 +112,30 @@ impl PatCtxt<'_, '_> {
113
112
}
114
113
}
115
114
116
- impl < ' tcx > MatchVisitor < ' _ , ' tcx > {
115
+ impl < ' p , ' tcx > MatchVisitor < ' _ , ' p , ' tcx > {
117
116
fn check_patterns ( & self , pat : & Pat < ' _ > ) {
118
117
pat. walk_always ( |pat| check_borrow_conflicts_in_at_patterns ( self , pat) ) ;
119
118
check_for_bindings_named_same_as_variants ( self , pat) ;
120
119
}
121
120
122
- fn lower_pattern < ' p > (
121
+ fn lower_pattern (
123
122
& self ,
124
123
cx : & mut MatchCheckCtxt < ' p , ' tcx > ,
125
124
pat : & ' tcx hir:: Pat < ' tcx > ,
126
125
have_errors : & mut bool ,
127
- ) -> ( & ' p super :: Pat < ' tcx > , Ty < ' tcx > ) {
126
+ ) -> & ' p DeconstructedPat < ' p , ' tcx > {
128
127
let mut patcx = PatCtxt :: new ( self . tcx , self . param_env , self . typeck_results ) ;
129
128
patcx. include_lint_checks ( ) ;
130
129
let pattern = patcx. lower_pattern ( pat) ;
131
- let pattern_ty = pattern. ty ;
132
- let pattern: & _ = cx. pattern_arena . alloc ( expand_pattern ( pattern) ) ;
130
+ let pattern: & _ = cx. pattern_arena . alloc ( DeconstructedPat :: from_pat ( cx, & pattern) ) ;
133
131
if !patcx. errors . is_empty ( ) {
134
132
* have_errors = true ;
135
133
patcx. report_inlining_errors ( ) ;
136
134
}
137
- ( pattern, pattern_ty )
135
+ pattern
138
136
}
139
137
140
- fn new_cx ( & self , hir_id : HirId ) -> MatchCheckCtxt < ' _ , ' tcx > {
138
+ fn new_cx ( & self , hir_id : HirId ) -> MatchCheckCtxt < ' p , ' tcx > {
141
139
MatchCheckCtxt {
142
140
tcx : self . tcx ,
143
141
param_env : self . param_env ,
@@ -149,8 +147,8 @@ impl<'tcx> MatchVisitor<'_, 'tcx> {
149
147
fn check_let ( & mut self , pat : & ' tcx hir:: Pat < ' tcx > , expr : & hir:: Expr < ' _ > , span : Span ) {
150
148
self . check_patterns ( pat) ;
151
149
let mut cx = self . new_cx ( expr. hir_id ) ;
152
- let tpat = self . lower_pattern ( & mut cx, pat, & mut false ) . 0 ;
153
- check_let_reachability ( & mut cx, pat. hir_id , & tpat, span) ;
150
+ let tpat = self . lower_pattern ( & mut cx, pat, & mut false ) ;
151
+ check_let_reachability ( & mut cx, pat. hir_id , tpat, span) ;
154
152
}
155
153
156
154
fn check_match (
@@ -166,8 +164,8 @@ impl<'tcx> MatchVisitor<'_, 'tcx> {
166
164
self . check_patterns ( & arm. pat ) ;
167
165
if let Some ( hir:: Guard :: IfLet ( ref pat, _) ) = arm. guard {
168
166
self . check_patterns ( pat) ;
169
- let tpat = self . lower_pattern ( & mut cx, pat, & mut false ) . 0 ;
170
- check_let_reachability ( & mut cx, pat. hir_id , & tpat, tpat. span ) ;
167
+ let tpat = self . lower_pattern ( & mut cx, pat, & mut false ) ;
168
+ check_let_reachability ( & mut cx, pat. hir_id , tpat, tpat. span ( ) ) ;
171
169
}
172
170
}
173
171
@@ -176,7 +174,7 @@ impl<'tcx> MatchVisitor<'_, 'tcx> {
176
174
let arms: Vec < _ > = arms
177
175
. iter ( )
178
176
. map ( |hir:: Arm { pat, guard, .. } | MatchArm {
179
- pat : self . lower_pattern ( & mut cx, pat, & mut have_errors) . 0 ,
177
+ pat : self . lower_pattern ( & mut cx, pat, & mut have_errors) ,
180
178
hir_id : pat. hir_id ,
181
179
has_guard : guard. is_some ( ) ,
182
180
} )
@@ -210,7 +208,8 @@ impl<'tcx> MatchVisitor<'_, 'tcx> {
210
208
fn check_irrefutable ( & self , pat : & ' tcx Pat < ' tcx > , origin : & str , sp : Option < Span > ) {
211
209
let mut cx = self . new_cx ( pat. hir_id ) ;
212
210
213
- let ( pattern, pattern_ty) = self . lower_pattern ( & mut cx, pat, & mut false ) ;
211
+ let pattern = self . lower_pattern ( & mut cx, pat, & mut false ) ;
212
+ let pattern_ty = pattern. ty ( ) ;
214
213
let arms = vec ! [ MatchArm { pat: pattern, hir_id: pat. hir_id, has_guard: false } ] ;
215
214
let report = compute_match_usefulness ( & cx, & arms, pat. hir_id , pattern_ty) ;
216
215
@@ -222,7 +221,7 @@ impl<'tcx> MatchVisitor<'_, 'tcx> {
222
221
return ;
223
222
}
224
223
225
- let joined_patterns = joined_uncovered_patterns ( & witnesses) ;
224
+ let joined_patterns = joined_uncovered_patterns ( & cx , & witnesses) ;
226
225
let mut err = struct_span_err ! (
227
226
self . tcx. sess,
228
227
pat. span,
@@ -298,7 +297,7 @@ fn const_not_var(
298
297
}
299
298
}
300
299
301
- fn check_for_bindings_named_same_as_variants ( cx : & MatchVisitor < ' _ , ' _ > , pat : & Pat < ' _ > ) {
300
+ fn check_for_bindings_named_same_as_variants ( cx : & MatchVisitor < ' _ , ' _ , ' _ > , pat : & Pat < ' _ > ) {
302
301
pat. walk_always ( |p| {
303
302
if let hir:: PatKind :: Binding ( _, _, ident, None ) = p. kind {
304
303
if let Some ( ty:: BindByValue ( hir:: Mutability :: Not ) ) =
@@ -340,12 +339,11 @@ fn check_for_bindings_named_same_as_variants(cx: &MatchVisitor<'_, '_>, pat: &Pa
340
339
}
341
340
342
341
/// Checks for common cases of "catchall" patterns that may not be intended as such.
343
- fn pat_is_catchall ( pat : & super :: Pat < ' _ > ) -> bool {
344
- use PatKind :: * ;
345
- match & * pat. kind {
346
- Binding { subpattern : None , .. } => true ,
347
- Binding { subpattern : Some ( s) , .. } | Deref { subpattern : s } => pat_is_catchall ( s) ,
348
- Leaf { subpatterns : s } => s. iter ( ) . all ( |p| pat_is_catchall ( & p. pattern ) ) ,
342
+ fn pat_is_catchall ( pat : & DeconstructedPat < ' _ , ' _ > ) -> bool {
343
+ use Constructor :: * ;
344
+ match pat. ctor ( ) {
345
+ Wildcard => true ,
346
+ Single => pat. iter_fields ( ) . all ( |pat| pat_is_catchall ( pat) ) ,
349
347
_ => false ,
350
348
}
351
349
}
@@ -424,11 +422,11 @@ fn irrefutable_let_pattern(tcx: TyCtxt<'_>, id: HirId, span: Span) {
424
422
fn check_let_reachability < ' p , ' tcx > (
425
423
cx : & mut MatchCheckCtxt < ' p , ' tcx > ,
426
424
pat_id : HirId ,
427
- pat : & ' p super :: Pat < ' tcx > ,
425
+ pat : & ' p DeconstructedPat < ' p , ' tcx > ,
428
426
span : Span ,
429
427
) {
430
428
let arms = [ MatchArm { pat, hir_id : pat_id, has_guard : false } ] ;
431
- let report = compute_match_usefulness ( & cx, & arms, pat_id, pat. ty ) ;
429
+ let report = compute_match_usefulness ( & cx, & arms, pat_id, pat. ty ( ) ) ;
432
430
433
431
// Report if the pattern is unreachable, which can only occur when the type is uninhabited.
434
432
// This also reports unreachable sub-patterns though, so we can't just replace it with an
@@ -450,7 +448,7 @@ fn report_arm_reachability<'p, 'tcx>(
450
448
let mut catchall = None ;
451
449
for ( arm, is_useful) in report. arm_usefulness . iter ( ) {
452
450
match is_useful {
453
- Unreachable => unreachable_pattern ( cx. tcx , arm. pat . span , arm. hir_id , catchall) ,
451
+ Unreachable => unreachable_pattern ( cx. tcx , arm. pat . span ( ) , arm. hir_id , catchall) ,
454
452
Reachable ( unreachables) if unreachables. is_empty ( ) => { }
455
453
// The arm is reachable, but contains unreachable subpatterns (from or-patterns).
456
454
Reachable ( unreachables) => {
@@ -463,7 +461,7 @@ fn report_arm_reachability<'p, 'tcx>(
463
461
}
464
462
}
465
463
if !arm. has_guard && catchall. is_none ( ) && pat_is_catchall ( arm. pat ) {
466
- catchall = Some ( arm. pat . span ) ;
464
+ catchall = Some ( arm. pat . span ( ) ) ;
467
465
}
468
466
}
469
467
}
@@ -473,7 +471,7 @@ fn non_exhaustive_match<'p, 'tcx>(
473
471
cx : & MatchCheckCtxt < ' p , ' tcx > ,
474
472
scrut_ty : Ty < ' tcx > ,
475
473
sp : Span ,
476
- witnesses : Vec < super :: Pat < ' tcx > > ,
474
+ witnesses : Vec < DeconstructedPat < ' p , ' tcx > > ,
477
475
is_empty_match : bool ,
478
476
) {
479
477
let non_empty_enum = match scrut_ty. kind ( ) {
@@ -490,7 +488,7 @@ fn non_exhaustive_match<'p, 'tcx>(
490
488
format ! ( "non-exhaustive patterns: type `{}` is non-empty" , scrut_ty) ,
491
489
) ;
492
490
} else {
493
- let joined_patterns = joined_uncovered_patterns ( & witnesses) ;
491
+ let joined_patterns = joined_uncovered_patterns ( cx , & witnesses) ;
494
492
err = create_e0004 (
495
493
cx. tcx . sess ,
496
494
sp,
@@ -517,7 +515,7 @@ fn non_exhaustive_match<'p, 'tcx>(
517
515
if ( scrut_ty == cx. tcx . types . usize || scrut_ty == cx. tcx . types . isize )
518
516
&& !is_empty_match
519
517
&& witnesses. len ( ) == 1
520
- && is_wildcard ( & witnesses[ 0 ] )
518
+ && matches ! ( witnesses[ 0 ] . ctor ( ) , Constructor :: NonExhaustive )
521
519
{
522
520
err. note ( & format ! (
523
521
"`{}` does not have a fixed maximum value, \
@@ -540,33 +538,40 @@ fn non_exhaustive_match<'p, 'tcx>(
540
538
err. emit ( ) ;
541
539
}
542
540
543
- crate fn joined_uncovered_patterns ( witnesses : & [ super :: Pat < ' _ > ] ) -> String {
541
+ crate fn joined_uncovered_patterns < ' p , ' tcx > (
542
+ cx : & MatchCheckCtxt < ' p , ' tcx > ,
543
+ witnesses : & [ DeconstructedPat < ' p , ' tcx > ] ,
544
+ ) -> String {
544
545
const LIMIT : usize = 3 ;
546
+ let pat_to_str = |pat : & DeconstructedPat < ' p , ' tcx > | pat. to_pat ( cx) . to_string ( ) ;
545
547
match witnesses {
546
548
[ ] => bug ! ( ) ,
547
- [ witness] => format ! ( "`{}`" , witness) ,
549
+ [ witness] => format ! ( "`{}`" , witness. to_pat ( cx ) ) ,
548
550
[ head @ .., tail] if head. len ( ) < LIMIT => {
549
- let head: Vec < _ > = head. iter ( ) . map ( < _ > :: to_string ) . collect ( ) ;
550
- format ! ( "`{}` and `{}`" , head. join( "`, `" ) , tail)
551
+ let head: Vec < _ > = head. iter ( ) . map ( pat_to_str ) . collect ( ) ;
552
+ format ! ( "`{}` and `{}`" , head. join( "`, `" ) , tail. to_pat ( cx ) )
551
553
}
552
554
_ => {
553
555
let ( head, tail) = witnesses. split_at ( LIMIT ) ;
554
- let head: Vec < _ > = head. iter ( ) . map ( < _ > :: to_string ) . collect ( ) ;
556
+ let head: Vec < _ > = head. iter ( ) . map ( pat_to_str ) . collect ( ) ;
555
557
format ! ( "`{}` and {} more" , head. join( "`, `" ) , tail. len( ) )
556
558
}
557
559
}
558
560
}
559
561
560
- crate fn pattern_not_covered_label ( witnesses : & [ super :: Pat < ' _ > ] , joined_patterns : & str ) -> String {
562
+ crate fn pattern_not_covered_label (
563
+ witnesses : & [ DeconstructedPat < ' _ , ' _ > ] ,
564
+ joined_patterns : & str ,
565
+ ) -> String {
561
566
format ! ( "pattern{} {} not covered" , rustc_errors:: pluralize!( witnesses. len( ) ) , joined_patterns)
562
567
}
563
568
564
569
/// Point at the definition of non-covered `enum` variants.
565
- fn adt_defined_here (
566
- cx : & MatchCheckCtxt < ' _ , ' _ > ,
570
+ fn adt_defined_here < ' p , ' tcx > (
571
+ cx : & MatchCheckCtxt < ' p , ' tcx > ,
567
572
err : & mut DiagnosticBuilder < ' _ > ,
568
- ty : Ty < ' _ > ,
569
- witnesses : & [ super :: Pat < ' _ > ] ,
573
+ ty : Ty < ' tcx > ,
574
+ witnesses : & [ DeconstructedPat < ' p , ' tcx > ] ,
570
575
) {
571
576
let ty = ty. peel_refs ( ) ;
572
577
if let ty:: Adt ( def, _) = ty. kind ( ) {
@@ -575,57 +580,42 @@ fn adt_defined_here(
575
580
}
576
581
577
582
if witnesses. len ( ) < 4 {
578
- for sp in maybe_point_at_variant ( ty , & witnesses) {
583
+ for sp in maybe_point_at_variant ( cx , def , witnesses. iter ( ) ) {
579
584
err. span_label ( sp, "not covered" ) ;
580
585
}
581
586
}
582
587
}
583
588
}
584
589
585
- fn maybe_point_at_variant ( ty : Ty < ' _ > , patterns : & [ super :: Pat < ' _ > ] ) -> Vec < Span > {
590
+ fn maybe_point_at_variant < ' a , ' p : ' a , ' tcx : ' a > (
591
+ cx : & MatchCheckCtxt < ' p , ' tcx > ,
592
+ def : & AdtDef ,
593
+ patterns : impl Iterator < Item = & ' a DeconstructedPat < ' p , ' tcx > > ,
594
+ ) -> Vec < Span > {
595
+ use Constructor :: * ;
586
596
let mut covered = vec ! [ ] ;
587
- if let ty:: Adt ( def, _) = ty. kind ( ) {
588
- // Don't point at variants that have already been covered due to other patterns to avoid
589
- // visual clutter.
590
- for pattern in patterns {
591
- use PatKind :: { AscribeUserType , Deref , Leaf , Or , Variant } ;
592
- match & * pattern. kind {
593
- AscribeUserType { subpattern, .. } | Deref { subpattern } => {
594
- covered. extend ( maybe_point_at_variant ( ty, slice:: from_ref ( & subpattern) ) ) ;
595
- }
596
- Variant { adt_def, variant_index, subpatterns, .. } if adt_def. did == def. did => {
597
- let sp = def. variants [ * variant_index] . ident . span ;
598
- if covered. contains ( & sp) {
599
- continue ;
600
- }
601
- covered. push ( sp) ;
602
-
603
- let pats = subpatterns
604
- . iter ( )
605
- . map ( |field_pattern| field_pattern. pattern . clone ( ) )
606
- . collect :: < Box < [ _ ] > > ( ) ;
607
- covered. extend ( maybe_point_at_variant ( ty, & pats) ) ;
608
- }
609
- Leaf { subpatterns } => {
610
- let pats = subpatterns
611
- . iter ( )
612
- . map ( |field_pattern| field_pattern. pattern . clone ( ) )
613
- . collect :: < Box < [ _ ] > > ( ) ;
614
- covered. extend ( maybe_point_at_variant ( ty, & pats) ) ;
597
+ for pattern in patterns {
598
+ if let Variant ( variant_index) = pattern. ctor ( ) {
599
+ if let ty:: Adt ( this_def, _) = pattern. ty ( ) . kind ( ) {
600
+ if this_def. did != def. did {
601
+ continue ;
615
602
}
616
- Or { pats } => {
617
- let pats = pats. iter ( ) . cloned ( ) . collect :: < Box < [ _ ] > > ( ) ;
618
- covered. extend ( maybe_point_at_variant ( ty, & pats) ) ;
619
- }
620
- _ => { }
621
603
}
604
+ let sp = def. variants [ * variant_index] . ident . span ;
605
+ if covered. contains ( & sp) {
606
+ // Don't point at variants that have already been covered due to other patterns to avoid
607
+ // visual clutter.
608
+ continue ;
609
+ }
610
+ covered. push ( sp) ;
622
611
}
612
+ covered. extend ( maybe_point_at_variant ( cx, def, pattern. iter_fields ( ) ) ) ;
623
613
}
624
614
covered
625
615
}
626
616
627
617
/// Check if a by-value binding is by-value. That is, check if the binding's type is not `Copy`.
628
- fn is_binding_by_move ( cx : & MatchVisitor < ' _ , ' _ > , hir_id : HirId , span : Span ) -> bool {
618
+ fn is_binding_by_move ( cx : & MatchVisitor < ' _ , ' _ , ' _ > , hir_id : HirId , span : Span ) -> bool {
629
619
!cx. typeck_results . node_type ( hir_id) . is_copy_modulo_regions ( cx. tcx . at ( span) , cx. param_env )
630
620
}
631
621
@@ -639,7 +629,7 @@ fn is_binding_by_move(cx: &MatchVisitor<'_, '_>, hir_id: HirId, span: Span) -> b
639
629
/// - `x @ Some(ref mut? y)`.
640
630
///
641
631
/// This analysis is *not* subsumed by NLL.
642
- fn check_borrow_conflicts_in_at_patterns ( cx : & MatchVisitor < ' _ , ' _ > , pat : & Pat < ' _ > ) {
632
+ fn check_borrow_conflicts_in_at_patterns ( cx : & MatchVisitor < ' _ , ' _ , ' _ > , pat : & Pat < ' _ > ) {
643
633
// Extract `sub` in `binding @ sub`.
644
634
let ( name, sub) = match & pat. kind {
645
635
hir:: PatKind :: Binding ( .., name, Some ( sub) ) => ( * name, sub) ,
0 commit comments