@@ -23,6 +23,7 @@ use crate::constructor::{
23
23
} ;
24
24
use crate :: lints:: lint_nonexhaustive_missing_variants;
25
25
use crate :: pat_column:: PatternColumn ;
26
+ use crate :: rustc:: print:: EnumInfo ;
26
27
use crate :: usefulness:: { compute_match_usefulness, PlaceValidity } ;
27
28
use crate :: { errors, Captures , PatCx , PrivateUninhabitedField } ;
28
29
@@ -824,77 +825,64 @@ impl<'p, 'tcx: 'p> RustcPatCtxt<'p, 'tcx> {
824
825
fn hoist_witness_pat ( & self , pat : & WitnessPat < ' p , ' tcx > ) -> print:: Pat < ' tcx > {
825
826
use print:: { FieldPat , Pat , PatKind } ;
826
827
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) ) ;
829
829
let kind = match pat. ctor ( ) {
830
830
Bool ( b) => PatKind :: Constant { value : mir:: Const :: from_bool ( cx. tcx , * b) } ,
831
831
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
+ } ;
851
846
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 ] ) } ,
865
856
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;
896
879
}
897
880
}
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 }
898
886
}
899
887
& Str ( value) => PatKind :: Constant { value } ,
900
888
Never if self . tcx . features ( ) . never_patterns => PatKind :: Never ,
@@ -912,6 +900,22 @@ impl<'p, 'tcx: 'p> RustcPatCtxt<'p, 'tcx> {
912
900
}
913
901
}
914
902
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
+
915
919
impl < ' p , ' tcx : ' p > PatCx for RustcPatCtxt < ' p , ' tcx > {
916
920
type Ty = RevealedTy < ' tcx > ;
917
921
type Error = ErrorGuaranteed ;
0 commit comments