@@ -54,11 +54,14 @@ use rustc_middle::ty::{self, Ty, TyCtxt};
54
54
55
55
use rustc_data_structures:: fx:: FxIndexMap ;
56
56
use rustc_hir as hir;
57
- use rustc_hir:: def:: { DefKind , Res } ;
57
+ use rustc_hir:: def:: { CtorOf , DefKind , Res } ;
58
58
use rustc_hir:: def_id:: LocalDefId ;
59
+ use rustc_hir:: pat_util:: EnumerateAndAdjustIterator ;
59
60
use rustc_hir:: PatKind ;
61
+ use rustc_index:: vec:: Idx ;
60
62
use rustc_infer:: infer:: InferCtxt ;
61
63
use rustc_span:: Span ;
64
+ use rustc_target:: abi:: VariantIdx ;
62
65
use rustc_trait_selection:: infer:: InferCtxtExt ;
63
66
64
67
#[ derive( Clone , Debug ) ]
@@ -77,8 +80,20 @@ pub enum PlaceBase {
77
80
pub enum ProjectionKind {
78
81
/// A dereference of a pointer, reference or `Box<T>` of the given type
79
82
Deref ,
80
- /// An index or a field
81
- Other ,
83
+
84
+ /// `B.F` where `B` is the base expression and `F` is
85
+ /// the field. The field is identified by which variant
86
+ /// it appears in along with a field index. The variant
87
+ /// is used for enums.
88
+ Field ( u32 , VariantIdx ) ,
89
+
90
+ /// Some index like `B[x]`, where `B` is the base
91
+ /// expression. We don't preserve the index `x` because
92
+ /// we won't need it.
93
+ Index ,
94
+
95
+ /// A subslice covering a range of values like `B[x..y]`.
96
+ Subslice ,
82
97
}
83
98
84
99
#[ derive( Clone , Debug ) ]
@@ -406,7 +421,20 @@ impl<'a, 'tcx> MemCategorizationContext<'a, 'tcx> {
406
421
hir:: ExprKind :: Field ( ref base, _) => {
407
422
let base = self . cat_expr ( & base) ?;
408
423
debug ! ( "cat_expr(cat_field): id={} expr={:?} base={:?}" , expr. hir_id, expr, base) ;
409
- Ok ( self . cat_projection ( expr, base, expr_ty) )
424
+
425
+ let field_idx = self
426
+ . tables
427
+ . field_indices ( )
428
+ . get ( expr. hir_id )
429
+ . cloned ( )
430
+ . expect ( "Field index not found" ) ;
431
+
432
+ Ok ( self . cat_projection (
433
+ expr,
434
+ base,
435
+ expr_ty,
436
+ ProjectionKind :: Field ( field_idx as u32 , VariantIdx :: new ( 0 ) ) ,
437
+ ) )
410
438
}
411
439
412
440
hir:: ExprKind :: Index ( ref base, _) => {
@@ -419,7 +447,7 @@ impl<'a, 'tcx> MemCategorizationContext<'a, 'tcx> {
419
447
self . cat_overloaded_place ( expr, base)
420
448
} else {
421
449
let base = self . cat_expr ( & base) ?;
422
- Ok ( self . cat_projection ( expr, base, expr_ty) )
450
+ Ok ( self . cat_projection ( expr, base, expr_ty, ProjectionKind :: Index ) )
423
451
}
424
452
}
425
453
@@ -533,9 +561,10 @@ impl<'a, 'tcx> MemCategorizationContext<'a, 'tcx> {
533
561
node : & N ,
534
562
base_place : PlaceWithHirId < ' tcx > ,
535
563
ty : Ty < ' tcx > ,
564
+ kind : ProjectionKind ,
536
565
) -> PlaceWithHirId < ' tcx > {
537
566
let mut projections = base_place. place . projections ;
538
- projections. push ( Projection { kind : ProjectionKind :: Other , ty : ty } ) ;
567
+ projections. push ( Projection { kind : kind , ty : ty } ) ;
539
568
let ret = PlaceWithHirId :: new (
540
569
node. hir_id ( ) ,
541
570
base_place. place . base_ty ,
@@ -609,6 +638,75 @@ impl<'a, 'tcx> MemCategorizationContext<'a, 'tcx> {
609
638
self . cat_pattern_ ( place, pat, & mut op)
610
639
}
611
640
641
+ /// Returns the variant index for an ADT used within a Struct or TupleStruct pattern
642
+ /// Here `pat_hir_id` is the HirId of the pattern itself.
643
+ fn variant_index_for_adt (
644
+ & self ,
645
+ qpath : & hir:: QPath < ' _ > ,
646
+ pat_hir_id : hir:: HirId ,
647
+ span : Span ,
648
+ ) -> McResult < VariantIdx > {
649
+ let res = self . tables . qpath_res ( qpath, pat_hir_id) ;
650
+ let ty = self . tables . node_type ( pat_hir_id) ;
651
+ let adt_def = match ty. kind {
652
+ ty:: Adt ( adt_def, _) => adt_def,
653
+ _ => {
654
+ self . tcx ( )
655
+ . sess
656
+ . delay_span_bug ( span, "struct or tuple struct pattern not applied to an ADT" ) ;
657
+ return Err ( ( ) ) ;
658
+ }
659
+ } ;
660
+
661
+ match res {
662
+ Res :: Def ( DefKind :: Variant , variant_id) => Ok ( adt_def. variant_index_with_id ( variant_id) ) ,
663
+ Res :: Def ( DefKind :: Ctor ( CtorOf :: Variant , ..) , variant_ctor_id) => {
664
+ Ok ( adt_def. variant_index_with_ctor_id ( variant_ctor_id) )
665
+ }
666
+ Res :: Def ( DefKind :: Ctor ( CtorOf :: Struct , ..) , _)
667
+ | Res :: Def ( DefKind :: Struct | DefKind :: Union | DefKind :: TyAlias | DefKind :: AssocTy , _)
668
+ | Res :: SelfCtor ( ..)
669
+ | Res :: SelfTy ( ..) => {
670
+ // Structs and Unions have only have one variant.
671
+ Ok ( VariantIdx :: new ( 0 ) )
672
+ }
673
+ _ => bug ! ( "expected ADT path, found={:?}" , res) ,
674
+ }
675
+ }
676
+
677
+ /// Returns the total number of fields in an ADT variant used within a pattern.
678
+ /// Here `pat_hir_id` is the HirId of the pattern itself.
679
+ fn total_fields_in_adt_variant (
680
+ & self ,
681
+ pat_hir_id : hir:: HirId ,
682
+ variant_index : VariantIdx ,
683
+ span : Span ,
684
+ ) -> McResult < usize > {
685
+ let ty = self . tables . node_type ( pat_hir_id) ;
686
+ match ty. kind {
687
+ ty:: Adt ( adt_def, _) => Ok ( adt_def. variants [ variant_index] . fields . len ( ) ) ,
688
+ _ => {
689
+ self . tcx ( )
690
+ . sess
691
+ . delay_span_bug ( span, "struct or tuple struct pattern not applied to an ADT" ) ;
692
+ return Err ( ( ) ) ;
693
+ }
694
+ }
695
+ }
696
+
697
+ /// Returns the total number of fields in a tuple used within a Tuple pattern.
698
+ /// Here `pat_hir_id` is the HirId of the pattern itself.
699
+ fn total_fields_in_tuple ( & self , pat_hir_id : hir:: HirId , span : Span ) -> McResult < usize > {
700
+ let ty = self . tables . node_type ( pat_hir_id) ;
701
+ match ty. kind {
702
+ ty:: Tuple ( substs) => Ok ( substs. len ( ) ) ,
703
+ _ => {
704
+ self . tcx ( ) . sess . delay_span_bug ( span, "tuple pattern not applied to a tuple" ) ;
705
+ return Err ( ( ) ) ;
706
+ }
707
+ }
708
+ }
709
+
612
710
// FIXME(#19596) This is a workaround, but there should be a better way to do this
613
711
fn cat_pattern_ < F > (
614
712
& self ,
@@ -679,20 +777,54 @@ impl<'a, 'tcx> MemCategorizationContext<'a, 'tcx> {
679
777
op ( & place_with_id, pat) ;
680
778
681
779
match pat. kind {
682
- PatKind :: TupleStruct ( _, ref subpats, _) | PatKind :: Tuple ( ref subpats, _) => {
683
- // S(p1, ..., pN) or (p1, ..., pN)
684
- for subpat in subpats. iter ( ) {
780
+ PatKind :: Tuple ( ref subpats, dots_pos) => {
781
+ // (p1, ..., pN)
782
+ let total_fields = self . total_fields_in_tuple ( pat. hir_id , pat. span ) ?;
783
+
784
+ for ( i, subpat) in subpats. iter ( ) . enumerate_and_adjust ( total_fields, dots_pos) {
685
785
let subpat_ty = self . pat_ty_adjusted ( & subpat) ?;
686
- let sub_place = self . cat_projection ( pat, place_with_id. clone ( ) , subpat_ty) ;
786
+ let projection_kind = ProjectionKind :: Field ( i as u32 , VariantIdx :: new ( 0 ) ) ;
787
+ let sub_place =
788
+ self . cat_projection ( pat, place_with_id. clone ( ) , subpat_ty, projection_kind) ;
687
789
self . cat_pattern_ ( sub_place, & subpat, op) ?;
688
790
}
689
791
}
690
792
691
- PatKind :: Struct ( _, field_pats, _) => {
793
+ PatKind :: TupleStruct ( ref qpath, ref subpats, dots_pos) => {
794
+ // S(p1, ..., pN)
795
+ let variant_index = self . variant_index_for_adt ( qpath, pat. hir_id , pat. span ) ?;
796
+ let total_fields =
797
+ self . total_fields_in_adt_variant ( pat. hir_id , variant_index, pat. span ) ?;
798
+
799
+ for ( i, subpat) in subpats. iter ( ) . enumerate_and_adjust ( total_fields, dots_pos) {
800
+ let subpat_ty = self . pat_ty_adjusted ( & subpat) ?;
801
+ let projection_kind = ProjectionKind :: Field ( i as u32 , variant_index) ;
802
+ let sub_place =
803
+ self . cat_projection ( pat, place_with_id. clone ( ) , subpat_ty, projection_kind) ;
804
+ self . cat_pattern_ ( sub_place, & subpat, op) ?;
805
+ }
806
+ }
807
+
808
+ PatKind :: Struct ( ref qpath, field_pats, _) => {
692
809
// S { f1: p1, ..., fN: pN }
810
+
811
+ let variant_index = self . variant_index_for_adt ( qpath, pat. hir_id , pat. span ) ?;
812
+
693
813
for fp in field_pats {
694
814
let field_ty = self . pat_ty_adjusted ( & fp. pat ) ?;
695
- let field_place = self . cat_projection ( pat, place_with_id. clone ( ) , field_ty) ;
815
+ let field_index = self
816
+ . tables
817
+ . field_indices ( )
818
+ . get ( fp. hir_id )
819
+ . cloned ( )
820
+ . expect ( "no index for a field" ) ;
821
+
822
+ let field_place = self . cat_projection (
823
+ pat,
824
+ place_with_id. clone ( ) ,
825
+ field_ty,
826
+ ProjectionKind :: Field ( field_index as u32 , variant_index) ,
827
+ ) ;
696
828
self . cat_pattern_ ( field_place, & fp. pat , op) ?;
697
829
}
698
830
}
@@ -723,13 +855,23 @@ impl<'a, 'tcx> MemCategorizationContext<'a, 'tcx> {
723
855
return Err ( ( ) ) ;
724
856
}
725
857
} ;
726
- let elt_place = self . cat_projection ( pat, place_with_id. clone ( ) , element_ty) ;
858
+ let elt_place = self . cat_projection (
859
+ pat,
860
+ place_with_id. clone ( ) ,
861
+ element_ty,
862
+ ProjectionKind :: Index ,
863
+ ) ;
727
864
for before_pat in before {
728
865
self . cat_pattern_ ( elt_place. clone ( ) , & before_pat, op) ?;
729
866
}
730
867
if let Some ( ref slice_pat) = * slice {
731
868
let slice_pat_ty = self . pat_ty_adjusted ( & slice_pat) ?;
732
- let slice_place = self . cat_projection ( pat, place_with_id, slice_pat_ty) ;
869
+ let slice_place = self . cat_projection (
870
+ pat,
871
+ place_with_id,
872
+ slice_pat_ty,
873
+ ProjectionKind :: Subslice ,
874
+ ) ;
733
875
self . cat_pattern_ ( slice_place, & slice_pat, op) ?;
734
876
}
735
877
for after_pat in after {
0 commit comments