@@ -5,16 +5,17 @@ use super::_match::{expand_pattern, is_useful, MatchCheckCtxt, Matrix, PatStack}
5
5
use super :: { PatCtxt , PatKind , PatternError } ;
6
6
7
7
use rustc:: hir:: map:: Map ;
8
- use rustc:: lint;
9
- use rustc:: session:: parse:: feature_err;
10
- use rustc:: session:: Session ;
11
8
use rustc:: ty:: { self , Ty , TyCtxt } ;
12
9
use rustc_errors:: { error_code, struct_span_err, Applicability , DiagnosticBuilder } ;
13
10
use rustc_hir as hir;
14
11
use rustc_hir:: def:: * ;
15
12
use rustc_hir:: def_id:: DefId ;
16
13
use rustc_hir:: intravisit:: { self , NestedVisitorMap , Visitor } ;
17
14
use rustc_hir:: { HirId , Pat } ;
15
+ use rustc_session:: lint:: builtin:: BINDINGS_WITH_VARIANT_NAME ;
16
+ use rustc_session:: lint:: builtin:: { IRREFUTABLE_LET_PATTERNS , UNREACHABLE_PATTERNS } ;
17
+ use rustc_session:: parse:: feature_err;
18
+ use rustc_session:: Session ;
18
19
use rustc_span:: symbol:: sym;
19
20
use rustc_span:: { MultiSpan , Span } ;
20
21
use syntax:: ast:: Mutability ;
@@ -67,18 +68,13 @@ impl<'tcx> Visitor<'tcx> for MatchVisitor<'_, 'tcx> {
67
68
hir:: LocalSource :: AwaitDesugar => ( "`await` future binding" , None ) ,
68
69
} ;
69
70
self . check_irrefutable ( & loc. pat , msg, sp) ;
70
-
71
- // Check legality of move bindings and `@` patterns.
72
71
self . check_patterns ( false , & loc. pat ) ;
73
72
}
74
73
75
- fn visit_body ( & mut self , body : & ' tcx hir:: Body < ' tcx > ) {
76
- intravisit:: walk_body ( self , body) ;
77
-
78
- for param in body. params {
79
- self . check_irrefutable ( & param. pat , "function argument" , None ) ;
80
- self . check_patterns ( false , & param. pat ) ;
81
- }
74
+ fn visit_param ( & mut self , param : & ' tcx hir:: Param < ' tcx > ) {
75
+ intravisit:: walk_param ( self , param) ;
76
+ self . check_irrefutable ( & param. pat , "function argument" , None ) ;
77
+ self . check_patterns ( false , & param. pat ) ;
82
78
}
83
79
}
84
80
@@ -123,6 +119,25 @@ impl<'tcx> MatchVisitor<'_, 'tcx> {
123
119
if !self . tcx . features ( ) . bindings_after_at {
124
120
check_legality_of_bindings_in_at_patterns ( self , pat) ;
125
121
}
122
+ check_for_bindings_named_same_as_variants ( self , pat) ;
123
+ }
124
+
125
+ fn lower_pattern < ' p > (
126
+ & self ,
127
+ cx : & mut MatchCheckCtxt < ' p , ' tcx > ,
128
+ pat : & ' tcx hir:: Pat < ' tcx > ,
129
+ have_errors : & mut bool ,
130
+ ) -> ( & ' p super :: Pat < ' tcx > , Ty < ' tcx > ) {
131
+ let mut patcx = PatCtxt :: new ( self . tcx , self . param_env , self . tables ) ;
132
+ patcx. include_lint_checks ( ) ;
133
+ let pattern = patcx. lower_pattern ( pat) ;
134
+ let pattern_ty = pattern. ty ;
135
+ let pattern: & _ = cx. pattern_arena . alloc ( expand_pattern ( cx, pattern) ) ;
136
+ if !patcx. errors . is_empty ( ) {
137
+ * have_errors = true ;
138
+ patcx. report_inlining_errors ( pat. span ) ;
139
+ }
140
+ ( pattern, pattern_ty)
126
141
}
127
142
128
143
fn check_match (
@@ -132,11 +147,8 @@ impl<'tcx> MatchVisitor<'_, 'tcx> {
132
147
source : hir:: MatchSource ,
133
148
) {
134
149
for arm in arms {
135
- // First, check legality of move bindings .
150
+ // Check the arm for some things unrelated to exhaustiveness .
136
151
self . check_patterns ( arm. guard . is_some ( ) , & arm. pat ) ;
137
-
138
- // Second, perform some lints.
139
- check_for_bindings_named_same_as_variants ( self , & arm. pat ) ;
140
152
}
141
153
142
154
let module = self . tcx . hir ( ) . get_module_parent ( scrut. hir_id ) ;
@@ -145,16 +157,8 @@ impl<'tcx> MatchVisitor<'_, 'tcx> {
145
157
146
158
let inlined_arms: Vec < _ > = arms
147
159
. iter ( )
148
- . map ( |arm| {
149
- let mut patcx = PatCtxt :: new ( self . tcx , self . param_env , self . tables ) ;
150
- patcx. include_lint_checks ( ) ;
151
- let pattern = patcx. lower_pattern ( & arm. pat ) ;
152
- let pattern: & _ = cx. pattern_arena . alloc ( expand_pattern ( cx, pattern) ) ;
153
- if !patcx. errors . is_empty ( ) {
154
- patcx. report_inlining_errors ( arm. pat . span ) ;
155
- have_errors = true ;
156
- }
157
- ( pattern, & * arm. pat , arm. guard . is_some ( ) )
160
+ . map ( |hir:: Arm { pat, guard, .. } | {
161
+ ( self . lower_pattern ( cx, pat, & mut have_errors) . 0 , pat. hir_id , guard. is_some ( ) )
158
162
} )
159
163
. collect ( ) ;
160
164
@@ -178,11 +182,7 @@ impl<'tcx> MatchVisitor<'_, 'tcx> {
178
182
fn check_irrefutable ( & self , pat : & ' tcx Pat < ' tcx > , origin : & str , sp : Option < Span > ) {
179
183
let module = self . tcx . hir ( ) . get_module_parent ( pat. hir_id ) ;
180
184
MatchCheckCtxt :: create_and_enter ( self . tcx , self . param_env , module, |ref mut cx| {
181
- let mut patcx = PatCtxt :: new ( self . tcx , self . param_env , self . tables ) ;
182
- patcx. include_lint_checks ( ) ;
183
- let pattern = patcx. lower_pattern ( pat) ;
184
- let pattern_ty = pattern. ty ;
185
- let pattern = cx. pattern_arena . alloc ( expand_pattern ( cx, pattern) ) ;
185
+ let ( pattern, pattern_ty) = self . lower_pattern ( cx, pat, & mut false ) ;
186
186
let pats: Matrix < ' _ , ' _ > = vec ! [ PatStack :: from_pattern( pattern) ] . into_iter ( ) . collect ( ) ;
187
187
188
188
let witnesses = match check_not_useful ( cx, pattern_ty, & pats, pat. hir_id ) {
@@ -285,7 +285,7 @@ fn check_for_bindings_named_same_as_variants(cx: &MatchVisitor<'_, '_>, pat: &Pa
285
285
let ty_path = cx. tcx . def_path_str ( edef. did ) ;
286
286
cx. tcx
287
287
. struct_span_lint_hir (
288
- lint :: builtin :: BINDINGS_WITH_VARIANT_NAME ,
288
+ BINDINGS_WITH_VARIANT_NAME ,
289
289
p. hir_id ,
290
290
p. span ,
291
291
& format ! (
@@ -310,79 +310,63 @@ fn check_for_bindings_named_same_as_variants(cx: &MatchVisitor<'_, '_>, pat: &Pa
310
310
}
311
311
312
312
/// Checks for common cases of "catchall" patterns that may not be intended as such.
313
- fn pat_is_catchall ( pat : & Pat < ' _ > ) -> bool {
314
- match pat . kind {
315
- hir :: PatKind :: Binding ( .. , None ) => true ,
316
- hir :: PatKind :: Binding ( .. , Some ( ref s ) ) => pat_is_catchall ( s ) ,
317
- hir :: PatKind :: Ref ( ref s , _ ) => pat_is_catchall ( s) ,
318
- hir :: PatKind :: Tuple ( ref v , _ ) => v . iter ( ) . all ( |p| pat_is_catchall ( & p) ) ,
313
+ fn pat_is_catchall ( pat : & super :: Pat < ' _ > ) -> bool {
314
+ use super :: PatKind :: * ;
315
+ match & * pat . kind {
316
+ Binding { subpattern : None , .. } => true ,
317
+ Binding { subpattern : Some ( s ) , .. } | Deref { subpattern : s } => pat_is_catchall ( s) ,
318
+ Leaf { subpatterns : s } => s . iter ( ) . all ( |p| pat_is_catchall ( & p. pattern ) ) ,
319
319
_ => false ,
320
320
}
321
321
}
322
322
323
+ fn unreachable_pattern ( tcx : TyCtxt < ' _ > , span : Span , id : HirId , catchall : Option < Span > ) {
324
+ let mut err = tcx. struct_span_lint_hir ( UNREACHABLE_PATTERNS , id, span, "unreachable pattern" ) ;
325
+ if let Some ( catchall) = catchall {
326
+ // We had a catchall pattern, hint at that.
327
+ err. span_label ( span, "unreachable pattern" ) ;
328
+ err. span_label ( catchall, "matches any value" ) ;
329
+ }
330
+ err. emit ( ) ;
331
+ }
332
+
333
+ fn irrefutable_let_pattern ( tcx : TyCtxt < ' _ > , span : Span , id : HirId , source : hir:: MatchSource ) {
334
+ let msg = match source {
335
+ hir:: MatchSource :: IfLetDesugar { .. } => "irrefutable if-let pattern" ,
336
+ hir:: MatchSource :: WhileLetDesugar => "irrefutable while-let pattern" ,
337
+ _ => bug ! ( ) ,
338
+ } ;
339
+ tcx. lint_hir ( IRREFUTABLE_LET_PATTERNS , id, span, msg) ;
340
+ }
341
+
323
342
/// Check for unreachable patterns.
324
343
fn check_arms < ' p , ' tcx > (
325
344
cx : & mut MatchCheckCtxt < ' p , ' tcx > ,
326
- arms : & [ ( & ' p super :: Pat < ' tcx > , & hir :: Pat < ' _ > , bool ) ] ,
345
+ arms : & [ ( & ' p super :: Pat < ' tcx > , HirId , bool ) ] ,
327
346
source : hir:: MatchSource ,
328
347
) -> Matrix < ' p , ' tcx > {
329
348
let mut seen = Matrix :: empty ( ) ;
330
349
let mut catchall = None ;
331
- for ( arm_index, ( pat, hir_pat , has_guard) ) in arms. iter ( ) . enumerate ( ) {
350
+ for ( arm_index, ( pat, id , has_guard) ) in arms. iter ( ) . copied ( ) . enumerate ( ) {
332
351
let v = PatStack :: from_pattern ( pat) ;
333
-
334
- match is_useful ( cx, & seen, & v, LeaveOutWitness , hir_pat. hir_id , true ) {
352
+ match is_useful ( cx, & seen, & v, LeaveOutWitness , id, true ) {
335
353
NotUseful => {
336
354
match source {
337
355
hir:: MatchSource :: IfDesugar { .. } | hir:: MatchSource :: WhileDesugar => bug ! ( ) ,
338
356
339
357
hir:: MatchSource :: IfLetDesugar { .. } | hir:: MatchSource :: WhileLetDesugar => {
340
- // check which arm we're on.
358
+ // Check which arm we're on.
341
359
match arm_index {
342
360
// The arm with the user-specified pattern.
343
- 0 => {
344
- cx. tcx . lint_hir (
345
- lint:: builtin:: UNREACHABLE_PATTERNS ,
346
- hir_pat. hir_id ,
347
- pat. span ,
348
- "unreachable pattern" ,
349
- ) ;
350
- }
361
+ 0 => unreachable_pattern ( cx. tcx , pat. span , id, None ) ,
351
362
// The arm with the wildcard pattern.
352
- 1 => {
353
- let msg = match source {
354
- hir:: MatchSource :: IfLetDesugar { .. } => {
355
- "irrefutable if-let pattern"
356
- }
357
- hir:: MatchSource :: WhileLetDesugar => {
358
- "irrefutable while-let pattern"
359
- }
360
- _ => bug ! ( ) ,
361
- } ;
362
- cx. tcx . lint_hir (
363
- lint:: builtin:: IRREFUTABLE_LET_PATTERNS ,
364
- hir_pat. hir_id ,
365
- pat. span ,
366
- msg,
367
- ) ;
368
- }
363
+ 1 => irrefutable_let_pattern ( cx. tcx , pat. span , id, source) ,
369
364
_ => bug ! ( ) ,
370
365
}
371
366
}
372
367
373
368
hir:: MatchSource :: ForLoopDesugar | hir:: MatchSource :: Normal => {
374
- let mut err = cx. tcx . struct_span_lint_hir (
375
- lint:: builtin:: UNREACHABLE_PATTERNS ,
376
- hir_pat. hir_id ,
377
- pat. span ,
378
- "unreachable pattern" ,
379
- ) ;
380
- // if we had a catchall pattern, hint at that
381
- if let Some ( catchall) = catchall {
382
- err. span_label ( pat. span , "unreachable pattern" ) ;
383
- err. span_label ( catchall, "matches any value" ) ;
384
- }
385
- err. emit ( ) ;
369
+ unreachable_pattern ( cx. tcx , pat. span , id, catchall) ;
386
370
}
387
371
388
372
// Unreachable patterns in try and await expressions occur when one of
@@ -392,19 +376,14 @@ fn check_arms<'p, 'tcx>(
392
376
}
393
377
Useful ( unreachable_subpatterns) => {
394
378
for pat in unreachable_subpatterns {
395
- cx. tcx . lint_hir (
396
- lint:: builtin:: UNREACHABLE_PATTERNS ,
397
- hir_pat. hir_id ,
398
- pat. span ,
399
- "unreachable pattern" ,
400
- ) ;
379
+ unreachable_pattern ( cx. tcx , pat. span , id, None ) ;
401
380
}
402
381
}
403
382
UsefulWithWitness ( _) => bug ! ( ) ,
404
383
}
405
384
if !has_guard {
406
385
seen. push ( v) ;
407
- if catchall. is_none ( ) && pat_is_catchall ( hir_pat ) {
386
+ if catchall. is_none ( ) && pat_is_catchall ( pat ) {
408
387
catchall = Some ( pat. span ) ;
409
388
}
410
389
}
0 commit comments