@@ -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