Skip to content

Commit 1acccb0

Browse files
arora-amanChrisPardynull-sleep
committed
Make hir ProjectionKind more precise
This commit also categorizing access as Field, Index, or Subslice. Ideas are taken from `mir::ProjectionElem`. Proposed changes: https://github.com/rust-lang/project-rfc-2229/blob/master/hir-place-target.md Closes: rust-lang/project-rfc-2229#1, rust-lang/project-rfc-2229#2 Co-authored-by: Aman Arora <me@aman-arora.com> Co-authored-by: Chris Pardy <chrispardy36@gmail.com> Co-authored-by: Dhruv Jauhar <dhruvjhr@gmail.com>
1 parent 70f9d23 commit 1acccb0

File tree

2 files changed

+159
-14
lines changed

2 files changed

+159
-14
lines changed

src/librustc_typeck/expr_use_visitor.rs

+3
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,10 @@ use rustc_hir as hir;
1111
use rustc_hir::def::Res;
1212
use rustc_hir::def_id::LocalDefId;
1313
use rustc_hir::PatKind;
14+
use rustc_index::vec::Idx;
1415
use rustc_infer::infer::InferCtxt;
1516
use rustc_middle::ty::{self, adjustment, TyCtxt};
17+
use rustc_target::abi::VariantIdx;
1618

1719
use crate::mem_categorization as mc;
1820
use rustc_span::Span;
@@ -396,6 +398,7 @@ impl<'a, 'tcx> ExprUseVisitor<'a, 'tcx> {
396398
&*with_expr,
397399
with_place.clone(),
398400
with_field.ty(self.tcx(), substs),
401+
mc::ProjectionKind::Field(f_index as u32, VariantIdx::new(0)),
399402
);
400403
self.delegate_consume(&field_place);
401404
}

src/librustc_typeck/mem_categorization.rs

+156-14
Original file line numberDiff line numberDiff line change
@@ -54,11 +54,14 @@ use rustc_middle::ty::{self, Ty, TyCtxt};
5454

5555
use rustc_data_structures::fx::FxIndexMap;
5656
use rustc_hir as hir;
57-
use rustc_hir::def::{DefKind, Res};
57+
use rustc_hir::def::{CtorOf, DefKind, Res};
5858
use rustc_hir::def_id::LocalDefId;
59+
use rustc_hir::pat_util::EnumerateAndAdjustIterator;
5960
use rustc_hir::PatKind;
61+
use rustc_index::vec::Idx;
6062
use rustc_infer::infer::InferCtxt;
6163
use rustc_span::Span;
64+
use rustc_target::abi::VariantIdx;
6265
use rustc_trait_selection::infer::InferCtxtExt;
6366

6467
#[derive(Clone, Debug)]
@@ -77,8 +80,20 @@ pub enum PlaceBase {
7780
pub 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

Comments
 (0)