1 // Copyright 2017 The Rust Project Developers. See the COPYRIGHT
2 // file at the top-level directory of this distribution and at
3 // http://rust-lang.org/COPYRIGHT.
5 // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6 // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7 // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8 // option. This file may not be copied, modified, or distributed
9 // except according to those terms.
11 //! From the NLL RFC: "The deep [aka 'supporting'] prefixes for an
12 //! place are formed by stripping away fields and derefs, except that
13 //! we stop when we reach the deref of a shared reference. [...] "
15 //! "Shallow prefixes are found by stripping away fields, but stop at
16 //! any dereference. So: writing a path like `a` is illegal if `a.b`
17 //! is borrowed. But: writing `a` is legal if `*a` is borrowed,
18 //! whether or not `a` is a shared or mutable reference. [...] "
20 use super::MirBorrowckCtxt;
23 use rustc::ty::{self, TyCtxt};
24 use rustc::mir::{Mir, Place, ProjectionElem};
26 pub trait IsPrefixOf<'tcx> {
27 fn is_prefix_of(&self, other: &Place<'tcx>) -> bool;
30 impl<'tcx> IsPrefixOf<'tcx> for Place<'tcx> {
31 fn is_prefix_of(&self, other: &Place<'tcx>) -> bool {
32 let mut cursor = other;
40 Place::Local(_) | Place::Static(_) => return false,
41 Place::Projection(ref proj) => {
50 pub(super) struct Prefixes<'cx, 'gcx: 'tcx, 'tcx: 'cx> {
52 tcx: TyCtxt<'cx, 'gcx, 'tcx>,
54 next: Option<&'cx Place<'tcx>>,
57 #[derive(Copy, Clone, PartialEq, Eq, Debug)]
59 pub(super) enum PrefixSet {
60 /// Doesn't stop until it returns the base case (a Local or
63 /// Stops at any dereference.
65 /// Stops at the deref of a shared reference.
69 impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
70 /// Returns an iterator over the prefixes of `place`
71 /// (inclusive) from longest to smallest, potentially
72 /// terminating the iteration early based on `kind`.
73 pub(super) fn prefixes(
75 place: &'cx Place<'tcx>,
77 ) -> Prefixes<'cx, 'gcx, 'tcx> {
87 impl<'cx, 'gcx, 'tcx> Iterator for Prefixes<'cx, 'gcx, 'tcx> {
88 type Item = &'cx Place<'tcx>;
89 fn next(&mut self) -> Option<Self::Item> {
90 let mut cursor = match self.next {
95 // Post-processing `place`: Enqueue any remaining
96 // work. Also, `place` may not be a prefix itself, but
97 // may hold one further down (e.g. we never return
98 // downcasts here, but may return a base of a downcast).
101 let proj = match *cursor {
103 Place::Local(_) | // search yielded this leaf
104 Place::Static(_) => {
109 Place::Projection(ref proj) => proj,
113 ProjectionElem::Field(_ /*field*/, _ /*ty*/) => {
114 // FIXME: add union handling
115 self.next = Some(&proj.base);
118 ProjectionElem::Downcast(..) |
119 ProjectionElem::Subslice { .. } |
120 ProjectionElem::ConstantIndex { .. } |
121 ProjectionElem::Index(_) => {
125 ProjectionElem::Deref => {
130 assert_eq!(proj.elem, ProjectionElem::Deref);
133 PrefixSet::Shallow => {
134 // shallow prefixes are found by stripping away
135 // fields, but stop at *any* dereference.
136 // So we can just stop the traversal now.
141 // all prefixes: just blindly enqueue the base
143 self.next = Some(&proj.base);
146 PrefixSet::Supporting => {
151 assert_eq!(self.kind, PrefixSet::Supporting);
152 // supporting prefixes: strip away fields and
153 // derefs, except we stop at the deref of a shared
156 let ty = proj.base.ty(self.mir, self.tcx).to_ty(self.tcx);
164 // don't continue traversing over derefs of raw pointers or shared borrows.
174 self.next = Some(&proj.base);
178 ty::Adt(..) if ty.is_box() => {
179 self.next = Some(&proj.base);
183 _ => panic!("unknown type fed to Projection Deref."),