diff --git a/src/librustc_typeck/check/regionck.rs b/src/librustc_typeck/check/regionck.rs
index d3bccaaa3e4..199f49ca323 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 b72fae96e4c..4e5ef4329c2 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 d619d37be2d..ac42ce80689 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<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.
@@ -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<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 },
         }
     }
 }
@@ -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 {
@@ -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<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) });
+        projections.push(Projection { kind: ProjectionKind::Deref, ty: deref_ty });
 
-        let ret = PlaceWithHirId::new(node.hir_id(), deref_ty, base_place.place.base, projections);
+        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 d40cdfcca9f..b10181062ff 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;