1 //! From the NLL RFC: "The deep [aka 'supporting'] prefixes for an
2 //! place are formed by stripping away fields and derefs, except that
3 //! we stop when we reach the deref of a shared reference. [...] "
5 //! "Shallow prefixes are found by stripping away fields, but stop at
6 //! any dereference. So: writing a path like `a` is illegal if `a.b`
7 //! is borrowed. But: writing `a` is legal if `*a` is borrowed,
8 //! whether or not `a` is a shared or mutable reference. [...] "
10 use super::MirBorrowckCtxt;
13 use rustc::ty::{self, TyCtxt};
14 use rustc::mir::{Mir, Place, PlaceBase, ProjectionElem};
16 pub trait IsPrefixOf<'tcx> {
17 fn is_prefix_of(&self, other: &Place<'tcx>) -> bool;
20 impl<'tcx> IsPrefixOf<'tcx> for Place<'tcx> {
21 fn is_prefix_of(&self, other: &Place<'tcx>) -> bool {
22 let mut cursor = other;
29 Place::Base(PlaceBase::Promoted(_)) |
30 Place::Base(PlaceBase::Local(_)) |
31 Place::Base(PlaceBase::Static(_)) => return false,
32 Place::Projection(ref proj) => {
41 pub(super) struct Prefixes<'cx, 'gcx: 'tcx, 'tcx: 'cx> {
43 tcx: TyCtxt<'cx, 'gcx, 'tcx>,
45 next: Option<&'cx Place<'tcx>>,
48 #[derive(Copy, Clone, PartialEq, Eq, Debug)]
50 pub(super) enum PrefixSet {
51 /// Doesn't stop until it returns the base case (a Local or
54 /// Stops at any dereference.
56 /// Stops at the deref of a shared reference.
60 impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
61 /// Returns an iterator over the prefixes of `place`
62 /// (inclusive) from longest to smallest, potentially
63 /// terminating the iteration early based on `kind`.
64 pub(super) fn prefixes(
66 place: &'cx Place<'tcx>,
68 ) -> Prefixes<'cx, 'gcx, 'tcx> {
78 impl<'cx, 'gcx, 'tcx> Iterator for Prefixes<'cx, 'gcx, 'tcx> {
79 type Item = &'cx Place<'tcx>;
80 fn next(&mut self) -> Option<Self::Item> {
81 let mut cursor = self.next?;
83 // Post-processing `place`: Enqueue any remaining
84 // work. Also, `place` may not be a prefix itself, but
85 // may hold one further down (e.g., we never return
86 // downcasts here, but may return a base of a downcast).
89 let proj = match *cursor {
90 Place::Base(PlaceBase::Promoted(_)) |
91 Place::Base(PlaceBase::Local(_)) | // search yielded this leaf
92 Place::Base(PlaceBase::Static(_)) => {
97 Place::Projection(ref proj) => proj,
101 ProjectionElem::Field(_ /*field*/, _ /*ty*/) => {
102 // FIXME: add union handling
103 self.next = Some(&proj.base);
106 ProjectionElem::Downcast(..) |
107 ProjectionElem::Subslice { .. } |
108 ProjectionElem::ConstantIndex { .. } |
109 ProjectionElem::Index(_) => {
113 ProjectionElem::Deref => {
118 assert_eq!(proj.elem, ProjectionElem::Deref);
121 PrefixSet::Shallow => {
122 // shallow prefixes are found by stripping away
123 // fields, but stop at *any* dereference.
124 // So we can just stop the traversal now.
129 // all prefixes: just blindly enqueue the base
131 self.next = Some(&proj.base);
134 PrefixSet::Supporting => {
139 assert_eq!(self.kind, PrefixSet::Supporting);
140 // supporting prefixes: strip away fields and
141 // derefs, except we stop at the deref of a shared
144 let ty = proj.base.ty(self.mir, self.tcx).to_ty(self.tcx);
152 // don't continue traversing over derefs of raw pointers or shared borrows.
162 self.next = Some(&proj.base);
166 ty::Adt(..) if ty.is_box() => {
167 self.next = Some(&proj.base);
171 _ => panic!("unknown type fed to Projection Deref."),