Merge remote-tracking branch 'rust-lang/master' into compiletest-json
This commit is contained in:
commit
d81de4871f
5012
src/libcore/iter.rs
5012
src/libcore/iter.rs
File diff suppressed because it is too large
Load Diff
2112
src/libcore/iter/iterator.rs
Normal file
2112
src/libcore/iter/iterator.rs
Normal file
File diff suppressed because it is too large
Load Diff
1657
src/libcore/iter/mod.rs
Normal file
1657
src/libcore/iter/mod.rs
Normal file
File diff suppressed because it is too large
Load Diff
548
src/libcore/iter/range.rs
Normal file
548
src/libcore/iter/range.rs
Normal file
@ -0,0 +1,548 @@
|
||||
// Copyright 2013-2016 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
use clone::Clone;
|
||||
use cmp::PartialOrd;
|
||||
use mem;
|
||||
use num::{Zero, One};
|
||||
use ops::{self, Add, Sub};
|
||||
use option::Option::{self, Some, None};
|
||||
use marker::Sized;
|
||||
use usize;
|
||||
|
||||
use super::{DoubleEndedIterator, ExactSizeIterator, Iterator};
|
||||
|
||||
/// Objects that can be stepped over in both directions.
|
||||
///
|
||||
/// The `steps_between` function provides a way to efficiently compare
|
||||
/// two `Step` objects.
|
||||
#[unstable(feature = "step_trait",
|
||||
reason = "likely to be replaced by finer-grained traits",
|
||||
issue = "27741")]
|
||||
pub trait Step: PartialOrd + Sized {
|
||||
/// Steps `self` if possible.
|
||||
fn step(&self, by: &Self) -> Option<Self>;
|
||||
|
||||
/// Returns the number of steps between two step objects. The count is
|
||||
/// inclusive of `start` and exclusive of `end`.
|
||||
///
|
||||
/// Returns `None` if it is not possible to calculate `steps_between`
|
||||
/// without overflow.
|
||||
fn steps_between(start: &Self, end: &Self, by: &Self) -> Option<usize>;
|
||||
}
|
||||
|
||||
macro_rules! step_impl_unsigned {
|
||||
($($t:ty)*) => ($(
|
||||
#[unstable(feature = "step_trait",
|
||||
reason = "likely to be replaced by finer-grained traits",
|
||||
issue = "27741")]
|
||||
impl Step for $t {
|
||||
#[inline]
|
||||
fn step(&self, by: &$t) -> Option<$t> {
|
||||
(*self).checked_add(*by)
|
||||
}
|
||||
#[inline]
|
||||
#[allow(trivial_numeric_casts)]
|
||||
fn steps_between(start: &$t, end: &$t, by: &$t) -> Option<usize> {
|
||||
if *by == 0 { return None; }
|
||||
if *start < *end {
|
||||
// Note: We assume $t <= usize here
|
||||
let diff = (*end - *start) as usize;
|
||||
let by = *by as usize;
|
||||
if diff % by > 0 {
|
||||
Some(diff / by + 1)
|
||||
} else {
|
||||
Some(diff / by)
|
||||
}
|
||||
} else {
|
||||
Some(0)
|
||||
}
|
||||
}
|
||||
}
|
||||
)*)
|
||||
}
|
||||
macro_rules! step_impl_signed {
|
||||
($($t:ty)*) => ($(
|
||||
#[unstable(feature = "step_trait",
|
||||
reason = "likely to be replaced by finer-grained traits",
|
||||
issue = "27741")]
|
||||
impl Step for $t {
|
||||
#[inline]
|
||||
fn step(&self, by: &$t) -> Option<$t> {
|
||||
(*self).checked_add(*by)
|
||||
}
|
||||
#[inline]
|
||||
#[allow(trivial_numeric_casts)]
|
||||
fn steps_between(start: &$t, end: &$t, by: &$t) -> Option<usize> {
|
||||
if *by == 0 { return None; }
|
||||
let diff: usize;
|
||||
let by_u: usize;
|
||||
if *by > 0 {
|
||||
if *start >= *end {
|
||||
return Some(0);
|
||||
}
|
||||
// Note: We assume $t <= isize here
|
||||
// Use .wrapping_sub and cast to usize to compute the
|
||||
// difference that may not fit inside the range of isize.
|
||||
diff = (*end as isize).wrapping_sub(*start as isize) as usize;
|
||||
by_u = *by as usize;
|
||||
} else {
|
||||
if *start <= *end {
|
||||
return Some(0);
|
||||
}
|
||||
diff = (*start as isize).wrapping_sub(*end as isize) as usize;
|
||||
by_u = (*by as isize).wrapping_mul(-1) as usize;
|
||||
}
|
||||
if diff % by_u > 0 {
|
||||
Some(diff / by_u + 1)
|
||||
} else {
|
||||
Some(diff / by_u)
|
||||
}
|
||||
}
|
||||
}
|
||||
)*)
|
||||
}
|
||||
|
||||
macro_rules! step_impl_no_between {
|
||||
($($t:ty)*) => ($(
|
||||
#[unstable(feature = "step_trait",
|
||||
reason = "likely to be replaced by finer-grained traits",
|
||||
issue = "27741")]
|
||||
impl Step for $t {
|
||||
#[inline]
|
||||
fn step(&self, by: &$t) -> Option<$t> {
|
||||
(*self).checked_add(*by)
|
||||
}
|
||||
#[inline]
|
||||
fn steps_between(_a: &$t, _b: &$t, _by: &$t) -> Option<usize> {
|
||||
None
|
||||
}
|
||||
}
|
||||
)*)
|
||||
}
|
||||
|
||||
step_impl_unsigned!(usize u8 u16 u32);
|
||||
step_impl_signed!(isize i8 i16 i32);
|
||||
#[cfg(target_pointer_width = "64")]
|
||||
step_impl_unsigned!(u64);
|
||||
#[cfg(target_pointer_width = "64")]
|
||||
step_impl_signed!(i64);
|
||||
// If the target pointer width is not 64-bits, we
|
||||
// assume here that it is less than 64-bits.
|
||||
#[cfg(not(target_pointer_width = "64"))]
|
||||
step_impl_no_between!(u64 i64);
|
||||
|
||||
/// An adapter for stepping range iterators by a custom amount.
|
||||
///
|
||||
/// The resulting iterator handles overflow by stopping. The `A`
|
||||
/// parameter is the type being iterated over, while `R` is the range
|
||||
/// type (usually one of `std::ops::{Range, RangeFrom, RangeInclusive}`.
|
||||
#[derive(Clone, Debug)]
|
||||
#[unstable(feature = "step_by", reason = "recent addition",
|
||||
issue = "27741")]
|
||||
pub struct StepBy<A, R> {
|
||||
step_by: A,
|
||||
range: R,
|
||||
}
|
||||
|
||||
impl<A: Step> ops::RangeFrom<A> {
|
||||
/// Creates an iterator starting at the same point, but stepping by
|
||||
/// the given amount at each iteration.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// # #![feature(step_by)]
|
||||
///
|
||||
/// for i in (0u8..).step_by(2).take(10) {
|
||||
/// println!("{}", i);
|
||||
/// }
|
||||
/// ```
|
||||
///
|
||||
/// This prints the first ten even natural integers (0 to 18).
|
||||
#[unstable(feature = "step_by", reason = "recent addition",
|
||||
issue = "27741")]
|
||||
pub fn step_by(self, by: A) -> StepBy<A, Self> {
|
||||
StepBy {
|
||||
step_by: by,
|
||||
range: self
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<A: Step> ops::Range<A> {
|
||||
/// Creates an iterator with the same range, but stepping by the
|
||||
/// given amount at each iteration.
|
||||
///
|
||||
/// The resulting iterator handles overflow by stopping.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// #![feature(step_by)]
|
||||
///
|
||||
/// for i in (0..10).step_by(2) {
|
||||
/// println!("{}", i);
|
||||
/// }
|
||||
/// ```
|
||||
///
|
||||
/// This prints:
|
||||
///
|
||||
/// ```text
|
||||
/// 0
|
||||
/// 2
|
||||
/// 4
|
||||
/// 6
|
||||
/// 8
|
||||
/// ```
|
||||
#[unstable(feature = "step_by", reason = "recent addition",
|
||||
issue = "27741")]
|
||||
pub fn step_by(self, by: A) -> StepBy<A, Self> {
|
||||
StepBy {
|
||||
step_by: by,
|
||||
range: self
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<A: Step> ops::RangeInclusive<A> {
|
||||
/// Creates an iterator with the same range, but stepping by the
|
||||
/// given amount at each iteration.
|
||||
///
|
||||
/// The resulting iterator handles overflow by stopping.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// #![feature(step_by, inclusive_range_syntax)]
|
||||
///
|
||||
/// for i in (0...10).step_by(2) {
|
||||
/// println!("{}", i);
|
||||
/// }
|
||||
/// ```
|
||||
///
|
||||
/// This prints:
|
||||
///
|
||||
/// ```text
|
||||
/// 0
|
||||
/// 2
|
||||
/// 4
|
||||
/// 6
|
||||
/// 8
|
||||
/// 10
|
||||
/// ```
|
||||
#[unstable(feature = "step_by", reason = "recent addition",
|
||||
issue = "27741")]
|
||||
pub fn step_by(self, by: A) -> StepBy<A, Self> {
|
||||
StepBy {
|
||||
step_by: by,
|
||||
range: self
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
impl<A> Iterator for StepBy<A, ops::RangeFrom<A>> where
|
||||
A: Clone,
|
||||
for<'a> &'a A: Add<&'a A, Output = A>
|
||||
{
|
||||
type Item = A;
|
||||
|
||||
#[inline]
|
||||
fn next(&mut self) -> Option<A> {
|
||||
let mut n = &self.range.start + &self.step_by;
|
||||
mem::swap(&mut n, &mut self.range.start);
|
||||
Some(n)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn size_hint(&self) -> (usize, Option<usize>) {
|
||||
(usize::MAX, None) // Too bad we can't specify an infinite lower bound
|
||||
}
|
||||
}
|
||||
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
impl<A: Step + Zero + Clone> Iterator for StepBy<A, ops::Range<A>> {
|
||||
type Item = A;
|
||||
|
||||
#[inline]
|
||||
fn next(&mut self) -> Option<A> {
|
||||
let rev = self.step_by < A::zero();
|
||||
if (rev && self.range.start > self.range.end) ||
|
||||
(!rev && self.range.start < self.range.end)
|
||||
{
|
||||
match self.range.start.step(&self.step_by) {
|
||||
Some(mut n) => {
|
||||
mem::swap(&mut self.range.start, &mut n);
|
||||
Some(n)
|
||||
},
|
||||
None => {
|
||||
let mut n = self.range.end.clone();
|
||||
mem::swap(&mut self.range.start, &mut n);
|
||||
Some(n)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn size_hint(&self) -> (usize, Option<usize>) {
|
||||
match Step::steps_between(&self.range.start,
|
||||
&self.range.end,
|
||||
&self.step_by) {
|
||||
Some(hint) => (hint, Some(hint)),
|
||||
None => (0, None)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[unstable(feature = "inclusive_range",
|
||||
reason = "recently added, follows RFC",
|
||||
issue = "28237")]
|
||||
impl<A: Step + Zero + Clone> Iterator for StepBy<A, ops::RangeInclusive<A>> {
|
||||
type Item = A;
|
||||
|
||||
#[inline]
|
||||
fn next(&mut self) -> Option<A> {
|
||||
use ops::RangeInclusive::*;
|
||||
|
||||
// this function has a sort of odd structure due to borrowck issues
|
||||
// we may need to replace self.range, so borrows of start and end need to end early
|
||||
|
||||
let (finishing, n) = match self.range {
|
||||
Empty { .. } => return None, // empty iterators yield no values
|
||||
|
||||
NonEmpty { ref mut start, ref mut end } => {
|
||||
let zero = A::zero();
|
||||
let rev = self.step_by < zero;
|
||||
|
||||
// march start towards (maybe past!) end and yield the old value
|
||||
if (rev && start >= end) ||
|
||||
(!rev && start <= end)
|
||||
{
|
||||
match start.step(&self.step_by) {
|
||||
Some(mut n) => {
|
||||
mem::swap(start, &mut n);
|
||||
(None, Some(n)) // yield old value, remain non-empty
|
||||
},
|
||||
None => {
|
||||
let mut n = end.clone();
|
||||
mem::swap(start, &mut n);
|
||||
(None, Some(n)) // yield old value, remain non-empty
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// found range in inconsistent state (start at or past end), so become empty
|
||||
(Some(mem::replace(end, zero)), None)
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// turn into an empty iterator if we've reached the end
|
||||
if let Some(end) = finishing {
|
||||
self.range = Empty { at: end };
|
||||
}
|
||||
|
||||
n
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn size_hint(&self) -> (usize, Option<usize>) {
|
||||
use ops::RangeInclusive::*;
|
||||
|
||||
match self.range {
|
||||
Empty { .. } => (0, Some(0)),
|
||||
|
||||
NonEmpty { ref start, ref end } =>
|
||||
match Step::steps_between(start,
|
||||
end,
|
||||
&self.step_by) {
|
||||
Some(hint) => (hint.saturating_add(1), hint.checked_add(1)),
|
||||
None => (0, None)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
macro_rules! range_exact_iter_impl {
|
||||
($($t:ty)*) => ($(
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
impl ExactSizeIterator for ops::Range<$t> { }
|
||||
|
||||
#[unstable(feature = "inclusive_range",
|
||||
reason = "recently added, follows RFC",
|
||||
issue = "28237")]
|
||||
impl ExactSizeIterator for ops::RangeInclusive<$t> { }
|
||||
)*)
|
||||
}
|
||||
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
impl<A: Step + One> Iterator for ops::Range<A> where
|
||||
for<'a> &'a A: Add<&'a A, Output = A>
|
||||
{
|
||||
type Item = A;
|
||||
|
||||
#[inline]
|
||||
fn next(&mut self) -> Option<A> {
|
||||
if self.start < self.end {
|
||||
let mut n = &self.start + &A::one();
|
||||
mem::swap(&mut n, &mut self.start);
|
||||
Some(n)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn size_hint(&self) -> (usize, Option<usize>) {
|
||||
match Step::steps_between(&self.start, &self.end, &A::one()) {
|
||||
Some(hint) => (hint, Some(hint)),
|
||||
None => (0, None)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Ranges of u64 and i64 are excluded because they cannot guarantee having
|
||||
// a length <= usize::MAX, which is required by ExactSizeIterator.
|
||||
range_exact_iter_impl!(usize u8 u16 u32 isize i8 i16 i32);
|
||||
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
impl<A: Step + One + Clone> DoubleEndedIterator for ops::Range<A> where
|
||||
for<'a> &'a A: Add<&'a A, Output = A>,
|
||||
for<'a> &'a A: Sub<&'a A, Output = A>
|
||||
{
|
||||
#[inline]
|
||||
fn next_back(&mut self) -> Option<A> {
|
||||
if self.start < self.end {
|
||||
self.end = &self.end - &A::one();
|
||||
Some(self.end.clone())
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
impl<A: Step + One> Iterator for ops::RangeFrom<A> where
|
||||
for<'a> &'a A: Add<&'a A, Output = A>
|
||||
{
|
||||
type Item = A;
|
||||
|
||||
#[inline]
|
||||
fn next(&mut self) -> Option<A> {
|
||||
let mut n = &self.start + &A::one();
|
||||
mem::swap(&mut n, &mut self.start);
|
||||
Some(n)
|
||||
}
|
||||
}
|
||||
|
||||
#[unstable(feature = "inclusive_range", reason = "recently added, follows RFC", issue = "28237")]
|
||||
impl<A: Step + One> Iterator for ops::RangeInclusive<A> where
|
||||
for<'a> &'a A: Add<&'a A, Output = A>
|
||||
{
|
||||
type Item = A;
|
||||
|
||||
#[inline]
|
||||
fn next(&mut self) -> Option<A> {
|
||||
use ops::RangeInclusive::*;
|
||||
|
||||
// this function has a sort of odd structure due to borrowck issues
|
||||
// we may need to replace self, so borrows of self.start and self.end need to end early
|
||||
|
||||
let (finishing, n) = match *self {
|
||||
Empty { .. } => (None, None), // empty iterators yield no values
|
||||
|
||||
NonEmpty { ref mut start, ref mut end } => {
|
||||
if start == end {
|
||||
(Some(mem::replace(end, A::one())), Some(mem::replace(start, A::one())))
|
||||
} else if start < end {
|
||||
let one = A::one();
|
||||
let mut n = &*start + &one;
|
||||
mem::swap(&mut n, start);
|
||||
|
||||
// if the iterator is done iterating, it will change from NonEmpty to Empty
|
||||
// to avoid unnecessary drops or clones, we'll reuse either start or end
|
||||
// (they are equal now, so it doesn't matter which)
|
||||
// to pull out end, we need to swap something back in -- use the previously
|
||||
// created A::one() as a dummy value
|
||||
|
||||
(if n == *end { Some(mem::replace(end, one)) } else { None },
|
||||
// ^ are we done yet?
|
||||
Some(n)) // < the value to output
|
||||
} else {
|
||||
(Some(mem::replace(start, A::one())), None)
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// turn into an empty iterator if this is the last value
|
||||
if let Some(end) = finishing {
|
||||
*self = Empty { at: end };
|
||||
}
|
||||
|
||||
n
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn size_hint(&self) -> (usize, Option<usize>) {
|
||||
use ops::RangeInclusive::*;
|
||||
|
||||
match *self {
|
||||
Empty { .. } => (0, Some(0)),
|
||||
|
||||
NonEmpty { ref start, ref end } =>
|
||||
match Step::steps_between(start, end, &A::one()) {
|
||||
Some(hint) => (hint.saturating_add(1), hint.checked_add(1)),
|
||||
None => (0, None),
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[unstable(feature = "inclusive_range", reason = "recently added, follows RFC", issue = "28237")]
|
||||
impl<A: Step + One> DoubleEndedIterator for ops::RangeInclusive<A> where
|
||||
for<'a> &'a A: Add<&'a A, Output = A>,
|
||||
for<'a> &'a A: Sub<&'a A, Output = A>
|
||||
{
|
||||
#[inline]
|
||||
fn next_back(&mut self) -> Option<A> {
|
||||
use ops::RangeInclusive::*;
|
||||
|
||||
// see Iterator::next for comments
|
||||
|
||||
let (finishing, n) = match *self {
|
||||
Empty { .. } => return None,
|
||||
|
||||
NonEmpty { ref mut start, ref mut end } => {
|
||||
if start == end {
|
||||
(Some(mem::replace(start, A::one())), Some(mem::replace(end, A::one())))
|
||||
} else if start < end {
|
||||
let one = A::one();
|
||||
let mut n = &*end - &one;
|
||||
mem::swap(&mut n, end);
|
||||
|
||||
(if n == *start { Some(mem::replace(start, one)) } else { None },
|
||||
Some(n))
|
||||
} else {
|
||||
(Some(mem::replace(end, A::one())), None)
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
if let Some(start) = finishing {
|
||||
*self = Empty { at: start };
|
||||
}
|
||||
|
||||
n
|
||||
}
|
||||
}
|
||||
|
270
src/libcore/iter/sources.rs
Normal file
270
src/libcore/iter/sources.rs
Normal file
@ -0,0 +1,270 @@
|
||||
// Copyright 2013-2016 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
use clone::Clone;
|
||||
use default::Default;
|
||||
use fmt;
|
||||
use marker;
|
||||
use option::Option::{self, Some, None};
|
||||
use usize;
|
||||
|
||||
use super::{DoubleEndedIterator, IntoIterator, Iterator, ExactSizeIterator};
|
||||
|
||||
/// An iterator that repeats an element endlessly.
|
||||
///
|
||||
/// This `struct` is created by the [`repeat()`] function. See its documentation for more.
|
||||
///
|
||||
/// [`repeat()`]: fn.repeat.html
|
||||
#[derive(Clone, Debug)]
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
pub struct Repeat<A> {
|
||||
element: A
|
||||
}
|
||||
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
impl<A: Clone> Iterator for Repeat<A> {
|
||||
type Item = A;
|
||||
|
||||
#[inline]
|
||||
fn next(&mut self) -> Option<A> { Some(self.element.clone()) }
|
||||
#[inline]
|
||||
fn size_hint(&self) -> (usize, Option<usize>) { (usize::MAX, None) }
|
||||
}
|
||||
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
impl<A: Clone> DoubleEndedIterator for Repeat<A> {
|
||||
#[inline]
|
||||
fn next_back(&mut self) -> Option<A> { Some(self.element.clone()) }
|
||||
}
|
||||
|
||||
/// Creates a new iterator that endlessly repeats a single element.
|
||||
///
|
||||
/// The `repeat()` function repeats a single value over and over and over and
|
||||
/// over and over and 🔁.
|
||||
///
|
||||
/// Infinite iterators like `repeat()` are often used with adapters like
|
||||
/// [`take()`], in order to make them finite.
|
||||
///
|
||||
/// [`take()`]: trait.Iterator.html#method.take
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// Basic usage:
|
||||
///
|
||||
/// ```
|
||||
/// use std::iter;
|
||||
///
|
||||
/// // the number four 4ever:
|
||||
/// let mut fours = iter::repeat(4);
|
||||
///
|
||||
/// assert_eq!(Some(4), fours.next());
|
||||
/// assert_eq!(Some(4), fours.next());
|
||||
/// assert_eq!(Some(4), fours.next());
|
||||
/// assert_eq!(Some(4), fours.next());
|
||||
/// assert_eq!(Some(4), fours.next());
|
||||
///
|
||||
/// // yup, still four
|
||||
/// assert_eq!(Some(4), fours.next());
|
||||
/// ```
|
||||
///
|
||||
/// Going finite with [`take()`]:
|
||||
///
|
||||
/// ```
|
||||
/// use std::iter;
|
||||
///
|
||||
/// // that last example was too many fours. Let's only have four fours.
|
||||
/// let mut four_fours = iter::repeat(4).take(4);
|
||||
///
|
||||
/// assert_eq!(Some(4), four_fours.next());
|
||||
/// assert_eq!(Some(4), four_fours.next());
|
||||
/// assert_eq!(Some(4), four_fours.next());
|
||||
/// assert_eq!(Some(4), four_fours.next());
|
||||
///
|
||||
/// // ... and now we're done
|
||||
/// assert_eq!(None, four_fours.next());
|
||||
/// ```
|
||||
#[inline]
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
pub fn repeat<T: Clone>(elt: T) -> Repeat<T> {
|
||||
Repeat{element: elt}
|
||||
}
|
||||
|
||||
/// An iterator that yields nothing.
|
||||
///
|
||||
/// This `struct` is created by the [`empty()`] function. See its documentation for more.
|
||||
///
|
||||
/// [`empty()`]: fn.empty.html
|
||||
#[stable(feature = "iter_empty", since = "1.2.0")]
|
||||
pub struct Empty<T>(marker::PhantomData<T>);
|
||||
|
||||
#[stable(feature = "core_impl_debug", since = "1.9.0")]
|
||||
impl<T> fmt::Debug for Empty<T> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
f.pad("Empty")
|
||||
}
|
||||
}
|
||||
|
||||
#[stable(feature = "iter_empty", since = "1.2.0")]
|
||||
impl<T> Iterator for Empty<T> {
|
||||
type Item = T;
|
||||
|
||||
fn next(&mut self) -> Option<T> {
|
||||
None
|
||||
}
|
||||
|
||||
fn size_hint(&self) -> (usize, Option<usize>){
|
||||
(0, Some(0))
|
||||
}
|
||||
}
|
||||
|
||||
#[stable(feature = "iter_empty", since = "1.2.0")]
|
||||
impl<T> DoubleEndedIterator for Empty<T> {
|
||||
fn next_back(&mut self) -> Option<T> {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
#[stable(feature = "iter_empty", since = "1.2.0")]
|
||||
impl<T> ExactSizeIterator for Empty<T> {
|
||||
fn len(&self) -> usize {
|
||||
0
|
||||
}
|
||||
}
|
||||
|
||||
// not #[derive] because that adds a Clone bound on T,
|
||||
// which isn't necessary.
|
||||
#[stable(feature = "iter_empty", since = "1.2.0")]
|
||||
impl<T> Clone for Empty<T> {
|
||||
fn clone(&self) -> Empty<T> {
|
||||
Empty(marker::PhantomData)
|
||||
}
|
||||
}
|
||||
|
||||
// not #[derive] because that adds a Default bound on T,
|
||||
// which isn't necessary.
|
||||
#[stable(feature = "iter_empty", since = "1.2.0")]
|
||||
impl<T> Default for Empty<T> {
|
||||
fn default() -> Empty<T> {
|
||||
Empty(marker::PhantomData)
|
||||
}
|
||||
}
|
||||
|
||||
/// Creates an iterator that yields nothing.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// Basic usage:
|
||||
///
|
||||
/// ```
|
||||
/// use std::iter;
|
||||
///
|
||||
/// // this could have been an iterator over i32, but alas, it's just not.
|
||||
/// let mut nope = iter::empty::<i32>();
|
||||
///
|
||||
/// assert_eq!(None, nope.next());
|
||||
/// ```
|
||||
#[stable(feature = "iter_empty", since = "1.2.0")]
|
||||
pub fn empty<T>() -> Empty<T> {
|
||||
Empty(marker::PhantomData)
|
||||
}
|
||||
|
||||
/// An iterator that yields an element exactly once.
|
||||
///
|
||||
/// This `struct` is created by the [`once()`] function. See its documentation for more.
|
||||
///
|
||||
/// [`once()`]: fn.once.html
|
||||
#[derive(Clone, Debug)]
|
||||
#[stable(feature = "iter_once", since = "1.2.0")]
|
||||
pub struct Once<T> {
|
||||
inner: ::option::IntoIter<T>
|
||||
}
|
||||
|
||||
#[stable(feature = "iter_once", since = "1.2.0")]
|
||||
impl<T> Iterator for Once<T> {
|
||||
type Item = T;
|
||||
|
||||
fn next(&mut self) -> Option<T> {
|
||||
self.inner.next()
|
||||
}
|
||||
|
||||
fn size_hint(&self) -> (usize, Option<usize>) {
|
||||
self.inner.size_hint()
|
||||
}
|
||||
}
|
||||
|
||||
#[stable(feature = "iter_once", since = "1.2.0")]
|
||||
impl<T> DoubleEndedIterator for Once<T> {
|
||||
fn next_back(&mut self) -> Option<T> {
|
||||
self.inner.next_back()
|
||||
}
|
||||
}
|
||||
|
||||
#[stable(feature = "iter_once", since = "1.2.0")]
|
||||
impl<T> ExactSizeIterator for Once<T> {
|
||||
fn len(&self) -> usize {
|
||||
self.inner.len()
|
||||
}
|
||||
}
|
||||
|
||||
/// Creates an iterator that yields an element exactly once.
|
||||
///
|
||||
/// This is commonly used to adapt a single value into a [`chain()`] of other
|
||||
/// kinds of iteration. Maybe you have an iterator that covers almost
|
||||
/// everything, but you need an extra special case. Maybe you have a function
|
||||
/// which works on iterators, but you only need to process one value.
|
||||
///
|
||||
/// [`chain()`]: trait.Iterator.html#method.chain
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// Basic usage:
|
||||
///
|
||||
/// ```
|
||||
/// use std::iter;
|
||||
///
|
||||
/// // one is the loneliest number
|
||||
/// let mut one = iter::once(1);
|
||||
///
|
||||
/// assert_eq!(Some(1), one.next());
|
||||
///
|
||||
/// // just one, that's all we get
|
||||
/// assert_eq!(None, one.next());
|
||||
/// ```
|
||||
///
|
||||
/// Chaining together with another iterator. Let's say that we want to iterate
|
||||
/// over each file of the `.foo` directory, but also a configuration file,
|
||||
/// `.foorc`:
|
||||
///
|
||||
/// ```no_run
|
||||
/// use std::iter;
|
||||
/// use std::fs;
|
||||
/// use std::path::PathBuf;
|
||||
///
|
||||
/// let dirs = fs::read_dir(".foo").unwrap();
|
||||
///
|
||||
/// // we need to convert from an iterator of DirEntry-s to an iterator of
|
||||
/// // PathBufs, so we use map
|
||||
/// let dirs = dirs.map(|file| file.unwrap().path());
|
||||
///
|
||||
/// // now, our iterator just for our config file
|
||||
/// let config = iter::once(PathBuf::from(".foorc"));
|
||||
///
|
||||
/// // chain the two iterators together into one big iterator
|
||||
/// let files = dirs.chain(config);
|
||||
///
|
||||
/// // this will give us all of the files in .foo as well as .foorc
|
||||
/// for f in files {
|
||||
/// println!("{:?}", f);
|
||||
/// }
|
||||
/// ```
|
||||
#[stable(feature = "iter_once", since = "1.2.0")]
|
||||
pub fn once<T>(value: T) -> Once<T> {
|
||||
Once { inner: Some(value).into_iter() }
|
||||
}
|
526
src/libcore/iter/traits.rs
Normal file
526
src/libcore/iter/traits.rs
Normal file
@ -0,0 +1,526 @@
|
||||
// Copyright 2013-2016 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
use option::Option::{self, Some};
|
||||
use marker::Sized;
|
||||
|
||||
use super::Iterator;
|
||||
|
||||
/// Conversion from an `Iterator`.
|
||||
///
|
||||
/// By implementing `FromIterator` for a type, you define how it will be
|
||||
/// created from an iterator. This is common for types which describe a
|
||||
/// collection of some kind.
|
||||
///
|
||||
/// `FromIterator`'s [`from_iter()`] is rarely called explicitly, and is instead
|
||||
/// used through [`Iterator`]'s [`collect()`] method. See [`collect()`]'s
|
||||
/// documentation for more examples.
|
||||
///
|
||||
/// [`from_iter()`]: #tymethod.from_iter
|
||||
/// [`Iterator`]: trait.Iterator.html
|
||||
/// [`collect()`]: trait.Iterator.html#method.collect
|
||||
///
|
||||
/// See also: [`IntoIterator`].
|
||||
///
|
||||
/// [`IntoIterator`]: trait.IntoIterator.html
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// Basic usage:
|
||||
///
|
||||
/// ```
|
||||
/// use std::iter::FromIterator;
|
||||
///
|
||||
/// let five_fives = std::iter::repeat(5).take(5);
|
||||
///
|
||||
/// let v = Vec::from_iter(five_fives);
|
||||
///
|
||||
/// assert_eq!(v, vec![5, 5, 5, 5, 5]);
|
||||
/// ```
|
||||
///
|
||||
/// Using [`collect()`] to implicitly use `FromIterator`:
|
||||
///
|
||||
/// ```
|
||||
/// let five_fives = std::iter::repeat(5).take(5);
|
||||
///
|
||||
/// let v: Vec<i32> = five_fives.collect();
|
||||
///
|
||||
/// assert_eq!(v, vec![5, 5, 5, 5, 5]);
|
||||
/// ```
|
||||
///
|
||||
/// Implementing `FromIterator` for your type:
|
||||
///
|
||||
/// ```
|
||||
/// use std::iter::FromIterator;
|
||||
///
|
||||
/// // A sample collection, that's just a wrapper over Vec<T>
|
||||
/// #[derive(Debug)]
|
||||
/// struct MyCollection(Vec<i32>);
|
||||
///
|
||||
/// // Let's give it some methods so we can create one and add things
|
||||
/// // to it.
|
||||
/// impl MyCollection {
|
||||
/// fn new() -> MyCollection {
|
||||
/// MyCollection(Vec::new())
|
||||
/// }
|
||||
///
|
||||
/// fn add(&mut self, elem: i32) {
|
||||
/// self.0.push(elem);
|
||||
/// }
|
||||
/// }
|
||||
///
|
||||
/// // and we'll implement FromIterator
|
||||
/// impl FromIterator<i32> for MyCollection {
|
||||
/// fn from_iter<I: IntoIterator<Item=i32>>(iter: I) -> Self {
|
||||
/// let mut c = MyCollection::new();
|
||||
///
|
||||
/// for i in iter {
|
||||
/// c.add(i);
|
||||
/// }
|
||||
///
|
||||
/// c
|
||||
/// }
|
||||
/// }
|
||||
///
|
||||
/// // Now we can make a new iterator...
|
||||
/// let iter = (0..5).into_iter();
|
||||
///
|
||||
/// // ... and make a MyCollection out of it
|
||||
/// let c = MyCollection::from_iter(iter);
|
||||
///
|
||||
/// assert_eq!(c.0, vec![0, 1, 2, 3, 4]);
|
||||
///
|
||||
/// // collect works too!
|
||||
///
|
||||
/// let iter = (0..5).into_iter();
|
||||
/// let c: MyCollection = iter.collect();
|
||||
///
|
||||
/// assert_eq!(c.0, vec![0, 1, 2, 3, 4]);
|
||||
/// ```
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
#[rustc_on_unimplemented="a collection of type `{Self}` cannot be \
|
||||
built from an iterator over elements of type `{A}`"]
|
||||
pub trait FromIterator<A>: Sized {
|
||||
/// Creates a value from an iterator.
|
||||
///
|
||||
/// See the [module-level documentation] for more.
|
||||
///
|
||||
/// [module-level documentation]: trait.FromIterator.html
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// Basic usage:
|
||||
///
|
||||
/// ```
|
||||
/// use std::iter::FromIterator;
|
||||
///
|
||||
/// let five_fives = std::iter::repeat(5).take(5);
|
||||
///
|
||||
/// let v = Vec::from_iter(five_fives);
|
||||
///
|
||||
/// assert_eq!(v, vec![5, 5, 5, 5, 5]);
|
||||
/// ```
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
fn from_iter<T: IntoIterator<Item=A>>(iter: T) -> Self;
|
||||
}
|
||||
|
||||
/// Conversion into an `Iterator`.
|
||||
///
|
||||
/// By implementing `IntoIterator` for a type, you define how it will be
|
||||
/// converted to an iterator. This is common for types which describe a
|
||||
/// collection of some kind.
|
||||
///
|
||||
/// One benefit of implementing `IntoIterator` is that your type will [work
|
||||
/// with Rust's `for` loop syntax](index.html#for-loops-and-intoiterator).
|
||||
///
|
||||
/// See also: [`FromIterator`].
|
||||
///
|
||||
/// [`FromIterator`]: trait.FromIterator.html
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// Basic usage:
|
||||
///
|
||||
/// ```
|
||||
/// let v = vec![1, 2, 3];
|
||||
///
|
||||
/// let mut iter = v.into_iter();
|
||||
///
|
||||
/// let n = iter.next();
|
||||
/// assert_eq!(Some(1), n);
|
||||
///
|
||||
/// let n = iter.next();
|
||||
/// assert_eq!(Some(2), n);
|
||||
///
|
||||
/// let n = iter.next();
|
||||
/// assert_eq!(Some(3), n);
|
||||
///
|
||||
/// let n = iter.next();
|
||||
/// assert_eq!(None, n);
|
||||
/// ```
|
||||
///
|
||||
/// Implementing `IntoIterator` for your type:
|
||||
///
|
||||
/// ```
|
||||
/// // A sample collection, that's just a wrapper over Vec<T>
|
||||
/// #[derive(Debug)]
|
||||
/// struct MyCollection(Vec<i32>);
|
||||
///
|
||||
/// // Let's give it some methods so we can create one and add things
|
||||
/// // to it.
|
||||
/// impl MyCollection {
|
||||
/// fn new() -> MyCollection {
|
||||
/// MyCollection(Vec::new())
|
||||
/// }
|
||||
///
|
||||
/// fn add(&mut self, elem: i32) {
|
||||
/// self.0.push(elem);
|
||||
/// }
|
||||
/// }
|
||||
///
|
||||
/// // and we'll implement IntoIterator
|
||||
/// impl IntoIterator for MyCollection {
|
||||
/// type Item = i32;
|
||||
/// type IntoIter = ::std::vec::IntoIter<i32>;
|
||||
///
|
||||
/// fn into_iter(self) -> Self::IntoIter {
|
||||
/// self.0.into_iter()
|
||||
/// }
|
||||
/// }
|
||||
///
|
||||
/// // Now we can make a new collection...
|
||||
/// let mut c = MyCollection::new();
|
||||
///
|
||||
/// // ... add some stuff to it ...
|
||||
/// c.add(0);
|
||||
/// c.add(1);
|
||||
/// c.add(2);
|
||||
///
|
||||
/// // ... and then turn it into an Iterator:
|
||||
/// for (i, n) in c.into_iter().enumerate() {
|
||||
/// assert_eq!(i as i32, n);
|
||||
/// }
|
||||
/// ```
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
pub trait IntoIterator {
|
||||
/// The type of the elements being iterated over.
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
type Item;
|
||||
|
||||
/// Which kind of iterator are we turning this into?
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
type IntoIter: Iterator<Item=Self::Item>;
|
||||
|
||||
/// Creates an iterator from a value.
|
||||
///
|
||||
/// See the [module-level documentation] for more.
|
||||
///
|
||||
/// [module-level documentation]: trait.IntoIterator.html
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// Basic usage:
|
||||
///
|
||||
/// ```
|
||||
/// let v = vec![1, 2, 3];
|
||||
///
|
||||
/// let mut iter = v.into_iter();
|
||||
///
|
||||
/// let n = iter.next();
|
||||
/// assert_eq!(Some(1), n);
|
||||
///
|
||||
/// let n = iter.next();
|
||||
/// assert_eq!(Some(2), n);
|
||||
///
|
||||
/// let n = iter.next();
|
||||
/// assert_eq!(Some(3), n);
|
||||
///
|
||||
/// let n = iter.next();
|
||||
/// assert_eq!(None, n);
|
||||
/// ```
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
fn into_iter(self) -> Self::IntoIter;
|
||||
}
|
||||
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
impl<I: Iterator> IntoIterator for I {
|
||||
type Item = I::Item;
|
||||
type IntoIter = I;
|
||||
|
||||
fn into_iter(self) -> I {
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
/// Extend a collection with the contents of an iterator.
|
||||
///
|
||||
/// Iterators produce a series of values, and collections can also be thought
|
||||
/// of as a series of values. The `Extend` trait bridges this gap, allowing you
|
||||
/// to extend a collection by including the contents of that iterator.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// Basic usage:
|
||||
///
|
||||
/// ```
|
||||
/// // You can extend a String with some chars:
|
||||
/// let mut message = String::from("The first three letters are: ");
|
||||
///
|
||||
/// message.extend(&['a', 'b', 'c']);
|
||||
///
|
||||
/// assert_eq!("abc", &message[29..32]);
|
||||
/// ```
|
||||
///
|
||||
/// Implementing `Extend`:
|
||||
///
|
||||
/// ```
|
||||
/// // A sample collection, that's just a wrapper over Vec<T>
|
||||
/// #[derive(Debug)]
|
||||
/// struct MyCollection(Vec<i32>);
|
||||
///
|
||||
/// // Let's give it some methods so we can create one and add things
|
||||
/// // to it.
|
||||
/// impl MyCollection {
|
||||
/// fn new() -> MyCollection {
|
||||
/// MyCollection(Vec::new())
|
||||
/// }
|
||||
///
|
||||
/// fn add(&mut self, elem: i32) {
|
||||
/// self.0.push(elem);
|
||||
/// }
|
||||
/// }
|
||||
///
|
||||
/// // since MyCollection has a list of i32s, we implement Extend for i32
|
||||
/// impl Extend<i32> for MyCollection {
|
||||
///
|
||||
/// // This is a bit simpler with the concrete type signature: we can call
|
||||
/// // extend on anything which can be turned into an Iterator which gives
|
||||
/// // us i32s. Because we need i32s to put into MyCollection.
|
||||
/// fn extend<T: IntoIterator<Item=i32>>(&mut self, iter: T) {
|
||||
///
|
||||
/// // The implementation is very straightforward: loop through the
|
||||
/// // iterator, and add() each element to ourselves.
|
||||
/// for elem in iter {
|
||||
/// self.add(elem);
|
||||
/// }
|
||||
/// }
|
||||
/// }
|
||||
///
|
||||
/// let mut c = MyCollection::new();
|
||||
///
|
||||
/// c.add(5);
|
||||
/// c.add(6);
|
||||
/// c.add(7);
|
||||
///
|
||||
/// // let's extend our collection with three more numbers
|
||||
/// c.extend(vec![1, 2, 3]);
|
||||
///
|
||||
/// // we've added these elements onto the end
|
||||
/// assert_eq!("MyCollection([5, 6, 7, 1, 2, 3])", format!("{:?}", c));
|
||||
/// ```
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
pub trait Extend<A> {
|
||||
/// Extends a collection with the contents of an iterator.
|
||||
///
|
||||
/// As this is the only method for this trait, the [trait-level] docs
|
||||
/// contain more details.
|
||||
///
|
||||
/// [trait-level]: trait.Extend.html
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// Basic usage:
|
||||
///
|
||||
/// ```
|
||||
/// // You can extend a String with some chars:
|
||||
/// let mut message = String::from("abc");
|
||||
///
|
||||
/// message.extend(['d', 'e', 'f'].iter());
|
||||
///
|
||||
/// assert_eq!("abcdef", &message);
|
||||
/// ```
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
fn extend<T: IntoIterator<Item=A>>(&mut self, iter: T);
|
||||
}
|
||||
|
||||
/// An iterator able to yield elements from both ends.
|
||||
///
|
||||
/// Something that implements `DoubleEndedIterator` has one extra capability
|
||||
/// over something that implements [`Iterator`]: the ability to also take
|
||||
/// `Item`s from the back, as well as the front.
|
||||
///
|
||||
/// It is important to note that both back and forth work on the same range,
|
||||
/// and do not cross: iteration is over when they meet in the middle.
|
||||
///
|
||||
/// In a similar fashion to the [`Iterator`] protocol, once a
|
||||
/// `DoubleEndedIterator` returns `None` from a `next_back()`, calling it again
|
||||
/// may or may not ever return `Some` again. `next()` and `next_back()` are
|
||||
/// interchangable for this purpose.
|
||||
///
|
||||
/// [`Iterator`]: trait.Iterator.html
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// Basic usage:
|
||||
///
|
||||
/// ```
|
||||
/// let numbers = vec![1, 2, 3];
|
||||
///
|
||||
/// let mut iter = numbers.iter();
|
||||
///
|
||||
/// assert_eq!(Some(&1), iter.next());
|
||||
/// assert_eq!(Some(&3), iter.next_back());
|
||||
/// assert_eq!(Some(&2), iter.next_back());
|
||||
/// assert_eq!(None, iter.next());
|
||||
/// assert_eq!(None, iter.next_back());
|
||||
/// ```
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
pub trait DoubleEndedIterator: Iterator {
|
||||
/// An iterator able to yield elements from both ends.
|
||||
///
|
||||
/// As this is the only method for this trait, the [trait-level] docs
|
||||
/// contain more details.
|
||||
///
|
||||
/// [trait-level]: trait.DoubleEndedIterator.html
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// Basic usage:
|
||||
///
|
||||
/// ```
|
||||
/// let numbers = vec![1, 2, 3];
|
||||
///
|
||||
/// let mut iter = numbers.iter();
|
||||
///
|
||||
/// assert_eq!(Some(&1), iter.next());
|
||||
/// assert_eq!(Some(&3), iter.next_back());
|
||||
/// assert_eq!(Some(&2), iter.next_back());
|
||||
/// assert_eq!(None, iter.next());
|
||||
/// assert_eq!(None, iter.next_back());
|
||||
/// ```
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
fn next_back(&mut self) -> Option<Self::Item>;
|
||||
}
|
||||
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
impl<'a, I: DoubleEndedIterator + ?Sized> DoubleEndedIterator for &'a mut I {
|
||||
fn next_back(&mut self) -> Option<I::Item> { (**self).next_back() }
|
||||
}
|
||||
|
||||
/// An iterator that knows its exact length.
|
||||
///
|
||||
/// Many [`Iterator`]s don't know how many times they will iterate, but some do.
|
||||
/// If an iterator knows how many times it can iterate, providing access to
|
||||
/// that information can be useful. For example, if you want to iterate
|
||||
/// backwards, a good start is to know where the end is.
|
||||
///
|
||||
/// When implementing an `ExactSizeIterator`, You must also implement
|
||||
/// [`Iterator`]. When doing so, the implementation of [`size_hint()`] *must*
|
||||
/// return the exact size of the iterator.
|
||||
///
|
||||
/// [`Iterator`]: trait.Iterator.html
|
||||
/// [`size_hint()`]: trait.Iterator.html#method.size_hint
|
||||
///
|
||||
/// The [`len()`] method has a default implementation, so you usually shouldn't
|
||||
/// implement it. However, you may be able to provide a more performant
|
||||
/// implementation than the default, so overriding it in this case makes sense.
|
||||
///
|
||||
/// [`len()`]: #method.len
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// Basic usage:
|
||||
///
|
||||
/// ```
|
||||
/// // a finite range knows exactly how many times it will iterate
|
||||
/// let five = 0..5;
|
||||
///
|
||||
/// assert_eq!(5, five.len());
|
||||
/// ```
|
||||
///
|
||||
/// In the [module level docs][moddocs], we implemented an [`Iterator`],
|
||||
/// `Counter`. Let's implement `ExactSizeIterator` for it as well:
|
||||
///
|
||||
/// [moddocs]: index.html
|
||||
///
|
||||
/// ```
|
||||
/// # struct Counter {
|
||||
/// # count: usize,
|
||||
/// # }
|
||||
/// # impl Counter {
|
||||
/// # fn new() -> Counter {
|
||||
/// # Counter { count: 0 }
|
||||
/// # }
|
||||
/// # }
|
||||
/// # impl Iterator for Counter {
|
||||
/// # type Item = usize;
|
||||
/// # fn next(&mut self) -> Option<usize> {
|
||||
/// # self.count += 1;
|
||||
/// # if self.count < 6 {
|
||||
/// # Some(self.count)
|
||||
/// # } else {
|
||||
/// # None
|
||||
/// # }
|
||||
/// # }
|
||||
/// # }
|
||||
/// impl ExactSizeIterator for Counter {
|
||||
/// // We already have the number of iterations, so we can use it directly.
|
||||
/// fn len(&self) -> usize {
|
||||
/// self.count
|
||||
/// }
|
||||
/// }
|
||||
///
|
||||
/// // And now we can use it!
|
||||
///
|
||||
/// let counter = Counter::new();
|
||||
///
|
||||
/// assert_eq!(0, counter.len());
|
||||
/// ```
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
pub trait ExactSizeIterator: Iterator {
|
||||
#[inline]
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
/// Returns the exact number of times the iterator will iterate.
|
||||
///
|
||||
/// This method has a default implementation, so you usually should not
|
||||
/// implement it directly. However, if you can provide a more efficient
|
||||
/// implementation, you can do so. See the [trait-level] docs for an
|
||||
/// example.
|
||||
///
|
||||
/// This function has the same safety guarantees as the [`size_hint()`]
|
||||
/// function.
|
||||
///
|
||||
/// [trait-level]: trait.ExactSizeIterator.html
|
||||
/// [`size_hint()`]: trait.Iterator.html#method.size_hint
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// Basic usage:
|
||||
///
|
||||
/// ```
|
||||
/// // a finite range knows exactly how many times it will iterate
|
||||
/// let five = 0..5;
|
||||
///
|
||||
/// assert_eq!(5, five.len());
|
||||
/// ```
|
||||
fn len(&self) -> usize {
|
||||
let (lower, upper) = self.size_hint();
|
||||
// Note: This assertion is overly defensive, but it checks the invariant
|
||||
// guaranteed by the trait. If this trait were rust-internal,
|
||||
// we could use debug_assert!; assert_eq! will check all Rust user
|
||||
// implementations too.
|
||||
assert_eq!(upper, Some(lower));
|
||||
lower
|
||||
}
|
||||
}
|
||||
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
impl<'a, I: ExactSizeIterator + ?Sized> ExactSizeIterator for &'a mut I {}
|
||||
|
@ -62,6 +62,9 @@
|
||||
// in the HIR, especially for multiple identifiers.
|
||||
|
||||
use hir;
|
||||
use hir::map::Definitions;
|
||||
use hir::map::definitions::DefPathData;
|
||||
use hir::def_id::DefIndex;
|
||||
|
||||
use std::collections::BTreeMap;
|
||||
use std::collections::HashMap;
|
||||
@ -92,10 +95,20 @@ pub struct LoweringContext<'a> {
|
||||
// A copy of cached_id, but is also set to an id while a node is lowered for
|
||||
// the first time.
|
||||
gensym_key: Cell<u32>,
|
||||
// We must keep the set of definitions up to date as we add nodes that
|
||||
// weren't in the AST.
|
||||
definitions: Option<&'a RefCell<Definitions>>,
|
||||
// As we walk the AST we must keep track of the current 'parent' def id (in
|
||||
// the form of a DefIndex) so that if we create a new node which introduces
|
||||
// a definition, then we can properly create the def id.
|
||||
parent_def: Cell<Option<DefIndex>>,
|
||||
}
|
||||
|
||||
impl<'a, 'hir> LoweringContext<'a> {
|
||||
pub fn new(id_assigner: &'a NodeIdAssigner, c: Option<&Crate>) -> LoweringContext<'a> {
|
||||
pub fn new(id_assigner: &'a NodeIdAssigner,
|
||||
c: Option<&Crate>,
|
||||
defs: &'a RefCell<Definitions>)
|
||||
-> LoweringContext<'a> {
|
||||
let crate_root = c.and_then(|c| {
|
||||
if std_inject::no_core(c) {
|
||||
None
|
||||
@ -113,6 +126,23 @@ impl<'a, 'hir> LoweringContext<'a> {
|
||||
cached_id: Cell::new(0),
|
||||
gensym_cache: RefCell::new(HashMap::new()),
|
||||
gensym_key: Cell::new(0),
|
||||
definitions: Some(defs),
|
||||
parent_def: Cell::new(None),
|
||||
}
|
||||
}
|
||||
|
||||
// Only use this when you want a LoweringContext for testing and won't look
|
||||
// up def ids for anything created during lowering.
|
||||
pub fn testing_context(id_assigner: &'a NodeIdAssigner) -> LoweringContext<'a> {
|
||||
LoweringContext {
|
||||
crate_root: None,
|
||||
id_cache: RefCell::new(HashMap::new()),
|
||||
id_assigner: id_assigner,
|
||||
cached_id: Cell::new(0),
|
||||
gensym_cache: RefCell::new(HashMap::new()),
|
||||
gensym_key: Cell::new(0),
|
||||
definitions: None,
|
||||
parent_def: Cell::new(None),
|
||||
}
|
||||
}
|
||||
|
||||
@ -146,6 +176,25 @@ impl<'a, 'hir> LoweringContext<'a> {
|
||||
fn diagnostic(&self) -> &Handler {
|
||||
self.id_assigner.diagnostic()
|
||||
}
|
||||
|
||||
fn with_parent_def<T, F: FnOnce() -> T>(&self, parent_id: NodeId, f: F) -> T {
|
||||
if self.definitions.is_none() {
|
||||
// This should only be used for testing.
|
||||
return f();
|
||||
}
|
||||
|
||||
let old_def = self.parent_def.get();
|
||||
self.parent_def.set(Some(self.get_def(parent_id)));
|
||||
let result = f();
|
||||
self.parent_def.set(old_def);
|
||||
|
||||
result
|
||||
}
|
||||
|
||||
fn get_def(&self, id: NodeId) -> DefIndex {
|
||||
let defs = self.definitions.unwrap().borrow();
|
||||
defs.opt_def_index(id).unwrap()
|
||||
}
|
||||
}
|
||||
|
||||
// Utility fn for setting and unsetting the cached id.
|
||||
@ -733,47 +782,51 @@ pub fn lower_item_kind(lctx: &LoweringContext, i: &ItemKind) -> hir::Item_ {
|
||||
}
|
||||
|
||||
pub fn lower_trait_item(lctx: &LoweringContext, i: &TraitItem) -> hir::TraitItem {
|
||||
hir::TraitItem {
|
||||
id: i.id,
|
||||
name: i.ident.name,
|
||||
attrs: lower_attrs(lctx, &i.attrs),
|
||||
node: match i.node {
|
||||
TraitItemKind::Const(ref ty, ref default) => {
|
||||
hir::ConstTraitItem(lower_ty(lctx, ty),
|
||||
default.as_ref().map(|x| lower_expr(lctx, x)))
|
||||
}
|
||||
TraitItemKind::Method(ref sig, ref body) => {
|
||||
hir::MethodTraitItem(lower_method_sig(lctx, sig),
|
||||
body.as_ref().map(|x| lower_block(lctx, x)))
|
||||
}
|
||||
TraitItemKind::Type(ref bounds, ref default) => {
|
||||
hir::TypeTraitItem(lower_bounds(lctx, bounds),
|
||||
default.as_ref().map(|x| lower_ty(lctx, x)))
|
||||
}
|
||||
},
|
||||
span: i.span,
|
||||
}
|
||||
lctx.with_parent_def(i.id, || {
|
||||
hir::TraitItem {
|
||||
id: i.id,
|
||||
name: i.ident.name,
|
||||
attrs: lower_attrs(lctx, &i.attrs),
|
||||
node: match i.node {
|
||||
TraitItemKind::Const(ref ty, ref default) => {
|
||||
hir::ConstTraitItem(lower_ty(lctx, ty),
|
||||
default.as_ref().map(|x| lower_expr(lctx, x)))
|
||||
}
|
||||
TraitItemKind::Method(ref sig, ref body) => {
|
||||
hir::MethodTraitItem(lower_method_sig(lctx, sig),
|
||||
body.as_ref().map(|x| lower_block(lctx, x)))
|
||||
}
|
||||
TraitItemKind::Type(ref bounds, ref default) => {
|
||||
hir::TypeTraitItem(lower_bounds(lctx, bounds),
|
||||
default.as_ref().map(|x| lower_ty(lctx, x)))
|
||||
}
|
||||
},
|
||||
span: i.span,
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
pub fn lower_impl_item(lctx: &LoweringContext, i: &ImplItem) -> hir::ImplItem {
|
||||
hir::ImplItem {
|
||||
id: i.id,
|
||||
name: i.ident.name,
|
||||
attrs: lower_attrs(lctx, &i.attrs),
|
||||
vis: lower_visibility(lctx, &i.vis),
|
||||
defaultness: lower_defaultness(lctx, i.defaultness),
|
||||
node: match i.node {
|
||||
ImplItemKind::Const(ref ty, ref expr) => {
|
||||
hir::ImplItemKind::Const(lower_ty(lctx, ty), lower_expr(lctx, expr))
|
||||
}
|
||||
ImplItemKind::Method(ref sig, ref body) => {
|
||||
hir::ImplItemKind::Method(lower_method_sig(lctx, sig), lower_block(lctx, body))
|
||||
}
|
||||
ImplItemKind::Type(ref ty) => hir::ImplItemKind::Type(lower_ty(lctx, ty)),
|
||||
ImplItemKind::Macro(..) => panic!("Shouldn't exist any more"),
|
||||
},
|
||||
span: i.span,
|
||||
}
|
||||
lctx.with_parent_def(i.id, || {
|
||||
hir::ImplItem {
|
||||
id: i.id,
|
||||
name: i.ident.name,
|
||||
attrs: lower_attrs(lctx, &i.attrs),
|
||||
vis: lower_visibility(lctx, &i.vis),
|
||||
defaultness: lower_defaultness(lctx, i.defaultness),
|
||||
node: match i.node {
|
||||
ImplItemKind::Const(ref ty, ref expr) => {
|
||||
hir::ImplItemKind::Const(lower_ty(lctx, ty), lower_expr(lctx, expr))
|
||||
}
|
||||
ImplItemKind::Method(ref sig, ref body) => {
|
||||
hir::ImplItemKind::Method(lower_method_sig(lctx, sig), lower_block(lctx, body))
|
||||
}
|
||||
ImplItemKind::Type(ref ty) => hir::ImplItemKind::Type(lower_ty(lctx, ty)),
|
||||
ImplItemKind::Macro(..) => panic!("Shouldn't exist any more"),
|
||||
},
|
||||
span: i.span,
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
pub fn lower_mod(lctx: &LoweringContext, m: &Mod) -> hir::Mod {
|
||||
@ -831,7 +884,9 @@ pub fn lower_item_id(_lctx: &LoweringContext, i: &Item) -> hir::ItemId {
|
||||
}
|
||||
|
||||
pub fn lower_item(lctx: &LoweringContext, i: &Item) -> hir::Item {
|
||||
let node = lower_item_kind(lctx, &i.node);
|
||||
let node = lctx.with_parent_def(i.id, || {
|
||||
lower_item_kind(lctx, &i.node)
|
||||
});
|
||||
|
||||
hir::Item {
|
||||
id: i.id,
|
||||
@ -844,21 +899,23 @@ pub fn lower_item(lctx: &LoweringContext, i: &Item) -> hir::Item {
|
||||
}
|
||||
|
||||
pub fn lower_foreign_item(lctx: &LoweringContext, i: &ForeignItem) -> hir::ForeignItem {
|
||||
hir::ForeignItem {
|
||||
id: i.id,
|
||||
name: i.ident.name,
|
||||
attrs: lower_attrs(lctx, &i.attrs),
|
||||
node: match i.node {
|
||||
ForeignItemKind::Fn(ref fdec, ref generics) => {
|
||||
hir::ForeignItemFn(lower_fn_decl(lctx, fdec), lower_generics(lctx, generics))
|
||||
}
|
||||
ForeignItemKind::Static(ref t, m) => {
|
||||
hir::ForeignItemStatic(lower_ty(lctx, t), m)
|
||||
}
|
||||
},
|
||||
vis: lower_visibility(lctx, &i.vis),
|
||||
span: i.span,
|
||||
}
|
||||
lctx.with_parent_def(i.id, || {
|
||||
hir::ForeignItem {
|
||||
id: i.id,
|
||||
name: i.ident.name,
|
||||
attrs: lower_attrs(lctx, &i.attrs),
|
||||
node: match i.node {
|
||||
ForeignItemKind::Fn(ref fdec, ref generics) => {
|
||||
hir::ForeignItemFn(lower_fn_decl(lctx, fdec), lower_generics(lctx, generics))
|
||||
}
|
||||
ForeignItemKind::Static(ref t, m) => {
|
||||
hir::ForeignItemStatic(lower_ty(lctx, t), m)
|
||||
}
|
||||
},
|
||||
vis: lower_visibility(lctx, &i.vis),
|
||||
span: i.span,
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
pub fn lower_method_sig(lctx: &LoweringContext, sig: &MethodSig) -> hir::MethodSig {
|
||||
@ -926,9 +983,11 @@ pub fn lower_pat(lctx: &LoweringContext, p: &Pat) -> P<hir::Pat> {
|
||||
node: match p.node {
|
||||
PatKind::Wild => hir::PatKind::Wild,
|
||||
PatKind::Ident(ref binding_mode, pth1, ref sub) => {
|
||||
hir::PatKind::Ident(lower_binding_mode(lctx, binding_mode),
|
||||
respan(pth1.span, lower_ident(lctx, pth1.node)),
|
||||
sub.as_ref().map(|x| lower_pat(lctx, x)))
|
||||
lctx.with_parent_def(p.id, || {
|
||||
hir::PatKind::Ident(lower_binding_mode(lctx, binding_mode),
|
||||
respan(pth1.span, lower_ident(lctx, pth1.node)),
|
||||
sub.as_ref().map(|x| lower_pat(lctx, x)))
|
||||
})
|
||||
}
|
||||
PatKind::Lit(ref e) => hir::PatKind::Lit(lower_expr(lctx, e)),
|
||||
PatKind::TupleStruct(ref pth, ref pats) => {
|
||||
@ -1202,9 +1261,11 @@ pub fn lower_expr(lctx: &LoweringContext, e: &Expr) -> P<hir::Expr> {
|
||||
hir::MatchSource::Normal)
|
||||
}
|
||||
ExprKind::Closure(capture_clause, ref decl, ref body) => {
|
||||
hir::ExprClosure(lower_capture_clause(lctx, capture_clause),
|
||||
lower_fn_decl(lctx, decl),
|
||||
lower_block(lctx, body))
|
||||
lctx.with_parent_def(e.id, || {
|
||||
hir::ExprClosure(lower_capture_clause(lctx, capture_clause),
|
||||
lower_fn_decl(lctx, decl),
|
||||
lower_block(lctx, body))
|
||||
})
|
||||
}
|
||||
ExprKind::Block(ref blk) => hir::ExprBlock(lower_block(lctx, blk)),
|
||||
ExprKind::Assign(ref el, ref er) => {
|
||||
@ -1602,7 +1663,12 @@ pub fn lower_expr(lctx: &LoweringContext, e: &Expr) -> P<hir::Expr> {
|
||||
// `{ let _result = ...; _result }`
|
||||
// underscore prevents an unused_variables lint if the head diverges
|
||||
let result_ident = lctx.str_to_ident("_result");
|
||||
let let_stmt = stmt_let(lctx, e.span, false, result_ident, match_expr, None);
|
||||
let let_stmt = stmt_let(lctx,
|
||||
e.span,
|
||||
false,
|
||||
result_ident,
|
||||
match_expr,
|
||||
None);
|
||||
let result = expr_ident(lctx, e.span, result_ident, None);
|
||||
let block = block_all(lctx, e.span, hir_vec![let_stmt], Some(result));
|
||||
// add the attributes to the outer returned expr node
|
||||
@ -1655,7 +1721,8 @@ pub fn lower_expr(lctx: &LoweringContext, e: &Expr) -> P<hir::Expr> {
|
||||
let err_ctor = expr_path(lctx, path, None);
|
||||
expr_call(lctx, e.span, err_ctor, hir_vec![from_expr], None)
|
||||
};
|
||||
let err_pat = pat_err(lctx, e.span, pat_ident(lctx, e.span, err_ident));
|
||||
let err_pat = pat_err(lctx, e.span,
|
||||
pat_ident(lctx, e.span, err_ident));
|
||||
let ret_expr = expr(lctx, e.span,
|
||||
hir::Expr_::ExprRet(Some(err_expr)), None);
|
||||
|
||||
@ -1938,12 +2005,22 @@ fn pat_ident_binding_mode(lctx: &LoweringContext,
|
||||
bm: hir::BindingMode)
|
||||
-> P<hir::Pat> {
|
||||
let pat_ident = hir::PatKind::Ident(bm,
|
||||
Spanned {
|
||||
span: span,
|
||||
node: ident,
|
||||
},
|
||||
None);
|
||||
pat(lctx, span, pat_ident)
|
||||
Spanned {
|
||||
span: span,
|
||||
node: ident,
|
||||
},
|
||||
None);
|
||||
|
||||
let pat = pat(lctx, span, pat_ident);
|
||||
|
||||
if let Some(defs) = lctx.definitions {
|
||||
let mut defs = defs.borrow_mut();
|
||||
defs.create_def_with_parent(lctx.parent_def.get(),
|
||||
pat.id,
|
||||
DefPathData::Binding(ident.name));
|
||||
}
|
||||
|
||||
pat
|
||||
}
|
||||
|
||||
fn pat_wild(lctx: &LoweringContext, span: Span) -> P<hir::Pat> {
|
||||
@ -2130,7 +2207,8 @@ mod test {
|
||||
let ast_in = quote_expr!(&cx, in HEAP { foo() });
|
||||
let ast_in = assigner.fold_expr(ast_in);
|
||||
|
||||
let lctx = LoweringContext::new(&assigner, None);
|
||||
let lctx = LoweringContext::testing_context(&assigner);
|
||||
|
||||
let hir1 = lower_expr(&lctx, &ast_if_let);
|
||||
let hir2 = lower_expr(&lctx, &ast_if_let);
|
||||
assert!(hir1 == hir2);
|
||||
|
@ -1,4 +1,4 @@
|
||||
// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
|
||||
// Copyright 2015-2016 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
@ -13,18 +13,16 @@ use super::MapEntry::*;
|
||||
|
||||
use hir::*;
|
||||
use hir::intravisit::Visitor;
|
||||
use hir::def_id::{CRATE_DEF_INDEX, DefId, DefIndex};
|
||||
use hir::def_id::DefId;
|
||||
use middle::cstore::InlinedItem;
|
||||
use std::iter::repeat;
|
||||
use syntax::ast::{NodeId, CRATE_NODE_ID, DUMMY_NODE_ID};
|
||||
use syntax::ast::{NodeId, CRATE_NODE_ID};
|
||||
use syntax::codemap::Span;
|
||||
|
||||
/// A Visitor that walks over an AST and collects Node's into an AST
|
||||
/// Map.
|
||||
/// A Visitor that walks over the HIR and collects Node's into a HIR map.
|
||||
pub struct NodeCollector<'ast> {
|
||||
pub krate: &'ast Crate,
|
||||
pub map: Vec<MapEntry<'ast>>,
|
||||
pub definitions: Definitions,
|
||||
pub parent_node: NodeId,
|
||||
}
|
||||
|
||||
@ -33,16 +31,10 @@ impl<'ast> NodeCollector<'ast> {
|
||||
let mut collector = NodeCollector {
|
||||
krate: krate,
|
||||
map: vec![],
|
||||
definitions: Definitions::new(),
|
||||
parent_node: CRATE_NODE_ID,
|
||||
};
|
||||
collector.insert_entry(CRATE_NODE_ID, RootCrate);
|
||||
|
||||
let result = collector.create_def_with_parent(None, CRATE_NODE_ID, DefPathData::CrateRoot);
|
||||
assert_eq!(result, CRATE_DEF_INDEX);
|
||||
|
||||
collector.create_def_with_parent(Some(CRATE_DEF_INDEX), DUMMY_NODE_ID, DefPathData::Misc);
|
||||
|
||||
collector
|
||||
}
|
||||
|
||||
@ -51,53 +43,20 @@ impl<'ast> NodeCollector<'ast> {
|
||||
parent_node: NodeId,
|
||||
parent_def_path: DefPath,
|
||||
parent_def_id: DefId,
|
||||
map: Vec<MapEntry<'ast>>,
|
||||
definitions: Definitions)
|
||||
map: Vec<MapEntry<'ast>>)
|
||||
-> NodeCollector<'ast> {
|
||||
let mut collector = NodeCollector {
|
||||
krate: krate,
|
||||
map: map,
|
||||
parent_node: parent_node,
|
||||
definitions: definitions,
|
||||
};
|
||||
|
||||
assert_eq!(parent_def_path.krate, parent_def_id.krate);
|
||||
let root_path = Box::new(InlinedRootPath {
|
||||
data: parent_def_path.data,
|
||||
def_id: parent_def_id,
|
||||
});
|
||||
|
||||
collector.insert_entry(parent_node, RootInlinedParent(parent));
|
||||
collector.create_def(parent_node, DefPathData::InlinedRoot(root_path));
|
||||
|
||||
collector
|
||||
}
|
||||
|
||||
fn parent_def(&self) -> Option<DefIndex> {
|
||||
let mut parent_node = Some(self.parent_node);
|
||||
while let Some(p) = parent_node {
|
||||
if let Some(q) = self.definitions.opt_def_index(p) {
|
||||
return Some(q);
|
||||
}
|
||||
parent_node = self.map[p as usize].parent_node();
|
||||
}
|
||||
None
|
||||
}
|
||||
|
||||
fn create_def(&mut self, node_id: NodeId, data: DefPathData) -> DefIndex {
|
||||
let parent_def = self.parent_def();
|
||||
debug!("create_def(node_id={:?}, data={:?}, parent_def={:?})", node_id, data, parent_def);
|
||||
self.definitions.create_def_with_parent(parent_def, node_id, data)
|
||||
}
|
||||
|
||||
fn create_def_with_parent(&mut self,
|
||||
parent: Option<DefIndex>,
|
||||
node_id: NodeId,
|
||||
data: DefPathData)
|
||||
-> DefIndex {
|
||||
self.definitions.create_def_with_parent(parent, node_id, data)
|
||||
}
|
||||
|
||||
fn insert_entry(&mut self, id: NodeId, entry: MapEntry<'ast>) {
|
||||
debug!("ast_map: {:?} => {:?}", id, entry);
|
||||
let len = self.map.len();
|
||||
@ -107,15 +66,17 @@ impl<'ast> NodeCollector<'ast> {
|
||||
self.map[id as usize] = entry;
|
||||
}
|
||||
|
||||
fn insert_def(&mut self, id: NodeId, node: Node<'ast>, data: DefPathData) -> DefIndex {
|
||||
self.insert(id, node);
|
||||
self.create_def(id, data)
|
||||
}
|
||||
|
||||
fn insert(&mut self, id: NodeId, node: Node<'ast>) {
|
||||
let entry = MapEntry::from_node(self.parent_node, node);
|
||||
self.insert_entry(id, entry);
|
||||
}
|
||||
|
||||
fn with_parent<F: FnOnce(&mut Self)>(&mut self, parent_id: NodeId, f: F) {
|
||||
let parent_node = self.parent_node;
|
||||
self.parent_node = parent_id;
|
||||
f(self);
|
||||
self.parent_node = parent_node;
|
||||
}
|
||||
}
|
||||
|
||||
impl<'ast> Visitor<'ast> for NodeCollector<'ast> {
|
||||
@ -130,188 +91,104 @@ impl<'ast> Visitor<'ast> for NodeCollector<'ast> {
|
||||
fn visit_item(&mut self, i: &'ast Item) {
|
||||
debug!("visit_item: {:?}", i);
|
||||
|
||||
// Pick the def data. This need not be unique, but the more
|
||||
// information we encapsulate into
|
||||
let def_data = match i.node {
|
||||
ItemDefaultImpl(..) | ItemImpl(..) =>
|
||||
DefPathData::Impl,
|
||||
ItemEnum(..) | ItemStruct(..) | ItemTrait(..) |
|
||||
ItemExternCrate(..) | ItemForeignMod(..) | ItemTy(..) =>
|
||||
DefPathData::TypeNs(i.name),
|
||||
ItemMod(..) =>
|
||||
DefPathData::Module(i.name),
|
||||
ItemStatic(..) | ItemConst(..) | ItemFn(..) =>
|
||||
DefPathData::ValueNs(i.name),
|
||||
ItemUse(..) =>
|
||||
DefPathData::Misc,
|
||||
};
|
||||
self.insert(i.id, NodeItem(i));
|
||||
|
||||
self.insert_def(i.id, NodeItem(i), def_data);
|
||||
|
||||
let parent_node = self.parent_node;
|
||||
self.parent_node = i.id;
|
||||
|
||||
match i.node {
|
||||
ItemImpl(..) => {}
|
||||
ItemEnum(ref enum_definition, _) => {
|
||||
for v in &enum_definition.variants {
|
||||
let variant_def_index =
|
||||
self.insert_def(v.node.data.id(),
|
||||
NodeVariant(v),
|
||||
DefPathData::EnumVariant(v.node.name));
|
||||
|
||||
for field in v.node.data.fields() {
|
||||
self.create_def_with_parent(
|
||||
Some(variant_def_index),
|
||||
field.id,
|
||||
DefPathData::Field(field.name));
|
||||
self.with_parent(i.id, |this| {
|
||||
match i.node {
|
||||
ItemEnum(ref enum_definition, _) => {
|
||||
for v in &enum_definition.variants {
|
||||
this.insert(v.node.data.id(), NodeVariant(v));
|
||||
}
|
||||
}
|
||||
}
|
||||
ItemForeignMod(..) => {
|
||||
}
|
||||
ItemStruct(ref struct_def, _) => {
|
||||
// If this is a tuple-like struct, register the constructor.
|
||||
if !struct_def.is_struct() {
|
||||
self.insert_def(struct_def.id(),
|
||||
NodeStructCtor(struct_def),
|
||||
DefPathData::StructCtor);
|
||||
}
|
||||
|
||||
for field in struct_def.fields() {
|
||||
self.create_def(field.id, DefPathData::Field(field.name));
|
||||
}
|
||||
}
|
||||
ItemTrait(_, _, ref bounds, _) => {
|
||||
for b in bounds.iter() {
|
||||
if let TraitTyParamBound(ref t, TraitBoundModifier::None) = *b {
|
||||
self.insert(t.trait_ref.ref_id, NodeItem(i));
|
||||
ItemStruct(ref struct_def, _) => {
|
||||
// If this is a tuple-like struct, register the constructor.
|
||||
if !struct_def.is_struct() {
|
||||
this.insert(struct_def.id(), NodeStructCtor(struct_def));
|
||||
}
|
||||
}
|
||||
}
|
||||
ItemUse(ref view_path) => {
|
||||
match view_path.node {
|
||||
ViewPathList(_, ref paths) => {
|
||||
for path in paths {
|
||||
self.insert(path.node.id(), NodeItem(i));
|
||||
ItemTrait(_, _, ref bounds, _) => {
|
||||
for b in bounds.iter() {
|
||||
if let TraitTyParamBound(ref t, TraitBoundModifier::None) = *b {
|
||||
this.insert(t.trait_ref.ref_id, NodeItem(i));
|
||||
}
|
||||
}
|
||||
_ => ()
|
||||
}
|
||||
ItemUse(ref view_path) => {
|
||||
match view_path.node {
|
||||
ViewPathList(_, ref paths) => {
|
||||
for path in paths {
|
||||
this.insert(path.node.id(), NodeItem(i));
|
||||
}
|
||||
}
|
||||
_ => ()
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
intravisit::walk_item(self, i);
|
||||
self.parent_node = parent_node;
|
||||
intravisit::walk_item(this, i);
|
||||
});
|
||||
}
|
||||
|
||||
fn visit_foreign_item(&mut self, foreign_item: &'ast ForeignItem) {
|
||||
self.insert_def(foreign_item.id,
|
||||
NodeForeignItem(foreign_item),
|
||||
DefPathData::ValueNs(foreign_item.name));
|
||||
self.insert(foreign_item.id, NodeForeignItem(foreign_item));
|
||||
|
||||
let parent_node = self.parent_node;
|
||||
self.parent_node = foreign_item.id;
|
||||
intravisit::walk_foreign_item(self, foreign_item);
|
||||
self.parent_node = parent_node;
|
||||
self.with_parent(foreign_item.id, |this| {
|
||||
intravisit::walk_foreign_item(this, foreign_item);
|
||||
});
|
||||
}
|
||||
|
||||
fn visit_generics(&mut self, generics: &'ast Generics) {
|
||||
for ty_param in generics.ty_params.iter() {
|
||||
self.insert_def(ty_param.id,
|
||||
NodeTyParam(ty_param),
|
||||
DefPathData::TypeParam(ty_param.name));
|
||||
self.insert(ty_param.id, NodeTyParam(ty_param));
|
||||
}
|
||||
|
||||
intravisit::walk_generics(self, generics);
|
||||
}
|
||||
|
||||
fn visit_trait_item(&mut self, ti: &'ast TraitItem) {
|
||||
let def_data = match ti.node {
|
||||
MethodTraitItem(..) | ConstTraitItem(..) => DefPathData::ValueNs(ti.name),
|
||||
TypeTraitItem(..) => DefPathData::TypeNs(ti.name),
|
||||
};
|
||||
|
||||
self.insert(ti.id, NodeTraitItem(ti));
|
||||
self.create_def(ti.id, def_data);
|
||||
|
||||
let parent_node = self.parent_node;
|
||||
self.parent_node = ti.id;
|
||||
|
||||
match ti.node {
|
||||
ConstTraitItem(_, Some(ref expr)) => {
|
||||
self.create_def(expr.id, DefPathData::Initializer);
|
||||
}
|
||||
_ => { }
|
||||
}
|
||||
|
||||
intravisit::walk_trait_item(self, ti);
|
||||
|
||||
self.parent_node = parent_node;
|
||||
self.with_parent(ti.id, |this| {
|
||||
intravisit::walk_trait_item(this, ti);
|
||||
});
|
||||
}
|
||||
|
||||
fn visit_impl_item(&mut self, ii: &'ast ImplItem) {
|
||||
let def_data = match ii.node {
|
||||
ImplItemKind::Method(..) | ImplItemKind::Const(..) => DefPathData::ValueNs(ii.name),
|
||||
ImplItemKind::Type(..) => DefPathData::TypeNs(ii.name),
|
||||
};
|
||||
self.insert(ii.id, NodeImplItem(ii));
|
||||
|
||||
self.insert_def(ii.id, NodeImplItem(ii), def_data);
|
||||
|
||||
let parent_node = self.parent_node;
|
||||
self.parent_node = ii.id;
|
||||
|
||||
match ii.node {
|
||||
ImplItemKind::Const(_, ref expr) => {
|
||||
self.create_def(expr.id, DefPathData::Initializer);
|
||||
}
|
||||
_ => { }
|
||||
}
|
||||
|
||||
intravisit::walk_impl_item(self, ii);
|
||||
|
||||
self.parent_node = parent_node;
|
||||
self.with_parent(ii.id, |this| {
|
||||
intravisit::walk_impl_item(this, ii);
|
||||
});
|
||||
}
|
||||
|
||||
fn visit_pat(&mut self, pat: &'ast Pat) {
|
||||
let maybe_binding = match pat.node {
|
||||
PatKind::Ident(_, id, _) => Some(id.node),
|
||||
_ => None
|
||||
};
|
||||
|
||||
if let Some(id) = maybe_binding {
|
||||
self.insert_def(pat.id, NodeLocal(pat), DefPathData::Binding(id.name));
|
||||
let node = if let PatKind::Ident(..) = pat.node {
|
||||
NodeLocal(pat)
|
||||
} else {
|
||||
self.insert(pat.id, NodePat(pat));
|
||||
}
|
||||
NodePat(pat)
|
||||
};
|
||||
self.insert(pat.id, node);
|
||||
|
||||
let parent_node = self.parent_node;
|
||||
self.parent_node = pat.id;
|
||||
intravisit::walk_pat(self, pat);
|
||||
self.parent_node = parent_node;
|
||||
self.with_parent(pat.id, |this| {
|
||||
intravisit::walk_pat(this, pat);
|
||||
});
|
||||
}
|
||||
|
||||
fn visit_expr(&mut self, expr: &'ast Expr) {
|
||||
self.insert(expr.id, NodeExpr(expr));
|
||||
|
||||
match expr.node {
|
||||
ExprClosure(..) => { self.create_def(expr.id, DefPathData::ClosureExpr); }
|
||||
_ => { }
|
||||
}
|
||||
|
||||
let parent_node = self.parent_node;
|
||||
self.parent_node = expr.id;
|
||||
intravisit::walk_expr(self, expr);
|
||||
self.parent_node = parent_node;
|
||||
self.with_parent(expr.id, |this| {
|
||||
intravisit::walk_expr(this, expr);
|
||||
});
|
||||
}
|
||||
|
||||
fn visit_stmt(&mut self, stmt: &'ast Stmt) {
|
||||
let id = stmt.node.id();
|
||||
self.insert(id, NodeStmt(stmt));
|
||||
let parent_node = self.parent_node;
|
||||
self.parent_node = id;
|
||||
intravisit::walk_stmt(self, stmt);
|
||||
self.parent_node = parent_node;
|
||||
|
||||
self.with_parent(id, |this| {
|
||||
intravisit::walk_stmt(this, stmt);
|
||||
});
|
||||
}
|
||||
|
||||
fn visit_fn(&mut self, fk: intravisit::FnKind<'ast>, fd: &'ast FnDecl,
|
||||
@ -322,22 +199,12 @@ impl<'ast> Visitor<'ast> for NodeCollector<'ast> {
|
||||
|
||||
fn visit_block(&mut self, block: &'ast Block) {
|
||||
self.insert(block.id, NodeBlock(block));
|
||||
let parent_node = self.parent_node;
|
||||
self.parent_node = block.id;
|
||||
intravisit::walk_block(self, block);
|
||||
self.parent_node = parent_node;
|
||||
self.with_parent(block.id, |this| {
|
||||
intravisit::walk_block(this, block);
|
||||
});
|
||||
}
|
||||
|
||||
fn visit_lifetime(&mut self, lifetime: &'ast Lifetime) {
|
||||
self.insert(lifetime.id, NodeLifetime(lifetime));
|
||||
}
|
||||
|
||||
fn visit_lifetime_def(&mut self, def: &'ast LifetimeDef) {
|
||||
self.create_def(def.lifetime.id, DefPathData::LifetimeDef(def.lifetime.name));
|
||||
self.visit_lifetime(&def.lifetime);
|
||||
}
|
||||
|
||||
fn visit_macro_def(&mut self, macro_def: &'ast MacroDef) {
|
||||
self.create_def(macro_def.id, DefPathData::MacroDef(macro_def.name));
|
||||
}
|
||||
}
|
||||
|
384
src/librustc/hir/map/def_collector.rs
Normal file
384
src/librustc/hir/map/def_collector.rs
Normal file
@ -0,0 +1,384 @@
|
||||
// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
use super::*;
|
||||
|
||||
use hir;
|
||||
use hir::intravisit;
|
||||
use hir::def_id::{CRATE_DEF_INDEX, DefId, DefIndex};
|
||||
|
||||
use middle::cstore::InlinedItem;
|
||||
|
||||
use syntax::ast::*;
|
||||
use syntax::visit;
|
||||
use syntax::parse::token;
|
||||
|
||||
/// Creates def ids for nodes in the HIR.
|
||||
pub struct DefCollector<'ast> {
|
||||
// If we are walking HIR (c.f., AST), we need to keep a reference to the
|
||||
// crate.
|
||||
hir_crate: Option<&'ast hir::Crate>,
|
||||
pub definitions: Definitions,
|
||||
parent_def: Option<DefIndex>,
|
||||
}
|
||||
|
||||
impl<'ast> DefCollector<'ast> {
|
||||
pub fn root() -> DefCollector<'ast> {
|
||||
let mut collector = DefCollector {
|
||||
hir_crate: None,
|
||||
definitions: Definitions::new(),
|
||||
parent_def: None,
|
||||
};
|
||||
let root = collector.create_def_with_parent(None, CRATE_NODE_ID, DefPathData::CrateRoot);
|
||||
assert_eq!(root, CRATE_DEF_INDEX);
|
||||
collector.parent_def = Some(root);
|
||||
|
||||
collector.create_def_with_parent(Some(CRATE_DEF_INDEX), DUMMY_NODE_ID, DefPathData::Misc);
|
||||
|
||||
collector
|
||||
}
|
||||
|
||||
pub fn extend(parent_node: NodeId,
|
||||
parent_def_path: DefPath,
|
||||
parent_def_id: DefId,
|
||||
definitions: Definitions)
|
||||
-> DefCollector<'ast> {
|
||||
let mut collector = DefCollector {
|
||||
hir_crate: None,
|
||||
parent_def: None,
|
||||
definitions: definitions,
|
||||
};
|
||||
|
||||
assert_eq!(parent_def_path.krate, parent_def_id.krate);
|
||||
let root_path = Box::new(InlinedRootPath {
|
||||
data: parent_def_path.data,
|
||||
def_id: parent_def_id,
|
||||
});
|
||||
|
||||
let def = collector.create_def(parent_node, DefPathData::InlinedRoot(root_path));
|
||||
collector.parent_def = Some(def);
|
||||
|
||||
collector
|
||||
}
|
||||
|
||||
pub fn walk_item(&mut self, ii: &'ast InlinedItem, krate: &'ast hir::Crate) {
|
||||
self.hir_crate = Some(krate);
|
||||
ii.visit(self);
|
||||
}
|
||||
|
||||
fn parent_def(&self) -> Option<DefIndex> {
|
||||
self.parent_def
|
||||
}
|
||||
|
||||
fn create_def(&mut self, node_id: NodeId, data: DefPathData) -> DefIndex {
|
||||
let parent_def = self.parent_def();
|
||||
debug!("create_def(node_id={:?}, data={:?}, parent_def={:?})", node_id, data, parent_def);
|
||||
self.definitions.create_def_with_parent(parent_def, node_id, data)
|
||||
}
|
||||
|
||||
fn create_def_with_parent(&mut self,
|
||||
parent: Option<DefIndex>,
|
||||
node_id: NodeId,
|
||||
data: DefPathData)
|
||||
-> DefIndex {
|
||||
self.definitions.create_def_with_parent(parent, node_id, data)
|
||||
}
|
||||
|
||||
fn with_parent<F: FnOnce(&mut Self)>(&mut self, parent_def: DefIndex, f: F) {
|
||||
let parent = self.parent_def;
|
||||
self.parent_def = Some(parent_def);
|
||||
f(self);
|
||||
self.parent_def = parent;
|
||||
}
|
||||
}
|
||||
|
||||
impl<'ast> visit::Visitor<'ast> for DefCollector<'ast> {
|
||||
fn visit_item(&mut self, i: &'ast Item) {
|
||||
debug!("visit_item: {:?}", i);
|
||||
|
||||
// Pick the def data. This need not be unique, but the more
|
||||
// information we encapsulate into
|
||||
let def_data = match i.node {
|
||||
ItemKind::DefaultImpl(..) | ItemKind::Impl(..) =>
|
||||
DefPathData::Impl,
|
||||
ItemKind::Enum(..) | ItemKind::Struct(..) | ItemKind::Trait(..) |
|
||||
ItemKind::ExternCrate(..) | ItemKind::ForeignMod(..) | ItemKind::Ty(..) =>
|
||||
DefPathData::TypeNs(i.ident.name),
|
||||
ItemKind::Mod(..) => DefPathData::Module(i.ident.name),
|
||||
ItemKind::Static(..) | ItemKind::Const(..) | ItemKind::Fn(..) =>
|
||||
DefPathData::ValueNs(i.ident.name),
|
||||
ItemKind::Mac(..) => DefPathData::MacroDef(i.ident.name),
|
||||
ItemKind::Use(..) => DefPathData::Misc,
|
||||
};
|
||||
let def = self.create_def(i.id, def_data);
|
||||
|
||||
self.with_parent(def, |this| {
|
||||
match i.node {
|
||||
ItemKind::Enum(ref enum_definition, _) => {
|
||||
for v in &enum_definition.variants {
|
||||
let variant_def_index =
|
||||
this.create_def(v.node.data.id(),
|
||||
DefPathData::EnumVariant(v.node.name.name));
|
||||
|
||||
for (index, field) in v.node.data.fields().iter().enumerate() {
|
||||
let name = field.ident.map(|ident| ident.name)
|
||||
.unwrap_or(token::intern(&index.to_string()));
|
||||
this.create_def_with_parent(Some(variant_def_index),
|
||||
field.id,
|
||||
DefPathData::Field(name));
|
||||
}
|
||||
}
|
||||
}
|
||||
ItemKind::Struct(ref struct_def, _) => {
|
||||
// If this is a tuple-like struct, register the constructor.
|
||||
if !struct_def.is_struct() {
|
||||
this.create_def(struct_def.id(),
|
||||
DefPathData::StructCtor);
|
||||
}
|
||||
|
||||
for (index, field) in struct_def.fields().iter().enumerate() {
|
||||
let name = field.ident.map(|ident| ident.name)
|
||||
.unwrap_or(token::intern(&index.to_string()));
|
||||
this.create_def(field.id, DefPathData::Field(name));
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
visit::walk_item(this, i);
|
||||
});
|
||||
}
|
||||
|
||||
fn visit_foreign_item(&mut self, foreign_item: &'ast ForeignItem) {
|
||||
let def = self.create_def(foreign_item.id, DefPathData::ValueNs(foreign_item.ident.name));
|
||||
|
||||
self.with_parent(def, |this| {
|
||||
visit::walk_foreign_item(this, foreign_item);
|
||||
});
|
||||
}
|
||||
|
||||
fn visit_generics(&mut self, generics: &'ast Generics) {
|
||||
for ty_param in generics.ty_params.iter() {
|
||||
self.create_def(ty_param.id, DefPathData::TypeParam(ty_param.ident.name));
|
||||
}
|
||||
|
||||
visit::walk_generics(self, generics);
|
||||
}
|
||||
|
||||
fn visit_trait_item(&mut self, ti: &'ast TraitItem) {
|
||||
let def_data = match ti.node {
|
||||
TraitItemKind::Method(..) | TraitItemKind::Const(..) =>
|
||||
DefPathData::ValueNs(ti.ident.name),
|
||||
TraitItemKind::Type(..) => DefPathData::TypeNs(ti.ident.name),
|
||||
};
|
||||
|
||||
let def = self.create_def(ti.id, def_data);
|
||||
self.with_parent(def, |this| {
|
||||
if let TraitItemKind::Const(_, Some(ref expr)) = ti.node {
|
||||
this.create_def(expr.id, DefPathData::Initializer);
|
||||
}
|
||||
|
||||
visit::walk_trait_item(this, ti);
|
||||
});
|
||||
}
|
||||
|
||||
fn visit_impl_item(&mut self, ii: &'ast ImplItem) {
|
||||
let def_data = match ii.node {
|
||||
ImplItemKind::Method(..) | ImplItemKind::Const(..) =>
|
||||
DefPathData::ValueNs(ii.ident.name),
|
||||
ImplItemKind::Type(..) => DefPathData::TypeNs(ii.ident.name),
|
||||
ImplItemKind::Macro(..) => DefPathData::MacroDef(ii.ident.name),
|
||||
};
|
||||
|
||||
let def = self.create_def(ii.id, def_data);
|
||||
self.with_parent(def, |this| {
|
||||
if let ImplItemKind::Const(_, ref expr) = ii.node {
|
||||
this.create_def(expr.id, DefPathData::Initializer);
|
||||
}
|
||||
|
||||
visit::walk_impl_item(this, ii);
|
||||
});
|
||||
}
|
||||
|
||||
fn visit_pat(&mut self, pat: &'ast Pat) {
|
||||
let parent_def = self.parent_def;
|
||||
|
||||
if let PatKind::Ident(_, id, _) = pat.node {
|
||||
let def = self.create_def(pat.id, DefPathData::Binding(id.node.name));
|
||||
self.parent_def = Some(def);
|
||||
}
|
||||
|
||||
visit::walk_pat(self, pat);
|
||||
self.parent_def = parent_def;
|
||||
}
|
||||
|
||||
fn visit_expr(&mut self, expr: &'ast Expr) {
|
||||
let parent_def = self.parent_def;
|
||||
|
||||
if let ExprKind::Closure(..) = expr.node {
|
||||
let def = self.create_def(expr.id, DefPathData::ClosureExpr);
|
||||
self.parent_def = Some(def);
|
||||
}
|
||||
|
||||
visit::walk_expr(self, expr);
|
||||
self.parent_def = parent_def;
|
||||
}
|
||||
|
||||
fn visit_lifetime_def(&mut self, def: &'ast LifetimeDef) {
|
||||
self.create_def(def.lifetime.id, DefPathData::LifetimeDef(def.lifetime.name));
|
||||
}
|
||||
|
||||
fn visit_macro_def(&mut self, macro_def: &'ast MacroDef) {
|
||||
self.create_def(macro_def.id, DefPathData::MacroDef(macro_def.ident.name));
|
||||
}
|
||||
}
|
||||
|
||||
// We walk the HIR rather than the AST when reading items from metadata.
|
||||
impl<'ast> intravisit::Visitor<'ast> for DefCollector<'ast> {
|
||||
/// Because we want to track parent items and so forth, enable
|
||||
/// deep walking so that we walk nested items in the context of
|
||||
/// their outer items.
|
||||
fn visit_nested_item(&mut self, item_id: hir::ItemId) {
|
||||
debug!("visit_nested_item: {:?}", item_id);
|
||||
let item = self.hir_crate.unwrap().item(item_id.id);
|
||||
self.visit_item(item)
|
||||
}
|
||||
|
||||
fn visit_item(&mut self, i: &'ast hir::Item) {
|
||||
debug!("visit_item: {:?}", i);
|
||||
|
||||
// Pick the def data. This need not be unique, but the more
|
||||
// information we encapsulate into
|
||||
let def_data = match i.node {
|
||||
hir::ItemDefaultImpl(..) | hir::ItemImpl(..) =>
|
||||
DefPathData::Impl,
|
||||
hir::ItemEnum(..) | hir::ItemStruct(..) | hir::ItemTrait(..) |
|
||||
hir::ItemExternCrate(..) | hir::ItemMod(..) | hir::ItemForeignMod(..) |
|
||||
hir::ItemTy(..) =>
|
||||
DefPathData::TypeNs(i.name),
|
||||
hir::ItemStatic(..) | hir::ItemConst(..) | hir::ItemFn(..) =>
|
||||
DefPathData::ValueNs(i.name),
|
||||
hir::ItemUse(..) => DefPathData::Misc,
|
||||
};
|
||||
let def = self.create_def(i.id, def_data);
|
||||
|
||||
self.with_parent(def, |this| {
|
||||
match i.node {
|
||||
hir::ItemEnum(ref enum_definition, _) => {
|
||||
for v in &enum_definition.variants {
|
||||
let variant_def_index =
|
||||
this.create_def(v.node.data.id(),
|
||||
DefPathData::EnumVariant(v.node.name));
|
||||
|
||||
for field in v.node.data.fields() {
|
||||
this.create_def_with_parent(Some(variant_def_index),
|
||||
field.id,
|
||||
DefPathData::Field(field.name));
|
||||
}
|
||||
}
|
||||
}
|
||||
hir::ItemStruct(ref struct_def, _) => {
|
||||
// If this is a tuple-like struct, register the constructor.
|
||||
if !struct_def.is_struct() {
|
||||
this.create_def(struct_def.id(),
|
||||
DefPathData::StructCtor);
|
||||
}
|
||||
|
||||
for field in struct_def.fields() {
|
||||
this.create_def(field.id, DefPathData::Field(field.name));
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
intravisit::walk_item(this, i);
|
||||
});
|
||||
}
|
||||
|
||||
fn visit_foreign_item(&mut self, foreign_item: &'ast hir::ForeignItem) {
|
||||
let def = self.create_def(foreign_item.id, DefPathData::ValueNs(foreign_item.name));
|
||||
|
||||
self.with_parent(def, |this| {
|
||||
intravisit::walk_foreign_item(this, foreign_item);
|
||||
});
|
||||
}
|
||||
|
||||
fn visit_generics(&mut self, generics: &'ast hir::Generics) {
|
||||
for ty_param in generics.ty_params.iter() {
|
||||
self.create_def(ty_param.id, DefPathData::TypeParam(ty_param.name));
|
||||
}
|
||||
|
||||
intravisit::walk_generics(self, generics);
|
||||
}
|
||||
|
||||
fn visit_trait_item(&mut self, ti: &'ast hir::TraitItem) {
|
||||
let def_data = match ti.node {
|
||||
hir::MethodTraitItem(..) | hir::ConstTraitItem(..) =>
|
||||
DefPathData::ValueNs(ti.name),
|
||||
hir::TypeTraitItem(..) => DefPathData::TypeNs(ti.name),
|
||||
};
|
||||
|
||||
let def = self.create_def(ti.id, def_data);
|
||||
self.with_parent(def, |this| {
|
||||
if let hir::ConstTraitItem(_, Some(ref expr)) = ti.node {
|
||||
this.create_def(expr.id, DefPathData::Initializer);
|
||||
}
|
||||
|
||||
intravisit::walk_trait_item(this, ti);
|
||||
});
|
||||
}
|
||||
|
||||
fn visit_impl_item(&mut self, ii: &'ast hir::ImplItem) {
|
||||
let def_data = match ii.node {
|
||||
hir::ImplItemKind::Method(..) | hir::ImplItemKind::Const(..) =>
|
||||
DefPathData::ValueNs(ii.name),
|
||||
hir::ImplItemKind::Type(..) => DefPathData::TypeNs(ii.name),
|
||||
};
|
||||
|
||||
let def = self.create_def(ii.id, def_data);
|
||||
self.with_parent(def, |this| {
|
||||
if let hir::ImplItemKind::Const(_, ref expr) = ii.node {
|
||||
this.create_def(expr.id, DefPathData::Initializer);
|
||||
}
|
||||
|
||||
intravisit::walk_impl_item(this, ii);
|
||||
});
|
||||
}
|
||||
|
||||
fn visit_pat(&mut self, pat: &'ast hir::Pat) {
|
||||
let parent_def = self.parent_def;
|
||||
|
||||
if let hir::PatKind::Ident(_, id, _) = pat.node {
|
||||
let def = self.create_def(pat.id, DefPathData::Binding(id.node.name));
|
||||
self.parent_def = Some(def);
|
||||
}
|
||||
|
||||
intravisit::walk_pat(self, pat);
|
||||
self.parent_def = parent_def;
|
||||
}
|
||||
|
||||
fn visit_expr(&mut self, expr: &'ast hir::Expr) {
|
||||
let parent_def = self.parent_def;
|
||||
|
||||
if let hir::ExprClosure(..) = expr.node {
|
||||
let def = self.create_def(expr.id, DefPathData::ClosureExpr);
|
||||
self.parent_def = Some(def);
|
||||
}
|
||||
|
||||
intravisit::walk_expr(self, expr);
|
||||
self.parent_def = parent_def;
|
||||
}
|
||||
|
||||
fn visit_lifetime_def(&mut self, def: &'ast hir::LifetimeDef) {
|
||||
self.create_def(def.lifetime.id, DefPathData::LifetimeDef(def.lifetime.name));
|
||||
}
|
||||
|
||||
fn visit_macro_def(&mut self, macro_def: &'ast hir::MacroDef) {
|
||||
self.create_def(macro_def.id, DefPathData::MacroDef(macro_def.name));
|
||||
}
|
||||
}
|
@ -11,6 +11,7 @@
|
||||
pub use self::Node::*;
|
||||
use self::MapEntry::*;
|
||||
use self::collector::NodeCollector;
|
||||
use self::def_collector::DefCollector;
|
||||
pub use self::definitions::{Definitions, DefKey, DefPath, DefPathData,
|
||||
DisambiguatedDefPathData, InlinedRootPath};
|
||||
|
||||
@ -21,9 +22,10 @@ use middle::cstore::InlinedItem as II;
|
||||
use hir::def_id::{CRATE_DEF_INDEX, DefId};
|
||||
|
||||
use syntax::abi::Abi;
|
||||
use syntax::ast::{self, Name, NodeId, DUMMY_NODE_ID};
|
||||
use syntax::ast::{self, Name, NodeId, DUMMY_NODE_ID, };
|
||||
use syntax::attr::ThinAttributesExt;
|
||||
use syntax::codemap::{Span, Spanned};
|
||||
use syntax::visit;
|
||||
|
||||
use hir::*;
|
||||
use hir::fold::Folder;
|
||||
@ -36,6 +38,7 @@ use std::mem;
|
||||
|
||||
pub mod blocks;
|
||||
mod collector;
|
||||
mod def_collector;
|
||||
pub mod definitions;
|
||||
|
||||
#[derive(Copy, Clone, Debug)]
|
||||
@ -193,7 +196,7 @@ pub struct Map<'ast> {
|
||||
/// plain old integers.
|
||||
map: RefCell<Vec<MapEntry<'ast>>>,
|
||||
|
||||
definitions: RefCell<Definitions>,
|
||||
definitions: &'ast RefCell<Definitions>,
|
||||
}
|
||||
|
||||
impl<'ast> Map<'ast> {
|
||||
@ -780,12 +783,18 @@ impl<F: FoldOps> Folder for IdAndSpanUpdater<F> {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn map_crate<'ast>(forest: &'ast mut Forest) -> Map<'ast> {
|
||||
let (map, definitions) = {
|
||||
let mut collector = NodeCollector::root(&forest.krate);
|
||||
intravisit::walk_crate(&mut collector, &forest.krate);
|
||||
(collector.map, collector.definitions)
|
||||
};
|
||||
pub fn collect_definitions<'ast>(krate: &'ast ast::Crate) -> Definitions {
|
||||
let mut def_collector = DefCollector::root();
|
||||
visit::walk_crate(&mut def_collector, krate);
|
||||
def_collector.definitions
|
||||
}
|
||||
|
||||
pub fn map_crate<'ast>(forest: &'ast mut Forest,
|
||||
definitions: &'ast RefCell<Definitions>)
|
||||
-> Map<'ast> {
|
||||
let mut collector = NodeCollector::root(&forest.krate);
|
||||
intravisit::walk_crate(&mut collector, &forest.krate);
|
||||
let map = collector.map;
|
||||
|
||||
if log_enabled!(::log::DEBUG) {
|
||||
// This only makes sense for ordered stores; note the
|
||||
@ -807,7 +816,7 @@ pub fn map_crate<'ast>(forest: &'ast mut Forest) -> Map<'ast> {
|
||||
forest: forest,
|
||||
dep_graph: forest.dep_graph.clone(),
|
||||
map: RefCell::new(map),
|
||||
definitions: RefCell::new(definitions),
|
||||
definitions: definitions,
|
||||
}
|
||||
}
|
||||
|
||||
@ -834,21 +843,24 @@ pub fn map_decoded_item<'ast, F: FoldOps>(map: &Map<'ast>,
|
||||
};
|
||||
|
||||
let ii = map.forest.inlined_items.alloc(ii);
|
||||
|
||||
let ii_parent_id = fld.new_id(DUMMY_NODE_ID);
|
||||
let mut collector =
|
||||
NodeCollector::extend(
|
||||
map.krate(),
|
||||
ii,
|
||||
ii_parent_id,
|
||||
parent_def_path,
|
||||
parent_def_id,
|
||||
mem::replace(&mut *map.map.borrow_mut(), vec![]),
|
||||
mem::replace(&mut *map.definitions.borrow_mut(), Definitions::new()));
|
||||
ii.visit(&mut collector);
|
||||
|
||||
let defs = mem::replace(&mut *map.definitions.borrow_mut(), Definitions::new());
|
||||
let mut def_collector = DefCollector::extend(ii_parent_id,
|
||||
parent_def_path.clone(),
|
||||
parent_def_id,
|
||||
defs);
|
||||
def_collector.walk_item(ii, map.krate());
|
||||
*map.definitions.borrow_mut() = def_collector.definitions;
|
||||
|
||||
let mut collector = NodeCollector::extend(map.krate(),
|
||||
ii,
|
||||
ii_parent_id,
|
||||
parent_def_path,
|
||||
parent_def_id,
|
||||
mem::replace(&mut *map.map.borrow_mut(), vec![]));
|
||||
ii.visit(&mut collector);
|
||||
*map.map.borrow_mut() = collector.map;
|
||||
*map.definitions.borrow_mut() = collector.definitions;
|
||||
|
||||
ii
|
||||
}
|
||||
|
@ -63,9 +63,6 @@ pub struct Mir<'tcx> {
|
||||
/// where execution begins
|
||||
pub const START_BLOCK: BasicBlock = BasicBlock(0);
|
||||
|
||||
/// where execution ends, on normal return
|
||||
pub const END_BLOCK: BasicBlock = BasicBlock(1);
|
||||
|
||||
impl<'tcx> Mir<'tcx> {
|
||||
pub fn all_basic_blocks(&self) -> Vec<BasicBlock> {
|
||||
(0..self.basic_blocks.len())
|
||||
@ -322,8 +319,7 @@ pub enum TerminatorKind<'tcx> {
|
||||
Resume,
|
||||
|
||||
/// Indicates a normal return. The ReturnPointer lvalue should
|
||||
/// have been filled in by now. This should only occur in the
|
||||
/// `END_BLOCK`.
|
||||
/// have been filled in by now. This should occur at most once.
|
||||
Return,
|
||||
|
||||
/// Drop the Lvalue
|
||||
|
@ -43,6 +43,7 @@ use super::Compilation;
|
||||
|
||||
use serialize::json;
|
||||
|
||||
use std::cell::RefCell;
|
||||
use std::collections::HashMap;
|
||||
use std::env;
|
||||
use std::ffi::{OsString, OsStr};
|
||||
@ -120,13 +121,24 @@ pub fn compile_input(sess: &Session,
|
||||
Ok(()));
|
||||
|
||||
let expanded_crate = assign_node_ids(sess, expanded_crate);
|
||||
// Lower ast -> hir.
|
||||
let lcx = LoweringContext::new(sess, Some(&expanded_crate));
|
||||
let dep_graph = DepGraph::new(sess.opts.build_dep_graph());
|
||||
let mut hir_forest = time(sess.time_passes(),
|
||||
"lowering ast -> hir",
|
||||
|| hir_map::Forest::new(lower_crate(&lcx, &expanded_crate),
|
||||
dep_graph));
|
||||
|
||||
// Collect defintions for def ids.
|
||||
let defs = &RefCell::new(time(sess.time_passes(),
|
||||
"collecting defs",
|
||||
|| hir_map::collect_definitions(&expanded_crate)));
|
||||
|
||||
time(sess.time_passes(),
|
||||
"external crate/lib resolution",
|
||||
|| LocalCrateReader::new(sess, &cstore, &defs, &expanded_crate, &id)
|
||||
.read_crates(&dep_graph));
|
||||
|
||||
// Lower ast -> hir.
|
||||
let lcx = LoweringContext::new(sess, Some(&expanded_crate), defs);
|
||||
let hir_forest = &mut time(sess.time_passes(),
|
||||
"lowering ast -> hir",
|
||||
|| hir_map::Forest::new(lower_crate(&lcx, &expanded_crate),
|
||||
dep_graph));
|
||||
|
||||
// Discard MTWT tables that aren't required past lowering to HIR.
|
||||
if !sess.opts.debugging_opts.keep_mtwt_tables &&
|
||||
@ -135,7 +147,12 @@ pub fn compile_input(sess: &Session,
|
||||
}
|
||||
|
||||
let arenas = ty::CtxtArenas::new();
|
||||
let hir_map = make_map(sess, &mut hir_forest);
|
||||
|
||||
// Construct the HIR map
|
||||
let hir_map = time(sess.time_passes(),
|
||||
"indexing hir",
|
||||
move || hir_map::map_crate(hir_forest, defs));
|
||||
|
||||
|
||||
write_out_deps(sess, &outputs, &id);
|
||||
|
||||
@ -171,7 +188,6 @@ pub fn compile_input(sess: &Session,
|
||||
};
|
||||
|
||||
phase_3_run_analysis_passes(sess,
|
||||
&cstore,
|
||||
hir_map,
|
||||
&arenas,
|
||||
&id,
|
||||
@ -726,20 +742,10 @@ pub fn assign_node_ids(sess: &Session, krate: ast::Crate) -> ast::Crate {
|
||||
krate
|
||||
}
|
||||
|
||||
pub fn make_map<'ast>(sess: &Session,
|
||||
forest: &'ast mut hir_map::Forest)
|
||||
-> hir_map::Map<'ast> {
|
||||
// Construct the HIR map
|
||||
time(sess.time_passes(),
|
||||
"indexing hir",
|
||||
move || hir_map::map_crate(forest))
|
||||
}
|
||||
|
||||
/// Run the resolution, typechecking, region checking and other
|
||||
/// miscellaneous analysis passes on the crate. Return various
|
||||
/// structures carrying the results of the analysis.
|
||||
pub fn phase_3_run_analysis_passes<'tcx, F, R>(sess: &'tcx Session,
|
||||
cstore: &CStore,
|
||||
hir_map: hir_map::Map<'tcx>,
|
||||
arenas: &'tcx ty::CtxtArenas<'tcx>,
|
||||
name: &str,
|
||||
@ -762,10 +768,6 @@ pub fn phase_3_run_analysis_passes<'tcx, F, R>(sess: &'tcx Session,
|
||||
|
||||
let time_passes = sess.time_passes();
|
||||
|
||||
time(time_passes,
|
||||
"external crate/lib resolution",
|
||||
|| LocalCrateReader::new(sess, cstore, &hir_map, name).read_crates());
|
||||
|
||||
let lang_items = time(time_passes, "language item collection", || {
|
||||
sess.track_errors(|| {
|
||||
middle::lang_items::collect_language_items(&sess, &hir_map)
|
||||
@ -778,8 +780,8 @@ pub fn phase_3_run_analysis_passes<'tcx, F, R>(sess: &'tcx Session,
|
||||
export_map,
|
||||
trait_map,
|
||||
glob_map,
|
||||
} = time(time_passes,
|
||||
"resolution",
|
||||
} = time(sess.time_passes(),
|
||||
"name resolution",
|
||||
|| resolve::resolve_crate(sess, &hir_map, make_glob_map));
|
||||
|
||||
let mut analysis = ty::CrateAnalysis {
|
||||
|
@ -199,14 +199,9 @@ pub fn run_compiler<'a>(args: &[String],
|
||||
// It is somewhat unfortunate that this is hardwired in - this is forced by
|
||||
// the fact that pretty_print_input requires the session by value.
|
||||
let pretty = callbacks.parse_pretty(&sess, &matches);
|
||||
match pretty {
|
||||
Some((ppm, opt_uii)) => {
|
||||
pretty::pretty_print_input(sess, &cstore, cfg, &input, ppm, opt_uii, ofile);
|
||||
return (Ok(()), None);
|
||||
}
|
||||
None => {
|
||||
// continue
|
||||
}
|
||||
if let Some((ppm, opt_uii)) = pretty {
|
||||
pretty::pretty_print_input(sess, &cstore, cfg, &input, ppm, opt_uii, ofile);
|
||||
return (Ok(()), None);
|
||||
}
|
||||
|
||||
let plugins = sess.opts.debugging_opts.extra_plugins.clone();
|
||||
|
@ -29,6 +29,7 @@ use rustc_borrowck as borrowck;
|
||||
use rustc_borrowck::graphviz as borrowck_dot;
|
||||
use rustc_resolve as resolve;
|
||||
use rustc_metadata::cstore::CStore;
|
||||
use rustc_metadata::creader::LocalCrateReader;
|
||||
|
||||
use rustc_mir::pretty::write_mir_pretty;
|
||||
use rustc_mir::graphviz::write_mir_graphviz;
|
||||
@ -43,6 +44,7 @@ use syntax::util::small_vector::SmallVector;
|
||||
|
||||
use graphviz as dot;
|
||||
|
||||
use std::cell::RefCell;
|
||||
use std::fs::File;
|
||||
use std::io::{self, Write};
|
||||
use std::iter;
|
||||
@ -179,7 +181,6 @@ impl PpSourceMode {
|
||||
}
|
||||
fn call_with_pp_support_hir<'tcx, A, B, F>(&self,
|
||||
sess: &'tcx Session,
|
||||
cstore: &CStore,
|
||||
ast_map: &hir_map::Map<'tcx>,
|
||||
arenas: &'tcx ty::CtxtArenas<'tcx>,
|
||||
id: &str,
|
||||
@ -206,7 +207,6 @@ impl PpSourceMode {
|
||||
}
|
||||
PpmTyped => {
|
||||
abort_on_err(driver::phase_3_run_analysis_passes(sess,
|
||||
cstore,
|
||||
ast_map.clone(),
|
||||
arenas,
|
||||
id,
|
||||
@ -721,7 +721,7 @@ pub fn pretty_print_input(sess: Session,
|
||||
let is_expanded = needs_expansion(&ppm);
|
||||
let compute_ast_map = needs_ast_map(&ppm, &opt_uii);
|
||||
let krate = if compute_ast_map {
|
||||
match driver::phase_2_configure_and_expand(&sess, &cstore, krate, &id[..], None) {
|
||||
match driver::phase_2_configure_and_expand(&sess, &cstore, krate, &id, None) {
|
||||
Err(_) => return,
|
||||
Ok(k) => driver::assign_node_ids(&sess, k),
|
||||
}
|
||||
@ -732,14 +732,18 @@ pub fn pretty_print_input(sess: Session,
|
||||
// There is some twisted, god-forsaken tangle of lifetimes here which makes
|
||||
// the ordering of stuff super-finicky.
|
||||
let mut hir_forest;
|
||||
let lcx = LoweringContext::new(&sess, Some(&krate));
|
||||
let arenas = ty::CtxtArenas::new();
|
||||
let mut _defs = None;
|
||||
let dep_graph = DepGraph::new(false);
|
||||
let arenas = ty::CtxtArenas::new();
|
||||
let _ignore = dep_graph.in_ignore();
|
||||
let ast_map = if compute_ast_map {
|
||||
_defs = Some(RefCell::new(hir_map::collect_definitions(&krate)));
|
||||
let defs = _defs.as_ref().unwrap();
|
||||
LocalCrateReader::new(&sess, &cstore, defs, &krate, &id).read_crates(&dep_graph);
|
||||
let lcx = LoweringContext::new(&sess, Some(&krate), defs);
|
||||
|
||||
hir_forest = hir_map::Forest::new(lower_crate(&lcx, &krate), dep_graph.clone());
|
||||
let map = driver::make_map(&sess, &mut hir_forest);
|
||||
Some(map)
|
||||
Some(hir_map::map_crate(&mut hir_forest, defs))
|
||||
} else {
|
||||
None
|
||||
};
|
||||
@ -752,7 +756,7 @@ pub fn pretty_print_input(sess: Session,
|
||||
.unwrap()
|
||||
.as_bytes()
|
||||
.to_vec();
|
||||
let mut rdr = &src[..];
|
||||
let mut rdr = &*src;
|
||||
|
||||
let mut out = Vec::new();
|
||||
|
||||
@ -777,7 +781,6 @@ pub fn pretty_print_input(sess: Session,
|
||||
(PpmHir(s), None) => {
|
||||
let out: &mut Write = &mut out;
|
||||
s.call_with_pp_support_hir(&sess,
|
||||
cstore,
|
||||
&ast_map.unwrap(),
|
||||
&arenas,
|
||||
&id,
|
||||
@ -799,7 +802,6 @@ pub fn pretty_print_input(sess: Session,
|
||||
(PpmHir(s), Some(uii)) => {
|
||||
let out: &mut Write = &mut out;
|
||||
s.call_with_pp_support_hir(&sess,
|
||||
cstore,
|
||||
&ast_map.unwrap(),
|
||||
&arenas,
|
||||
&id,
|
||||
@ -840,7 +842,6 @@ pub fn pretty_print_input(sess: Session,
|
||||
None
|
||||
};
|
||||
abort_on_err(driver::phase_3_run_analysis_passes(&sess,
|
||||
&cstore,
|
||||
ast_map,
|
||||
&arenas,
|
||||
&id,
|
||||
@ -887,7 +888,6 @@ pub fn pretty_print_input(sess: Session,
|
||||
Some(code) => {
|
||||
let variants = gather_flowgraph_variants(&sess);
|
||||
abort_on_err(driver::phase_3_run_analysis_passes(&sess,
|
||||
&cstore,
|
||||
ast_map,
|
||||
&arenas,
|
||||
&id,
|
||||
|
@ -27,8 +27,10 @@ use rustc::ty::{self, Ty, TyCtxt, TypeFoldable};
|
||||
use rustc::ty::relate::TypeRelation;
|
||||
use rustc::infer::{self, InferOk, InferResult, TypeOrigin};
|
||||
use rustc_metadata::cstore::CStore;
|
||||
use rustc_metadata::creader::LocalCrateReader;
|
||||
use rustc::hir::map as hir_map;
|
||||
use rustc::session::{self, config};
|
||||
use std::cell::RefCell;
|
||||
use std::rc::Rc;
|
||||
use syntax::ast;
|
||||
use syntax::abi::Abi;
|
||||
@ -119,13 +121,15 @@ fn test_env<F>(source_string: &str,
|
||||
let krate = driver::phase_2_configure_and_expand(&sess, &cstore, krate, "test", None)
|
||||
.expect("phase 2 aborted");
|
||||
|
||||
let krate = driver::assign_node_ids(&sess, krate);
|
||||
let lcx = LoweringContext::new(&sess, Some(&krate));
|
||||
let dep_graph = DepGraph::new(false);
|
||||
let krate = driver::assign_node_ids(&sess, krate);
|
||||
let defs = &RefCell::new(hir_map::collect_definitions(&krate));
|
||||
LocalCrateReader::new(&sess, &cstore, defs, &krate, "test_crate").read_crates(&dep_graph);
|
||||
let lcx = LoweringContext::new(&sess, Some(&krate), defs);
|
||||
let _ignore = dep_graph.in_ignore();
|
||||
let mut hir_forest = hir_map::Forest::new(lower_crate(&lcx, &krate), dep_graph.clone());
|
||||
let mut hir_forest = &mut hir_map::Forest::new(lower_crate(&lcx, &krate), dep_graph.clone());
|
||||
let arenas = ty::CtxtArenas::new();
|
||||
let ast_map = driver::make_map(&sess, &mut hir_forest);
|
||||
let ast_map = hir_map::map_crate(hir_forest, defs);
|
||||
|
||||
// run just enough stuff to build a tcx:
|
||||
let lang_items = lang_items::collect_language_items(&sess, &ast_map);
|
||||
|
@ -1339,7 +1339,7 @@ fn roundtrip(in_item: hir::Item) {
|
||||
fn test_basic() {
|
||||
let cx = mk_ctxt();
|
||||
let fnia = FakeNodeIdAssigner;
|
||||
let lcx = LoweringContext::new(&fnia, None);
|
||||
let lcx = LoweringContext::testing_context(&fnia);
|
||||
roundtrip(lower_item(&lcx, "e_item!(&cx,
|
||||
fn foo() {}
|
||||
).unwrap()));
|
||||
@ -1349,7 +1349,7 @@ fn test_basic() {
|
||||
fn test_smalltalk() {
|
||||
let cx = mk_ctxt();
|
||||
let fnia = FakeNodeIdAssigner;
|
||||
let lcx = LoweringContext::new(&fnia, None);
|
||||
let lcx = LoweringContext::testing_context(&fnia);
|
||||
roundtrip(lower_item(&lcx, "e_item!(&cx,
|
||||
fn foo() -> isize { 3 + 4 } // first smalltalk program ever executed.
|
||||
).unwrap()));
|
||||
@ -1359,7 +1359,7 @@ fn test_smalltalk() {
|
||||
fn test_more() {
|
||||
let cx = mk_ctxt();
|
||||
let fnia = FakeNodeIdAssigner;
|
||||
let lcx = LoweringContext::new(&fnia, None);
|
||||
let lcx = LoweringContext::testing_context(&fnia);
|
||||
roundtrip(lower_item(&lcx, "e_item!(&cx,
|
||||
fn foo(x: usize, y: usize) -> usize {
|
||||
let z = x + y;
|
||||
@ -1378,7 +1378,7 @@ fn test_simplification() {
|
||||
}
|
||||
).unwrap();
|
||||
let fnia = FakeNodeIdAssigner;
|
||||
let lcx = LoweringContext::new(&fnia, None);
|
||||
let lcx = LoweringContext::testing_context(&fnia);
|
||||
let hir_item = lower_item(&lcx, &item);
|
||||
let item_in = InlinedItemRef::Item(&hir_item);
|
||||
let item_out = simplify_ast(item_in);
|
||||
|
@ -18,7 +18,7 @@ use decoder;
|
||||
use loader::{self, CratePaths};
|
||||
|
||||
use rustc::hir::svh::Svh;
|
||||
use rustc::dep_graph::DepNode;
|
||||
use rustc::dep_graph::{DepGraph, DepNode};
|
||||
use rustc::session::{config, Session};
|
||||
use rustc::session::search_paths::PathKind;
|
||||
use rustc::middle::cstore::{CrateStore, validate_crate_name, ExternCrate};
|
||||
@ -37,15 +37,15 @@ use syntax::parse;
|
||||
use syntax::attr;
|
||||
use syntax::attr::AttrMetaMethods;
|
||||
use syntax::parse::token::InternedString;
|
||||
use rustc::hir::intravisit::Visitor;
|
||||
use rustc::hir;
|
||||
use syntax::visit;
|
||||
use log;
|
||||
|
||||
pub struct LocalCrateReader<'a, 'b:'a> {
|
||||
pub struct LocalCrateReader<'a> {
|
||||
sess: &'a Session,
|
||||
cstore: &'a CStore,
|
||||
creader: CrateReader<'a>,
|
||||
ast_map: &'a hir_map::Map<'b>,
|
||||
krate: &'a ast::Crate,
|
||||
defintions: &'a RefCell<hir_map::Definitions>,
|
||||
}
|
||||
|
||||
pub struct CrateReader<'a> {
|
||||
@ -56,9 +56,10 @@ pub struct CrateReader<'a> {
|
||||
local_crate_name: String,
|
||||
}
|
||||
|
||||
impl<'a, 'b, 'hir> Visitor<'hir> for LocalCrateReader<'a, 'b> {
|
||||
fn visit_item(&mut self, a: &'hir hir::Item) {
|
||||
impl<'a, 'ast> visit::Visitor<'ast> for LocalCrateReader<'a> {
|
||||
fn visit_item(&mut self, a: &'ast ast::Item) {
|
||||
self.process_item(a);
|
||||
visit::walk_item(self, a);
|
||||
}
|
||||
}
|
||||
|
||||
@ -80,11 +81,8 @@ fn dump_crates(cstore: &CStore) {
|
||||
fn should_link(i: &ast::Item) -> bool {
|
||||
!attr::contains_name(&i.attrs, "no_link")
|
||||
}
|
||||
// Dup for the hir
|
||||
fn should_link_hir(i: &hir::Item) -> bool {
|
||||
!attr::contains_name(&i.attrs, "no_link")
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
struct CrateInfo {
|
||||
ident: String,
|
||||
name: String,
|
||||
@ -181,31 +179,6 @@ impl<'a> CrateReader<'a> {
|
||||
}
|
||||
}
|
||||
|
||||
// Dup of the above, but for the hir
|
||||
fn extract_crate_info_hir(&self, i: &hir::Item) -> Option<CrateInfo> {
|
||||
match i.node {
|
||||
hir::ItemExternCrate(ref path_opt) => {
|
||||
debug!("resolving extern crate stmt. ident: {} path_opt: {:?}",
|
||||
i.name, path_opt);
|
||||
let name = match *path_opt {
|
||||
Some(name) => {
|
||||
validate_crate_name(Some(self.sess), &name.as_str(),
|
||||
Some(i.span));
|
||||
name.to_string()
|
||||
}
|
||||
None => i.name.to_string(),
|
||||
};
|
||||
Some(CrateInfo {
|
||||
ident: i.name.to_string(),
|
||||
name: name,
|
||||
id: i.id,
|
||||
should_link: should_link_hir(i),
|
||||
})
|
||||
}
|
||||
_ => None
|
||||
}
|
||||
}
|
||||
|
||||
fn existing_match(&self, name: &str, hash: Option<&Svh>, kind: PathKind)
|
||||
-> Option<ast::CrateNum> {
|
||||
let mut ret = None;
|
||||
@ -776,29 +749,30 @@ impl<'a> CrateReader<'a> {
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, 'b> LocalCrateReader<'a, 'b> {
|
||||
impl<'a> LocalCrateReader<'a> {
|
||||
pub fn new(sess: &'a Session,
|
||||
cstore: &'a CStore,
|
||||
map: &'a hir_map::Map<'b>,
|
||||
defs: &'a RefCell<hir_map::Definitions>,
|
||||
krate: &'a ast::Crate,
|
||||
local_crate_name: &str)
|
||||
-> LocalCrateReader<'a, 'b> {
|
||||
-> LocalCrateReader<'a> {
|
||||
LocalCrateReader {
|
||||
sess: sess,
|
||||
cstore: cstore,
|
||||
creader: CrateReader::new(sess, cstore, local_crate_name),
|
||||
ast_map: map,
|
||||
krate: krate,
|
||||
defintions: defs,
|
||||
}
|
||||
}
|
||||
|
||||
// Traverses an AST, reading all the information about use'd crates and
|
||||
// extern libraries necessary for later resolving, typechecking, linking,
|
||||
// etc.
|
||||
pub fn read_crates(&mut self) {
|
||||
let _task = self.ast_map.dep_graph.in_task(DepNode::CrateReader);
|
||||
let krate = self.ast_map.krate();
|
||||
pub fn read_crates(&mut self, dep_graph: &DepGraph) {
|
||||
let _task = dep_graph.in_task(DepNode::CrateReader);
|
||||
|
||||
self.process_crate(krate);
|
||||
krate.visit_all_items(self);
|
||||
self.process_crate(self.krate);
|
||||
visit::walk_crate(self, self.krate);
|
||||
self.creader.inject_allocator_crate();
|
||||
|
||||
if log_enabled!(log::INFO) {
|
||||
@ -811,34 +785,34 @@ impl<'a, 'b> LocalCrateReader<'a, 'b> {
|
||||
self.creader.register_statically_included_foreign_items();
|
||||
}
|
||||
|
||||
fn process_crate(&self, c: &hir::Crate) {
|
||||
fn process_crate(&self, c: &ast::Crate) {
|
||||
for a in c.attrs.iter().filter(|m| m.name() == "link_args") {
|
||||
match a.value_str() {
|
||||
Some(ref linkarg) => self.cstore.add_used_link_args(&linkarg),
|
||||
None => { /* fallthrough */ }
|
||||
if let Some(ref linkarg) = a.value_str() {
|
||||
self.cstore.add_used_link_args(&linkarg);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn process_item(&mut self, i: &hir::Item) {
|
||||
fn process_item(&mut self, i: &ast::Item) {
|
||||
match i.node {
|
||||
hir::ItemExternCrate(_) => {
|
||||
if !should_link_hir(i) {
|
||||
ast::ItemKind::ExternCrate(_) => {
|
||||
if !should_link(i) {
|
||||
return;
|
||||
}
|
||||
|
||||
match self.creader.extract_crate_info_hir(i) {
|
||||
match self.creader.extract_crate_info(i) {
|
||||
Some(info) => {
|
||||
let (cnum, _, _) = self.creader.resolve_crate(&None,
|
||||
&info.ident,
|
||||
&info.name,
|
||||
None,
|
||||
i.span,
|
||||
PathKind::Crate,
|
||||
true);
|
||||
let def_id = self.ast_map.local_def_id(i.id);
|
||||
&info.ident,
|
||||
&info.name,
|
||||
None,
|
||||
i.span,
|
||||
PathKind::Crate,
|
||||
true);
|
||||
|
||||
let len = self.ast_map.def_path(def_id).data.len();
|
||||
let defs = self.defintions.borrow();
|
||||
let def_id = defs.opt_local_def_id(i.id).unwrap();
|
||||
let len = defs.def_path(def_id.index).data.len();
|
||||
|
||||
self.creader.update_extern_crate(cnum,
|
||||
ExternCrate {
|
||||
@ -852,12 +826,12 @@ impl<'a, 'b> LocalCrateReader<'a, 'b> {
|
||||
None => ()
|
||||
}
|
||||
}
|
||||
hir::ItemForeignMod(ref fm) => self.process_foreign_mod(i, fm),
|
||||
ast::ItemKind::ForeignMod(ref fm) => self.process_foreign_mod(i, fm),
|
||||
_ => { }
|
||||
}
|
||||
}
|
||||
|
||||
fn process_foreign_mod(&mut self, i: &hir::Item, fm: &hir::ForeignMod) {
|
||||
fn process_foreign_mod(&mut self, i: &ast::Item, fm: &ast::ForeignMod) {
|
||||
if fm.abi == Abi::Rust || fm.abi == Abi::RustIntrinsic || fm.abi == Abi::PlatformIntrinsic {
|
||||
return;
|
||||
}
|
||||
|
@ -262,7 +262,8 @@ impl<'a,'tcx> Builder<'a,'tcx> {
|
||||
}
|
||||
};
|
||||
let extent = this.extent_of_return_scope();
|
||||
this.exit_scope(expr_span, extent, block, END_BLOCK);
|
||||
let return_block = this.return_block();
|
||||
this.exit_scope(expr_span, extent, block, return_block);
|
||||
this.cfg.start_new_block().unit()
|
||||
}
|
||||
ExprKind::Call { ty, fun, args } => {
|
||||
|
@ -26,23 +26,23 @@ pub struct Builder<'a, 'tcx: 'a> {
|
||||
|
||||
fn_span: Span,
|
||||
|
||||
// the current set of scopes, updated as we traverse;
|
||||
// see the `scope` module for more details
|
||||
/// the current set of scopes, updated as we traverse;
|
||||
/// see the `scope` module for more details
|
||||
scopes: Vec<scope::Scope<'tcx>>,
|
||||
|
||||
// for each scope, a span of blocks that defines it;
|
||||
// we track these for use in region and borrow checking,
|
||||
// but these are liable to get out of date once optimization
|
||||
// begins. They are also hopefully temporary, and will be
|
||||
// no longer needed when we adopt graph-based regions.
|
||||
/// for each scope, a span of blocks that defines it;
|
||||
/// we track these for use in region and borrow checking,
|
||||
/// but these are liable to get out of date once optimization
|
||||
/// begins. They are also hopefully temporary, and will be
|
||||
/// no longer needed when we adopt graph-based regions.
|
||||
scope_auxiliary: ScopeAuxiliaryVec,
|
||||
|
||||
// the current set of loops; see the `scope` module for more
|
||||
// details
|
||||
/// the current set of loops; see the `scope` module for more
|
||||
/// details
|
||||
loop_scopes: Vec<scope::LoopScope>,
|
||||
|
||||
// the vector of all scopes that we have created thus far;
|
||||
// we track this for debuginfo later
|
||||
/// the vector of all scopes that we have created thus far;
|
||||
/// we track this for debuginfo later
|
||||
scope_datas: Vec<ScopeData>,
|
||||
|
||||
var_decls: Vec<VarDecl<'tcx>>,
|
||||
@ -50,9 +50,11 @@ pub struct Builder<'a, 'tcx: 'a> {
|
||||
temp_decls: Vec<TempDecl<'tcx>>,
|
||||
unit_temp: Option<Lvalue<'tcx>>,
|
||||
|
||||
// cached block with a RESUME terminator; we create this at the
|
||||
// first panic
|
||||
/// cached block with the RESUME terminator; this is created
|
||||
/// when first set of cleanups are built.
|
||||
cached_resume_block: Option<BasicBlock>,
|
||||
/// cached block with the RETURN terminator
|
||||
cached_return_block: Option<BasicBlock>,
|
||||
}
|
||||
|
||||
struct CFG<'tcx> {
|
||||
@ -182,11 +184,10 @@ pub fn construct<'a,'tcx>(hir: Cx<'a,'tcx>,
|
||||
var_indices: FnvHashMap(),
|
||||
unit_temp: None,
|
||||
cached_resume_block: None,
|
||||
cached_return_block: None
|
||||
};
|
||||
|
||||
assert_eq!(builder.cfg.start_new_block(), START_BLOCK);
|
||||
assert_eq!(builder.cfg.start_new_block(), END_BLOCK);
|
||||
|
||||
|
||||
let mut arg_decls = None; // assigned to `Some` in closures below
|
||||
let call_site_extent =
|
||||
@ -206,12 +207,12 @@ pub fn construct<'a,'tcx>(hir: Cx<'a,'tcx>,
|
||||
block.unit()
|
||||
}));
|
||||
|
||||
let return_block = builder.return_block();
|
||||
builder.cfg.terminate(block, call_site_scope_id, span,
|
||||
TerminatorKind::Goto { target: END_BLOCK });
|
||||
builder.cfg.terminate(END_BLOCK, call_site_scope_id, span,
|
||||
TerminatorKind::Goto { target: return_block });
|
||||
builder.cfg.terminate(return_block, call_site_scope_id, span,
|
||||
TerminatorKind::Return);
|
||||
|
||||
END_BLOCK.unit()
|
||||
return_block.unit()
|
||||
});
|
||||
|
||||
assert!(
|
||||
@ -329,6 +330,17 @@ impl<'a,'tcx> Builder<'a,'tcx> {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn return_block(&mut self) -> BasicBlock {
|
||||
match self.cached_return_block {
|
||||
Some(rb) => rb,
|
||||
None => {
|
||||
let rb = self.cfg.start_new_block();
|
||||
self.cached_return_block = Some(rb);
|
||||
rb
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
|
@ -43,9 +43,8 @@ pub struct RemoveDeadBlocks;
|
||||
impl<'tcx> MirPass<'tcx> for RemoveDeadBlocks {
|
||||
fn run_pass(&mut self, _: &TyCtxt<'tcx>, _: NodeId, mir: &mut Mir<'tcx>) {
|
||||
let mut seen = BitVector::new(mir.basic_blocks.len());
|
||||
// These blocks are always required.
|
||||
// This block is always required.
|
||||
seen.insert(START_BLOCK.index());
|
||||
seen.insert(END_BLOCK.index());
|
||||
|
||||
let mut worklist = Vec::with_capacity(4);
|
||||
worklist.push(START_BLOCK);
|
||||
|
@ -17,10 +17,10 @@ use super::data::*;
|
||||
use super::dump::Dump;
|
||||
use super::span_utils::SpanUtils;
|
||||
|
||||
pub struct CsvDumper<'a, 'b, W: 'b> {
|
||||
pub struct CsvDumper<'tcx, 'b, W: 'b> {
|
||||
output: &'b mut W,
|
||||
dump_spans: bool,
|
||||
span: SpanUtils<'a>
|
||||
span: SpanUtils<'tcx>
|
||||
}
|
||||
|
||||
impl<'a, 'b, W: Write> CsvDumper<'a, 'b, W> {
|
||||
|
@ -42,7 +42,7 @@ use syntax::visit::{self, Visitor};
|
||||
use syntax::print::pprust::{path_to_string, ty_to_string};
|
||||
use syntax::ptr::P;
|
||||
|
||||
use rustc::hir::lowering::{lower_expr, LoweringContext};
|
||||
use rustc::hir::lowering::lower_expr;
|
||||
|
||||
use super::{escape, generated_code, SaveContext, PathCollector};
|
||||
use super::data::*;
|
||||
@ -60,12 +60,12 @@ macro_rules! down_cast_data {
|
||||
};
|
||||
}
|
||||
|
||||
pub struct DumpVisitor<'l, 'tcx: 'l, D: 'l> {
|
||||
pub struct DumpVisitor<'l, 'tcx: 'l, 'll, D: 'll> {
|
||||
save_ctxt: SaveContext<'l, 'tcx>,
|
||||
sess: &'l Session,
|
||||
tcx: &'l TyCtxt<'tcx>,
|
||||
analysis: &'l ty::CrateAnalysis<'l>,
|
||||
dumper: &'l mut D,
|
||||
dumper: &'ll mut D,
|
||||
|
||||
span: SpanUtils<'l>,
|
||||
|
||||
@ -77,22 +77,19 @@ pub struct DumpVisitor<'l, 'tcx: 'l, D: 'l> {
|
||||
// one macro use per unique callsite span.
|
||||
mac_defs: HashSet<Span>,
|
||||
mac_uses: HashSet<Span>,
|
||||
|
||||
}
|
||||
|
||||
impl <'l, 'tcx, D> DumpVisitor<'l, 'tcx, D>
|
||||
where D: Dump
|
||||
{
|
||||
impl<'l, 'tcx: 'l, 'll, D: Dump + 'll> DumpVisitor<'l, 'tcx, 'll, D> {
|
||||
pub fn new(tcx: &'l TyCtxt<'tcx>,
|
||||
lcx: &'l LoweringContext<'l>,
|
||||
save_ctxt: SaveContext<'l, 'tcx>,
|
||||
analysis: &'l ty::CrateAnalysis<'l>,
|
||||
dumper: &'l mut D)
|
||||
-> DumpVisitor<'l, 'tcx, D> {
|
||||
dumper: &'ll mut D)
|
||||
-> DumpVisitor<'l, 'tcx, 'll, D> {
|
||||
let span_utils = SpanUtils::new(&tcx.sess);
|
||||
DumpVisitor {
|
||||
sess: &tcx.sess,
|
||||
tcx: tcx,
|
||||
save_ctxt: SaveContext::from_span_utils(tcx, lcx, span_utils.clone()),
|
||||
save_ctxt: save_ctxt,
|
||||
analysis: analysis,
|
||||
dumper: dumper,
|
||||
span: span_utils.clone(),
|
||||
@ -103,7 +100,7 @@ where D: Dump
|
||||
}
|
||||
|
||||
fn nest<F>(&mut self, scope_id: NodeId, f: F)
|
||||
where F: FnOnce(&mut DumpVisitor<'l, 'tcx, D>)
|
||||
where F: FnOnce(&mut DumpVisitor<'l, 'tcx, 'll, D>)
|
||||
{
|
||||
let parent_scope = self.cur_scope;
|
||||
self.cur_scope = scope_id;
|
||||
@ -982,7 +979,7 @@ where D: Dump
|
||||
}
|
||||
}
|
||||
|
||||
impl<'l, 'tcx, 'v, D: Dump + 'l> Visitor<'v> for DumpVisitor<'l, 'tcx, D> {
|
||||
impl<'v, 'l, 'tcx: 'l, 'll, D: Dump +'ll> Visitor<'v> for DumpVisitor<'l, 'tcx, 'll, D> {
|
||||
fn visit_item(&mut self, item: &ast::Item) {
|
||||
use syntax::ast::ItemKind::*;
|
||||
self.process_macro_use(item.span, item.id);
|
||||
|
@ -73,7 +73,7 @@ pub mod recorder {
|
||||
pub struct SaveContext<'l, 'tcx: 'l> {
|
||||
tcx: &'l TyCtxt<'tcx>,
|
||||
lcx: &'l lowering::LoweringContext<'l>,
|
||||
span_utils: SpanUtils<'l>,
|
||||
span_utils: SpanUtils<'tcx>,
|
||||
}
|
||||
|
||||
macro_rules! option_try(
|
||||
@ -90,7 +90,7 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> {
|
||||
|
||||
pub fn from_span_utils(tcx: &'l TyCtxt<'tcx>,
|
||||
lcx: &'l lowering::LoweringContext<'l>,
|
||||
span_utils: SpanUtils<'l>)
|
||||
span_utils: SpanUtils<'tcx>)
|
||||
-> SaveContext<'l, 'tcx> {
|
||||
SaveContext {
|
||||
tcx: tcx,
|
||||
@ -680,7 +680,7 @@ impl<'v> Visitor<'v> for PathCollector {
|
||||
pub fn process_crate<'l, 'tcx>(tcx: &'l TyCtxt<'tcx>,
|
||||
lcx: &'l lowering::LoweringContext<'l>,
|
||||
krate: &ast::Crate,
|
||||
analysis: &ty::CrateAnalysis,
|
||||
analysis: &'l ty::CrateAnalysis<'l>,
|
||||
cratename: &str,
|
||||
odir: Option<&Path>) {
|
||||
let _ignore = tcx.dep_graph.in_ignore();
|
||||
@ -726,9 +726,10 @@ pub fn process_crate<'l, 'tcx>(tcx: &'l TyCtxt<'tcx>,
|
||||
});
|
||||
root_path.pop();
|
||||
|
||||
let utils = SpanUtils::new(&tcx.sess);
|
||||
let utils: SpanUtils<'tcx> = SpanUtils::new(&tcx.sess);
|
||||
let save_ctxt = SaveContext::new(tcx, lcx);
|
||||
let mut dumper = CsvDumper::new(&mut output_file, utils);
|
||||
let mut visitor = DumpVisitor::new(tcx, lcx, analysis, &mut dumper);
|
||||
let mut visitor = DumpVisitor::new(tcx, save_ctxt, analysis, &mut dumper);
|
||||
// FIXME: we don't write anything!
|
||||
|
||||
visitor.dump_crate_info(cratename, krate);
|
||||
|
@ -26,6 +26,8 @@ use syntax::parse::token::{keywords, Token};
|
||||
#[derive(Clone)]
|
||||
pub struct SpanUtils<'a> {
|
||||
pub sess: &'a Session,
|
||||
// FIXME given that we clone SpanUtils all over the place, this err_count is
|
||||
// probably useless and any logic relying on it is bogus.
|
||||
pub err_count: Cell<isize>,
|
||||
}
|
||||
|
||||
|
@ -164,8 +164,6 @@ pub fn trans_mir<'blk, 'tcx: 'blk>(fcx: &'blk FunctionContext<'blk, 'tcx>) {
|
||||
.map(|&bb|{
|
||||
if bb == mir::START_BLOCK {
|
||||
fcx.new_block("start", None)
|
||||
} else if bb == mir::END_BLOCK {
|
||||
fcx.new_block("end", None)
|
||||
} else {
|
||||
fcx.new_block(&format!("{:?}", bb), None)
|
||||
}
|
||||
|
@ -22,6 +22,7 @@ use rustc_trans::back::link;
|
||||
use rustc_resolve as resolve;
|
||||
use rustc::hir::lowering::{lower_crate, LoweringContext};
|
||||
use rustc_metadata::cstore::CStore;
|
||||
use rustc_metadata::creader::LocalCrateReader;
|
||||
|
||||
use syntax::{ast, codemap, errors};
|
||||
use syntax::errors::emitter::ColorConfig;
|
||||
@ -151,14 +152,18 @@ pub fn run_core(search_paths: SearchPaths,
|
||||
.expect("phase_2_configure_and_expand aborted in rustdoc!");
|
||||
|
||||
let krate = driver::assign_node_ids(&sess, krate);
|
||||
let dep_graph = DepGraph::new(false);
|
||||
|
||||
let defs = &RefCell::new(hir_map::collect_definitions(&krate));
|
||||
LocalCrateReader::new(&sess, &cstore, &defs, &krate, &name).read_crates(&dep_graph);
|
||||
let lcx = LoweringContext::new(&sess, Some(&krate), defs);
|
||||
|
||||
// Lower ast -> hir.
|
||||
let lcx = LoweringContext::new(&sess, Some(&krate));
|
||||
let mut hir_forest = hir_map::Forest::new(lower_crate(&lcx, &krate), DepGraph::new(false));
|
||||
let mut hir_forest = hir_map::Forest::new(lower_crate(&lcx, &krate), dep_graph);
|
||||
let arenas = ty::CtxtArenas::new();
|
||||
let hir_map = driver::make_map(&sess, &mut hir_forest);
|
||||
let hir_map = hir_map::map_crate(&mut hir_forest, defs);
|
||||
|
||||
abort_on_err(driver::phase_3_run_analysis_passes(&sess,
|
||||
&cstore,
|
||||
hir_map,
|
||||
&arenas,
|
||||
&name,
|
||||
|
@ -24,19 +24,17 @@ use fold::FoldItem::Strip;
|
||||
|
||||
/// Strip items marked `#[doc(hidden)]`
|
||||
pub fn strip_hidden(krate: clean::Crate) -> plugins::PluginResult {
|
||||
let mut stripped = DefIdSet();
|
||||
let mut retained = DefIdSet();
|
||||
|
||||
// strip all #[doc(hidden)] items
|
||||
let krate = {
|
||||
struct Stripper<'a> {
|
||||
stripped: &'a mut DefIdSet
|
||||
retained: &'a mut DefIdSet
|
||||
}
|
||||
impl<'a> fold::DocFolder for Stripper<'a> {
|
||||
fn fold_item(&mut self, i: Item) -> Option<Item> {
|
||||
if i.attrs.list("doc").has_word("hidden") {
|
||||
debug!("found one in strip_hidden; removing");
|
||||
self.stripped.insert(i.def_id);
|
||||
|
||||
// use a dedicated hidden item for given item type if any
|
||||
match i.inner {
|
||||
clean::StructFieldItem(..) | clean::ModuleItem(..) => {
|
||||
@ -44,42 +42,19 @@ pub fn strip_hidden(krate: clean::Crate) -> plugins::PluginResult {
|
||||
}
|
||||
_ => return None,
|
||||
}
|
||||
} else {
|
||||
self.retained.insert(i.def_id);
|
||||
}
|
||||
self.fold_item_recur(i)
|
||||
}
|
||||
}
|
||||
let mut stripper = Stripper{ stripped: &mut stripped };
|
||||
let mut stripper = Stripper{ retained: &mut retained };
|
||||
stripper.fold_crate(krate)
|
||||
};
|
||||
|
||||
// strip any traits implemented on stripped items
|
||||
{
|
||||
struct ImplStripper<'a> {
|
||||
stripped: &'a mut DefIdSet
|
||||
}
|
||||
impl<'a> fold::DocFolder for ImplStripper<'a> {
|
||||
fn fold_item(&mut self, i: Item) -> Option<Item> {
|
||||
if let clean::ImplItem(clean::Impl{
|
||||
for_: clean::ResolvedPath{ did, .. },
|
||||
ref trait_, ..
|
||||
}) = i.inner {
|
||||
// Impls for stripped types don't need to exist
|
||||
if self.stripped.contains(&did) {
|
||||
return None;
|
||||
}
|
||||
// Impls of stripped traits also don't need to exist
|
||||
if let Some(did) = trait_.def_id() {
|
||||
if self.stripped.contains(&did) {
|
||||
return None;
|
||||
}
|
||||
}
|
||||
}
|
||||
self.fold_item_recur(i)
|
||||
}
|
||||
}
|
||||
let mut stripper = ImplStripper{ stripped: &mut stripped };
|
||||
stripper.fold_crate(krate)
|
||||
}
|
||||
// strip all impls referencing stripped items
|
||||
let mut stripper = ImplStripper { retained: &retained };
|
||||
stripper.fold_crate(krate)
|
||||
}
|
||||
|
||||
/// Strip private items from the point of view of a crate or externally from a
|
||||
@ -98,11 +73,9 @@ pub fn strip_private(mut krate: clean::Crate) -> plugins::PluginResult {
|
||||
krate = ImportStripper.fold_crate(stripper.fold_crate(krate));
|
||||
}
|
||||
|
||||
// strip all private implementations of traits
|
||||
{
|
||||
let mut stripper = ImplStripper(&retained);
|
||||
stripper.fold_crate(krate)
|
||||
}
|
||||
// strip all impls referencing private items
|
||||
let mut stripper = ImplStripper { retained: &retained };
|
||||
stripper.fold_crate(krate)
|
||||
}
|
||||
|
||||
struct Stripper<'a> {
|
||||
@ -201,13 +174,21 @@ impl<'a> fold::DocFolder for Stripper<'a> {
|
||||
}
|
||||
}
|
||||
|
||||
// This stripper discards all private impls of traits
|
||||
struct ImplStripper<'a>(&'a DefIdSet);
|
||||
// This stripper discards all impls which reference stripped items
|
||||
struct ImplStripper<'a> {
|
||||
retained: &'a DefIdSet
|
||||
}
|
||||
|
||||
impl<'a> fold::DocFolder for ImplStripper<'a> {
|
||||
fn fold_item(&mut self, i: Item) -> Option<Item> {
|
||||
if let clean::ImplItem(ref imp) = i.inner {
|
||||
if let Some(did) = imp.for_.def_id() {
|
||||
if did.is_local() && !self.retained.contains(&did) {
|
||||
return None;
|
||||
}
|
||||
}
|
||||
if let Some(did) = imp.trait_.def_id() {
|
||||
if did.is_local() && !self.0.contains(&did) {
|
||||
if did.is_local() && !self.retained.contains(&did) {
|
||||
return None;
|
||||
}
|
||||
}
|
||||
|
@ -94,15 +94,17 @@ pub fn run(input: &str,
|
||||
"rustdoc-test", None)
|
||||
.expect("phase_2_configure_and_expand aborted in rustdoc!");
|
||||
let krate = driver::assign_node_ids(&sess, krate);
|
||||
let lcx = LoweringContext::new(&sess, Some(&krate));
|
||||
let dep_graph = DepGraph::new(false);
|
||||
let defs = &RefCell::new(hir_map::collect_definitions(&krate));
|
||||
|
||||
let lcx = LoweringContext::new(&sess, Some(&krate), defs);
|
||||
let krate = lower_crate(&lcx, &krate);
|
||||
|
||||
let opts = scrape_test_config(&krate);
|
||||
|
||||
let dep_graph = DepGraph::new(false);
|
||||
let _ignore = dep_graph.in_ignore();
|
||||
let mut forest = hir_map::Forest::new(krate, dep_graph.clone());
|
||||
let map = hir_map::map_crate(&mut forest);
|
||||
let map = hir_map::map_crate(&mut forest, defs);
|
||||
|
||||
let ctx = core::DocContext {
|
||||
map: &map,
|
||||
|
@ -20,6 +20,7 @@ extern crate rustc_metadata;
|
||||
extern crate rustc_resolve;
|
||||
#[macro_use] extern crate syntax;
|
||||
|
||||
use std::cell::RefCell;
|
||||
use std::ffi::{CStr, CString};
|
||||
use std::mem::transmute;
|
||||
use std::path::PathBuf;
|
||||
@ -35,6 +36,7 @@ use rustc::session::build_session;
|
||||
use rustc_driver::{driver, abort_on_err};
|
||||
use rustc::hir::lowering::{lower_crate, LoweringContext};
|
||||
use rustc_resolve::MakeGlobMap;
|
||||
use rustc_metadata::creader::LocalCrateReader;
|
||||
use rustc_metadata::cstore::CStore;
|
||||
use libc::c_void;
|
||||
|
||||
@ -237,15 +239,17 @@ fn compile_program(input: &str, sysroot: PathBuf)
|
||||
let krate = driver::phase_2_configure_and_expand(&sess, &cstore, krate, &id, None)
|
||||
.expect("phase_2 returned `None`");
|
||||
|
||||
let krate = driver::assign_node_ids(&sess, krate);
|
||||
let lcx = LoweringContext::new(&sess, Some(&krate));
|
||||
let dep_graph = DepGraph::new(sess.opts.build_dep_graph());
|
||||
let krate = driver::assign_node_ids(&sess, krate);
|
||||
let defs = RefCell::new(ast_map::collect_definitions(&krate));
|
||||
LocalCrateReader::new(&sess, &cstore, &defs, &krate, &id).read_crates(&dep_graph);
|
||||
let lcx = LoweringContext::new(&sess, Some(&krate), &defs);
|
||||
let mut hir_forest = ast_map::Forest::new(lower_crate(&lcx, &krate), dep_graph);
|
||||
let arenas = ty::CtxtArenas::new();
|
||||
let ast_map = driver::make_map(&sess, &mut hir_forest);
|
||||
let ast_map = ast_map::map_crate(&mut hir_forest, &defs);
|
||||
|
||||
abort_on_err(driver::phase_3_run_analysis_passes(
|
||||
&sess, &cstore, ast_map, &arenas, &id,
|
||||
&sess, ast_map, &arenas, &id,
|
||||
MakeGlobMap::No, |tcx, mir_map, analysis, _| {
|
||||
|
||||
let trans = driver::phase_4_translate_to_llvm(tcx, mir_map.unwrap(), analysis);
|
||||
|
20
src/test/rustdoc/issue-33069.rs
Normal file
20
src/test/rustdoc/issue-33069.rs
Normal file
@ -0,0 +1,20 @@
|
||||
// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
pub trait Bar {}
|
||||
|
||||
#[doc(hidden)]
|
||||
pub mod hidden {
|
||||
pub struct Foo;
|
||||
}
|
||||
|
||||
// @has issue_33069/trait.Bar.html
|
||||
// @!has - '//code' 'impl Bar for Foo'
|
||||
impl Bar for hidden::Foo {}
|
Loading…
Reference in New Issue
Block a user