Skip to content

Commit

Permalink
typeck: adding type information to projection
Browse files Browse the repository at this point in the history
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 rust-lang/project-rfc-2229#5
  • Loading branch information
Azhng committed Jun 29, 2020
1 parent 6bb3dbf commit 7d7221c
Show file tree
Hide file tree
Showing 4 changed files with 54 additions and 25 deletions.
6 changes: 3 additions & 3 deletions src/librustc_typeck/check/regionck.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}
Expand Down Expand Up @@ -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!(
Expand Down
4 changes: 2 additions & 2 deletions src/librustc_typeck/expr_use_visitor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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() {
Expand Down Expand Up @@ -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
Expand Down
67 changes: 48 additions & 19 deletions src/librustc_typeck/mem_categorization.rs
Original file line number Diff line number Diff line change
Expand Up @@ -73,27 +73,30 @@ 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<T>` 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.
///
/// 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.
Expand All @@ -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<Projection<'tcx>>,
) -> 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 },
}
}
}
Expand All @@ -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<Item = Ty<'tcx>> + '_ {
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 {
Expand Down Expand Up @@ -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
}
Expand Down Expand Up @@ -552,18 +576,23 @@ impl<'a, 'tcx> MemCategorizationContext<'a, 'tcx> {
) -> McResult<PlaceWithHirId<'tcx>> {
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)
}
Expand Down Expand Up @@ -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);
Expand Down
2 changes: 1 addition & 1 deletion src/tools/clippy/clippy_lints/src/escape.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down

0 comments on commit 7d7221c

Please sign in to comment.