@@ -827,7 +827,6 @@ impl<'p, 'tcx: 'p> RustcPatCtxt<'p, 'tcx> {
827827 fn hoist_witness_pat ( & self , pat : & WitnessPat < ' p , ' tcx > ) -> print:: Pat < ' tcx > {
828828 use print:: { FieldPat , Pat , PatKind } ;
829829 let cx = self ;
830- let is_wildcard = |pat : & Pat < ' _ > | matches ! ( pat. kind, PatKind :: Wild ) ;
831830 let hoist = |p| Box :: new ( cx. hoist_witness_pat ( p) ) ;
832831 let mut subpatterns = pat. iter_fields ( ) . map ( hoist) ;
833832 let kind = match pat. ctor ( ) {
@@ -862,37 +861,35 @@ impl<'p, 'tcx: 'p> RustcPatCtxt<'p, 'tcx> {
862861 // ignore this issue.
863862 Ref => PatKind :: Deref { subpattern : subpatterns. next ( ) . unwrap ( ) } ,
864863 Slice ( slice) => {
865- match slice. kind {
866- SliceKind :: FixedLen ( _) => PatKind :: Slice {
867- prefix : subpatterns. collect ( ) ,
868- has_dot_dot : false ,
869- suffix : Box :: new ( [ ] ) ,
870- } ,
871- SliceKind :: VarLen ( prefix, _) => {
872- let mut subpatterns = subpatterns. peekable ( ) ;
873- let mut prefix: Vec < _ > = subpatterns. by_ref ( ) . take ( prefix) . collect ( ) ;
874- if slice. array_len . is_some ( ) {
875- // Improves diagnostics a bit: if the type is a known-size array, instead
876- // of reporting `[x, _, .., _, y]`, we prefer to report `[x, .., y]`.
877- // This is incorrect if the size is not known, since `[_, ..]` captures
878- // arrays of lengths `>= 1` whereas `[..]` captures any length.
879- while !prefix. is_empty ( ) && is_wildcard ( prefix. last ( ) . unwrap ( ) ) {
880- prefix. pop ( ) ;
881- }
882- while subpatterns. peek ( ) . is_some ( )
883- && is_wildcard ( subpatterns. peek ( ) . unwrap ( ) )
884- {
885- subpatterns. next ( ) ;
886- }
887- }
888- let suffix: Box < [ _ ] > = subpatterns. collect ( ) ;
889- PatKind :: Slice {
890- prefix : prefix. into_boxed_slice ( ) ,
891- has_dot_dot : true ,
892- suffix,
893- }
864+ let ( prefix_len, has_dot_dot) = match slice. kind {
865+ SliceKind :: FixedLen ( len) => ( len, false ) ,
866+ SliceKind :: VarLen ( prefix_len, _) => ( prefix_len, true ) ,
867+ } ;
868+
869+ let ( mut prefix, mut suffix) = pat. fields . split_at ( prefix_len) ;
870+
871+ // If the pattern contains a `..`, but is applied to values of statically-known
872+ // length (arrays), then we can slightly simplify diagnostics by merging any
873+ // adjacent wildcard patterns into the `..`: `[x, _, .., _, y]` => `[x, .., y]`.
874+ // (This simplification isn't allowed for slice values, because in that case
875+ // `[x, .., y]` would match some slices that `[x, _, .., _, y]` would not.)
876+ if has_dot_dot && slice. array_len . is_some ( ) {
877+ while let [ rest @ .., last] = prefix
878+ && would_print_as_wildcard ( cx. tcx , last)
879+ {
880+ prefix = rest;
881+ }
882+ while let [ first, rest @ ..] = suffix
883+ && would_print_as_wildcard ( cx. tcx , first)
884+ {
885+ suffix = rest;
894886 }
895887 }
888+
889+ let prefix = prefix. iter ( ) . map ( hoist) . collect ( ) ;
890+ let suffix = suffix. iter ( ) . map ( hoist) . collect ( ) ;
891+
892+ PatKind :: Slice { prefix, has_dot_dot, suffix }
896893 }
897894 & Str ( value) => PatKind :: Constant { value } ,
898895 Never if self . tcx . features ( ) . never_patterns => PatKind :: Never ,
@@ -910,6 +907,22 @@ impl<'p, 'tcx: 'p> RustcPatCtxt<'p, 'tcx> {
910907 }
911908}
912909
910+ /// Returns `true` if the given pattern would be printed as a wildcard (`_`).
911+ fn would_print_as_wildcard ( tcx : TyCtxt < ' _ > , p : & WitnessPat < ' _ , ' _ > ) -> bool {
912+ match p. ctor ( ) {
913+ Constructor :: IntRange ( IntRange {
914+ lo : MaybeInfiniteInt :: NegInfinity ,
915+ hi : MaybeInfiniteInt :: PosInfinity ,
916+ } )
917+ | Constructor :: Wildcard
918+ | Constructor :: NonExhaustive
919+ | Constructor :: Hidden
920+ | Constructor :: PrivateUninhabited => true ,
921+ Constructor :: Never if !tcx. features ( ) . never_patterns => true ,
922+ _ => false ,
923+ }
924+ }
925+
913926impl < ' p , ' tcx : ' p > PatCx for RustcPatCtxt < ' p , ' tcx > {
914927 type Ty = RevealedTy < ' tcx > ;
915928 type Error = ErrorGuaranteed ;
0 commit comments