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::Local(_)) |
30 Place::Base(PlaceBase::Static(_)) => return false,
31 Place::Projection(ref proj) => {
40 pub(super) struct Prefixes<'cx, 'gcx: 'tcx, 'tcx: 'cx> {
42 tcx: TyCtxt<'cx, 'gcx, 'tcx>,
44 next: Option<&'cx Place<'tcx>>,
47 #[derive(Copy, Clone, PartialEq, Eq, Debug)]
49 pub(super) enum PrefixSet {
50 /// Doesn't stop until it returns the base case (a Local or
53 /// Stops at any dereference.
55 /// Stops at the deref of a shared reference.
59 impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
60 /// Returns an iterator over the prefixes of `place`
61 /// (inclusive) from longest to smallest, potentially
62 /// terminating the iteration early based on `kind`.
63 pub(super) fn prefixes(
65 place: &'cx Place<'tcx>,
67 ) -> Prefixes<'cx, 'gcx, 'tcx> {
77 impl<'cx, 'gcx, 'tcx> Iterator for Prefixes<'cx, 'gcx, 'tcx> {
78 type Item = &'cx Place<'tcx>;
79 fn next(&mut self) -> Option<Self::Item> {
80 let mut cursor = self.next?;
82 // Post-processing `place`: Enqueue any remaining
83 // work. Also, `place` may not be a prefix itself, but
84 // may hold one further down (e.g., we never return
85 // downcasts here, but may return a base of a downcast).
88 let proj = match *cursor {
89 Place::Base(PlaceBase::Local(_)) | // search yielded this leaf
90 Place::Base(PlaceBase::Static(_)) => {
95 Place::Projection(ref proj) => proj,
99 ProjectionElem::Field(_ /*field*/, _ /*ty*/) => {
100 // FIXME: add union handling
101 self.next = Some(&proj.base);
104 ProjectionElem::Downcast(..) |
105 ProjectionElem::Subslice { .. } |
106 ProjectionElem::ConstantIndex { .. } |
107 ProjectionElem::Index(_) => {
111 ProjectionElem::Deref => {
116 assert_eq!(proj.elem, ProjectionElem::Deref);
119 PrefixSet::Shallow => {
120 // shallow prefixes are found by stripping away
121 // fields, but stop at *any* dereference.
122 // So we can just stop the traversal now.
127 // all prefixes: just blindly enqueue the base
129 self.next = Some(&proj.base);
132 PrefixSet::Supporting => {
137 assert_eq!(self.kind, PrefixSet::Supporting);
138 // supporting prefixes: strip away fields and
139 // derefs, except we stop at the deref of a shared
142 let ty = proj.base.ty(self.mir, self.tcx).to_ty(self.tcx);
150 // don't continue traversing over derefs of raw pointers or shared borrows.
160 self.next = Some(&proj.base);
164 ty::Adt(..) if ty.is_box() => {
165 self.next = Some(&proj.base);
169 _ => panic!("unknown type fed to Projection Deref."),