diff options
| author | bors <bors@rust-lang.org> | 2019-04-19 09:57:26 +0000 |
|---|---|---|
| committer | bors <bors@rust-lang.org> | 2019-04-19 09:57:26 +0000 |
| commit | 22fa4bb0ebdfe9fcd7962f1fa6e758c036c878e6 (patch) | |
| tree | 519d99f4c120a338fe25cab86c8d794996e6c8a6 /src/librustc | |
| parent | 6c22051411208f8f54bd1d85377c327a1e949712 (diff) | |
| parent | 0a386baa5f27270012f262881a62b75d1a115a82 (diff) | |
| download | rust-22fa4bb0ebdfe9fcd7962f1fa6e758c036c878e6.tar.gz rust-22fa4bb0ebdfe9fcd7962f1fa6e758c036c878e6.zip | |
Auto merge of #60063 - spastorino:place2_2, r=oli-obk
Convert Place unroll to a proper iterator r? @oli-obk
Diffstat (limited to 'src/librustc')
| -rw-r--r-- | src/librustc/mir/mod.rs | 94 |
1 files changed, 94 insertions, 0 deletions
diff --git a/src/librustc/mir/mod.rs b/src/librustc/mir/mod.rs index 3f376fb052a..b4f63d9a40c 100644 --- a/src/librustc/mir/mod.rs +++ b/src/librustc/mir/mod.rs @@ -20,6 +20,7 @@ use crate::rustc_serialize::{self as serialize}; use smallvec::SmallVec; use std::borrow::Cow; use std::fmt::{self, Debug, Formatter, Write}; +use std::iter::FusedIterator; use std::ops::{Index, IndexMut}; use std::slice; use std::vec::IntoIter; @@ -2058,8 +2059,101 @@ impl<'tcx> Place<'tcx> { Place::Base(PlaceBase::Static(..)) => None, } } + + /// Recursively "iterates" over place components, generating a `PlaceBase` and + /// `PlaceProjections` list and invoking `op` with a `PlaceProjectionsIter`. + pub fn iterate<R>( + &self, + op: impl FnOnce(&PlaceBase<'tcx>, PlaceProjectionsIter<'_, 'tcx>) -> R, + ) -> R { + self.iterate2(&PlaceProjections::Empty, op) + } + + fn iterate2<R>( + &self, + next: &PlaceProjections<'_, 'tcx>, + op: impl FnOnce(&PlaceBase<'tcx>, PlaceProjectionsIter<'_, 'tcx>) -> R, + ) -> R { + match self { + Place::Projection(interior) => interior.base.iterate2( + &PlaceProjections::List { + projection: interior, + next, + }, + op, + ), + + Place::Base(base) => op(base, next.iter()), + } + } +} + +/// A linked list of projections running up the stack; begins with the +/// innermost projection and extends to the outermost (e.g., `a.b.c` +/// would have the place `b` with a "next" pointer to `b.c`). +/// Created by `Place::iterate`. +/// +/// 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 enum PlaceProjections<'p, 'tcx: 'p> { + Empty, + + List { + projection: &'p PlaceProjection<'tcx>, + next: &'p PlaceProjections<'p, 'tcx>, + } +} + +impl<'p, 'tcx> PlaceProjections<'p, 'tcx> { + fn iter(&self) -> PlaceProjectionsIter<'_, 'tcx> { + PlaceProjectionsIter { value: self } + } } +impl<'p, 'tcx> IntoIterator for &'p PlaceProjections<'p, 'tcx> { + type Item = &'p PlaceProjection<'tcx>; + type IntoIter = PlaceProjectionsIter<'p, 'tcx>; + + /// Converts a list of `PlaceProjection` components into an iterator; + /// this iterator yields up a never-ending stream of `Option<&Place>`. + /// These begin with the "innermost" projection 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 into_iter(self) -> Self::IntoIter { + self.iter() + } +} + +/// Iterator over components; see `PlaceProjections::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 PlaceProjectionsIter<'p, 'tcx: 'p> { + pub value: &'p PlaceProjections<'p, 'tcx>, +} + +impl<'p, 'tcx> Iterator for PlaceProjectionsIter<'p, 'tcx> { + type Item = &'p PlaceProjection<'tcx>; + + fn next(&mut self) -> Option<Self::Item> { + if let &PlaceProjections::List { projection, next } = self.value { + self.value = next; + Some(projection) + } else { + None + } + } +} + +impl<'p, 'tcx> FusedIterator for PlaceProjectionsIter<'p, 'tcx> {} + impl<'tcx> Debug for Place<'tcx> { fn fmt(&self, fmt: &mut Formatter<'_>) -> fmt::Result { use self::Place::*; |
