提交 66fe4ff7 编写于 作者: S Santiago Pastorino

Move unroll_place to Place::unroll

上级 6ed6f146
......@@ -2058,6 +2058,81 @@ pub fn base_local(&self) -> Option<Local> {
Place::Base(PlaceBase::Static(..)) => None,
}
}
/// Recursively "unroll" a place into a `PlaceComponents` list,
/// invoking `op` with a `PlaceComponentsIter`.
pub fn unroll<R>(
&self,
next: Option<&PlaceComponents<'_, 'tcx>>,
op: impl FnOnce(PlaceComponentsIter<'_, 'tcx>) -> R,
) -> R {
match self {
Place::Projection(interior) => interior.base.unroll(
Some(&PlaceComponents {
component: self,
next,
}),
op,
),
Place::Base(PlaceBase::Local(_)) | Place::Base(PlaceBase::Static(_)) => {
let list = PlaceComponents {
component: self,
next,
};
op(list.iter())
}
}
}
}
/// A linked list of places running up the stack; begins with the
/// innermost place and extends to projections (e.g., `a.b` would have
/// the place `a` with a "next" pointer to `a.b`). Created by
/// `Place::unroll`.
///
/// N.B., this particular impl strategy is not the most obvious. It was
/// chosen because it makes a measurable difference to NLL
/// performance, as this code (`borrow_conflicts_with_place`) is somewhat hot.
pub struct PlaceComponents<'p, 'tcx: 'p> {
pub component: &'p Place<'tcx>,
pub next: Option<&'p PlaceComponents<'p, 'tcx>>,
}
impl<'p, 'tcx> PlaceComponents<'p, 'tcx> {
/// Converts a list of `Place` components into an iterator; this
/// iterator yields up a never-ending stream of `Option<&Place>`.
/// These begin with the "innermost" place and then with each
/// projection therefrom. So given a place like `a.b.c` it would
/// yield up:
///
/// ```notrust
/// Some(`a`), Some(`a.b`), Some(`a.b.c`), None, None, ...
/// ```
fn iter(&self) -> PlaceComponentsIter<'_, 'tcx> {
PlaceComponentsIter { value: Some(self) }
}
}
/// Iterator over components; see `PlaceComponents::iter` for more
/// information.
///
/// N.B., this is not a *true* Rust iterator -- the code above just
/// manually invokes `next`. This is because we (sometimes) want to
/// keep executing even after `None` has been returned.
pub struct PlaceComponentsIter<'p, 'tcx: 'p> {
pub value: Option<&'p PlaceComponents<'p, 'tcx>>,
}
impl<'p, 'tcx> PlaceComponentsIter<'p, 'tcx> {
pub fn next(&mut self) -> Option<&'p Place<'tcx>> {
if let Some(&PlaceComponents { component, next }) = self.value {
self.value = next;
Some(component)
} else {
None
}
}
}
impl<'tcx> Debug for Place<'tcx> {
......
......@@ -2,7 +2,9 @@
use crate::borrow_check::Overlap;
use crate::borrow_check::{Deep, Shallow, AccessDepth};
use rustc::hir;
use rustc::mir::{BorrowKind, Mir, Place, PlaceBase, Projection, ProjectionElem, StaticKind};
use rustc::mir::{
BorrowKind, Mir, Place, PlaceBase, Projection, ProjectionElem, PlaceComponentsIter, StaticKind
};
use rustc::ty::{self, TyCtxt};
use std::cmp::max;
......@@ -65,8 +67,8 @@ pub(super) fn borrow_conflicts_with_place<'gcx, 'tcx>(
}
}
unroll_place(borrow_place, None, |borrow_components| {
unroll_place(access_place, None, |access_components| {
borrow_place.unroll(None, |borrow_components| {
access_place.unroll(None, |access_components| {
place_components_conflict(
tcx,
mir,
......@@ -272,82 +274,6 @@ fn place_components_conflict<'gcx, 'tcx>(
}
}
/// A linked list of places running up the stack; begins with the
/// innermost place and extends to projections (e.g., `a.b` would have
/// the place `a` with a "next" pointer to `a.b`). Created by
/// `unroll_place`.
///
/// N.B., this particular impl strategy is not the most obvious. It was
/// chosen because it makes a measurable difference to NLL
/// performance, as this code (`borrow_conflicts_with_place`) is somewhat hot.
struct PlaceComponents<'p, 'tcx: 'p> {
component: &'p Place<'tcx>,
next: Option<&'p PlaceComponents<'p, 'tcx>>,
}
impl<'p, 'tcx> PlaceComponents<'p, 'tcx> {
/// Converts a list of `Place` components into an iterator; this
/// iterator yields up a never-ending stream of `Option<&Place>`.
/// These begin with the "innermost" place and then with each
/// projection therefrom. So given a place like `a.b.c` it would
/// yield up:
///
/// ```notrust
/// Some(`a`), Some(`a.b`), Some(`a.b.c`), None, None, ...
/// ```
fn iter(&self) -> PlaceComponentsIter<'_, 'tcx> {
PlaceComponentsIter { value: Some(self) }
}
}
/// Iterator over components; see `PlaceComponents::iter` for more
/// information.
///
/// N.B., this is not a *true* Rust iterator -- the code above just
/// manually invokes `next`. This is because we (sometimes) want to
/// keep executing even after `None` has been returned.
struct PlaceComponentsIter<'p, 'tcx: 'p> {
value: Option<&'p PlaceComponents<'p, 'tcx>>,
}
impl<'p, 'tcx> PlaceComponentsIter<'p, 'tcx> {
fn next(&mut self) -> Option<&'p Place<'tcx>> {
if let Some(&PlaceComponents { component, next }) = self.value {
self.value = next;
Some(component)
} else {
None
}
}
}
/// Recursively "unroll" a place into a `PlaceComponents` list,
/// invoking `op` with a `PlaceComponentsIter`.
fn unroll_place<'tcx, R>(
place: &Place<'tcx>,
next: Option<&PlaceComponents<'_, 'tcx>>,
op: impl FnOnce(PlaceComponentsIter<'_, 'tcx>) -> R,
) -> R {
match place {
Place::Projection(interior) => unroll_place(
&interior.base,
Some(&PlaceComponents {
component: place,
next,
}),
op,
),
Place::Base(PlaceBase::Local(_)) | Place::Base(PlaceBase::Static(_)) => {
let list = PlaceComponents {
component: place,
next,
};
op(list.iter())
}
}
}
// Given that the bases of `elem1` and `elem2` are always either equal
// or disjoint (and have the same type!), return the overlap situation
// between `elem1` and `elem2`.
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册