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