From 7d7221c250404ed468d893a642da961ef824a76b Mon Sep 17 00:00:00 2001 From: Azhng Date: Wed, 24 Jun 2020 16:33:31 -0400 Subject: [PATCH] typeck: adding type information to projection This commit modifies the Place as follow: * remove 'ty' from ProjectionKind * add type information into to Projection * replace 'ty' in Place with 'base_ty' * introduce 'ty()' in `Place` to return the final type of the `Place` * introduce `ty_before_projection()` in `Place` to return the type of a `Place` before i'th projection is applied Closes https://github.com/rust-lang/project-rfc-2229/issues/5 --- src/librustc_typeck/check/regionck.rs | 6 +- src/librustc_typeck/expr_use_visitor.rs | 4 +- src/librustc_typeck/mem_categorization.rs | 67 +++++++++++++++------ src/tools/clippy/clippy_lints/src/escape.rs | 2 +- 4 files changed, 54 insertions(+), 25 deletions(-) diff --git a/src/librustc_typeck/check/regionck.rs b/src/librustc_typeck/check/regionck.rs index d3bccaaa3e4b9..199f49ca323e0 100644 --- a/src/librustc_typeck/check/regionck.rs +++ b/src/librustc_typeck/check/regionck.rs @@ -488,7 +488,7 @@ impl<'a, 'tcx> RegionCtxt<'a, 'tcx> { ) { if let mc::PlaceBase::Rvalue = place_with_id.place.base { if place_with_id.place.projections.is_empty() { - let typ = self.resolve_type(place_with_id.place.ty); + let typ = self.resolve_type(place_with_id.place.ty()); let body_id = self.body_id; let _ = dropck::check_drop_obligations(self, typ, span, body_id); } @@ -640,8 +640,8 @@ impl<'a, 'tcx> RegionCtxt<'a, 'tcx> { borrow_kind: ty::BorrowKind, borrow_place: &mc::PlaceWithHirId<'tcx>, ) { - let origin = infer::DataBorrowed(borrow_place.place.ty, span); - self.type_must_outlive(origin, borrow_place.place.ty, borrow_region); + let origin = infer::DataBorrowed(borrow_place.place.ty(), span); + self.type_must_outlive(origin, borrow_place.place.ty(), borrow_region); for pointer_ty in borrow_place.place.deref_tys() { debug!( diff --git a/src/librustc_typeck/expr_use_visitor.rs b/src/librustc_typeck/expr_use_visitor.rs index b72fae96e4ca0..4e5ef4329c2c6 100644 --- a/src/librustc_typeck/expr_use_visitor.rs +++ b/src/librustc_typeck/expr_use_visitor.rs @@ -384,7 +384,7 @@ impl<'a, 'tcx> ExprUseVisitor<'a, 'tcx> { // Select just those fields of the `with` // expression that will actually be used - match with_place.place.ty.kind { + match with_place.place.ty().kind { ty::Adt(adt, substs) if adt.is_struct() => { // Consume those fields of the with expression that are needed. for (f_index, with_field) in adt.non_enum_variant().fields.iter().enumerate() { @@ -583,7 +583,7 @@ fn copy_or_move<'a, 'tcx>( place_with_id: &PlaceWithHirId<'tcx>, ) -> ConsumeMode { if !mc.type_is_copy_modulo_regions( - place_with_id.place.ty, + place_with_id.place.ty(), mc.tcx().hir().span(place_with_id.hir_id), ) { Move diff --git a/src/librustc_typeck/mem_categorization.rs b/src/librustc_typeck/mem_categorization.rs index d619d37be2d7b..ac42ce80689ec 100644 --- a/src/librustc_typeck/mem_categorization.rs +++ b/src/librustc_typeck/mem_categorization.rs @@ -73,18 +73,21 @@ pub enum PlaceBase { Upvar(ty::UpvarId), } -#[derive(Clone, Debug)] -pub enum ProjectionKind<'tcx> { +#[derive(Clone, Debug, Eq, PartialEq)] +pub enum ProjectionKind { /// A dereference of a pointer, reference or `Box` of the given type - Deref(Ty<'tcx>), + Deref, /// An index or a field Other, } #[derive(Clone, Debug)] pub struct Projection<'tcx> { + // Type after the projection is being applied. + ty: Ty<'tcx>, + /// Defines the type of access - kind: ProjectionKind<'tcx>, + kind: ProjectionKind, } /// A `Place` represents how a value is located in memory. @@ -92,8 +95,8 @@ pub struct Projection<'tcx> { /// This is an HIR version of `mir::Place` #[derive(Clone, Debug)] pub struct Place<'tcx> { - /// The type of the `Place` - pub ty: Ty<'tcx>, + /// The type of the `PlaceBase` + pub base_ty: Ty<'tcx>, /// The "outermost" place that holds this value. pub base: PlaceBase, /// How this place is derived from the base place. @@ -115,13 +118,13 @@ pub struct PlaceWithHirId<'tcx> { impl<'tcx> PlaceWithHirId<'tcx> { crate fn new( hir_id: hir::HirId, - ty: Ty<'tcx>, + base_ty: Ty<'tcx>, base: PlaceBase, projections: Vec>, ) -> PlaceWithHirId<'tcx> { PlaceWithHirId { hir_id: hir_id, - place: Place { ty: ty, base: base, projections: projections }, + place: Place { base_ty: base_ty, base: base, projections: projections }, } } } @@ -134,10 +137,26 @@ impl<'tcx> Place<'tcx> { /// `x: &*const u32` and the `Place` is `**x`, then the types returned are ///`*const u32` then `&*const u32`. crate fn deref_tys(&self) -> impl Iterator> + '_ { - self.projections.iter().rev().filter_map(|proj| { - if let ProjectionKind::Deref(deref_ty) = proj.kind { Some(deref_ty) } else { None } + self.projections.iter().enumerate().rev().filter_map(move |(index, proj)| { + if ProjectionKind::Deref == proj.kind { + Some(self.ty_before_projection(index)) + } else { + None + } }) } + + // Returns the type of this `Place` after all projections have been applied. + pub fn ty(&self) -> Ty<'tcx> { + self.projections.last().map_or_else(|| self.base_ty, |proj| proj.ty) + } + + // Returns the type of this `Place` immediately before `projection_index`th projection + // is applied. + crate fn ty_before_projection(&self, projection_index: usize) -> Ty<'tcx> { + assert!(projection_index < self.projections.len()); + if projection_index == 0 { self.base_ty } else { self.projections[projection_index - 1].ty } + } } crate trait HirNode { @@ -516,8 +535,13 @@ impl<'a, 'tcx> MemCategorizationContext<'a, 'tcx> { ty: Ty<'tcx>, ) -> PlaceWithHirId<'tcx> { let mut projections = base_place.place.projections; - projections.push(Projection { kind: ProjectionKind::Other }); - let ret = PlaceWithHirId::new(node.hir_id(), ty, base_place.place.base, projections); + projections.push(Projection { kind: ProjectionKind::Other, ty: ty }); + let ret = PlaceWithHirId::new( + node.hir_id(), + base_place.place.base_ty, + base_place.place.base, + projections, + ); debug!("cat_field ret {:?}", ret); ret } @@ -552,18 +576,23 @@ impl<'a, 'tcx> MemCategorizationContext<'a, 'tcx> { ) -> McResult> { debug!("cat_deref: base_place={:?}", base_place); - let base_ty = base_place.place.ty; - let deref_ty = match base_ty.builtin_deref(true) { + let base_curr_ty = base_place.place.ty(); + let deref_ty = match base_curr_ty.builtin_deref(true) { Some(mt) => mt.ty, None => { - debug!("explicit deref of non-derefable type: {:?}", base_ty); + debug!("explicit deref of non-derefable type: {:?}", base_curr_ty); return Err(()); } }; let mut projections = base_place.place.projections; - projections.push(Projection { kind: ProjectionKind::Deref(base_ty) }); - - let ret = PlaceWithHirId::new(node.hir_id(), deref_ty, base_place.place.base, projections); + projections.push(Projection { kind: ProjectionKind::Deref, ty: deref_ty }); + + let ret = PlaceWithHirId::new( + node.hir_id(), + base_place.place.base_ty, + base_place.place.base, + projections, + ); debug!("cat_deref ret {:?}", ret); Ok(ret) } @@ -687,7 +716,7 @@ impl<'a, 'tcx> MemCategorizationContext<'a, 'tcx> { } PatKind::Slice(before, ref slice, after) => { - let element_ty = match place_with_id.place.ty.builtin_index() { + let element_ty = match place_with_id.place.ty().builtin_index() { Some(ty) => ty, None => { debug!("explicit index of non-indexable type {:?}", place_with_id); diff --git a/src/tools/clippy/clippy_lints/src/escape.rs b/src/tools/clippy/clippy_lints/src/escape.rs index 59af475af175e..fcb574e437481 100644 --- a/src/tools/clippy/clippy_lints/src/escape.rs +++ b/src/tools/clippy/clippy_lints/src/escape.rs @@ -150,7 +150,7 @@ impl<'a, 'tcx> Delegate<'tcx> for EscapeDelegate<'a, 'tcx> { return; } - if is_non_trait_box(cmt.place.ty) && !self.is_large_box(cmt.place.ty) { + if is_non_trait_box(cmt.place.ty()) && !self.is_large_box(cmt.place.ty()) { self.set.insert(cmt.hir_id); } return;