@@ -20,6 +20,7 @@ use crate::rustc_serialize::{self as serialize};
2020use smallvec:: SmallVec ;
2121use std:: borrow:: Cow ;
2222use std:: fmt:: { self , Debug , Formatter , Write } ;
23+ use std:: iter:: FusedIterator ;
2324use std:: ops:: { Index , IndexMut } ;
2425use std:: slice;
2526use 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+
20632157impl < ' tcx > Debug for Place < ' tcx > {
20642158 fn fmt ( & self , fmt : & mut Formatter < ' _ > ) -> fmt:: Result {
20652159 use self :: Place :: * ;
0 commit comments