Skip to content

Commit 22fa4bb

Browse files
committed
Auto merge of #60063 - spastorino:place2_2, r=oli-obk
Convert Place unroll to a proper iterator r? @oli-obk
2 parents 6c22051 + 0a386ba commit 22fa4bb

File tree

2 files changed

+298
-254
lines changed

2 files changed

+298
-254
lines changed

src/librustc/mir/mod.rs

+94
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ use crate::rustc_serialize::{self as serialize};
2020
use smallvec::SmallVec;
2121
use std::borrow::Cow;
2222
use std::fmt::{self, Debug, Formatter, Write};
23+
use std::iter::FusedIterator;
2324
use std::ops::{Index, IndexMut};
2425
use std::slice;
2526
use std::vec::IntoIter;
@@ -2058,8 +2059,101 @@ impl<'tcx> Place<'tcx> {
20582059
Place::Base(PlaceBase::Static(..)) => None,
20592060
}
20602061
}
2062+
2063+
/// Recursively "iterates" over place components, generating a `PlaceBase` and
2064+
/// `PlaceProjections` list and invoking `op` with a `PlaceProjectionsIter`.
2065+
pub fn iterate<R>(
2066+
&self,
2067+
op: impl FnOnce(&PlaceBase<'tcx>, PlaceProjectionsIter<'_, 'tcx>) -> R,
2068+
) -> R {
2069+
self.iterate2(&PlaceProjections::Empty, op)
2070+
}
2071+
2072+
fn iterate2<R>(
2073+
&self,
2074+
next: &PlaceProjections<'_, 'tcx>,
2075+
op: impl FnOnce(&PlaceBase<'tcx>, PlaceProjectionsIter<'_, 'tcx>) -> R,
2076+
) -> R {
2077+
match self {
2078+
Place::Projection(interior) => interior.base.iterate2(
2079+
&PlaceProjections::List {
2080+
projection: interior,
2081+
next,
2082+
},
2083+
op,
2084+
),
2085+
2086+
Place::Base(base) => op(base, next.iter()),
2087+
}
2088+
}
2089+
}
2090+
2091+
/// A linked list of projections running up the stack; begins with the
2092+
/// innermost projection and extends to the outermost (e.g., `a.b.c`
2093+
/// would have the place `b` with a "next" pointer to `b.c`).
2094+
/// Created by `Place::iterate`.
2095+
///
2096+
/// N.B., this particular impl strategy is not the most obvious. It was
2097+
/// chosen because it makes a measurable difference to NLL
2098+
/// performance, as this code (`borrow_conflicts_with_place`) is somewhat hot.
2099+
pub enum PlaceProjections<'p, 'tcx: 'p> {
2100+
Empty,
2101+
2102+
List {
2103+
projection: &'p PlaceProjection<'tcx>,
2104+
next: &'p PlaceProjections<'p, 'tcx>,
2105+
}
2106+
}
2107+
2108+
impl<'p, 'tcx> PlaceProjections<'p, 'tcx> {
2109+
fn iter(&self) -> PlaceProjectionsIter<'_, 'tcx> {
2110+
PlaceProjectionsIter { value: self }
2111+
}
20612112
}
20622113

2114+
impl<'p, 'tcx> IntoIterator for &'p PlaceProjections<'p, 'tcx> {
2115+
type Item = &'p PlaceProjection<'tcx>;
2116+
type IntoIter = PlaceProjectionsIter<'p, 'tcx>;
2117+
2118+
/// Converts a list of `PlaceProjection` components into an iterator;
2119+
/// this iterator yields up a never-ending stream of `Option<&Place>`.
2120+
/// These begin with the "innermost" projection and then with each
2121+
/// projection therefrom. So given a place like `a.b.c` it would
2122+
/// yield up:
2123+
///
2124+
/// ```notrust
2125+
/// Some(`a`), Some(`a.b`), Some(`a.b.c`), None, None, ...
2126+
/// ```
2127+
fn into_iter(self) -> Self::IntoIter {
2128+
self.iter()
2129+
}
2130+
}
2131+
2132+
/// Iterator over components; see `PlaceProjections::iter` for more
2133+
/// information.
2134+
///
2135+
/// N.B., this is not a *true* Rust iterator -- the code above just
2136+
/// manually invokes `next`. This is because we (sometimes) want to
2137+
/// keep executing even after `None` has been returned.
2138+
pub struct PlaceProjectionsIter<'p, 'tcx: 'p> {
2139+
pub value: &'p PlaceProjections<'p, 'tcx>,
2140+
}
2141+
2142+
impl<'p, 'tcx> Iterator for PlaceProjectionsIter<'p, 'tcx> {
2143+
type Item = &'p PlaceProjection<'tcx>;
2144+
2145+
fn next(&mut self) -> Option<Self::Item> {
2146+
if let &PlaceProjections::List { projection, next } = self.value {
2147+
self.value = next;
2148+
Some(projection)
2149+
} else {
2150+
None
2151+
}
2152+
}
2153+
}
2154+
2155+
impl<'p, 'tcx> FusedIterator for PlaceProjectionsIter<'p, 'tcx> {}
2156+
20632157
impl<'tcx> Debug for Place<'tcx> {
20642158
fn fmt(&self, fmt: &mut Formatter<'_>) -> fmt::Result {
20652159
use self::Place::*;

0 commit comments

Comments
 (0)