@@ -5,16 +5,17 @@ use super::_match::{expand_pattern, is_useful, MatchCheckCtxt, Matrix, PatStack}
55use super :: { PatCtxt , PatKind , PatternError } ;
66
77use rustc:: hir:: map:: Map ;
8- use rustc:: lint;
9- use rustc:: session:: parse:: feature_err;
10- use rustc:: session:: Session ;
118use rustc:: ty:: { self , Ty , TyCtxt } ;
129use rustc_errors:: { error_code, struct_span_err, Applicability , DiagnosticBuilder } ;
1310use rustc_hir as hir;
1411use rustc_hir:: def:: * ;
1512use rustc_hir:: def_id:: DefId ;
1613use rustc_hir:: intravisit:: { self , NestedVisitorMap , Visitor } ;
1714use 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 ;
1819use rustc_span:: symbol:: sym;
1920use rustc_span:: { MultiSpan , Span } ;
2021use syntax:: ast:: Mutability ;
@@ -67,18 +68,13 @@ impl<'tcx> Visitor<'tcx> for MatchVisitor<'_, 'tcx> {
6768 hir:: LocalSource :: AwaitDesugar => ( "`await` future binding" , None ) ,
6869 } ;
6970 self . check_irrefutable ( & loc. pat , msg, sp) ;
70-
71- // Check legality of move bindings and `@` patterns.
7271 self . check_patterns ( false , & loc. pat ) ;
7372 }
7473
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 ) ;
8278 }
8379}
8480
@@ -123,6 +119,25 @@ impl<'tcx> MatchVisitor<'_, 'tcx> {
123119 if !self . tcx . features ( ) . bindings_after_at {
124120 check_legality_of_bindings_in_at_patterns ( self , pat) ;
125121 }
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)
126141 }
127142
128143 fn check_match (
@@ -132,11 +147,8 @@ impl<'tcx> MatchVisitor<'_, 'tcx> {
132147 source : hir:: MatchSource ,
133148 ) {
134149 for arm in arms {
135- // First, check legality of move bindings .
150+ // Check the arm for some things unrelated to exhaustiveness .
136151 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 ) ;
140152 }
141153
142154 let module = self . tcx . hir ( ) . get_module_parent ( scrut. hir_id ) ;
@@ -145,16 +157,8 @@ impl<'tcx> MatchVisitor<'_, 'tcx> {
145157
146158 let inlined_arms: Vec < _ > = arms
147159 . 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 ( ) )
158162 } )
159163 . collect ( ) ;
160164
@@ -178,11 +182,7 @@ impl<'tcx> MatchVisitor<'_, 'tcx> {
178182 fn check_irrefutable ( & self , pat : & ' tcx Pat < ' tcx > , origin : & str , sp : Option < Span > ) {
179183 let module = self . tcx . hir ( ) . get_module_parent ( pat. hir_id ) ;
180184 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 ) ;
186186 let pats: Matrix < ' _ , ' _ > = vec ! [ PatStack :: from_pattern( pattern) ] . into_iter ( ) . collect ( ) ;
187187
188188 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
285285 let ty_path = cx. tcx . def_path_str ( edef. did ) ;
286286 cx. tcx
287287 . struct_span_lint_hir (
288- lint :: builtin :: BINDINGS_WITH_VARIANT_NAME ,
288+ BINDINGS_WITH_VARIANT_NAME ,
289289 p. hir_id ,
290290 p. span ,
291291 & format ! (
@@ -310,79 +310,63 @@ fn check_for_bindings_named_same_as_variants(cx: &MatchVisitor<'_, '_>, pat: &Pa
310310}
311311
312312/// 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 ) ) ,
319319 _ => false ,
320320 }
321321}
322322
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+
323342/// Check for unreachable patterns.
324343fn check_arms < ' p , ' tcx > (
325344 cx : & mut MatchCheckCtxt < ' p , ' tcx > ,
326- arms : & [ ( & ' p super :: Pat < ' tcx > , & hir :: Pat < ' _ > , bool ) ] ,
345+ arms : & [ ( & ' p super :: Pat < ' tcx > , HirId , bool ) ] ,
327346 source : hir:: MatchSource ,
328347) -> Matrix < ' p , ' tcx > {
329348 let mut seen = Matrix :: empty ( ) ;
330349 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 ( ) {
332351 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 ) {
335353 NotUseful => {
336354 match source {
337355 hir:: MatchSource :: IfDesugar { .. } | hir:: MatchSource :: WhileDesugar => bug ! ( ) ,
338356
339357 hir:: MatchSource :: IfLetDesugar { .. } | hir:: MatchSource :: WhileLetDesugar => {
340- // check which arm we're on.
358+ // Check which arm we're on.
341359 match arm_index {
342360 // 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 ) ,
351362 // 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) ,
369364 _ => bug ! ( ) ,
370365 }
371366 }
372367
373368 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) ;
386370 }
387371
388372 // Unreachable patterns in try and await expressions occur when one of
@@ -392,19 +376,14 @@ fn check_arms<'p, 'tcx>(
392376 }
393377 Useful ( unreachable_subpatterns) => {
394378 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 ) ;
401380 }
402381 }
403382 UsefulWithWitness ( _) => bug ! ( ) ,
404383 }
405384 if !has_guard {
406385 seen. push ( v) ;
407- if catchall. is_none ( ) && pat_is_catchall ( hir_pat ) {
386+ if catchall. is_none ( ) && pat_is_catchall ( pat ) {
408387 catchall = Some ( pat. span ) ;
409388 }
410389 }
0 commit comments