1+ use super :: deconstruct_pat:: { Constructor , DeconstructedPat } ;
12use super :: usefulness:: {
2- compute_match_usefulness, expand_pattern, is_wildcard, MatchArm , MatchCheckCtxt , Reachability ,
3- UsefulnessReport ,
3+ compute_match_usefulness, MatchArm , MatchCheckCtxt , Reachability , UsefulnessReport ,
44} ;
55use super :: { PatCtxt , PatternError } ;
66
@@ -12,26 +12,25 @@ use rustc_hir::def::*;
1212use rustc_hir:: def_id:: DefId ;
1313use rustc_hir:: intravisit:: { self , NestedVisitorMap , Visitor } ;
1414use 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 } ;
1716use rustc_session:: lint:: builtin:: {
1817 BINDINGS_WITH_VARIANT_NAME , IRREFUTABLE_LET_PATTERNS , UNREACHABLE_PATTERNS ,
1918} ;
2019use rustc_session:: Session ;
2120use rustc_span:: { DesugaringKind , ExpnKind , Span } ;
22- use std:: slice;
2321
2422crate fn check_match ( tcx : TyCtxt < ' _ > , def_id : DefId ) {
2523 let body_id = match def_id. as_local ( ) {
2624 None => return ,
2725 Some ( id) => tcx. hir ( ) . body_owned_by ( tcx. hir ( ) . local_def_id_to_hir_id ( id) ) ,
2826 } ;
2927
28+ let pattern_arena = TypedArena :: default ( ) ;
3029 let mut visitor = MatchVisitor {
3130 tcx,
3231 typeck_results : tcx. typeck_body ( body_id) ,
3332 param_env : tcx. param_env ( def_id) ,
34- pattern_arena : TypedArena :: default ( ) ,
33+ pattern_arena : & pattern_arena ,
3534 } ;
3635 visitor. visit_body ( tcx. hir ( ) . body ( body_id) ) ;
3736}
@@ -40,14 +39,14 @@ fn create_e0004(sess: &Session, sp: Span, error_message: String) -> DiagnosticBu
4039 struct_span_err ! ( sess, sp, E0004 , "{}" , & error_message)
4140}
4241
43- struct MatchVisitor < ' a , ' tcx > {
42+ struct MatchVisitor < ' a , ' p , ' tcx > {
4443 tcx : TyCtxt < ' tcx > ,
4544 typeck_results : & ' a ty:: TypeckResults < ' tcx > ,
4645 param_env : ty:: ParamEnv < ' tcx > ,
47- pattern_arena : TypedArena < super :: Pat < ' tcx > > ,
46+ pattern_arena : & ' p TypedArena < DeconstructedPat < ' p , ' tcx > > ,
4847}
4948
50- impl < ' tcx > Visitor < ' tcx > for MatchVisitor < ' _ , ' tcx > {
49+ impl < ' tcx > Visitor < ' tcx > for MatchVisitor < ' _ , ' _ , ' tcx > {
5150 type Map = intravisit:: ErasedMap < ' tcx > ;
5251
5352 fn nested_visit_map ( & mut self ) -> NestedVisitorMap < Self :: Map > {
@@ -113,31 +112,30 @@ impl PatCtxt<'_, '_> {
113112 }
114113}
115114
116- impl < ' tcx > MatchVisitor < ' _ , ' tcx > {
115+ impl < ' p , ' tcx > MatchVisitor < ' _ , ' p , ' tcx > {
117116 fn check_patterns ( & self , pat : & Pat < ' _ > ) {
118117 pat. walk_always ( |pat| check_borrow_conflicts_in_at_patterns ( self , pat) ) ;
119118 check_for_bindings_named_same_as_variants ( self , pat) ;
120119 }
121120
122- fn lower_pattern < ' p > (
121+ fn lower_pattern (
123122 & self ,
124123 cx : & mut MatchCheckCtxt < ' p , ' tcx > ,
125124 pat : & ' tcx hir:: Pat < ' tcx > ,
126125 have_errors : & mut bool ,
127- ) -> ( & ' p super :: Pat < ' tcx > , Ty < ' tcx > ) {
126+ ) -> & ' p DeconstructedPat < ' p , ' tcx > {
128127 let mut patcx = PatCtxt :: new ( self . tcx , self . param_env , self . typeck_results ) ;
129128 patcx. include_lint_checks ( ) ;
130129 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) ) ;
133131 if !patcx. errors . is_empty ( ) {
134132 * have_errors = true ;
135133 patcx. report_inlining_errors ( ) ;
136134 }
137- ( pattern, pattern_ty )
135+ pattern
138136 }
139137
140- fn new_cx ( & self , hir_id : HirId ) -> MatchCheckCtxt < ' _ , ' tcx > {
138+ fn new_cx ( & self , hir_id : HirId ) -> MatchCheckCtxt < ' p , ' tcx > {
141139 MatchCheckCtxt {
142140 tcx : self . tcx ,
143141 param_env : self . param_env ,
@@ -149,8 +147,8 @@ impl<'tcx> MatchVisitor<'_, 'tcx> {
149147 fn check_let ( & mut self , pat : & ' tcx hir:: Pat < ' tcx > , expr : & hir:: Expr < ' _ > , span : Span ) {
150148 self . check_patterns ( pat) ;
151149 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) ;
154152 }
155153
156154 fn check_match (
@@ -166,8 +164,8 @@ impl<'tcx> MatchVisitor<'_, 'tcx> {
166164 self . check_patterns ( & arm. pat ) ;
167165 if let Some ( hir:: Guard :: IfLet ( ref pat, _) ) = arm. guard {
168166 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 ( ) ) ;
171169 }
172170 }
173171
@@ -176,7 +174,7 @@ impl<'tcx> MatchVisitor<'_, 'tcx> {
176174 let arms: Vec < _ > = arms
177175 . iter ( )
178176 . 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) ,
180178 hir_id : pat. hir_id ,
181179 has_guard : guard. is_some ( ) ,
182180 } )
@@ -210,7 +208,8 @@ impl<'tcx> MatchVisitor<'_, 'tcx> {
210208 fn check_irrefutable ( & self , pat : & ' tcx Pat < ' tcx > , origin : & str , sp : Option < Span > ) {
211209 let mut cx = self . new_cx ( pat. hir_id ) ;
212210
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 ( ) ;
214213 let arms = vec ! [ MatchArm { pat: pattern, hir_id: pat. hir_id, has_guard: false } ] ;
215214 let report = compute_match_usefulness ( & cx, & arms, pat. hir_id , pattern_ty) ;
216215
@@ -222,7 +221,7 @@ impl<'tcx> MatchVisitor<'_, 'tcx> {
222221 return ;
223222 }
224223
225- let joined_patterns = joined_uncovered_patterns ( & witnesses) ;
224+ let joined_patterns = joined_uncovered_patterns ( & cx , & witnesses) ;
226225 let mut err = struct_span_err ! (
227226 self . tcx. sess,
228227 pat. span,
@@ -298,7 +297,7 @@ fn const_not_var(
298297 }
299298}
300299
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 < ' _ > ) {
302301 pat. walk_always ( |p| {
303302 if let hir:: PatKind :: Binding ( _, _, ident, None ) = p. kind {
304303 if let Some ( ty:: BindByValue ( hir:: Mutability :: Not ) ) =
@@ -340,12 +339,11 @@ fn check_for_bindings_named_same_as_variants(cx: &MatchVisitor<'_, '_>, pat: &Pa
340339}
341340
342341/// 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) ) ,
349347 _ => false ,
350348 }
351349}
@@ -424,11 +422,11 @@ fn irrefutable_let_pattern(tcx: TyCtxt<'_>, id: HirId, span: Span) {
424422fn check_let_reachability < ' p , ' tcx > (
425423 cx : & mut MatchCheckCtxt < ' p , ' tcx > ,
426424 pat_id : HirId ,
427- pat : & ' p super :: Pat < ' tcx > ,
425+ pat : & ' p DeconstructedPat < ' p , ' tcx > ,
428426 span : Span ,
429427) {
430428 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 ( ) ) ;
432430
433431 // Report if the pattern is unreachable, which can only occur when the type is uninhabited.
434432 // 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>(
450448 let mut catchall = None ;
451449 for ( arm, is_useful) in report. arm_usefulness . iter ( ) {
452450 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) ,
454452 Reachable ( unreachables) if unreachables. is_empty ( ) => { }
455453 // The arm is reachable, but contains unreachable subpatterns (from or-patterns).
456454 Reachable ( unreachables) => {
@@ -463,7 +461,7 @@ fn report_arm_reachability<'p, 'tcx>(
463461 }
464462 }
465463 if !arm. has_guard && catchall. is_none ( ) && pat_is_catchall ( arm. pat ) {
466- catchall = Some ( arm. pat . span ) ;
464+ catchall = Some ( arm. pat . span ( ) ) ;
467465 }
468466 }
469467}
@@ -473,7 +471,7 @@ fn non_exhaustive_match<'p, 'tcx>(
473471 cx : & MatchCheckCtxt < ' p , ' tcx > ,
474472 scrut_ty : Ty < ' tcx > ,
475473 sp : Span ,
476- witnesses : Vec < super :: Pat < ' tcx > > ,
474+ witnesses : Vec < DeconstructedPat < ' p , ' tcx > > ,
477475 is_empty_match : bool ,
478476) {
479477 let non_empty_enum = match scrut_ty. kind ( ) {
@@ -490,7 +488,7 @@ fn non_exhaustive_match<'p, 'tcx>(
490488 format ! ( "non-exhaustive patterns: type `{}` is non-empty" , scrut_ty) ,
491489 ) ;
492490 } else {
493- let joined_patterns = joined_uncovered_patterns ( & witnesses) ;
491+ let joined_patterns = joined_uncovered_patterns ( cx , & witnesses) ;
494492 err = create_e0004 (
495493 cx. tcx . sess ,
496494 sp,
@@ -517,7 +515,7 @@ fn non_exhaustive_match<'p, 'tcx>(
517515 if ( scrut_ty == cx. tcx . types . usize || scrut_ty == cx. tcx . types . isize )
518516 && !is_empty_match
519517 && witnesses. len ( ) == 1
520- && is_wildcard ( & witnesses[ 0 ] )
518+ && matches ! ( witnesses[ 0 ] . ctor ( ) , Constructor :: NonExhaustive )
521519 {
522520 err. note ( & format ! (
523521 "`{}` does not have a fixed maximum value, \
@@ -540,33 +538,40 @@ fn non_exhaustive_match<'p, 'tcx>(
540538 err. emit ( ) ;
541539}
542540
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 {
544545 const LIMIT : usize = 3 ;
546+ let pat_to_str = |pat : & DeconstructedPat < ' p , ' tcx > | pat. to_pat ( cx) . to_string ( ) ;
545547 match witnesses {
546548 [ ] => bug ! ( ) ,
547- [ witness] => format ! ( "`{}`" , witness) ,
549+ [ witness] => format ! ( "`{}`" , witness. to_pat ( cx ) ) ,
548550 [ 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 ) )
551553 }
552554 _ => {
553555 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 ( ) ;
555557 format ! ( "`{}` and {} more" , head. join( "`, `" ) , tail. len( ) )
556558 }
557559 }
558560}
559561
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 {
561566 format ! ( "pattern{} {} not covered" , rustc_errors:: pluralize!( witnesses. len( ) ) , joined_patterns)
562567}
563568
564569/// 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 > ,
567572 err : & mut DiagnosticBuilder < ' _ > ,
568- ty : Ty < ' _ > ,
569- witnesses : & [ super :: Pat < ' _ > ] ,
573+ ty : Ty < ' tcx > ,
574+ witnesses : & [ DeconstructedPat < ' p , ' tcx > ] ,
570575) {
571576 let ty = ty. peel_refs ( ) ;
572577 if let ty:: Adt ( def, _) = ty. kind ( ) {
@@ -575,57 +580,42 @@ fn adt_defined_here(
575580 }
576581
577582 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 ( ) ) {
579584 err. span_label ( sp, "not covered" ) ;
580585 }
581586 }
582587 }
583588}
584589
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 :: * ;
586596 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 ;
615602 }
616- Or { pats } => {
617- let pats = pats. iter ( ) . cloned ( ) . collect :: < Box < [ _ ] > > ( ) ;
618- covered. extend ( maybe_point_at_variant ( ty, & pats) ) ;
619- }
620- _ => { }
621603 }
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) ;
622611 }
612+ covered. extend ( maybe_point_at_variant ( cx, def, pattern. iter_fields ( ) ) ) ;
623613 }
624614 covered
625615}
626616
627617/// 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 {
629619 !cx. typeck_results . node_type ( hir_id) . is_copy_modulo_regions ( cx. tcx . at ( span) , cx. param_env )
630620}
631621
@@ -639,7 +629,7 @@ fn is_binding_by_move(cx: &MatchVisitor<'_, '_>, hir_id: HirId, span: Span) -> b
639629/// - `x @ Some(ref mut? y)`.
640630///
641631/// 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 < ' _ > ) {
643633 // Extract `sub` in `binding @ sub`.
644634 let ( name, sub) = match & pat. kind {
645635 hir:: PatKind :: Binding ( .., name, Some ( sub) ) => ( * name, sub) ,
0 commit comments