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, 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;
30 Place::Local(_) | Place::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 {
90 Place::Local(_) | // search yielded this leaf
96 Place::Projection(ref proj) => proj,
100 ProjectionElem::Field(_ /*field*/, _ /*ty*/) => {
101 // FIXME: add union handling
102 self.next = Some(&proj.base);
105 ProjectionElem::Downcast(..) |
106 ProjectionElem::Subslice { .. } |
107 ProjectionElem::ConstantIndex { .. } |
108 ProjectionElem::Index(_) => {
112 ProjectionElem::Deref => {
117 assert_eq!(proj.elem, ProjectionElem::Deref);
120 PrefixSet::Shallow => {
121 // shallow prefixes are found by stripping away
122 // fields, but stop at *any* dereference.
123 // So we can just stop the traversal now.
128 // all prefixes: just blindly enqueue the base
130 self.next = Some(&proj.base);
133 PrefixSet::Supporting => {
138 assert_eq!(self.kind, PrefixSet::Supporting);
139 // supporting prefixes: strip away fields and
140 // derefs, except we stop at the deref of a shared
143 let ty = proj.base.ty(self.mir, self.tcx).to_ty(self.tcx);
151 // don't continue traversing over derefs of raw pointers or shared borrows.
161 self.next = Some(&proj.base);
165 ty::Adt(..) if ty.is_box() => {
166 self.next = Some(&proj.base);
170 _ => panic!("unknown type fed to Projection Deref."),