@@ -23,6 +23,7 @@ use crate::constructor::{
2323} ; 
2424use  crate :: lints:: lint_nonexhaustive_missing_variants; 
2525use  crate :: pat_column:: PatternColumn ; 
26+ use  crate :: rustc:: print:: EnumInfo ; 
2627use  crate :: usefulness:: { compute_match_usefulness,  PlaceValidity } ; 
2728use  crate :: { errors,  Captures ,  PatCx ,  PrivateUninhabitedField } ; 
2829
@@ -824,77 +825,64 @@ impl<'p, 'tcx: 'p> RustcPatCtxt<'p, 'tcx> {
824825     fn  hoist_witness_pat ( & self ,  pat :  & WitnessPat < ' p ,  ' tcx > )  -> print:: Pat < ' tcx >  { 
825826        use  print:: { FieldPat ,  Pat ,  PatKind } ; 
826827        let  cx = self ; 
827-         let  is_wildcard = |pat :  & Pat < ' _ > | matches ! ( pat. kind,  PatKind :: Wild ) ; 
828-         let  mut  subpatterns = pat. iter_fields ( ) . map ( |p| Box :: new ( cx. hoist_witness_pat ( p) ) ) ; 
828+         let  hoist = |p| Box :: new ( cx. hoist_witness_pat ( p) ) ; 
829829        let  kind = match  pat. ctor ( )  { 
830830            Bool ( b)  => PatKind :: Constant  {  value :  mir:: Const :: from_bool ( cx. tcx ,  * b)  } , 
831831            IntRange ( range)  => return  self . hoist_pat_range ( range,  * pat. ty ( ) ) , 
832-             Struct  | Variant ( _)  | UnionField  => match  pat. ty ( ) . kind ( )  { 
833-                 ty:: Tuple ( ..)  => PatKind :: Leaf  { 
834-                     subpatterns :  subpatterns
835-                         . enumerate ( ) 
836-                         . map ( |( i,  pattern) | FieldPat  {  field :  FieldIdx :: new ( i) ,  pattern } ) 
837-                         . collect ( ) , 
838-                 } , 
839-                 ty:: Adt ( adt_def,  _)  if  adt_def. is_box ( )  => { 
840-                     // Without `box_patterns`, the only legal pattern of type `Box` is `_` (outside 
841-                     // of `std`). So this branch is only reachable when the feature is enabled and 
842-                     // the pattern is a box pattern. 
843-                     PatKind :: Deref  {  subpattern :  subpatterns. next ( ) . unwrap ( )  } 
844-                 } 
845-                 ty:: Adt ( adt_def,  _args)  => { 
846-                     let  variant_index = RustcPatCtxt :: variant_index_for_adt ( & pat. ctor ( ) ,  * adt_def) ; 
847-                     let  subpatterns = subpatterns
848-                         . enumerate ( ) 
849-                         . map ( |( i,  pattern) | FieldPat  {  field :  FieldIdx :: new ( i) ,  pattern } ) 
850-                         . collect ( ) ; 
832+             Struct  if  pat. ty ( ) . is_box ( )  => { 
833+                 // Outside of the `alloc` crate, the only way to create a struct pattern 
834+                 // of type `Box` is to use a `box` pattern via #[feature(box_patterns)]. 
835+                 PatKind :: Box  {  subpattern :  hoist ( & pat. fields [ 0 ] )  } 
836+             } 
837+             Struct  | Variant ( _)  | UnionField  => { 
838+                 let  enum_info = match  * pat. ty ( ) . kind ( )  { 
839+                     ty:: Adt ( adt_def,  _)  if  adt_def. is_enum ( )  => EnumInfo :: Enum  { 
840+                         adt_def, 
841+                         variant_index :  RustcPatCtxt :: variant_index_for_adt ( pat. ctor ( ) ,  adt_def) , 
842+                     } , 
843+                     ty:: Adt ( ..)  | ty:: Tuple ( ..)  => EnumInfo :: NotEnum , 
844+                     _ => bug ! ( "unexpected ctor for type {:?} {:?}" ,  pat. ctor( ) ,  * pat. ty( ) ) , 
845+                 } ; 
851846
852-                     if  adt_def. is_enum ( )  { 
853-                         PatKind :: Variant  {  adt_def :  * adt_def,  variant_index,  subpatterns } 
854-                     }  else  { 
855-                         PatKind :: Leaf  {  subpatterns } 
856-                     } 
857-                 } 
858-                 _ => bug ! ( "unexpected ctor for type {:?} {:?}" ,  pat. ctor( ) ,  * pat. ty( ) ) , 
859-             } , 
860-             // Note: given the expansion of `&str` patterns done in `expand_pattern`, we should 
861-             // be careful to reconstruct the correct constant pattern here. However a string 
862-             // literal pattern will never be reported as a non-exhaustiveness witness, so we 
863-             // ignore this issue. 
864-             Ref  => PatKind :: Deref  {  subpattern :  subpatterns. next ( ) . unwrap ( )  } , 
847+                 let  subpatterns = pat
848+                     . iter_fields ( ) 
849+                     . enumerate ( ) 
850+                     . map ( |( i,  pat) | FieldPat  {  field :  FieldIdx :: new ( i) ,  pattern :  hoist ( pat)  } ) 
851+                     . collect :: < Vec < _ > > ( ) ; 
852+ 
853+                 PatKind :: StructLike  {  enum_info,  subpatterns } 
854+             } 
855+             Ref  => PatKind :: Deref  {  subpattern :  hoist ( & pat. fields [ 0 ] )  } , 
865856            Slice ( slice)  => { 
866-                 match  slice. kind  { 
867-                     SliceKind :: FixedLen ( _)  => PatKind :: Slice  { 
868-                         prefix :  subpatterns. collect ( ) , 
869-                         slice :  None , 
870-                         suffix :  Box :: new ( [ ] ) , 
871-                     } , 
872-                     SliceKind :: VarLen ( prefix,  _)  => { 
873-                         let  mut  subpatterns = subpatterns. peekable ( ) ; 
874-                         let  mut  prefix:  Vec < _ >  = subpatterns. by_ref ( ) . take ( prefix) . collect ( ) ; 
875-                         if  slice. array_len . is_some ( )  { 
876-                             // Improves diagnostics a bit: if the type is a known-size array, instead 
877-                             // of reporting `[x, _, .., _, y]`, we prefer to report `[x, .., y]`. 
878-                             // This is incorrect if the size is not known, since `[_, ..]` captures 
879-                             // arrays of lengths `>= 1` whereas `[..]` captures any length. 
880-                             while  !prefix. is_empty ( )  && is_wildcard ( prefix. last ( ) . unwrap ( ) )  { 
881-                                 prefix. pop ( ) ; 
882-                             } 
883-                             while  subpatterns. peek ( ) . is_some ( ) 
884-                                 && is_wildcard ( subpatterns. peek ( ) . unwrap ( ) ) 
885-                             { 
886-                                 subpatterns. next ( ) ; 
887-                             } 
888-                         } 
889-                         let  suffix:  Box < [ _ ] >  = subpatterns. collect ( ) ; 
890-                         let  wild = Pat  {  ty :  pat. ty ( ) . inner ( ) ,  kind :  PatKind :: Wild  } ; 
891-                         PatKind :: Slice  { 
892-                             prefix :  prefix. into_boxed_slice ( ) , 
893-                             slice :  Some ( Box :: new ( wild) ) , 
894-                             suffix, 
895-                         } 
857+                 let  ( prefix_len,  has_dot_dot)  = match  slice. kind  { 
858+                     SliceKind :: FixedLen ( len)  => ( len,  false ) , 
859+                     SliceKind :: VarLen ( prefix_len,  _)  => ( prefix_len,  true ) , 
860+                 } ; 
861+ 
862+                 let  ( mut  prefix,  mut  suffix)  = pat. fields . split_at ( prefix_len) ; 
863+ 
864+                 // If the pattern contains a `..`, but is applied to values of statically-known 
865+                 // length (arrays), then we can slightly simplify diagnostics by merging any 
866+                 // adjacent wildcard patterns into the `..`: `[x, _, .., _, y]` => `[x, .., y]`. 
867+                 // (This simplification isn't allowed for slice values, because in that case 
868+                 // `[x, .., y]` would match some slices that `[x, _, .., _, y]` would not.) 
869+                 if  has_dot_dot && slice. array_len . is_some ( )  { 
870+                     while  let  [ rest @ ..,  last]  = prefix
871+                         && would_print_as_wildcard ( cx. tcx ,  last) 
872+                     { 
873+                         prefix = rest; 
874+                     } 
875+                     while  let  [ first,  rest @ ..]  = suffix
876+                         && would_print_as_wildcard ( cx. tcx ,  first) 
877+                     { 
878+                         suffix = rest; 
896879                    } 
897880                } 
881+ 
882+                 let  prefix = prefix. iter ( ) . map ( hoist) . collect ( ) ; 
883+                 let  suffix = suffix. iter ( ) . map ( hoist) . collect ( ) ; 
884+ 
885+                 PatKind :: Slice  {  prefix,  has_dot_dot,  suffix } 
898886            } 
899887            & Str ( value)  => PatKind :: Constant  {  value } , 
900888            Never  if  self . tcx . features ( ) . never_patterns  => PatKind :: Never , 
@@ -912,6 +900,22 @@ impl<'p, 'tcx: 'p> RustcPatCtxt<'p, 'tcx> {
912900    } 
913901} 
914902
903+ /// Returns `true` if the given pattern would be printed as a wildcard (`_`). 
904+ fn  would_print_as_wildcard ( tcx :  TyCtxt < ' _ > ,  p :  & WitnessPat < ' _ ,  ' _ > )  -> bool  { 
905+     match  p. ctor ( )  { 
906+         Constructor :: IntRange ( IntRange  { 
907+             lo :  MaybeInfiniteInt :: NegInfinity , 
908+             hi :  MaybeInfiniteInt :: PosInfinity , 
909+         } ) 
910+         | Constructor :: Wildcard 
911+         | Constructor :: NonExhaustive 
912+         | Constructor :: Hidden 
913+         | Constructor :: PrivateUninhabited  => true , 
914+         Constructor :: Never  if  !tcx. features ( ) . never_patterns  => true , 
915+         _ => false , 
916+     } 
917+ } 
918+ 
915919impl < ' p ,  ' tcx :  ' p >  PatCx  for  RustcPatCtxt < ' p ,  ' tcx >  { 
916920    type  Ty  = RevealedTy < ' tcx > ; 
917921    type  Error  = ErrorGuaranteed ; 
0 commit comments