@@ -54,11 +54,14 @@ use rustc_middle::ty::{self, Ty, TyCtxt};
5454
5555use rustc_data_structures:: fx:: FxIndexMap ;
5656use rustc_hir as hir;
57- use rustc_hir:: def:: { DefKind , Res } ;
57+ use rustc_hir:: def:: { CtorOf , DefKind , Res } ;
5858use rustc_hir:: def_id:: LocalDefId ;
59+ use rustc_hir:: pat_util:: EnumerateAndAdjustIterator ;
5960use rustc_hir:: PatKind ;
61+ use rustc_index:: vec:: Idx ;
6062use rustc_infer:: infer:: InferCtxt ;
6163use rustc_span:: Span ;
64+ use rustc_target:: abi:: VariantIdx ;
6265use rustc_trait_selection:: infer:: InferCtxtExt ;
6366
6467#[ derive( Clone , Debug ) ]
@@ -77,8 +80,20 @@ pub enum PlaceBase {
7780pub enum ProjectionKind {
7881 /// A dereference of a pointer, reference or `Box<T>` of the given type
7982 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 ,
8297}
8398
8499#[ derive( Clone , Debug ) ]
@@ -406,7 +421,20 @@ impl<'a, 'tcx> MemCategorizationContext<'a, 'tcx> {
406421 hir:: ExprKind :: Field ( ref base, _) => {
407422 let base = self . cat_expr ( & base) ?;
408423 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+ ) )
410438 }
411439
412440 hir:: ExprKind :: Index ( ref base, _) => {
@@ -419,7 +447,7 @@ impl<'a, 'tcx> MemCategorizationContext<'a, 'tcx> {
419447 self . cat_overloaded_place ( expr, base)
420448 } else {
421449 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 ) )
423451 }
424452 }
425453
@@ -533,9 +561,10 @@ impl<'a, 'tcx> MemCategorizationContext<'a, 'tcx> {
533561 node : & N ,
534562 base_place : PlaceWithHirId < ' tcx > ,
535563 ty : Ty < ' tcx > ,
564+ kind : ProjectionKind ,
536565 ) -> PlaceWithHirId < ' tcx > {
537566 let mut projections = base_place. place . projections ;
538- projections. push ( Projection { kind : ProjectionKind :: Other , ty : ty } ) ;
567+ projections. push ( Projection { kind : kind , ty : ty } ) ;
539568 let ret = PlaceWithHirId :: new (
540569 node. hir_id ( ) ,
541570 base_place. place . base_ty ,
@@ -609,6 +638,75 @@ impl<'a, 'tcx> MemCategorizationContext<'a, 'tcx> {
609638 self . cat_pattern_ ( place, pat, & mut op)
610639 }
611640
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+
612710 // FIXME(#19596) This is a workaround, but there should be a better way to do this
613711 fn cat_pattern_ < F > (
614712 & self ,
@@ -679,20 +777,54 @@ impl<'a, 'tcx> MemCategorizationContext<'a, 'tcx> {
679777 op ( & place_with_id, pat) ;
680778
681779 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) {
685785 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) ;
687789 self . cat_pattern_ ( sub_place, & subpat, op) ?;
688790 }
689791 }
690792
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, _) => {
692809 // S { f1: p1, ..., fN: pN }
810+
811+ let variant_index = self . variant_index_for_adt ( qpath, pat. hir_id , pat. span ) ?;
812+
693813 for fp in field_pats {
694814 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+ ) ;
696828 self . cat_pattern_ ( field_place, & fp. pat , op) ?;
697829 }
698830 }
@@ -723,13 +855,23 @@ impl<'a, 'tcx> MemCategorizationContext<'a, 'tcx> {
723855 return Err ( ( ) ) ;
724856 }
725857 } ;
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+ ) ;
727864 for before_pat in before {
728865 self . cat_pattern_ ( elt_place. clone ( ) , & before_pat, op) ?;
729866 }
730867 if let Some ( ref slice_pat) = * slice {
731868 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+ ) ;
733875 self . cat_pattern_ ( slice_place, & slice_pat, op) ?;
734876 }
735877 for after_pat in after {
0 commit comments