@@ -20,6 +20,7 @@ use crate::rustc_serialize::{self as serialize};
20
20
use smallvec:: SmallVec ;
21
21
use std:: borrow:: Cow ;
22
22
use std:: fmt:: { self , Debug , Formatter , Write } ;
23
+ use std:: iter:: FusedIterator ;
23
24
use std:: ops:: { Index , IndexMut } ;
24
25
use std:: slice;
25
26
use std:: vec:: IntoIter ;
@@ -2058,8 +2059,101 @@ impl<'tcx> Place<'tcx> {
2058
2059
Place :: Base ( PlaceBase :: Static ( ..) ) => None ,
2059
2060
}
2060
2061
}
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
+ }
2061
2112
}
2062
2113
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
+
2063
2157
impl < ' tcx > Debug for Place < ' tcx > {
2064
2158
fn fmt ( & self , fmt : & mut Formatter < ' _ > ) -> fmt:: Result {
2065
2159
use self :: Place :: * ;
0 commit comments