This macro causes the current thread to panic. You can give it a message
to panic with:
-```rust,no_run
+```rust,should_panic
panic!("oh no!");
```
takes two values and checks them for equality. `true` passes, `false` `panic!`s.
Like this:
-```rust,no_run
+```rust,should_panic
// A-ok!
assert!(true);
# We want a version of `range` which doesn't allocate an intermediate list,
# specifically it should use a lazy iterator. In Python 2 this was `xrange`, but
# if we're running with Python 3 then we need to use `range` instead.
-if sys.version_info.major >= 3:
+if sys.version_info[0] >= 3:
xrange = range
#===============================================================================
use core::cmp::Ordering;
use core::fmt;
use core::hash::{self, Hash};
+use core::iter::FusedIterator;
use core::marker::{self, Unsize};
use core::mem;
use core::ops::{CoerceUnsized, Deref, DerefMut};
#[stable(feature = "rust1", since = "1.0.0")]
impl<I: ExactSizeIterator + ?Sized> ExactSizeIterator for Box<I> {}
+#[unstable(feature = "fused", issue = "35602")]
+impl<I: FusedIterator + ?Sized> FusedIterator for Box<I> {}
+
/// `FnBox` is a version of the `FnOnce` intended for use with boxed
/// closure objects. The idea is that where one would normally store a
#![feature(unsafe_no_drop_flag, filling_drop)]
#![feature(unsize)]
-#![cfg_attr(not(test), feature(raw, fn_traits, placement_new_protocol))]
+#![cfg_attr(not(test), feature(fused, raw, fn_traits, placement_new_protocol))]
#![cfg_attr(test, feature(test, box_heap))]
// Allow testing this library
#![stable(feature = "rust1", since = "1.0.0")]
use core::ops::{Drop, Deref, DerefMut};
-use core::iter::FromIterator;
+use core::iter::{FromIterator, FusedIterator};
use core::mem::swap;
use core::mem::size_of;
use core::ptr;
#[stable(feature = "rust1", since = "1.0.0")]
impl<'a, T> ExactSizeIterator for Iter<'a, T> {}
+#[unstable(feature = "fused", issue = "35602")]
+impl<'a, T> FusedIterator for Iter<'a, T> {}
+
/// An iterator that moves out of a `BinaryHeap`.
#[stable(feature = "rust1", since = "1.0.0")]
#[derive(Clone)]
#[stable(feature = "rust1", since = "1.0.0")]
impl<T> ExactSizeIterator for IntoIter<T> {}
+#[unstable(feature = "fused", issue = "35602")]
+impl<T> FusedIterator for IntoIter<T> {}
+
/// An iterator that drains a `BinaryHeap`.
#[stable(feature = "drain", since = "1.6.0")]
pub struct Drain<'a, T: 'a> {
#[stable(feature = "rust1", since = "1.0.0")]
impl<'a, T: 'a> ExactSizeIterator for Drain<'a, T> {}
+#[unstable(feature = "fused", issue = "35602")]
+impl<'a, T: 'a> FusedIterator for Drain<'a, T> {}
+
#[stable(feature = "rust1", since = "1.0.0")]
impl<T: Ord> From<Vec<T>> for BinaryHeap<T> {
fn from(vec: Vec<T>) -> BinaryHeap<T> {
use core::cmp::Ordering;
use core::fmt::Debug;
use core::hash::{Hash, Hasher};
-use core::iter::{FromIterator, Peekable};
+use core::iter::{FromIterator, Peekable, FusedIterator};
use core::marker::PhantomData;
use core::ops::Index;
use core::{fmt, intrinsics, mem, ptr};
}
}
+#[unstable(feature = "fused", issue = "35602")]
+impl<'a, K, V> FusedIterator for Iter<'a, K, V> {}
+
impl<'a, K: 'a, V: 'a> DoubleEndedIterator for Iter<'a, K, V> {
fn next_back(&mut self) -> Option<(&'a K, &'a V)> {
if self.length == 0 {
}
}
+#[unstable(feature = "fused", issue = "35602")]
+impl<'a, K, V> FusedIterator for IterMut<'a, K, V> {}
+
impl<K, V> IntoIterator for BTreeMap<K, V> {
type Item = (K, V);
type IntoIter = IntoIter<K, V>;
}
}
+#[unstable(feature = "fused", issue = "35602")]
+impl<K, V> FusedIterator for IntoIter<K, V> {}
+
impl<'a, K, V> Iterator for Keys<'a, K, V> {
type Item = &'a K;
}
}
+#[unstable(feature = "fused", issue = "35602")]
+impl<'a, K, V> FusedIterator for Keys<'a, K, V> {}
+
impl<'a, K, V> Clone for Keys<'a, K, V> {
fn clone(&self) -> Keys<'a, K, V> {
Keys { inner: self.inner.clone() }
}
}
+#[unstable(feature = "fused", issue = "35602")]
+impl<'a, K, V> FusedIterator for Values<'a, K, V> {}
+
impl<'a, K, V> Clone for Values<'a, K, V> {
fn clone(&self) -> Values<'a, K, V> {
Values { inner: self.inner.clone() }
}
}
+#[unstable(feature = "fused", issue = "35602")]
+impl<'a, K, V> FusedIterator for ValuesMut<'a, K, V> {}
+
+
impl<'a, K, V> Range<'a, K, V> {
unsafe fn next_unchecked(&mut self) -> (&'a K, &'a V) {
let handle = self.front;
}
}
+#[unstable(feature = "fused", issue = "35602")]
+impl<'a, K, V> FusedIterator for Range<'a, K, V> {}
+
impl<'a, K, V> Clone for Range<'a, K, V> {
fn clone(&self) -> Range<'a, K, V> {
Range {
}
}
+#[unstable(feature = "fused", issue = "35602")]
+impl<'a, K, V> FusedIterator for RangeMut<'a, K, V> {}
+
impl<'a, K, V> RangeMut<'a, K, V> {
unsafe fn next_back_unchecked(&mut self) -> (&'a K, &'a mut V) {
let handle = ptr::read(&self.back);
use core::cmp::{min, max};
use core::fmt::Debug;
use core::fmt;
-use core::iter::{Peekable, FromIterator};
+use core::iter::{Peekable, FromIterator, FusedIterator};
use core::ops::{BitOr, BitAnd, BitXor, Sub};
use borrow::Borrow;
fn len(&self) -> usize { self.iter.len() }
}
+#[unstable(feature = "fused", issue = "35602")]
+impl<'a, T> FusedIterator for Iter<'a, T> {}
#[stable(feature = "rust1", since = "1.0.0")]
impl<T> Iterator for IntoIter<T> {
fn len(&self) -> usize { self.iter.len() }
}
+#[unstable(feature = "fused", issue = "35602")]
+impl<T> FusedIterator for IntoIter<T> {}
impl<'a, T> Clone for Range<'a, T> {
fn clone(&self) -> Range<'a, T> {
}
}
+#[unstable(feature = "fused", issue = "35602")]
+impl<'a, T> FusedIterator for Range<'a, T> {}
+
/// Compare `x` and `y`, but return `short` if x is None and `long` if y is None
fn cmp_opt<T: Ord>(x: Option<&T>, y: Option<&T>, short: Ordering, long: Ordering) -> Ordering {
match (x, y) {
}
}
+#[unstable(feature = "fused", issue = "35602")]
+impl<'a, T: Ord> FusedIterator for Difference<'a, T> {}
+
impl<'a, T> Clone for SymmetricDifference<'a, T> {
fn clone(&self) -> SymmetricDifference<'a, T> {
SymmetricDifference {
}
}
+#[unstable(feature = "fused", issue = "35602")]
+impl<'a, T: Ord> FusedIterator for SymmetricDifference<'a, T> {}
+
impl<'a, T> Clone for Intersection<'a, T> {
fn clone(&self) -> Intersection<'a, T> {
Intersection {
}
}
+#[unstable(feature = "fused", issue = "35602")]
+impl<'a, T: Ord> FusedIterator for Intersection<'a, T> {}
+
impl<'a, T> Clone for Union<'a, T> {
fn clone(&self) -> Union<'a, T> {
Union {
(max(a_len, b_len), Some(a_len + b_len))
}
}
+
+#[unstable(feature = "fused", issue = "35602")]
+impl<'a, T: Ord> FusedIterator for Union<'a, T> {}
use core::marker;
use core::fmt;
-use core::iter::FromIterator;
+use core::iter::{FromIterator, FusedIterator};
use core::ops::{Sub, BitOr, BitAnd, BitXor};
// FIXME(contentions): implement union family of methods? (general design may be
}
}
+#[unstable(feature = "fused", issue = "35602")]
+impl<E: CLike> FusedIterator for Iter<E> {}
+
impl<E: CLike> FromIterator<E> for EnumSet<E> {
fn from_iter<I: IntoIterator<Item = E>>(iter: I) -> EnumSet<E> {
let mut ret = EnumSet::new();
#![feature(core_intrinsics)]
#![feature(dropck_parametricity)]
#![feature(fmt_internals)]
+#![feature(fused)]
#![feature(heap_api)]
#![feature(inclusive_range)]
#![feature(lang_items)]
use core::cmp::Ordering;
use core::fmt;
use core::hash::{Hasher, Hash};
-use core::iter::FromIterator;
+use core::iter::{FromIterator, FusedIterator};
use core::marker::PhantomData;
use core::mem;
use core::ops::{BoxPlace, InPlace, Place, Placer};
#[stable(feature = "rust1", since = "1.0.0")]
impl<'a, T> ExactSizeIterator for Iter<'a, T> {}
+#[unstable(feature = "fused", issue = "35602")]
+impl<'a, T> FusedIterator for Iter<'a, T> {}
+
#[stable(feature = "rust1", since = "1.0.0")]
impl<'a, T> Iterator for IterMut<'a, T> {
type Item = &'a mut T;
#[stable(feature = "rust1", since = "1.0.0")]
impl<'a, T> ExactSizeIterator for IterMut<'a, T> {}
+#[unstable(feature = "fused", issue = "35602")]
+impl<'a, T> FusedIterator for IterMut<'a, T> {}
+
impl<'a, T> IterMut<'a, T> {
/// Inserts the given element just after the element most recently returned by `.next()`.
/// The inserted element does not appear in the iteration.
#[stable(feature = "rust1", since = "1.0.0")]
impl<T> ExactSizeIterator for IntoIter<T> {}
+#[unstable(feature = "fused", issue = "35602")]
+impl<T> FusedIterator for IntoIter<T> {}
+
#[stable(feature = "rust1", since = "1.0.0")]
impl<T> FromIterator<T> for LinkedList<T> {
fn from_iter<I: IntoIterator<Item = T>>(iter: I) -> Self {
use core::str::pattern::Pattern;
use core::str::pattern::{Searcher, ReverseSearcher, DoubleEndedSearcher};
use core::mem;
+use core::iter::FusedIterator;
use rustc_unicode::str::{UnicodeStr, Utf16Encoder};
use vec_deque::VecDeque;
}
}
+#[unstable(feature = "fused", issue = "35602")]
+impl<'a> FusedIterator for EncodeUtf16<'a> {}
+
// Return the initial codepoint accumulator for the first byte.
// The first byte is special, only want bottom 5 bits for width 2, 4 bits
// for width 3, and 3 bits for width 4
use core::fmt;
use core::hash;
-use core::iter::FromIterator;
+use core::iter::{FromIterator, FusedIterator};
use core::mem;
use core::ops::{self, Add, AddAssign, Index, IndexMut};
use core::ptr;
self.iter.next_back()
}
}
+
+#[unstable(feature = "fused", issue = "35602")]
+impl<'a> FusedIterator for Drain<'a> {}
use core::fmt;
use core::hash::{self, Hash};
use core::intrinsics::{arith_offset, assume};
-use core::iter::FromIterator;
+use core::iter::{FromIterator, FusedIterator};
use core::mem;
use core::ops::{Index, IndexMut};
use core::ops;
#[stable(feature = "rust1", since = "1.0.0")]
impl<T> ExactSizeIterator for IntoIter<T> {}
+#[unstable(feature = "fused", issue = "35602")]
+impl<T> FusedIterator for IntoIter<T> {}
+
#[stable(feature = "vec_into_iter_clone", since = "1.8.0")]
impl<T: Clone> Clone for IntoIter<T> {
fn clone(&self) -> IntoIter<T> {
#[stable(feature = "rust1", since = "1.0.0")]
impl<'a, T> ExactSizeIterator for Drain<'a, T> {}
+
+#[unstable(feature = "fused", issue = "35602")]
+impl<'a, T> FusedIterator for Drain<'a, T> {}
use core::cmp::Ordering;
use core::fmt;
-use core::iter::{repeat, FromIterator};
+use core::iter::{repeat, FromIterator, FusedIterator};
use core::mem;
use core::ops::{Index, IndexMut};
use core::ptr;
#[stable(feature = "rust1", since = "1.0.0")]
impl<'a, T> ExactSizeIterator for Iter<'a, T> {}
+#[unstable(feature = "fused", issue = "35602")]
+impl<'a, T> FusedIterator for Iter<'a, T> {}
+
+
/// `VecDeque` mutable iterator.
#[stable(feature = "rust1", since = "1.0.0")]
pub struct IterMut<'a, T: 'a> {
#[stable(feature = "rust1", since = "1.0.0")]
impl<'a, T> ExactSizeIterator for IterMut<'a, T> {}
+#[unstable(feature = "fused", issue = "35602")]
+impl<'a, T> FusedIterator for IterMut<'a, T> {}
+
/// A by-value VecDeque iterator
#[derive(Clone)]
#[stable(feature = "rust1", since = "1.0.0")]
#[stable(feature = "rust1", since = "1.0.0")]
impl<T> ExactSizeIterator for IntoIter<T> {}
+#[unstable(feature = "fused", issue = "35602")]
+impl<T> FusedIterator for IntoIter<T> {}
+
/// A draining VecDeque iterator
#[stable(feature = "drain", since = "1.6.0")]
pub struct Drain<'a, T: 'a> {
#[stable(feature = "rust1", since = "1.0.0")]
impl<'a, T: 'a> ExactSizeIterator for Drain<'a, T> {}
+#[unstable(feature = "fused", issue = "35602")]
+impl<'a, T: 'a> FusedIterator for Drain<'a, T> {}
+
#[stable(feature = "rust1", since = "1.0.0")]
impl<A: PartialEq> PartialEq for VecDeque<A> {
fn eq(&self, other: &VecDeque<A>) -> bool {
}
}
+#[unstable(feature = "coerce_unsized", issue = "27732")]
+impl<T: CoerceUnsized<U>, U> CoerceUnsized<Cell<U>> for Cell<T> {}
+
/// A mutable memory location with dynamically checked borrow rules
///
/// See the [module-level documentation](index.html) for more.
}
}
+#[unstable(feature = "coerce_unsized", issue = "27732")]
+impl<T: CoerceUnsized<U>, U> CoerceUnsized<RefCell<U>> for RefCell<T> {}
+
struct BorrowRef<'b> {
borrow: &'b Cell<BorrowFlag>,
}
UnsafeCell::new(t)
}
}
+
+#[unstable(feature = "coerce_unsized", issue = "27732")]
+impl<T: CoerceUnsized<U>, U> CoerceUnsized<UnsafeCell<U>> for UnsafeCell<T> {}
+
+#[allow(unused)]
+fn assert_coerce_unsized(a: UnsafeCell<&i32>, b: Cell<&i32>, c: RefCell<&i32>) {
+ let _: UnsafeCell<&Send> = a;
+ let _: Cell<&Send> = b;
+ let _: RefCell<&Send> = c;
+}
use prelude::v1::*;
use char_private::is_printable;
+use iter::FusedIterator;
use mem::transmute;
// UTF-8 ranges and tags for encoding characters
}
}
+#[unstable(feature = "fused", issue = "35602")]
+impl FusedIterator for EscapeUnicode {}
+
/// An iterator that yields the literal escape code of a `char`.
///
/// This `struct` is created by the [`escape_default()`] method on [`char`]. See
}
}
+#[unstable(feature = "fused", issue = "35602")]
+impl FusedIterator for EscapeDefault {}
+
/// An iterator that yields the literal escape code of a `char`.
///
/// This `struct` is created by the [`escape_debug()`] method on [`char`]. See its
#[unstable(feature = "char_escape_debug", issue = "35068")]
impl ExactSizeIterator for EscapeDebug { }
+#[unstable(feature = "fused", issue = "35602")]
+impl FusedIterator for EscapeDebug {}
+
/// An iterator over `u8` entries represending the UTF-8 encoding of a `char`
/// value.
///
}
}
+#[unstable(feature = "fused", issue = "35602")]
+impl FusedIterator for EncodeUtf8 {}
+
/// An iterator over `u16` entries represending the UTF-16 encoding of a `char`
/// value.
///
}
}
+#[unstable(feature = "fused", issue = "35602")]
+impl FusedIterator for EncodeUtf16 {}
/// An iterator over an iterator of bytes of the characters the bytes represent
/// as UTF-8
})
}
}
+
+#[unstable(feature = "fused", issue = "35602")]
+impl<I: FusedIterator<Item = u8>> FusedIterator for DecodeUtf8<I> {}
/// bar: f32,
/// }
///
-///
/// fn main() {
/// let options: SomeOptions = Default::default();
/// }
pub use self::traits::{FromIterator, IntoIterator, DoubleEndedIterator, Extend};
#[stable(feature = "rust1", since = "1.0.0")]
pub use self::traits::{ExactSizeIterator, Sum, Product};
+#[unstable(feature = "fused", issue = "35602")]
+pub use self::traits::FusedIterator;
mod iterator;
mod range;
impl<I> ExactSizeIterator for Rev<I>
where I: ExactSizeIterator + DoubleEndedIterator {}
+#[unstable(feature = "fused", issue = "35602")]
+impl<I> FusedIterator for Rev<I>
+ where I: FusedIterator + DoubleEndedIterator {}
+
/// An iterator that clones the elements of an underlying iterator.
///
/// This `struct` is created by the [`cloned()`] method on [`Iterator`]. See its
where I: ExactSizeIterator<Item=&'a T>, T: Clone
{}
+#[unstable(feature = "fused", issue = "35602")]
+impl<'a, I, T: 'a> FusedIterator for Cloned<I>
+ where I: FusedIterator<Item=&'a T>, T: Clone
+{}
+
/// An iterator that repeats endlessly.
///
/// This `struct` is created by the [`cycle()`] method on [`Iterator`]. See its
}
}
+#[unstable(feature = "fused", issue = "35602")]
+impl<I> FusedIterator for Cycle<I> where I: Clone + Iterator {}
+
/// An iterator that strings two iterators together.
///
/// This `struct` is created by the [`chain()`] method on [`Iterator`]. See its
}
}
+// Note: *both* must be fused to handle double-ended iterators.
+#[unstable(feature = "fused", issue = "35602")]
+impl<A, B> FusedIterator for Chain<A, B>
+ where A: FusedIterator,
+ B: FusedIterator<Item=A::Item>,
+{}
+
/// An iterator that iterates two other iterators simultaneously.
///
/// This `struct` is created by the [`zip()`] method on [`Iterator`]. See its
}
+#[unstable(feature = "fused", issue = "35602")]
+impl<A, B> FusedIterator for Zip<A, B>
+ where A: FusedIterator, B: FusedIterator, {}
+
/// An iterator that maps the values of `iter` with `f`.
///
/// This `struct` is created by the [`map()`] method on [`Iterator`]. See its
impl<B, I: ExactSizeIterator, F> ExactSizeIterator for Map<I, F>
where F: FnMut(I::Item) -> B {}
+#[unstable(feature = "fused", issue = "35602")]
+impl<B, I: FusedIterator, F> FusedIterator for Map<I, F>
+ where F: FnMut(I::Item) -> B {}
+
/// An iterator that filters the elements of `iter` with `predicate`.
///
/// This `struct` is created by the [`filter()`] method on [`Iterator`]. See its
}
}
+#[unstable(feature = "fused", issue = "35602")]
+impl<I: FusedIterator, P> FusedIterator for Filter<I, P>
+ where P: FnMut(&I::Item) -> bool {}
+
/// An iterator that uses `f` to both filter and map elements from `iter`.
///
/// This `struct` is created by the [`filter_map()`] method on [`Iterator`]. See its
}
}
+#[unstable(feature = "fused", issue = "35602")]
+impl<B, I: FusedIterator, F> FusedIterator for FilterMap<I, F>
+ where F: FnMut(I::Item) -> Option<B> {}
+
/// An iterator that yields the current count and the element during iteration.
///
/// This `struct` is created by the [`enumerate()`] method on [`Iterator`]. See its
}
}
+#[unstable(feature = "fused", issue = "35602")]
+impl<I> FusedIterator for Enumerate<I> where I: FusedIterator {}
+
/// An iterator with a `peek()` that returns an optional reference to the next
/// element.
///
#[stable(feature = "rust1", since = "1.0.0")]
impl<I: ExactSizeIterator> ExactSizeIterator for Peekable<I> {}
+#[unstable(feature = "fused", issue = "35602")]
+impl<I: FusedIterator> FusedIterator for Peekable<I> {}
+
impl<I: Iterator> Peekable<I> {
/// Returns a reference to the next() value without advancing the iterator.
///
}
}
+#[unstable(feature = "fused", issue = "35602")]
+impl<I, P> FusedIterator for SkipWhile<I, P>
+ where I: FusedIterator, P: FnMut(&I::Item) -> bool {}
+
/// An iterator that only accepts elements while `predicate` is true.
///
/// This `struct` is created by the [`take_while()`] method on [`Iterator`]. See its
}
}
+#[unstable(feature = "fused", issue = "35602")]
+impl<I, P> FusedIterator for TakeWhile<I, P>
+ where I: FusedIterator, P: FnMut(&I::Item) -> bool {}
+
/// An iterator that skips over `n` elements of `iter`.
///
/// This `struct` is created by the [`skip()`] method on [`Iterator`]. See its
}
}
+#[unstable(feature = "fused", issue = "35602")]
+impl<I> FusedIterator for Skip<I> where I: FusedIterator {}
+
/// An iterator that only iterates over the first `n` iterations of `iter`.
///
/// This `struct` is created by the [`take()`] method on [`Iterator`]. See its
#[stable(feature = "rust1", since = "1.0.0")]
impl<I> ExactSizeIterator for Take<I> where I: ExactSizeIterator {}
+#[unstable(feature = "fused", issue = "35602")]
+impl<I> FusedIterator for Take<I> where I: FusedIterator {}
/// An iterator to maintain state while iterating another iterator.
///
}
}
+#[unstable(feature = "fused", issue = "35602")]
+impl<B, I, St, F> FusedIterator for Scan<I, St, F>
+ where I: FusedIterator, F: FnMut(&mut St, I::Item) -> Option<B> {}
+
/// An iterator that maps each element to an iterator, and yields the elements
/// of the produced iterators.
///
}
}
+#[unstable(feature = "fused", issue = "35602")]
+impl<I, U, F> FusedIterator for FlatMap<I, U, F>
+ where I: FusedIterator, U: IntoIterator, F: FnMut(I::Item) -> U {}
+
/// An iterator that yields `None` forever after the underlying iterator
/// yields `None` once.
///
done: bool
}
+#[unstable(feature = "fused", issue = "35602")]
+impl<I> FusedIterator for Fuse<I> where I: Iterator {}
+
#[stable(feature = "rust1", since = "1.0.0")]
impl<I> Iterator for Fuse<I> where I: Iterator {
type Item = <I as Iterator>::Item;
#[inline]
- fn next(&mut self) -> Option<<I as Iterator>::Item> {
+ default fn next(&mut self) -> Option<<I as Iterator>::Item> {
if self.done {
None
} else {
}
#[inline]
- fn nth(&mut self, n: usize) -> Option<I::Item> {
+ default fn nth(&mut self, n: usize) -> Option<I::Item> {
if self.done {
None
} else {
}
#[inline]
- fn last(self) -> Option<I::Item> {
+ default fn last(self) -> Option<I::Item> {
if self.done {
None
} else {
}
#[inline]
- fn count(self) -> usize {
+ default fn count(self) -> usize {
if self.done {
0
} else {
}
#[inline]
- fn size_hint(&self) -> (usize, Option<usize>) {
+ default fn size_hint(&self) -> (usize, Option<usize>) {
if self.done {
(0, Some(0))
} else {
#[stable(feature = "rust1", since = "1.0.0")]
impl<I> DoubleEndedIterator for Fuse<I> where I: DoubleEndedIterator {
#[inline]
- fn next_back(&mut self) -> Option<<I as Iterator>::Item> {
+ default fn next_back(&mut self) -> Option<<I as Iterator>::Item> {
if self.done {
None
} else {
}
}
+unsafe impl<I> TrustedRandomAccess for Fuse<I>
+ where I: TrustedRandomAccess,
+{
+ unsafe fn get_unchecked(&mut self, i: usize) -> I::Item {
+ self.iter.get_unchecked(i)
+ }
+}
+
+#[unstable(feature = "fused", issue = "35602")]
+impl<I> Iterator for Fuse<I> where I: FusedIterator {
+ #[inline]
+ fn next(&mut self) -> Option<<I as Iterator>::Item> {
+ self.iter.next()
+ }
+
+ #[inline]
+ fn nth(&mut self, n: usize) -> Option<I::Item> {
+ self.iter.nth(n)
+ }
+
+ #[inline]
+ fn last(self) -> Option<I::Item> {
+ self.iter.last()
+ }
+
+ #[inline]
+ fn count(self) -> usize {
+ self.iter.count()
+ }
+
+ #[inline]
+ fn size_hint(&self) -> (usize, Option<usize>) {
+ self.iter.size_hint()
+ }
+}
+
+#[unstable(feature = "fused", reason = "recently added", issue = "35602")]
+impl<I> DoubleEndedIterator for Fuse<I>
+ where I: DoubleEndedIterator + FusedIterator
+{
+ #[inline]
+ fn next_back(&mut self) -> Option<<I as Iterator>::Item> {
+ self.iter.next_back()
+ }
+}
+
+
#[stable(feature = "rust1", since = "1.0.0")]
impl<I> ExactSizeIterator for Fuse<I> where I: ExactSizeIterator {}
#[stable(feature = "rust1", since = "1.0.0")]
impl<I: ExactSizeIterator, F> ExactSizeIterator for Inspect<I, F>
where F: FnMut(&I::Item) {}
+
+#[unstable(feature = "fused", issue = "35602")]
+impl<I: FusedIterator, F> FusedIterator for Inspect<I, F>
+ where F: FnMut(&I::Item) {}
use marker::Sized;
use usize;
-use super::{DoubleEndedIterator, ExactSizeIterator, Iterator};
+use super::{DoubleEndedIterator, ExactSizeIterator, Iterator, FusedIterator};
/// Objects that can be stepped over in both directions.
///
}
}
+#[unstable(feature = "fused", issue = "35602")]
+impl<A> FusedIterator for StepBy<A, ops::RangeFrom<A>>
+ where A: Clone, for<'a> &'a A: Add<&'a A, Output = A> {}
+
#[stable(feature = "rust1", since = "1.0.0")]
impl<A: Step + Clone> Iterator for StepBy<A, ops::Range<A>> {
type Item = A;
}
}
+#[unstable(feature = "fused", issue = "35602")]
+impl<A: Step + Clone> FusedIterator for StepBy<A, ops::Range<A>> {}
+
#[unstable(feature = "inclusive_range",
reason = "recently added, follows RFC",
issue = "28237")]
}
}
+#[unstable(feature = "fused", issue = "35602")]
+impl<A: Step + Clone> FusedIterator for StepBy<A, ops::RangeInclusive<A>> {}
+
macro_rules! range_exact_iter_impl {
($($t:ty)*) => ($(
#[stable(feature = "rust1", since = "1.0.0")]
}
}
+#[unstable(feature = "fused", issue = "35602")]
+impl<A> FusedIterator for ops::Range<A>
+ where A: Step, for<'a> &'a A: Add<&'a A, Output = A> {}
+
#[stable(feature = "rust1", since = "1.0.0")]
impl<A: Step> Iterator for ops::RangeFrom<A> where
for<'a> &'a A: Add<&'a A, Output = A>
}
}
+#[unstable(feature = "fused", issue = "35602")]
+impl<A> FusedIterator for ops::RangeFrom<A>
+ where A: Step, for<'a> &'a A: Add<&'a A, Output = A> {}
+
#[unstable(feature = "inclusive_range", reason = "recently added, follows RFC", issue = "28237")]
impl<A: Step> Iterator for ops::RangeInclusive<A> where
for<'a> &'a A: Add<&'a A, Output = A>
n
}
}
+
+#[unstable(feature = "fused", issue = "35602")]
+impl<A> FusedIterator for ops::RangeInclusive<A>
+ where A: Step, for<'a> &'a A: Add<&'a A, Output = A> {}
use option::Option::{self, Some, None};
use usize;
-use super::{DoubleEndedIterator, IntoIterator, Iterator, ExactSizeIterator};
+use super::{DoubleEndedIterator, IntoIterator, Iterator, ExactSizeIterator, FusedIterator};
/// An iterator that repeats an element endlessly.
///
fn next_back(&mut self) -> Option<A> { Some(self.element.clone()) }
}
+#[unstable(feature = "fused", issue = "35602")]
+impl<A: Clone> FusedIterator for Repeat<A> {}
+
/// Creates a new iterator that endlessly repeats a single element.
///
/// The `repeat()` function repeats a single value over and over and over and
}
}
+#[unstable(feature = "fused", issue = "35602")]
+impl<T> FusedIterator for Empty<T> {}
+
// not #[derive] because that adds a Clone bound on T,
// which isn't necessary.
#[stable(feature = "iter_empty", since = "1.2.0")]
}
}
+#[unstable(feature = "fused", issue = "35602")]
+impl<T> FusedIterator for Once<T> {}
+
/// Creates an iterator that yields an element exactly once.
///
/// This is commonly used to adapt a single value into a [`chain()`] of other
integer_sum_product! { i8 i16 i32 i64 isize u8 u16 u32 u64 usize }
float_sum_product! { f32 f64 }
+
+/// An iterator that always continues to yield `None` when exhausted.
+///
+/// Calling next on a fused iterator that has returned `None` once is guaranteed
+/// to return `None` again. This trait is should be implemented by all iterators
+/// that behave this way because it allows for some significant optimizations.
+///
+/// Note: In general, you should not use `FusedIterator` in generic bounds if
+/// you need a fused iterator. Instead, you should just call `Iterator::fused()`
+/// on the iterator. If the iterator is already fused, the additional `Fuse`
+/// wrapper will be a no-op with no performance penalty.
+#[unstable(feature = "fused", issue = "35602")]
+pub trait FusedIterator: Iterator {}
+
+#[unstable(feature = "fused", issue = "35602")]
+impl<'a, I: FusedIterator + ?Sized> FusedIterator for &'a mut I {}
///
/// # Examples
///
-/// A trivial implementation of `Sub`. When `Foo - Foo` happens, it ends up
-/// calling `sub`, and therefore, `main` prints `Subtracting!`.
+/// This example creates a `Point` struct that implements the `Sub` trait, and
+/// then demonstrates subtracting two `Point`s.
///
/// ```
/// use std::ops::Sub;
///
-/// struct Foo;
+/// #[derive(Debug)]
+/// struct Point {
+/// x: i32,
+/// y: i32,
+/// }
///
-/// impl Sub for Foo {
-/// type Output = Foo;
+/// impl Sub for Point {
+/// type Output = Point;
///
-/// fn sub(self, _rhs: Foo) -> Foo {
-/// println!("Subtracting!");
-/// self
+/// fn sub(self, other: Point) -> Point {
+/// Point {
+/// x: self.x - other.x,
+/// y: self.y - other.y,
+/// }
+/// }
+/// }
+///
+/// impl PartialEq for Point {
+/// fn eq(&self, other: &Self) -> bool {
+/// self.x == other.x && self.y == other.y
/// }
/// }
///
/// fn main() {
-/// Foo - Foo;
+/// assert_eq!(Point { x: 3, y: 3 } - Point { x: 2, y: 3 },
+/// Point { x: 1, y: 0 });
/// }
/// ```
#[lang = "sub"]
///
/// # Examples
///
-/// A trivial implementation of `Div`. When `Foo / Foo` happens, it ends up
-/// calling `div`, and therefore, `main` prints `Dividing!`.
+/// Implementing a `Div`idable rational number struct:
///
/// ```
/// use std::ops::Div;
///
-/// struct Foo;
+/// // The uniqueness of rational numbers in lowest terms is a consequence of
+/// // the fundamental theorem of arithmetic.
+/// #[derive(Eq)]
+/// #[derive(PartialEq, Debug)]
+/// struct Rational {
+/// nominator: usize,
+/// denominator: usize,
+/// }
///
-/// impl Div for Foo {
-/// type Output = Foo;
+/// impl Rational {
+/// fn new(nominator: usize, denominator: usize) -> Self {
+/// if denominator == 0 {
+/// panic!("Zero is an invalid denominator!");
+/// }
///
-/// fn div(self, _rhs: Foo) -> Foo {
-/// println!("Dividing!");
-/// self
+/// // Reduce to lowest terms by dividing by the greatest common
+/// // divisor.
+/// let gcd = gcd(nominator, denominator);
+/// Rational {
+/// nominator: nominator / gcd,
+/// denominator: denominator / gcd,
+/// }
+/// }
+/// }
+///
+/// impl Div for Rational {
+/// // The division of rational numbers is a closed operation.
+/// type Output = Self;
+///
+/// fn div(self, rhs: Self) -> Self {
+/// if rhs.nominator == 0 {
+/// panic!("Cannot divide by zero-valued `Rational`!");
+/// }
+///
+/// let nominator = self.nominator * rhs.denominator;
+/// let denominator = self.denominator * rhs.nominator;
+/// Rational::new(nominator, denominator)
/// }
/// }
///
+/// // Euclid's two-thousand-year-old algorithm for finding the greatest common
+/// // divisor.
+/// fn gcd(x: usize, y: usize) -> usize {
+/// let mut x = x;
+/// let mut y = y;
+/// while y != 0 {
+/// let t = y;
+/// y = x % y;
+/// x = t;
+/// }
+/// x
+/// }
+///
/// fn main() {
-/// Foo / Foo;
+/// assert_eq!(Rational::new(1, 2), Rational::new(2, 4));
+/// assert_eq!(Rational::new(1, 2) / Rational::new(3, 4),
+/// Rational::new(2, 3));
/// }
/// ```
///
///
/// # Examples
///
-/// A trivial implementation of `SubAssign`. When `Foo -= Foo` happens, it ends up
-/// calling `sub_assign`, and therefore, `main` prints `Subtracting!`.
+/// This example creates a `Point` struct that implements the `SubAssign`
+/// trait, and then demonstrates sub-assigning to a mutable `Point`.
///
/// ```
/// use std::ops::SubAssign;
///
-/// struct Foo;
+/// #[derive(Debug)]
+/// struct Point {
+/// x: i32,
+/// y: i32,
+/// }
///
-/// impl SubAssign for Foo {
-/// fn sub_assign(&mut self, _rhs: Foo) {
-/// println!("Subtracting!");
+/// impl SubAssign for Point {
+/// fn sub_assign(&mut self, other: Point) {
+/// *self = Point {
+/// x: self.x - other.x,
+/// y: self.y - other.y,
+/// };
/// }
/// }
///
-/// # #[allow(unused_assignments)]
-/// fn main() {
-/// let mut foo = Foo;
-/// foo -= Foo;
+/// impl PartialEq for Point {
+/// fn eq(&self, other: &Self) -> bool {
+/// self.x == other.x && self.y == other.y
+/// }
/// }
+///
+/// let mut point = Point { x: 3, y: 3 };
+/// point -= Point { x: 2, y: 3 };
+/// assert_eq!(point, Point {x: 1, y: 0});
/// ```
#[lang = "sub_assign"]
#[stable(feature = "op_assign_traits", since = "1.8.0")]
use clone::Clone;
use convert::From;
use default::Default;
-use iter::ExactSizeIterator;
-use iter::{Iterator, DoubleEndedIterator, FromIterator, IntoIterator};
+use iter::{Iterator, FromIterator, IntoIterator, ExactSizeIterator, DoubleEndedIterator};
+use iter::FusedIterator;
use mem;
use ops::FnOnce;
use result::Result::{Ok, Err};
}
impl<A> ExactSizeIterator for Item<A> {}
+impl<A> FusedIterator for Item<A> {}
/// An iterator over a reference of the contained item in an Option.
#[stable(feature = "rust1", since = "1.0.0")]
#[stable(feature = "rust1", since = "1.0.0")]
impl<'a, A> ExactSizeIterator for Iter<'a, A> {}
+#[unstable(feature = "fused", issue = "35602")]
+impl<'a, A> FusedIterator for Iter<'a, A> {}
+
#[stable(feature = "rust1", since = "1.0.0")]
impl<'a, A> Clone for Iter<'a, A> {
fn clone(&self) -> Iter<'a, A> {
#[stable(feature = "rust1", since = "1.0.0")]
impl<'a, A> ExactSizeIterator for IterMut<'a, A> {}
+#[unstable(feature = "fused", issue = "35602")]
+impl<'a, A> FusedIterator for IterMut<'a, A> {}
+
/// An iterator over the item contained inside an Option.
#[derive(Clone, Debug)]
#[stable(feature = "rust1", since = "1.0.0")]
#[stable(feature = "rust1", since = "1.0.0")]
impl<A> ExactSizeIterator for IntoIter<A> {}
+#[unstable(feature = "fused", issue = "35602")]
+impl<A> FusedIterator for IntoIter<A> {}
+
/////////////////////////////////////////////////////////////////////////////
// FromIterator
/////////////////////////////////////////////////////////////////////////////
use clone::Clone;
use fmt;
use iter::{Iterator, DoubleEndedIterator, FromIterator, ExactSizeIterator, IntoIterator};
+use iter::FusedIterator;
use ops::FnOnce;
use option::Option::{self, None, Some};
#[stable(feature = "rust1", since = "1.0.0")]
impl<'a, T> ExactSizeIterator for Iter<'a, T> {}
+#[unstable(feature = "fused", issue = "35602")]
+impl<'a, T> FusedIterator for Iter<'a, T> {}
+
#[stable(feature = "rust1", since = "1.0.0")]
impl<'a, T> Clone for Iter<'a, T> {
fn clone(&self) -> Iter<'a, T> { Iter { inner: self.inner } }
#[stable(feature = "rust1", since = "1.0.0")]
impl<'a, T> ExactSizeIterator for IterMut<'a, T> {}
+#[unstable(feature = "fused", issue = "35602")]
+impl<'a, T> FusedIterator for IterMut<'a, T> {}
+
/// An iterator over the value in a `Ok` variant of a `Result`.
#[derive(Debug)]
#[stable(feature = "rust1", since = "1.0.0")]
#[stable(feature = "rust1", since = "1.0.0")]
impl<T> ExactSizeIterator for IntoIter<T> {}
+#[unstable(feature = "fused", issue = "35602")]
+impl<T> FusedIterator for IntoIter<T> {}
+
/////////////////////////////////////////////////////////////////////////////
// FromIterator
/////////////////////////////////////////////////////////////////////////////
#[stable(feature = "rust1", since = "1.0.0")]
impl<'a, T> ExactSizeIterator for Iter<'a, T> {}
+#[unstable(feature = "fused", issue = "35602")]
+impl<'a, T> FusedIterator for Iter<'a, T> {}
+
#[stable(feature = "rust1", since = "1.0.0")]
impl<'a, T> Clone for Iter<'a, T> {
fn clone(&self) -> Iter<'a, T> { Iter { ptr: self.ptr, end: self.end, _marker: self._marker } }
#[stable(feature = "rust1", since = "1.0.0")]
impl<'a, T> ExactSizeIterator for IterMut<'a, T> {}
+#[unstable(feature = "fused", issue = "35602")]
+impl<'a, T> FusedIterator for IterMut<'a, T> {}
+
/// An internal abstraction over the splitting iterators, so that
/// splitn, splitn_mut etc can be implemented once.
#[doc(hidden)]
}
}
+#[unstable(feature = "fused", issue = "35602")]
+impl<'a, T, P> FusedIterator for Split<'a, T, P> where P: FnMut(&T) -> bool {}
+
/// An iterator over the subslices of the vector which are separated
/// by elements that match `pred`.
#[stable(feature = "rust1", since = "1.0.0")]
}
}
+#[unstable(feature = "fused", issue = "35602")]
+impl<'a, T, P> FusedIterator for SplitMut<'a, T, P> where P: FnMut(&T) -> bool {}
+
/// An private iterator over subslices separated by elements that
/// match a predicate function, splitting at most a fixed number of
/// times.
self.inner.size_hint()
}
}
+
+ #[unstable(feature = "fused", issue = "35602")]
+ impl<'a, $elem, P> FusedIterator for $name<'a, $elem, P>
+ where P: FnMut(&T) -> bool {}
}
}
#[stable(feature = "rust1", since = "1.0.0")]
impl<'a, T> ExactSizeIterator for Windows<'a, T> {}
+#[unstable(feature = "fused", issue = "35602")]
+impl<'a, T> FusedIterator for Windows<'a, T> {}
+
/// An iterator over a slice in (non-overlapping) chunks (`size` elements at a
/// time).
///
#[stable(feature = "rust1", since = "1.0.0")]
impl<'a, T> ExactSizeIterator for Chunks<'a, T> {}
+#[unstable(feature = "fused", issue = "35602")]
+impl<'a, T> FusedIterator for Chunks<'a, T> {}
+
/// An iterator over a slice in (non-overlapping) mutable chunks (`size`
/// elements at a time). When the slice len is not evenly divided by the chunk
/// size, the last slice of the iteration will be the remainder.
#[stable(feature = "rust1", since = "1.0.0")]
impl<'a, T> ExactSizeIterator for ChunksMut<'a, T> {}
+#[unstable(feature = "fused", issue = "35602")]
+impl<'a, T> FusedIterator for ChunksMut<'a, T> {}
+
//
// Free functions
//
use default::Default;
use fmt;
use iter::ExactSizeIterator;
-use iter::{Map, Cloned, Iterator, DoubleEndedIterator};
+use iter::{Map, Cloned, Iterator, DoubleEndedIterator, FusedIterator};
use marker::Sized;
use mem;
use ops::{Fn, FnMut, FnOnce};
/// Reads the last code point out of a byte iterator (assuming a
/// UTF-8-like encoding).
#[inline]
-fn next_code_point_reverse<'a,
- I: DoubleEndedIterator<Item = &'a u8>>(bytes: &mut I) -> Option<u32> {
+fn next_code_point_reverse<'a, I>(bytes: &mut I) -> Option<u32>
+ where I: DoubleEndedIterator<Item = &'a u8>,
+{
// Decode UTF-8
let w = match bytes.next_back() {
None => return None,
}
}
+#[unstable(feature = "fused", issue = "35602")]
+impl<'a> FusedIterator for Chars<'a> {}
+
impl<'a> Chars<'a> {
/// View the underlying data as a subslice of the original data.
///
}
}
+#[unstable(feature = "fused", issue = "35602")]
+impl<'a> FusedIterator for CharIndices<'a> {}
+
impl<'a> CharIndices<'a> {
/// View the underlying data as a subslice of the original data.
///
}
}
+#[unstable(feature = "fused", issue = "35602")]
+impl<'a> FusedIterator for Bytes<'a> {}
+
/// This macro generates a Clone impl for string pattern API
/// wrapper types of the form X<'a, P>
macro_rules! derive_pattern_clone {
}
}
+ #[unstable(feature = "fused", issue = "35602")]
+ impl<'a, P: Pattern<'a>> FusedIterator for $forward_iterator<'a, P> {}
+
+ #[unstable(feature = "fused", issue = "35602")]
+ impl<'a, P: Pattern<'a>> FusedIterator for $reverse_iterator<'a, P>
+ where P::Searcher: ReverseSearcher<'a> {}
+
generate_pattern_iterators!($($t)* with $(#[$common_stability_attribute])*,
$forward_iterator,
$reverse_iterator, $iterty);
}
}
+#[unstable(feature = "fused", issue = "35602")]
+impl<'a> FusedIterator for Lines<'a> {}
+
/// Created with the method [`lines_any()`].
///
/// [`lines_any()`]: ../../std/primitive.str.html#method.lines_any
}
}
+#[unstable(feature = "fused", issue = "35602")]
+#[allow(deprecated)]
+impl<'a> FusedIterator for LinesAny<'a> {}
+
/*
Section: Comparing strings
*/
}
}
+ if label == "Krate" {
+ // special case
+ return Ok(DepNode::Krate);
+ }
+
check! {
CollectItem,
BorrowCheck,
pub type CaptureModeMap = NodeMap<CaptureClause>;
-#[derive(Clone)]
+#[derive(Clone, Debug)]
pub struct TraitCandidate {
pub def_id: DefId,
pub import_id: Option<NodeId>,
use rustc::util::nodemap::NodeSet;
use rustc_back::sha2::{Sha256, Digest};
use rustc_borrowck as borrowck;
-use rustc_incremental;
+use rustc_incremental::{self, IncrementalHashesMap};
use rustc_resolve::{MakeGlobMap, Resolver};
use rustc_metadata::macro_import;
use rustc_metadata::creader::read_local_crates;
resolutions,
&arenas,
&crate_name,
- |tcx, mir_map, analysis, result| {
+ |tcx, mir_map, analysis, incremental_hashes_map, result| {
{
// Eventually, we will want to track plugins.
let _ignore = tcx.dep_graph.in_ignore();
}
let trans = phase_4_translate_to_llvm(tcx,
mir_map.unwrap(),
- analysis);
+ analysis,
+ &incremental_hashes_map);
if log_enabled!(::log::INFO) {
println!("Post-trans");
where F: for<'a> FnOnce(TyCtxt<'a, 'tcx, 'tcx>,
Option<MirMap<'tcx>>,
ty::CrateAnalysis,
+ IncrementalHashesMap,
CompileResult) -> R
{
macro_rules! try_with_f {
- ($e: expr, ($t: expr, $m: expr, $a: expr)) => {
+ ($e: expr, ($t: expr, $m: expr, $a: expr, $h: expr)) => {
match $e {
Ok(x) => x,
Err(x) => {
- f($t, $m, $a, Err(x));
+ f($t, $m, $a, $h, Err(x));
return Err(x);
}
}
index,
name,
|tcx| {
+ let incremental_hashes_map =
+ time(time_passes,
+ "compute_incremental_hashes_map",
+ || rustc_incremental::compute_incremental_hashes_map(tcx));
time(time_passes,
"load_dep_graph",
- || rustc_incremental::load_dep_graph(tcx));
+ || rustc_incremental::load_dep_graph(tcx, &incremental_hashes_map));
// passes are timed inside typeck
- try_with_f!(typeck::check_crate(tcx), (tcx, None, analysis));
+ try_with_f!(typeck::check_crate(tcx), (tcx, None, analysis, incremental_hashes_map));
time(time_passes,
"const checking",
// lint warnings and so on -- kindck used to do this abort, but
// kindck is gone now). -nmatsakis
if sess.err_count() > 0 {
- return Ok(f(tcx, Some(mir_map), analysis, Err(sess.err_count())));
+ return Ok(f(tcx,
+ Some(mir_map),
+ analysis,
+ incremental_hashes_map,
+ Err(sess.err_count())));
}
analysis.reachable =
// The above three passes generate errors w/o aborting
if sess.err_count() > 0 {
- return Ok(f(tcx, Some(mir_map), analysis, Err(sess.err_count())));
+ return Ok(f(tcx,
+ Some(mir_map),
+ analysis,
+ incremental_hashes_map,
+ Err(sess.err_count())));
}
- Ok(f(tcx, Some(mir_map), analysis, Ok(())))
+ Ok(f(tcx, Some(mir_map), analysis, incremental_hashes_map, Ok(())))
})
}
/// Run the translation phase to LLVM, after which the AST and analysis can
pub fn phase_4_translate_to_llvm<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
mut mir_map: MirMap<'tcx>,
- analysis: ty::CrateAnalysis)
+ analysis: ty::CrateAnalysis,
+ incremental_hashes_map: &IncrementalHashesMap)
-> trans::CrateTranslation {
let time_passes = tcx.sess.time_passes();
let translation =
time(time_passes,
"translation",
- move || trans::trans_crate(tcx, &mir_map, analysis));
+ move || trans::trans_crate(tcx, &mir_map, analysis, &incremental_hashes_map));
time(time_passes,
"assert dep graph",
time(time_passes,
"serialize dep graph",
- move || rustc_incremental::save_dep_graph(tcx));
+ move || rustc_incremental::save_dep_graph(tcx, &incremental_hashes_map));
translation
}
resolutions.clone(),
arenas,
id,
- |tcx, _, _, _| {
+ |tcx, _, _, _, _| {
let annotation = TypedAnnotation {
tcx: tcx,
};
resolutions.clone(),
arenas,
crate_name,
- |tcx, mir_map, _, _| {
+ |tcx, mir_map, _, _, _| {
match ppm {
PpmMir | PpmMirCFG => {
if let Some(mir_map) = mir_map {
--- /dev/null
+// Copyright 2012-2014 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 rustc::hir::def_id::DefId;
+use rustc::ty::TyCtxt;
+use rustc::util::nodemap::DefIdMap;
+
+pub struct DefPathHashes<'a, 'tcx: 'a> {
+ tcx: TyCtxt<'a, 'tcx, 'tcx>,
+ data: DefIdMap<u64>,
+}
+
+impl<'a, 'tcx> DefPathHashes<'a, 'tcx> {
+ pub fn new(tcx: TyCtxt<'a, 'tcx, 'tcx>) -> Self {
+ DefPathHashes {
+ tcx: tcx,
+ data: DefIdMap()
+ }
+ }
+
+ pub fn hash(&mut self, def_id: DefId) -> u64 {
+ let tcx = self.tcx;
+ *self.data.entry(def_id)
+ .or_insert_with(|| {
+ let def_path = tcx.def_path(def_id);
+ def_path.deterministic_hash(tcx)
+ })
+ }
+}
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-//! Calculation of a Strict Version Hash for crates. For a length
-//! comment explaining the general idea, see `librustc/middle/svh.rs`.
-
+//! Calculation of the (misnamed) "strict version hash" for crates and
+//! items. This hash is used to tell when the HIR changed in such a
+//! way that results from previous compilations may no longer be
+//! applicable and hence must be recomputed. It should probably be
+//! renamed to the ICH (incremental compilation hash).
+//!
+//! The hashes for all items are computed once at the beginning of
+//! compilation and stored into a map. In addition, a hash is computed
+//! of the **entire crate**.
+//!
+//! Storing the hashes in a map avoids the need to compute them twice
+//! (once when loading prior incremental results and once when
+//! saving), but it is also important for correctness: at least as of
+//! the time of this writing, the typeck passes rewrites entries in
+//! the dep-map in-place to accommodate UFCS resolutions. Since name
+//! resolution is part of the hash, the result is that hashes computed
+//! at the end of compilation would be different from those computed
+//! at the beginning.
+
+use syntax::ast;
use syntax::attr::AttributeMethods;
use std::hash::{Hash, SipHasher, Hasher};
+use rustc::dep_graph::DepNode;
+use rustc::hir;
use rustc::hir::def_id::{CRATE_DEF_INDEX, DefId};
-use rustc::hir::map::{NodeItem, NodeForeignItem};
-use rustc::hir::svh::Svh;
+use rustc::hir::intravisit as visit;
use rustc::ty::TyCtxt;
-use rustc::hir::intravisit::{self, Visitor};
+use rustc_data_structures::fnv::FnvHashMap;
+use self::def_path_hash::DefPathHashes;
use self::svh_visitor::StrictVersionHashVisitor;
+mod def_path_hash;
mod svh_visitor;
-pub trait SvhCalculate {
- /// Calculate the SVH for an entire krate.
- fn calculate_krate_hash(self) -> Svh;
-
- /// Calculate the SVH for a particular item.
- fn calculate_item_hash(self, def_id: DefId) -> u64;
+pub type IncrementalHashesMap = FnvHashMap<DepNode<DefId>, u64>;
+
+pub fn compute_incremental_hashes_map<'a, 'tcx: 'a>(tcx: TyCtxt<'a, 'tcx, 'tcx>)
+ -> IncrementalHashesMap {
+ let _ignore = tcx.dep_graph.in_ignore();
+ let krate = tcx.map.krate();
+ let mut visitor = HashItemsVisitor { tcx: tcx,
+ hashes: FnvHashMap(),
+ def_path_hashes: DefPathHashes::new(tcx) };
+ visitor.calculate_def_id(DefId::local(CRATE_DEF_INDEX), |v| visit::walk_crate(v, krate));
+ krate.visit_all_items(&mut visitor);
+ visitor.compute_crate_hash();
+ visitor.hashes
}
-impl<'a, 'tcx> SvhCalculate for TyCtxt<'a, 'tcx, 'tcx> {
- fn calculate_krate_hash(self) -> Svh {
- // FIXME (#14132): This is better than it used to be, but it still not
- // ideal. We now attempt to hash only the relevant portions of the
- // Crate AST as well as the top-level crate attributes. (However,
- // the hashing of the crate attributes should be double-checked
- // to ensure it is not incorporating implementation artifacts into
- // the hash that are not otherwise visible.)
+struct HashItemsVisitor<'a, 'tcx: 'a> {
+ tcx: TyCtxt<'a, 'tcx, 'tcx>,
+ def_path_hashes: DefPathHashes<'a, 'tcx>,
+ hashes: IncrementalHashesMap,
+}
- let crate_disambiguator = self.sess.local_crate_disambiguator();
- let krate = self.map.krate();
+impl<'a, 'tcx> HashItemsVisitor<'a, 'tcx> {
+ fn calculate_node_id<W>(&mut self, id: ast::NodeId, walk_op: W)
+ where W: for<'v> FnMut(&mut StrictVersionHashVisitor<'v, 'a, 'tcx>)
+ {
+ let def_id = self.tcx.map.local_def_id(id);
+ self.calculate_def_id(def_id, walk_op)
+ }
- // FIXME: this should use SHA1, not SipHash. SipHash is not built to
- // avoid collisions.
+ fn calculate_def_id<W>(&mut self, def_id: DefId, mut walk_op: W)
+ where W: for<'v> FnMut(&mut StrictVersionHashVisitor<'v, 'a, 'tcx>)
+ {
+ assert!(def_id.is_local());
+ debug!("HashItemsVisitor::calculate(def_id={:?})", def_id);
+ // FIXME: this should use SHA1, not SipHash. SipHash is not
+ // built to avoid collisions.
let mut state = SipHasher::new();
- debug!("state: {:?}", state);
+ walk_op(&mut StrictVersionHashVisitor::new(&mut state,
+ self.tcx,
+ &mut self.def_path_hashes));
+ let item_hash = state.finish();
+ self.hashes.insert(DepNode::Hir(def_id), item_hash);
+ debug!("calculate_item_hash: def_id={:?} hash={:?}", def_id, item_hash);
+ }
+
+ fn compute_crate_hash(&mut self) {
+ let krate = self.tcx.map.krate();
- // FIXME(#32753) -- at (*) we `to_le` for endianness, but is
- // this enough, and does it matter anyway?
- "crate_disambiguator".hash(&mut state);
- crate_disambiguator.len().to_le().hash(&mut state); // (*)
- crate_disambiguator.hash(&mut state);
+ let mut crate_state = SipHasher::new();
- debug!("crate_disambiguator: {:?}", crate_disambiguator);
- debug!("state: {:?}", state);
+ let crate_disambiguator = self.tcx.sess.local_crate_disambiguator();
+ "crate_disambiguator".hash(&mut crate_state);
+ crate_disambiguator.len().hash(&mut crate_state);
+ crate_disambiguator.hash(&mut crate_state);
+ // add each item (in some deterministic order) to the overall
+ // crate hash.
{
- let mut visit = StrictVersionHashVisitor::new(&mut state, self);
- krate.visit_all_items(&mut visit);
+ let def_path_hashes = &mut self.def_path_hashes;
+ let mut item_hashes: Vec<_> =
+ self.hashes.iter()
+ .map(|(item_dep_node, &item_hash)| {
+ // convert from a DepNode<DefId> tp a
+ // DepNode<u64> where the u64 is the
+ // hash of the def-id's def-path:
+ let item_dep_node =
+ item_dep_node.map_def(|&did| Some(def_path_hashes.hash(did)))
+ .unwrap();
+ (item_dep_node, item_hash)
+ })
+ .collect();
+ item_hashes.sort(); // avoid artificial dependencies on item ordering
+ item_hashes.hash(&mut crate_state);
}
- // FIXME (#14132): This hash is still sensitive to e.g. the
- // spans of the crate Attributes and their underlying
- // MetaItems; we should make ContentHashable impl for those
- // types and then use hash_content. But, since all crate
- // attributes should appear near beginning of the file, it is
- // not such a big deal to be sensitive to their spans for now.
- //
- // We hash only the MetaItems instead of the entire Attribute
- // to avoid hashing the AttrId
for attr in &krate.attrs {
debug!("krate attr {:?}", attr);
- attr.meta().hash(&mut state);
+ attr.meta().hash(&mut crate_state);
}
- Svh::new(state.finish())
+ let crate_hash = crate_state.finish();
+ self.hashes.insert(DepNode::Krate, crate_hash);
+ debug!("calculate_crate_hash: crate_hash={:?}", crate_hash);
}
+}
- fn calculate_item_hash(self, def_id: DefId) -> u64 {
- assert!(def_id.is_local());
-
- debug!("calculate_item_hash(def_id={:?})", def_id);
-
- let mut state = SipHasher::new();
-
- {
- let mut visit = StrictVersionHashVisitor::new(&mut state, self);
- if def_id.index == CRATE_DEF_INDEX {
- // the crate root itself is not registered in the map
- // as an item, so we have to fetch it this way
- let krate = self.map.krate();
- intravisit::walk_crate(&mut visit, krate);
- } else {
- let node_id = self.map.as_local_node_id(def_id).unwrap();
- match self.map.find(node_id) {
- Some(NodeItem(item)) => visit.visit_item(item),
- Some(NodeForeignItem(item)) => visit.visit_foreign_item(item),
- r => bug!("calculate_item_hash: expected an item for node {} not {:?}",
- node_id, r),
- }
- }
- }
-
- let hash = state.finish();
- debug!("calculate_item_hash: def_id={:?} hash={:?}", def_id, hash);
+impl<'a, 'tcx> visit::Visitor<'tcx> for HashItemsVisitor<'a, 'tcx> {
+ fn visit_item(&mut self, item: &'tcx hir::Item) {
+ self.calculate_node_id(item.id, |v| v.visit_item(item));
+ visit::walk_item(self, item);
+ }
- hash
+ fn visit_foreign_item(&mut self, item: &'tcx hir::ForeignItem) {
+ self.calculate_node_id(item.id, |v| v.visit_foreign_item(item));
+ visit::walk_foreign_item(self, item);
}
}
+
use rustc::hir::def_id::DefId;
use rustc::hir::intravisit as visit;
use rustc::hir::intravisit::{Visitor, FnKind};
-use rustc::hir::map::DefPath;
use rustc::ty::TyCtxt;
use std::hash::{Hash, SipHasher};
-pub struct StrictVersionHashVisitor<'a, 'tcx: 'a> {
- pub tcx: TyCtxt<'a, 'tcx, 'tcx>,
+use super::def_path_hash::DefPathHashes;
+
+pub struct StrictVersionHashVisitor<'a, 'hash: 'a, 'tcx: 'hash> {
+ pub tcx: TyCtxt<'hash, 'tcx, 'tcx>,
pub st: &'a mut SipHasher,
+
+ // collect a deterministic hash of def-ids that we have seen
+ def_path_hashes: &'a mut DefPathHashes<'hash, 'tcx>,
}
-impl<'a, 'tcx> StrictVersionHashVisitor<'a, 'tcx> {
+impl<'a, 'hash, 'tcx> StrictVersionHashVisitor<'a, 'hash, 'tcx> {
pub fn new(st: &'a mut SipHasher,
- tcx: TyCtxt<'a, 'tcx, 'tcx>)
+ tcx: TyCtxt<'hash, 'tcx, 'tcx>,
+ def_path_hashes: &'a mut DefPathHashes<'hash, 'tcx>)
-> Self {
- StrictVersionHashVisitor { st: st, tcx: tcx }
+ StrictVersionHashVisitor { st: st, tcx: tcx, def_path_hashes: def_path_hashes }
}
- fn hash_def_path(&mut self, path: &DefPath) {
- path.deterministic_hash_to(self.tcx, self.st);
+ fn compute_def_id_hash(&mut self, def_id: DefId) -> u64 {
+ self.def_path_hashes.hash(def_id)
}
}
SawStmtSemi,
}
-impl<'a, 'tcx> Visitor<'a> for StrictVersionHashVisitor<'a, 'tcx> {
+impl<'a, 'hash, 'tcx> Visitor<'tcx> for StrictVersionHashVisitor<'a, 'hash, 'tcx> {
fn visit_nested_item(&mut self, _: ItemId) {
// Each item is hashed independently; ignore nested items.
}
- fn visit_variant_data(&mut self, s: &'a VariantData, name: Name,
- g: &'a Generics, _: NodeId, _: Span) {
+ fn visit_variant_data(&mut self, s: &'tcx VariantData, name: Name,
+ g: &'tcx Generics, _: NodeId, _: Span) {
debug!("visit_variant_data: st={:?}", self.st);
SawStructDef(name.as_str()).hash(self.st);
visit::walk_generics(self, g);
visit::walk_struct_def(self, s)
}
- fn visit_variant(&mut self, v: &'a Variant, g: &'a Generics, item_id: NodeId) {
+ fn visit_variant(&mut self, v: &'tcx Variant, g: &'tcx Generics, item_id: NodeId) {
debug!("visit_variant: st={:?}", self.st);
SawVariant.hash(self.st);
// walk_variant does not call walk_generics, so do it here.
SawIdent(name.as_str()).hash(self.st);
}
- fn visit_lifetime(&mut self, l: &'a Lifetime) {
+ fn visit_lifetime(&mut self, l: &'tcx Lifetime) {
debug!("visit_lifetime: st={:?}", self.st);
SawLifetime(l.name.as_str()).hash(self.st);
}
- fn visit_lifetime_def(&mut self, l: &'a LifetimeDef) {
+ fn visit_lifetime_def(&mut self, l: &'tcx LifetimeDef) {
debug!("visit_lifetime_def: st={:?}", self.st);
SawLifetimeDef(l.lifetime.name.as_str()).hash(self.st);
}
// monomorphization and cross-crate inlining generally implies
// that a change to a crate body will require downstream
// crates to be recompiled.
- fn visit_expr(&mut self, ex: &'a Expr) {
+ fn visit_expr(&mut self, ex: &'tcx Expr) {
debug!("visit_expr: st={:?}", self.st);
SawExpr(saw_expr(&ex.node)).hash(self.st); visit::walk_expr(self, ex)
}
- fn visit_stmt(&mut self, s: &'a Stmt) {
+ fn visit_stmt(&mut self, s: &'tcx Stmt) {
debug!("visit_stmt: st={:?}", self.st);
// We don't want to modify the hash for decls, because
visit::walk_stmt(self, s)
}
- fn visit_foreign_item(&mut self, i: &'a ForeignItem) {
+ fn visit_foreign_item(&mut self, i: &'tcx ForeignItem) {
debug!("visit_foreign_item: st={:?}", self.st);
// FIXME (#14132) ideally we would incorporate privacy (or
SawForeignItem.hash(self.st); visit::walk_foreign_item(self, i)
}
- fn visit_item(&mut self, i: &'a Item) {
+ fn visit_item(&mut self, i: &'tcx Item) {
debug!("visit_item: {:?} st={:?}", i, self.st);
// FIXME (#14132) ideally would incorporate reachability
SawItem.hash(self.st); visit::walk_item(self, i)
}
- fn visit_mod(&mut self, m: &'a Mod, _s: Span, n: NodeId) {
+ fn visit_mod(&mut self, m: &'tcx Mod, _s: Span, n: NodeId) {
debug!("visit_mod: st={:?}", self.st);
SawMod.hash(self.st); visit::walk_mod(self, m, n)
}
- fn visit_ty(&mut self, t: &'a Ty) {
+ fn visit_ty(&mut self, t: &'tcx Ty) {
debug!("visit_ty: st={:?}", self.st);
SawTy.hash(self.st); visit::walk_ty(self, t)
}
- fn visit_generics(&mut self, g: &'a Generics) {
+ fn visit_generics(&mut self, g: &'tcx Generics) {
debug!("visit_generics: st={:?}", self.st);
SawGenerics.hash(self.st); visit::walk_generics(self, g)
}
- fn visit_fn(&mut self, fk: FnKind<'a>, fd: &'a FnDecl,
- b: &'a Block, s: Span, n: NodeId) {
+ fn visit_fn(&mut self, fk: FnKind<'tcx>, fd: &'tcx FnDecl,
+ b: &'tcx Block, s: Span, n: NodeId) {
debug!("visit_fn: st={:?}", self.st);
SawFn.hash(self.st); visit::walk_fn(self, fk, fd, b, s, n)
}
- fn visit_trait_item(&mut self, ti: &'a TraitItem) {
+ fn visit_trait_item(&mut self, ti: &'tcx TraitItem) {
debug!("visit_trait_item: st={:?}", self.st);
SawTraitItem.hash(self.st); visit::walk_trait_item(self, ti)
}
- fn visit_impl_item(&mut self, ii: &'a ImplItem) {
+ fn visit_impl_item(&mut self, ii: &'tcx ImplItem) {
debug!("visit_impl_item: st={:?}", self.st);
SawImplItem.hash(self.st); visit::walk_impl_item(self, ii)
}
- fn visit_struct_field(&mut self, s: &'a StructField) {
+ fn visit_struct_field(&mut self, s: &'tcx StructField) {
debug!("visit_struct_field: st={:?}", self.st);
SawStructField.hash(self.st); visit::walk_struct_field(self, s)
}
- fn visit_path(&mut self, path: &'a Path, _: ast::NodeId) {
+ fn visit_path(&mut self, path: &'tcx Path, _: ast::NodeId) {
debug!("visit_path: st={:?}", self.st);
SawPath.hash(self.st); visit::walk_path(self, path)
}
- fn visit_block(&mut self, b: &'a Block) {
+ fn visit_block(&mut self, b: &'tcx Block) {
debug!("visit_block: st={:?}", self.st);
SawBlock.hash(self.st); visit::walk_block(self, b)
}
- fn visit_pat(&mut self, p: &'a Pat) {
+ fn visit_pat(&mut self, p: &'tcx Pat) {
debug!("visit_pat: st={:?}", self.st);
SawPat.hash(self.st); visit::walk_pat(self, p)
}
- fn visit_local(&mut self, l: &'a Local) {
+ fn visit_local(&mut self, l: &'tcx Local) {
debug!("visit_local: st={:?}", self.st);
SawLocal.hash(self.st); visit::walk_local(self, l)
}
- fn visit_arm(&mut self, a: &'a Arm) {
+ fn visit_arm(&mut self, a: &'tcx Arm) {
debug!("visit_arm: st={:?}", self.st);
SawArm.hash(self.st); visit::walk_arm(self, a)
}
SawErr,
}
-impl<'a, 'tcx> StrictVersionHashVisitor<'a, 'tcx> {
+impl<'a, 'hash, 'tcx> StrictVersionHashVisitor<'a, 'hash, 'tcx> {
fn hash_resolve(&mut self, id: ast::NodeId) {
// Because whether or not a given id has an entry is dependent
// solely on expr variant etc, we don't need to hash whether
// variant it is above when we visit the HIR).
if let Some(def) = self.tcx.def_map.borrow().get(&id) {
+ debug!("hash_resolve: id={:?} def={:?} st={:?}", id, def, self.st);
self.hash_partial_def(def);
}
if let Some(traits) = self.tcx.trait_map.get(&id) {
+ debug!("hash_resolve: id={:?} traits={:?} st={:?}", id, traits, self.st);
traits.len().hash(self.st);
- for candidate in traits {
- self.hash_def_id(candidate.def_id);
- }
+
+ // The ordering of the candidates is not fixed. So we hash
+ // the def-ids and then sort them and hash the collection.
+ let mut candidates: Vec<_> =
+ traits.iter()
+ .map(|&TraitCandidate { def_id, import_id: _ }| {
+ self.compute_def_id_hash(def_id)
+ })
+ .collect();
+ candidates.sort();
+ candidates.hash(self.st);
}
}
fn hash_def_id(&mut self, def_id: DefId) {
- let def_path = self.tcx.def_path(def_id);
- self.hash_def_path(&def_path);
+ self.compute_def_id_hash(def_id).hash(self.st);
}
fn hash_partial_def(&mut self, def: &PathResolution) {
mod persist;
pub use assert_dep_graph::assert_dep_graph;
-pub use calculate_svh::SvhCalculate;
+pub use calculate_svh::compute_incremental_hashes_map;
+pub use calculate_svh::IncrementalHashesMap;
pub use persist::load_dep_graph;
pub use persist::save_dep_graph;
pub use persist::save_trans_partition;
debug!("assert_dirty({:?})", dep_node);
match dep_node {
+ DepNode::Krate |
DepNode::Hir(_) => {
// HIR nodes are inputs, so if we are asserting that the HIR node is
// dirty, we check the dirty input set.
debug!("assert_clean({:?})", dep_node);
match dep_node {
+ DepNode::Krate |
DepNode::Hir(_) => {
// For HIR nodes, check the inputs.
if self.dirty_inputs.contains(&dep_node) {
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-use calculate_svh::SvhCalculate;
use rbml::Error;
use rbml::opaque::Decoder;
use rustc::dep_graph::DepNode;
use std::fs::File;
use syntax::ast;
+use IncrementalHashesMap;
use super::data::*;
use super::util::*;
pub struct HashContext<'a, 'tcx: 'a> {
pub tcx: TyCtxt<'a, 'tcx, 'tcx>,
+ incremental_hashes_map: &'a IncrementalHashesMap,
item_metadata_hashes: FnvHashMap<DefId, u64>,
crate_hashes: FnvHashMap<ast::CrateNum, Svh>,
}
impl<'a, 'tcx> HashContext<'a, 'tcx> {
- pub fn new(tcx: TyCtxt<'a, 'tcx, 'tcx>) -> Self {
+ pub fn new(tcx: TyCtxt<'a, 'tcx, 'tcx>,
+ incremental_hashes_map: &'a IncrementalHashesMap)
+ -> Self {
HashContext {
tcx: tcx,
+ incremental_hashes_map: incremental_hashes_map,
item_metadata_hashes: FnvHashMap(),
crate_hashes: FnvHashMap(),
}
pub fn is_hashable(dep_node: &DepNode<DefId>) -> bool {
match *dep_node {
+ DepNode::Krate |
DepNode::Hir(_) => true,
DepNode::MetaData(def_id) => !def_id.is_local(),
_ => false,
}
}
- pub fn hash(&mut self, dep_node: &DepNode<DefId>) -> Option<(DefId, u64)> {
+ pub fn hash(&mut self, dep_node: &DepNode<DefId>) -> Option<u64> {
match *dep_node {
+ DepNode::Krate => {
+ Some(self.incremental_hashes_map[dep_node])
+ }
+
// HIR nodes (which always come from our crate) are an input:
DepNode::Hir(def_id) => {
- Some((def_id, self.hir_hash(def_id)))
+ assert!(def_id.is_local(),
+ "cannot hash HIR for non-local def-id {:?} => {:?}",
+ def_id,
+ self.tcx.item_path_str(def_id));
+
+ assert!(!self.tcx.map.is_inlined_def_id(def_id),
+ "cannot hash HIR for inlined def-id {:?} => {:?}",
+ def_id,
+ self.tcx.item_path_str(def_id));
+
+ Some(self.incremental_hashes_map[dep_node])
}
// MetaData from other crates is an *input* to us.
// don't hash them, but we do compute a hash for them and
// save it for others to use.
DepNode::MetaData(def_id) if !def_id.is_local() => {
- Some((def_id, self.metadata_hash(def_id)))
+ Some(self.metadata_hash(def_id))
}
_ => {
}
}
- fn hir_hash(&mut self, def_id: DefId) -> u64 {
- assert!(def_id.is_local(),
- "cannot hash HIR for non-local def-id {:?} => {:?}",
- def_id,
- self.tcx.item_path_str(def_id));
-
- assert!(!self.tcx.map.is_inlined_def_id(def_id),
- "cannot hash HIR for inlined def-id {:?} => {:?}",
- def_id,
- self.tcx.item_path_str(def_id));
-
- // FIXME(#32753) -- should we use a distinct hash here
- self.tcx.calculate_item_hash(def_id)
- }
-
fn metadata_hash(&mut self, def_id: DefId) -> u64 {
debug!("metadata_hash(def_id={:?})", def_id);
use std::fs::{self, File};
use std::path::{Path};
+use IncrementalHashesMap;
use super::data::*;
use super::directory::*;
use super::dirty_clean;
/// early in compilation, before we've really done any work, but
/// actually it doesn't matter all that much.) See `README.md` for
/// more general overview.
-pub fn load_dep_graph<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) {
+pub fn load_dep_graph<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
+ incremental_hashes_map: &IncrementalHashesMap) {
if tcx.sess.opts.incremental.is_none() {
return;
}
let _ignore = tcx.dep_graph.in_ignore();
- load_dep_graph_if_exists(tcx);
+ load_dep_graph_if_exists(tcx, incremental_hashes_map);
}
-fn load_dep_graph_if_exists<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) {
+fn load_dep_graph_if_exists<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
+ incremental_hashes_map: &IncrementalHashesMap) {
let dep_graph_path = dep_graph_path(tcx).unwrap();
let dep_graph_data = match load_data(tcx.sess, &dep_graph_path) {
Some(p) => p,
None => return // no file
};
- match decode_dep_graph(tcx, &dep_graph_data, &work_products_data) {
+ match decode_dep_graph(tcx, incremental_hashes_map, &dep_graph_data, &work_products_data) {
Ok(dirty_nodes) => dirty_nodes,
Err(err) => {
tcx.sess.warn(
/// Decode the dep graph and load the edges/nodes that are still clean
/// into `tcx.dep_graph`.
pub fn decode_dep_graph<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
+ incremental_hashes_map: &IncrementalHashesMap,
dep_graph_data: &[u8],
work_products_data: &[u8])
-> Result<(), Error>
// reason for this is that this way we can include nodes that have
// been removed (which no longer have a `DefId` in the current
// compilation).
- let dirty_raw_source_nodes = dirty_nodes(tcx, &serialized_dep_graph.hashes, &retraced);
+ let dirty_raw_source_nodes = dirty_nodes(tcx,
+ incremental_hashes_map,
+ &serialized_dep_graph.hashes,
+ &retraced);
// Create a list of (raw-source-node ->
// retracted-target-node) edges. In the process of retracing the
/// Computes which of the original set of def-ids are dirty. Stored in
/// a bit vector where the index is the DefPathIndex.
fn dirty_nodes<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
- hashes: &[SerializedHash],
+ incremental_hashes_map: &IncrementalHashesMap,
+ serialized_hashes: &[SerializedHash],
retraced: &RetracedDefIdDirectory)
-> DirtyNodes {
- let mut hcx = HashContext::new(tcx);
+ let mut hcx = HashContext::new(tcx, incremental_hashes_map);
let mut dirty_nodes = FnvHashSet();
- for hash in hashes {
+ for hash in serialized_hashes {
if let Some(dep_node) = retraced.map(&hash.dep_node) {
- let (_, current_hash) = hcx.hash(&dep_node).unwrap();
+ let current_hash = hcx.hash(&dep_node).unwrap();
if current_hash == hash.hash {
continue;
}
let mut hashes = FnvHashMap();
for input in inputs.values().flat_map(|v| v.iter().cloned()) {
hashes.entry(input)
- .or_insert_with(|| hcx.hash(input).unwrap().1);
+ .or_insert_with(|| hcx.hash(input).unwrap());
}
Predecessors {
use std::fs::{self, File};
use std::path::PathBuf;
+use IncrementalHashesMap;
use super::data::*;
use super::directory::*;
use super::hash::*;
use super::preds::*;
use super::util::*;
-pub fn save_dep_graph<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) {
+pub fn save_dep_graph<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
+ incremental_hashes_map: &IncrementalHashesMap) {
debug!("save_dep_graph()");
let _ignore = tcx.dep_graph.in_ignore();
let sess = tcx.sess;
if sess.opts.incremental.is_none() {
return;
}
- let mut hcx = HashContext::new(tcx);
+ let mut hcx = HashContext::new(tcx, incremental_hashes_map);
let mut builder = DefIdDirectoryBuilder::new(tcx);
let query = tcx.dep_graph.query();
let preds = Predecessors::new(&query, &mut hcx);
use util::common::time;
use util::fs::fix_windows_verbatim_for_gcc;
use rustc::dep_graph::DepNode;
-use rustc::ty::TyCtxt;
+use rustc::hir::svh::Svh;
use rustc_back::tempdir::TempDir;
+use rustc_incremental::IncrementalHashesMap;
-use rustc_incremental::SvhCalculate;
use std::ascii;
use std::char;
use std::env;
}
-pub fn build_link_meta<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
- name: &str)
- -> LinkMeta {
+pub fn build_link_meta(incremental_hashes_map: &IncrementalHashesMap,
+ name: &str)
+ -> LinkMeta {
let r = LinkMeta {
crate_name: name.to_owned(),
- crate_hash: tcx.calculate_krate_hash(),
+ crate_hash: Svh::new(incremental_hashes_map[&DepNode::Krate]),
};
info!("{:?}", r);
return r;
use rustc::util::common::time;
use rustc::mir::mir_map::MirMap;
use rustc_data_structures::graph::OUTGOING;
+use rustc_incremental::IncrementalHashesMap;
use session::config::{self, NoDebugInfo, FullDebugInfo};
use session::Session;
use _match;
pub fn trans_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
mir_map: &MirMap<'tcx>,
- analysis: ty::CrateAnalysis)
+ analysis: ty::CrateAnalysis,
+ incremental_hashes_map: &IncrementalHashesMap)
-> CrateTranslation {
let _task = tcx.dep_graph.in_task(DepNode::TransCrate);
tcx.sess.opts.debug_assertions
};
- let link_meta = link::build_link_meta(tcx, name);
+ let link_meta = link::build_link_meta(incremental_hashes_map, name);
let shared_ccx = SharedCrateContext::new(tcx,
&mir_map,
// are zero. Since I don't quite know how to phrase things at
// the moment, give a kind of vague error message.
if trait_params.len() != impl_params.len() {
- span_err!(ccx.tcx.sess, span, E0195,
+ struct_span_err!(ccx.tcx.sess, span, E0195,
"lifetime parameters or bounds on method `{}` do \
- not match the trait declaration",
- impl_m.name);
+ not match the trait declaration",impl_m.name)
+ .span_label(span, &format!("lifetimes do not match trait"))
+ .emit();
return false;
}
#![stable(feature = "rust1", since = "1.0.0")]
use core::char::CharExt as C;
+use core::iter::FusedIterator;
use core::fmt;
use tables::{conversions, derived_property, general_category, property};
}
}
+#[unstable(feature = "fused", issue = "35602")]
+impl FusedIterator for ToLowercase {}
+
/// Returns an iterator that yields the uppercase equivalent of a `char`.
///
/// This `struct` is created by the [`to_uppercase()`] method on [`char`]. See
}
}
+#[unstable(feature = "fused", issue = "35602")]
+impl FusedIterator for ToUppercase {}
enum CaseMappingIter {
Three(char, char, char),
#![feature(char_escape_debug)]
#![feature(core_char_ext)]
#![feature(decode_utf8)]
+#![feature(fused)]
#![feature(lang_items)]
#![feature(staged_api)]
#![feature(unicode)]
//! methods provided by the unicode parts of the CharExt trait.
use core::char;
-use core::iter::Filter;
+use core::iter::{Filter, FusedIterator};
use core::str::Split;
/// An iterator over the non-whitespace substrings of a string,
}
}
+#[unstable(feature = "fused", issue = "35602")]
+impl<I> FusedIterator for Utf16Encoder<I>
+ where I: FusedIterator<Item = char> {}
+
impl<'a> Iterator for SplitWhitespace<'a> {
type Item = &'a str;
self.inner.next_back()
}
}
+
+#[unstable(feature = "fused", issue = "35602")]
+impl<'a> FusedIterator for SplitWhitespace<'a> {}
resolutions,
&arenas,
&name,
- |tcx, _, analysis, result| {
+ |tcx, _, analysis, _, result| {
if let Err(_) = result {
sess.fatal("Compilation failed, aborting rustdoc");
}
use mem;
use ops::Range;
+use iter::FusedIterator;
/// Extension methods for ASCII-subset only operations on string slices.
///
}
#[stable(feature = "rust1", since = "1.0.0")]
impl ExactSizeIterator for EscapeDefault {}
+#[unstable(feature = "fused", issue = "35602")]
+impl FusedIterator for EscapeDefault {}
+
static ASCII_LOWERCASE_MAP: [u8; 256] = [
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
use cmp::max;
use fmt::{self, Debug};
use hash::{Hash, Hasher, BuildHasher, SipHasher13};
-use iter::FromIterator;
+use iter::{FromIterator, FusedIterator};
use mem::{self, replace};
use ops::{Deref, Index};
use rand::{self, Rng};
#[inline] fn len(&self) -> usize { self.inner.len() }
}
+#[unstable(feature = "fused", issue = "35602")]
+impl<'a, K, V> FusedIterator for Iter<'a, K, V> {}
+
#[stable(feature = "rust1", since = "1.0.0")]
impl<'a, K, V> Iterator for IterMut<'a, K, V> {
type Item = (&'a K, &'a mut V);
impl<'a, K, V> ExactSizeIterator for IterMut<'a, K, V> {
#[inline] fn len(&self) -> usize { self.inner.len() }
}
+#[unstable(feature = "fused", issue = "35602")]
+impl<'a, K, V> FusedIterator for IterMut<'a, K, V> {}
#[stable(feature = "rust1", since = "1.0.0")]
impl<K, V> Iterator for IntoIter<K, V> {
impl<K, V> ExactSizeIterator for IntoIter<K, V> {
#[inline] fn len(&self) -> usize { self.inner.len() }
}
+#[unstable(feature = "fused", issue = "35602")]
+impl<K, V> FusedIterator for IntoIter<K, V> {}
#[stable(feature = "rust1", since = "1.0.0")]
impl<'a, K, V> Iterator for Keys<'a, K, V> {
impl<'a, K, V> ExactSizeIterator for Keys<'a, K, V> {
#[inline] fn len(&self) -> usize { self.inner.len() }
}
+#[unstable(feature = "fused", issue = "35602")]
+impl<'a, K, V> FusedIterator for Keys<'a, K, V> {}
#[stable(feature = "rust1", since = "1.0.0")]
impl<'a, K, V> Iterator for Values<'a, K, V> {
impl<'a, K, V> ExactSizeIterator for Values<'a, K, V> {
#[inline] fn len(&self) -> usize { self.inner.len() }
}
+#[unstable(feature = "fused", issue = "35602")]
+impl<'a, K, V> FusedIterator for Values<'a, K, V> {}
#[stable(feature = "map_values_mut", since = "1.10.0")]
impl<'a, K, V> Iterator for ValuesMut<'a, K, V> {
impl<'a, K, V> ExactSizeIterator for ValuesMut<'a, K, V> {
#[inline] fn len(&self) -> usize { self.inner.len() }
}
+#[unstable(feature = "fused", issue = "35602")]
+impl<'a, K, V> FusedIterator for ValuesMut<'a, K, V> {}
#[stable(feature = "rust1", since = "1.0.0")]
impl<'a, K, V> Iterator for Drain<'a, K, V> {
impl<'a, K, V> ExactSizeIterator for Drain<'a, K, V> {
#[inline] fn len(&self) -> usize { self.inner.len() }
}
+#[unstable(feature = "fused", issue = "35602")]
+impl<'a, K, V> FusedIterator for Drain<'a, K, V> {}
impl<'a, K, V> Entry<'a, K, V> {
#[stable(feature = "rust1", since = "1.0.0")]
use borrow::Borrow;
use fmt;
use hash::{Hash, BuildHasher};
-use iter::{Chain, FromIterator};
+use iter::{Chain, FromIterator, FusedIterator};
use ops::{BitOr, BitAnd, BitXor, Sub};
use super::Recover;
impl<'a, K> ExactSizeIterator for Iter<'a, K> {
fn len(&self) -> usize { self.iter.len() }
}
+#[unstable(feature = "fused", issue = "35602")]
+impl<'a, K> FusedIterator for Iter<'a, K> {}
#[stable(feature = "rust1", since = "1.0.0")]
impl<K> Iterator for IntoIter<K> {
impl<K> ExactSizeIterator for IntoIter<K> {
fn len(&self) -> usize { self.iter.len() }
}
+#[unstable(feature = "fused", issue = "35602")]
+impl<K> FusedIterator for IntoIter<K> {}
#[stable(feature = "rust1", since = "1.0.0")]
impl<'a, K> Iterator for Drain<'a, K> {
impl<'a, K> ExactSizeIterator for Drain<'a, K> {
fn len(&self) -> usize { self.iter.len() }
}
+#[unstable(feature = "fused", issue = "35602")]
+impl<'a, K> FusedIterator for Drain<'a, K> {}
#[stable(feature = "rust1", since = "1.0.0")]
impl<'a, T, S> Clone for Intersection<'a, T, S> {
}
}
+#[unstable(feature = "fused", issue = "35602")]
+impl<'a, T, S> FusedIterator for Intersection<'a, T, S>
+ where T: Eq + Hash, S: BuildHasher
+{}
+
#[stable(feature = "rust1", since = "1.0.0")]
impl<'a, T, S> Clone for Difference<'a, T, S> {
fn clone(&self) -> Difference<'a, T, S> {
}
}
+#[unstable(feature = "fused", issue = "35602")]
+impl<'a, T, S> FusedIterator for Difference<'a, T, S>
+ where T: Eq + Hash, S: BuildHasher
+{}
+
#[stable(feature = "rust1", since = "1.0.0")]
impl<'a, T, S> Clone for SymmetricDifference<'a, T, S> {
fn clone(&self) -> SymmetricDifference<'a, T, S> {
fn size_hint(&self) -> (usize, Option<usize>) { self.iter.size_hint() }
}
+#[unstable(feature = "fused", issue = "35602")]
+impl<'a, T, S> FusedIterator for SymmetricDifference<'a, T, S>
+ where T: Eq + Hash, S: BuildHasher
+{}
+
#[stable(feature = "rust1", since = "1.0.0")]
impl<'a, T, S> Clone for Union<'a, T, S> {
fn clone(&self) -> Union<'a, T, S> { Union { iter: self.iter.clone() } }
}
+#[unstable(feature = "fused", issue = "35602")]
+impl<'a, T, S> FusedIterator for Union<'a, T, S>
+ where T: Eq + Hash, S: BuildHasher
+{}
+
#[stable(feature = "rust1", since = "1.0.0")]
impl<'a, T, S> Iterator for Union<'a, T, S>
where T: Eq + Hash, S: BuildHasher
#![feature(float_from_str_radix)]
#![feature(fn_traits)]
#![feature(fnbox)]
+#![feature(fused)]
#![feature(hashmap_hasher)]
#![feature(heap_api)]
#![feature(inclusive_range)]
use fs;
use hash::{Hash, Hasher};
use io;
-use iter;
+use iter::{self, FusedIterator};
use mem;
use ops::{self, Deref};
use string::String;
}
}
+#[unstable(feature = "fused", issue = "35602")]
+impl<'a> FusedIterator for Iter<'a> {}
+
#[stable(feature = "rust1", since = "1.0.0")]
impl<'a> Iterator for Components<'a> {
type Item = Component<'a>;
}
}
+#[unstable(feature = "fused", issue = "35602")]
+impl<'a> FusedIterator for Components<'a> {}
+
#[stable(feature = "rust1", since = "1.0.0")]
impl<'a> cmp::PartialEq for Components<'a> {
fn eq(&self, other: &Components<'a>) -> bool {
-Subproject commit c37d3747da75c280237dc2d6b925078e69555499
+Subproject commit 755bc3db4ff795865ea31b5b4f38ac920d8acacb
impl Trait for Foo {
fn bar<'a,'b>(x: &'a str, y: &'b str) { //~ ERROR E0195
+ //~^ lifetimes do not match trait
}
}
impl<'a> NoLifetime for Foo<'a> {
fn get<'p, T : Test<'a>>(&self) -> T {
//~^ ERROR E0195
+//~| lifetimes do not match trait
return *self as T;
}
}
--- /dev/null
+// Copyright 2014 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.
+
+// Test that the crate hash is not affected by reordering items.
+
+// revisions:rpass1 rpass2 rpass3
+// compile-flags: -Z query-dep-graph
+
+#![feature(rustc_attrs)]
+
+// Check that reordering otherwise identical items is not considered a
+// change at all.
+#[rustc_clean(label="Krate", cfg="rpass2")]
+
+// But removing an item, naturally, is.
+#[rustc_dirty(label="Krate", cfg="rpass3")]
+
+#[cfg(rpass1)]
+pub struct X {
+ pub x: u32,
+}
+
+pub struct Y {
+ pub x: u32,
+}
+
+#[cfg(rpass2)]
+pub struct X {
+ pub x: u32,
+}
+
+pub fn main() { }
--- /dev/null
+// 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.
+
+// Regression test for #35593. Check that we can reuse this trivially
+// equal example.
+
+// revisions:rpass1 rpass2
+
+#![feature(rustc_attrs)]
+#![rustc_partition_reused(module="issue_35593", cfg="rpass2")]
+
+fn main() {
+ println!("hello world");
+}
// Here the only thing which changes is the string constant in `x`.
// Therefore, the compiler deduces (correctly) that typeck is not
// needed even for callers of `x`.
-//
-// It is not entirely clear why `TransCrateItem` invalidates `y` and
-// `z`, actually, I think it's because of the structure of
-// trans. -nmatsakis
fn main() { }
mod y {
use x;
- // FIXME(#35078) -- when body of `x` changes, we treat it as
- // though signature changed.
- #[rustc_dirty(label="TypeckItemBody", cfg="rpass2")]
- #[rustc_dirty(label="TransCrateItem", cfg="rpass2")]
+ #[rustc_clean(label="TypeckItemBody", cfg="rpass2")]
+ #[rustc_clean(label="TransCrateItem", cfg="rpass2")]
pub fn y() {
x::x();
}