2017-12-06 12:27:38 -06:00
|
|
|
//! From the NLL RFC: "The deep [aka 'supporting'] prefixes for an
|
|
|
|
//! place are formed by stripping away fields and derefs, except that
|
|
|
|
//! we stop when we reach the deref of a shared reference. [...] "
|
|
|
|
//!
|
|
|
|
//! "Shallow prefixes are found by stripping away fields, but stop at
|
|
|
|
//! any dereference. So: writing a path like `a` is illegal if `a.b`
|
|
|
|
//! is borrowed. But: writing `a` is legal if `*a` is borrowed,
|
|
|
|
//! whether or not `a` is a shared or mutable reference. [...] "
|
|
|
|
|
|
|
|
use super::MirBorrowckCtxt;
|
|
|
|
|
2019-12-03 10:51:58 -06:00
|
|
|
use rustc::mir::{Place, PlaceBase, PlaceRef, ProjectionElem, ReadOnlyBodyAndCache};
|
2019-12-22 16:42:04 -06:00
|
|
|
use rustc::ty::{self, TyCtxt};
|
2020-01-04 19:37:57 -06:00
|
|
|
use rustc_hir as hir;
|
2017-12-06 12:27:38 -06:00
|
|
|
|
2019-07-11 12:25:37 -05:00
|
|
|
pub trait IsPrefixOf<'cx, 'tcx> {
|
|
|
|
fn is_prefix_of(&self, other: PlaceRef<'cx, 'tcx>) -> bool;
|
2017-12-06 12:27:38 -06:00
|
|
|
}
|
|
|
|
|
2019-07-11 12:25:37 -05:00
|
|
|
impl<'cx, 'tcx> IsPrefixOf<'cx, 'tcx> for PlaceRef<'cx, 'tcx> {
|
|
|
|
fn is_prefix_of(&self, other: PlaceRef<'cx, 'tcx>) -> bool {
|
2019-07-29 17:07:28 -05:00
|
|
|
self.base == other.base
|
|
|
|
&& self.projection.len() <= other.projection.len()
|
|
|
|
&& self.projection == &other.projection[..self.projection.len()]
|
2017-12-06 12:27:38 -06:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-06-14 11:39:39 -05:00
|
|
|
pub(super) struct Prefixes<'cx, 'tcx> {
|
2019-12-03 10:51:58 -06:00
|
|
|
body: ReadOnlyBodyAndCache<'cx, 'tcx>,
|
2019-06-13 16:48:52 -05:00
|
|
|
tcx: TyCtxt<'tcx>,
|
2017-12-06 12:27:38 -06:00
|
|
|
kind: PrefixSet,
|
2019-10-04 00:56:57 -05:00
|
|
|
next: Option<PlaceRef<'cx, 'tcx>>,
|
2017-12-06 12:27:38 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
#[derive(Copy, Clone, PartialEq, Eq, Debug)]
|
|
|
|
#[allow(dead_code)]
|
|
|
|
pub(super) enum PrefixSet {
|
|
|
|
/// Doesn't stop until it returns the base case (a Local or
|
|
|
|
/// Static prefix).
|
|
|
|
All,
|
|
|
|
/// Stops at any dereference.
|
|
|
|
Shallow,
|
|
|
|
/// Stops at the deref of a shared reference.
|
|
|
|
Supporting,
|
|
|
|
}
|
|
|
|
|
2019-06-13 16:48:52 -05:00
|
|
|
impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
2017-12-06 12:27:38 -06:00
|
|
|
/// Returns an iterator over the prefixes of `place`
|
|
|
|
/// (inclusive) from longest to smallest, potentially
|
|
|
|
/// terminating the iteration early based on `kind`.
|
2019-04-30 11:58:24 -05:00
|
|
|
pub(super) fn prefixes(
|
|
|
|
&self,
|
2019-07-11 12:25:37 -05:00
|
|
|
place_ref: PlaceRef<'cx, 'tcx>,
|
2019-04-30 11:58:24 -05:00
|
|
|
kind: PrefixSet,
|
|
|
|
) -> Prefixes<'cx, 'tcx> {
|
2019-12-22 16:42:04 -06:00
|
|
|
Prefixes { next: Some(place_ref), kind, body: self.body, tcx: self.infcx.tcx }
|
2017-12-06 12:27:38 -06:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-06-13 16:48:52 -05:00
|
|
|
impl<'cx, 'tcx> Iterator for Prefixes<'cx, 'tcx> {
|
2019-07-11 12:25:37 -05:00
|
|
|
type Item = PlaceRef<'cx, 'tcx>;
|
2017-12-06 12:27:38 -06:00
|
|
|
fn next(&mut self) -> Option<Self::Item> {
|
2018-11-20 22:01:56 -06:00
|
|
|
let mut cursor = self.next?;
|
2017-12-06 12:27:38 -06:00
|
|
|
|
|
|
|
// Post-processing `place`: Enqueue any remaining
|
|
|
|
// work. Also, `place` may not be a prefix itself, but
|
2018-11-26 20:59:49 -06:00
|
|
|
// may hold one further down (e.g., we never return
|
2017-12-06 12:27:38 -06:00
|
|
|
// downcasts here, but may return a base of a downcast).
|
|
|
|
|
|
|
|
'cursor: loop {
|
2019-07-29 17:07:28 -05:00
|
|
|
match &cursor {
|
2019-07-11 12:25:37 -05:00
|
|
|
PlaceRef {
|
|
|
|
base: PlaceBase::Local(_),
|
2019-07-29 17:07:28 -05:00
|
|
|
projection: [],
|
2019-07-11 12:25:37 -05:00
|
|
|
}
|
2019-04-30 11:58:24 -05:00
|
|
|
| // search yielded this leaf
|
2019-07-11 12:25:37 -05:00
|
|
|
PlaceRef {
|
|
|
|
base: PlaceBase::Static(_),
|
2019-07-29 17:07:28 -05:00
|
|
|
projection: [],
|
2019-07-11 12:25:37 -05:00
|
|
|
} => {
|
2017-12-06 12:27:38 -06:00
|
|
|
self.next = None;
|
|
|
|
return Some(cursor);
|
|
|
|
}
|
2019-07-11 12:25:37 -05:00
|
|
|
PlaceRef {
|
|
|
|
base: _,
|
2019-08-24 19:53:20 -05:00
|
|
|
projection: [proj_base @ .., elem],
|
2019-07-29 17:07:28 -05:00
|
|
|
} => {
|
|
|
|
match elem {
|
|
|
|
ProjectionElem::Field(_ /*field*/, _ /*ty*/) => {
|
|
|
|
// FIXME: add union handling
|
|
|
|
self.next = Some(PlaceRef {
|
|
|
|
base: cursor.base,
|
|
|
|
projection: proj_base,
|
|
|
|
});
|
|
|
|
return Some(cursor);
|
|
|
|
}
|
|
|
|
ProjectionElem::Downcast(..) |
|
|
|
|
ProjectionElem::Subslice { .. } |
|
|
|
|
ProjectionElem::ConstantIndex { .. } |
|
|
|
|
ProjectionElem::Index(_) => {
|
|
|
|
cursor = PlaceRef {
|
|
|
|
base: cursor.base,
|
|
|
|
projection: proj_base,
|
|
|
|
};
|
|
|
|
continue 'cursor;
|
|
|
|
}
|
|
|
|
ProjectionElem::Deref => {
|
|
|
|
// (handled below)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
assert_eq!(*elem, ProjectionElem::Deref);
|
|
|
|
|
|
|
|
match self.kind {
|
|
|
|
PrefixSet::Shallow => {
|
2019-09-12 14:20:20 -05:00
|
|
|
// Shallow prefixes are found by stripping away
|
2019-07-29 17:07:28 -05:00
|
|
|
// fields, but stop at *any* dereference.
|
|
|
|
// So we can just stop the traversal now.
|
|
|
|
self.next = None;
|
|
|
|
return Some(cursor);
|
|
|
|
}
|
|
|
|
PrefixSet::All => {
|
2019-09-12 14:20:20 -05:00
|
|
|
// All prefixes: just blindly enqueue the base
|
|
|
|
// of the projection.
|
2019-07-29 17:07:28 -05:00
|
|
|
self.next = Some(PlaceRef {
|
|
|
|
base: cursor.base,
|
|
|
|
projection: proj_base,
|
|
|
|
});
|
|
|
|
return Some(cursor);
|
|
|
|
}
|
|
|
|
PrefixSet::Supporting => {
|
2019-09-12 14:20:20 -05:00
|
|
|
// Fall through!
|
2019-07-29 17:07:28 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
assert_eq!(self.kind, PrefixSet::Supporting);
|
2019-09-12 14:20:20 -05:00
|
|
|
// Supporting prefixes: strip away fields and
|
2019-07-29 17:07:28 -05:00
|
|
|
// derefs, except we stop at the deref of a shared
|
|
|
|
// reference.
|
|
|
|
|
2019-12-03 04:55:58 -06:00
|
|
|
let ty = Place::ty_from(cursor.base, proj_base, *self.body, self.tcx).ty;
|
2019-09-16 13:08:35 -05:00
|
|
|
match ty.kind {
|
2019-07-29 17:07:28 -05:00
|
|
|
ty::RawPtr(_) |
|
|
|
|
ty::Ref(
|
|
|
|
_, /*rgn*/
|
|
|
|
_, /*ty*/
|
2019-12-16 10:28:40 -06:00
|
|
|
hir::Mutability::Not
|
2019-07-29 17:07:28 -05:00
|
|
|
) => {
|
|
|
|
// don't continue traversing over derefs of raw pointers or shared
|
|
|
|
// borrows.
|
|
|
|
self.next = None;
|
|
|
|
return Some(cursor);
|
|
|
|
}
|
|
|
|
|
|
|
|
ty::Ref(
|
|
|
|
_, /*rgn*/
|
|
|
|
_, /*ty*/
|
2019-12-16 10:28:40 -06:00
|
|
|
hir::Mutability::Mut,
|
2019-07-29 17:07:28 -05:00
|
|
|
) => {
|
|
|
|
self.next = Some(PlaceRef {
|
|
|
|
base: cursor.base,
|
|
|
|
projection: proj_base,
|
|
|
|
});
|
|
|
|
return Some(cursor);
|
|
|
|
}
|
|
|
|
|
|
|
|
ty::Adt(..) if ty.is_box() => {
|
|
|
|
self.next = Some(PlaceRef {
|
|
|
|
base: cursor.base,
|
|
|
|
projection: proj_base,
|
|
|
|
});
|
|
|
|
return Some(cursor);
|
|
|
|
}
|
|
|
|
|
|
|
|
_ => panic!("unknown type fed to Projection Deref."),
|
|
|
|
}
|
2017-12-06 12:27:38 -06:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|