diff --git a/src/doc/trpl/unsafe.md b/src/doc/trpl/unsafe.md index 3acd1eefe89d0..2bd86fa987f4b 100644 --- a/src/doc/trpl/unsafe.md +++ b/src/doc/trpl/unsafe.md @@ -576,6 +576,10 @@ extern fn panic_fmt(args: &core::fmt::Arguments, #[lang = "eh_personality"] extern fn eh_personality() {} # #[start] fn start(argc: isize, argv: *const *const u8) -> isize { 0 } # fn main() {} +# mod std { // for-loops +# pub use core::iter; +# pub use core::option; +# } ``` Note that there is one extra lang item here which differs from the examples diff --git a/src/libcollections/binary_heap.rs b/src/libcollections/binary_heap.rs index f717fc6075d46..8c2163d7e14a6 100644 --- a/src/libcollections/binary_heap.rs +++ b/src/libcollections/binary_heap.rs @@ -153,7 +153,7 @@ use core::prelude::*; use core::default::Default; -use core::iter::FromIterator; +use core::iter::{FromIterator, IntoIterator}; use core::mem::{zeroed, replace, swap}; use core::ptr; @@ -655,6 +655,22 @@ impl FromIterator for BinaryHeap { } } +impl IntoIterator for BinaryHeap { + type Iter = IntoIter; + + fn into_iter(self) -> IntoIter { + self.into_iter() + } +} + +impl<'a, T> IntoIterator for &'a BinaryHeap where T: Ord { + type Iter = Iter<'a, T>; + + fn into_iter(self) -> Iter<'a, T> { + self.iter() + } +} + #[stable(feature = "rust1", since = "1.0.0")] impl Extend for BinaryHeap { fn extend>(&mut self, mut iter: Iter) { diff --git a/src/libcollections/bit.rs b/src/libcollections/bit.rs index c627574057969..d676cfca9294e 100644 --- a/src/libcollections/bit.rs +++ b/src/libcollections/bit.rs @@ -89,7 +89,7 @@ use core::fmt; use core::hash; use core::iter::RandomAccessIterator; use core::iter::{Chain, Enumerate, Repeat, Skip, Take, repeat, Cloned}; -use core::iter::{self, FromIterator}; +use core::iter::{self, FromIterator, IntoIterator}; use core::num::Int; use core::ops::Index; use core::slice; @@ -1070,6 +1070,14 @@ impl<'a> RandomAccessIterator for Iter<'a> { } } +impl<'a> IntoIterator for &'a Bitv { + type Iter = Iter<'a>; + + fn into_iter(self) -> Iter<'a> { + self.iter() + } +} + /// An implementation of a set using a bit vector as an underlying /// representation for holding unsigned numerical elements. /// @@ -1873,6 +1881,13 @@ impl<'a> Iterator for SymmetricDifference<'a> { #[inline] fn size_hint(&self) -> (uint, Option) { self.0.size_hint() } } +impl<'a> IntoIterator for &'a BitvSet { + type Iter = SetIter<'a>; + + fn into_iter(self) -> SetIter<'a> { + self.iter() + } +} #[cfg(test)] mod tests { diff --git a/src/libcollections/btree/map.rs b/src/libcollections/btree/map.rs index 4f2c2cb60287e..27783ff941a41 100644 --- a/src/libcollections/btree/map.rs +++ b/src/libcollections/btree/map.rs @@ -24,7 +24,7 @@ use core::cmp::Ordering; use core::default::Default; use core::fmt::Debug; use core::hash::{Hash, Hasher}; -use core::iter::{Map, FromIterator}; +use core::iter::{Map, FromIterator, IntoIterator}; use core::ops::{Index, IndexMut}; use core::{iter, fmt, mem}; use Bound::{self, Included, Excluded, Unbounded}; @@ -478,6 +478,30 @@ impl BTreeMap { } } +impl IntoIterator for BTreeMap { + type Iter = IntoIter; + + fn into_iter(self) -> IntoIter { + self.into_iter() + } +} + +impl<'a, K, V> IntoIterator for &'a BTreeMap { + type Iter = Iter<'a, K, V>; + + fn into_iter(self) -> Iter<'a, K, V> { + self.iter() + } +} + +impl<'a, K, V> IntoIterator for &'a mut BTreeMap { + type Iter = IterMut<'a, K, V>; + + fn into_iter(mut self) -> IterMut<'a, K, V> { + self.iter_mut() + } +} + /// A helper enum useful for deciding whether to continue a loop since we can't /// return from a closure enum Continuation { diff --git a/src/libcollections/btree/node.rs b/src/libcollections/btree/node.rs index ea167348a644c..8d6f06b25c5be 100644 --- a/src/libcollections/btree/node.rs +++ b/src/libcollections/btree/node.rs @@ -271,7 +271,7 @@ impl DoubleEndedIterator for RawItems { #[unsafe_destructor] impl Drop for RawItems { fn drop(&mut self) { - for _ in *self {} + for _ in self.by_ref() {} } } @@ -1374,9 +1374,9 @@ impl Drop for MoveTraversalImpl { fn drop(&mut self) { // We need to cleanup the stored values manually, as the RawItems destructor would run // after our deallocation. - for _ in self.keys {} - for _ in self.vals {} - for _ in self.edges {} + for _ in self.keys.by_ref() {} + for _ in self.vals.by_ref() {} + for _ in self.edges.by_ref() {} let (alignment, size) = calculate_allocation_generic::(self.capacity, self.is_leaf); diff --git a/src/libcollections/btree/set.rs b/src/libcollections/btree/set.rs index a090e4f24ce1d..e6d7d2a37eb78 100644 --- a/src/libcollections/btree/set.rs +++ b/src/libcollections/btree/set.rs @@ -18,7 +18,7 @@ use core::cmp::Ordering::{self, Less, Greater, Equal}; use core::default::Default; use core::fmt::Debug; use core::fmt; -use core::iter::{Peekable, Map, FromIterator}; +use core::iter::{Peekable, Map, FromIterator, IntoIterator}; use core::ops::{BitOr, BitAnd, BitXor, Sub}; use btree_map::{BTreeMap, Keys}; @@ -480,6 +480,22 @@ impl FromIterator for BTreeSet { } } +impl IntoIterator for BTreeSet { + type Iter = IntoIter; + + fn into_iter(self) -> IntoIter { + self.into_iter() + } +} + +impl<'a, T> IntoIterator for &'a BTreeSet { + type Iter = Iter<'a, T>; + + fn into_iter(self) -> Iter<'a, T> { + self.iter() + } +} + #[stable(feature = "rust1", since = "1.0.0")] impl Extend for BTreeSet { #[inline] diff --git a/src/libcollections/dlist.rs b/src/libcollections/dlist.rs index aded4b8a7ac9e..48bf820e6f6a2 100644 --- a/src/libcollections/dlist.rs +++ b/src/libcollections/dlist.rs @@ -28,7 +28,7 @@ use core::cmp::Ordering; use core::default::Default; use core::fmt; use core::hash::{Writer, Hasher, Hash}; -use core::iter::{self, FromIterator}; +use core::iter::{self, FromIterator, IntoIterator}; use core::mem; use core::ptr; @@ -830,6 +830,30 @@ impl FromIterator for DList { } } +impl IntoIterator for DList { + type Iter = IntoIter; + + fn into_iter(self) -> IntoIter { + self.into_iter() + } +} + +impl<'a, T> IntoIterator for &'a DList { + type Iter = Iter<'a, T>; + + fn into_iter(self) -> Iter<'a, T> { + self.iter() + } +} + +impl<'a, T> IntoIterator for &'a mut DList { + type Iter = IterMut<'a, T>; + + fn into_iter(mut self) -> IterMut<'a, T> { + self.iter_mut() + } +} + #[stable(feature = "rust1", since = "1.0.0")] impl Extend for DList { fn extend>(&mut self, mut iterator: T) { diff --git a/src/libcollections/enum_set.rs b/src/libcollections/enum_set.rs index b542259eba0dd..a9e64a5c282ea 100644 --- a/src/libcollections/enum_set.rs +++ b/src/libcollections/enum_set.rs @@ -16,7 +16,7 @@ use core::prelude::*; use core::fmt; use core::num::Int; -use core::iter::FromIterator; +use core::iter::{FromIterator, IntoIterator}; use core::ops::{Sub, BitOr, BitAnd, BitXor}; // FIXME(contentions): implement union family of methods? (general design may be wrong here) @@ -256,6 +256,14 @@ impl FromIterator for EnumSet { } } +impl<'a, E> IntoIterator for &'a EnumSet where E: CLike { + type Iter = Iter; + + fn into_iter(self) -> Iter { + self.iter() + } +} + impl Extend for EnumSet { fn extend>(&mut self, mut iterator: I) { for element in iterator { diff --git a/src/libcollections/lib.rs b/src/libcollections/lib.rs index 82b92d26d28bc..f28262dc0fea7 100644 --- a/src/libcollections/lib.rs +++ b/src/libcollections/lib.rs @@ -34,6 +34,8 @@ #![feature(unicode)] #![feature(hash)] #![cfg_attr(test, feature(test))] +// NOTE(stage0): remove after a snapshot +#![cfg_attr(not(stage0), allow(unused_mut))] #[macro_use] extern crate core; @@ -114,6 +116,8 @@ mod std { pub use core::marker; // derive(Copy) pub use core::hash; // derive(Hash) pub use core::ops; // RangeFull + // for-loops + pub use core::iter; } #[cfg(test)] diff --git a/src/libcollections/ring_buf.rs b/src/libcollections/ring_buf.rs index 34910f59fe036..a19b3c221b1ef 100644 --- a/src/libcollections/ring_buf.rs +++ b/src/libcollections/ring_buf.rs @@ -19,7 +19,7 @@ use core::prelude::*; use core::cmp::Ordering; use core::default::Default; use core::fmt; -use core::iter::{self, repeat, FromIterator, RandomAccessIterator}; +use core::iter::{self, repeat, FromIterator, IntoIterator, RandomAccessIterator}; use core::marker; use core::mem; use core::num::{Int, UnsignedInt}; @@ -1510,7 +1510,7 @@ pub struct Drain<'a, T: 'a> { #[stable(feature = "rust1", since = "1.0.0")] impl<'a, T: 'a> Drop for Drain<'a, T> { fn drop(&mut self) { - for _ in *self {} + for _ in self.by_ref() {} self.inner.head = 0; self.inner.tail = 0; } @@ -1609,6 +1609,30 @@ impl FromIterator for RingBuf { } } +impl IntoIterator for RingBuf { + type Iter = IntoIter; + + fn into_iter(self) -> IntoIter { + self.into_iter() + } +} + +impl<'a, T> IntoIterator for &'a RingBuf { + type Iter = Iter<'a, T>; + + fn into_iter(self) -> Iter<'a, T> { + self.iter() + } +} + +impl<'a, T> IntoIterator for &'a mut RingBuf { + type Iter = IterMut<'a, T>; + + fn into_iter(mut self) -> IterMut<'a, T> { + self.iter_mut() + } +} + #[stable(feature = "rust1", since = "1.0.0")] impl Extend for RingBuf { fn extend>(&mut self, mut iterator: T) { diff --git a/src/libcollections/slice.rs b/src/libcollections/slice.rs index 56d969b89466c..57ee4704a9ee0 100644 --- a/src/libcollections/slice.rs +++ b/src/libcollections/slice.rs @@ -1958,7 +1958,7 @@ mod tests { let mut amt = 0; let mut it = v.permutations(); let (min_size, max_opt) = it.size_hint(); - for _perm in it { + for _perm in it.by_ref() { amt += 1; } assert_eq!(amt, it.swaps.swaps_made); diff --git a/src/libcollections/str.rs b/src/libcollections/str.rs index 35591a5e9effb..d6ee4dc5f6742 100644 --- a/src/libcollections/str.rs +++ b/src/libcollections/str.rs @@ -199,7 +199,7 @@ impl<'a> Iterator for Decompositions<'a> { } if !self.sorted { - for ch in self.iter { + for ch in self.iter.by_ref() { let buffer = &mut self.buffer; let sorted = &mut self.sorted; { @@ -279,7 +279,7 @@ impl<'a> Iterator for Recompositions<'a> { loop { match self.state { Composing => { - for ch in self.iter { + for ch in self.iter.by_ref() { let ch_class = unicode::char::canonical_combining_class(ch); if self.composee.is_none() { if ch_class != 0 { @@ -2154,7 +2154,7 @@ mod tests { let s = "ศไทย中华Việt Nam"; let mut it = s.chars(); it.next(); - assert!(it.zip(it.clone()).all(|(x,y)| x == y)); + assert!(it.clone().zip(it).all(|(x,y)| x == y)); } #[test] diff --git a/src/libcollections/vec.rs b/src/libcollections/vec.rs index 5dd88dbb02524..1d20d39b11512 100644 --- a/src/libcollections/vec.rs +++ b/src/libcollections/vec.rs @@ -56,7 +56,7 @@ use core::cmp::{Ordering}; use core::default::Default; use core::fmt; use core::hash::{self, Hash}; -use core::iter::{repeat, FromIterator}; +use core::iter::{repeat, FromIterator, IntoIterator}; use core::marker::{ContravariantLifetime, InvariantType}; use core::mem; use core::nonzero::NonZero; @@ -65,6 +65,7 @@ use core::ops::{Index, IndexMut, Deref, Add}; use core::ops; use core::ptr; use core::raw::Slice as RawSlice; +use core::slice; use core::uint; /// A growable list type, written `Vec` but pronounced 'vector.' @@ -1404,6 +1405,30 @@ impl FromIterator for Vec { } } +impl IntoIterator for Vec { + type Iter = IntoIter; + + fn into_iter(self) -> IntoIter { + self.into_iter() + } +} + +impl<'a, T> IntoIterator for &'a Vec { + type Iter = slice::Iter<'a, T>; + + fn into_iter(self) -> slice::Iter<'a, T> { + self.iter() + } +} + +impl<'a, T> IntoIterator for &'a mut Vec { + type Iter = slice::IterMut<'a, T>; + + fn into_iter(mut self) -> slice::IterMut<'a, T> { + self.iter_mut() + } +} + #[unstable(feature = "collections", reason = "waiting on Extend stability")] impl Extend for Vec { #[inline] @@ -1623,7 +1648,7 @@ impl IntoIter { #[unstable(feature = "collections")] pub fn into_inner(mut self) -> Vec { unsafe { - for _x in self { } + for _x in self.by_ref() { } let IntoIter { allocation, cap, ptr: _ptr, end: _end } = self; mem::forget(self); Vec { ptr: NonZero::new(allocation), cap: cap, len: 0 } @@ -1701,7 +1726,7 @@ impl Drop for IntoIter { fn drop(&mut self) { // destroy the remaining elements if self.cap != 0 { - for _x in *self {} + for _x in self.by_ref() {} unsafe { dealloc(self.allocation, self.cap); } @@ -1791,7 +1816,7 @@ impl<'a, T> Drop for Drain<'a, T> { // so we can use #[unsafe_no_drop_flag]. // destroy the remaining elements - for _x in *self {} + for _x in self.by_ref() {} } } diff --git a/src/libcollections/vec_map.rs b/src/libcollections/vec_map.rs index 9f83b91fc9bbd..2846414bb9acc 100644 --- a/src/libcollections/vec_map.rs +++ b/src/libcollections/vec_map.rs @@ -19,7 +19,7 @@ use core::cmp::Ordering; use core::default::Default; use core::fmt; use core::hash::{Hash, Writer, Hasher}; -use core::iter::{Enumerate, FilterMap, Map, FromIterator}; +use core::iter::{Enumerate, FilterMap, Map, FromIterator, IntoIterator}; use core::iter; use core::mem::replace; use core::ops::{Index, IndexMut}; @@ -536,6 +536,30 @@ impl FromIterator<(uint, V)> for VecMap { } } +impl IntoIterator for VecMap { + type Iter = IntoIter; + + fn into_iter(self) -> IntoIter { + self.into_iter() + } +} + +impl<'a, T> IntoIterator for &'a VecMap { + type Iter = Iter<'a, T>; + + fn into_iter(self) -> Iter<'a, T> { + self.iter() + } +} + +impl<'a, T> IntoIterator for &'a mut VecMap { + type Iter = IterMut<'a, T>; + + fn into_iter(mut self) -> IterMut<'a, T> { + self.iter_mut() + } +} + #[stable(feature = "rust1", since = "1.0.0")] impl Extend<(uint, V)> for VecMap { fn extend>(&mut self, mut iter: Iter) { diff --git a/src/libcore/array.rs b/src/libcore/array.rs index a81615944fb46..ec3d9783255cb 100644 --- a/src/libcore/array.rs +++ b/src/libcore/array.rs @@ -18,12 +18,14 @@ use clone::Clone; use cmp::{PartialEq, Eq, PartialOrd, Ord, Ordering}; use fmt; use hash::{Hash, Hasher, self}; +use iter::IntoIterator; use marker::Copy; #[cfg(stage0)] use ops::{Deref, FullRange}; #[cfg(not(stage0))] use ops::Deref; use option::Option; +use slice::{Iter, IterMut, SliceExt}; // macro for implementing n-ary tuple functions and operations macro_rules! array_impls { @@ -49,6 +51,22 @@ macro_rules! array_impls { } } + impl<'a, T> IntoIterator for &'a [T; $N] { + type Iter = Iter<'a, T>; + + fn into_iter(self) -> Iter<'a, T> { + self.iter() + } + } + + impl<'a, T> IntoIterator for &'a mut [T; $N] { + type Iter = IterMut<'a, T>; + + fn into_iter(self) -> IterMut<'a, T> { + self.iter_mut() + } + } + #[stable(feature = "rust1", since = "1.0.0")] impl PartialEq<[B; $N]> for [A; $N] where A: PartialEq { #[inline] diff --git a/src/libcore/iter.rs b/src/libcore/iter.rs index b6b2f9c57fe7b..b0906651da803 100644 --- a/src/libcore/iter.rs +++ b/src/libcore/iter.rs @@ -122,6 +122,22 @@ pub trait FromIterator { fn from_iter>(iterator: T) -> Self; } +/// Conversion into an `Iterator` +pub trait IntoIterator { + type Iter: Iterator; + + /// Consumes `Self` and returns an iterator over it + fn into_iter(self) -> Self::Iter; +} + +impl IntoIterator for I where I: Iterator { + type Iter = I; + + fn into_iter(self) -> I { + self + } +} + /// A type growable from an `Iterator` implementation #[stable(feature = "rust1", since = "1.0.0")] pub trait Extend { @@ -178,7 +194,7 @@ pub trait IteratorExt: Iterator + Sized { #[inline] #[stable(feature = "rust1", since = "1.0.0")] fn nth(&mut self, mut n: usize) -> Option { - for x in *self { + for x in self.by_ref() { if n == 0 { return Some(x) } n -= 1; } @@ -475,7 +491,7 @@ pub trait IteratorExt: Iterator + Sized { /// fn process>(it: U) -> isize { /// let mut it = it.fuse(); /// let mut sum = 0; - /// for x in it { + /// for x in it.by_ref() { /// if x > 5 { /// break; /// } @@ -643,7 +659,7 @@ pub trait IteratorExt: Iterator + Sized { #[inline] #[stable(feature = "rust1", since = "1.0.0")] fn any(&mut self, mut f: F) -> bool where F: FnMut(Self::Item) -> bool { - for x in *self { if f(x) { return true; } } + for x in self.by_ref() { if f(x) { return true; } } false } @@ -663,7 +679,7 @@ pub trait IteratorExt: Iterator + Sized { fn find

(&mut self, mut predicate: P) -> Option where P: FnMut(&Self::Item) -> bool, { - for x in *self { + for x in self.by_ref() { if predicate(&x) { return Some(x) } } None @@ -686,7 +702,7 @@ pub trait IteratorExt: Iterator + Sized { P: FnMut(Self::Item) -> bool, { let mut i = 0; - for x in *self { + for x in self.by_ref() { if predicate(x) { return Some(i); } @@ -1312,7 +1328,7 @@ impl ExactSizeIterator for Cloned where {} /// An iterator that repeats endlessly -#[derive(Clone, Copy)] +#[derive(Clone)] #[must_use = "iterator adaptors are lazy and do nothing unless consumed"] #[stable(feature = "rust1", since = "1.0.0")] pub struct Cycle { @@ -1647,7 +1663,7 @@ impl Iterator for Filter where I: Iterator, P: FnMut(& #[inline] fn next(&mut self) -> Option { - for x in self.iter { + for x in self.iter.by_ref() { if (self.predicate)(&x) { return Some(x); } else { @@ -1711,7 +1727,7 @@ impl Iterator for FilterMap where #[inline] fn next(&mut self) -> Option { - for x in self.iter { + for x in self.iter.by_ref() { match (self.f)(x) { Some(y) => return Some(y), None => () @@ -1810,7 +1826,6 @@ impl RandomAccessIterator for Enumerate where I: RandomAccessIterator { /// An iterator with a `peek()` that returns an optional reference to the next element. #[must_use = "iterator adaptors are lazy and do nothing unless consumed"] #[stable(feature = "rust1", since = "1.0.0")] -#[derive(Copy)] pub struct Peekable where I: Iterator { iter: I, peeked: Option, @@ -1897,7 +1912,7 @@ impl Iterator for SkipWhile where I: Iterator, P: FnMu #[inline] fn next(&mut self) -> Option { - for x in self.iter { + for x in self.iter.by_ref() { if self.flag || !(self.predicate)(&x) { self.flag = true; return Some(x); @@ -2190,7 +2205,7 @@ impl Iterator for FlatMap where fn next(&mut self) -> Option { loop { for inner in self.frontiter.iter_mut() { - for x in *inner { + for x in inner.by_ref() { return Some(x) } } @@ -2484,7 +2499,7 @@ impl Iterator for Unfold where F: FnMut(&mut St) -> Option { @@ -2520,7 +2535,7 @@ impl + Clone> Iterator for Counter { } /// An iterator over the range [start, stop) -#[derive(Clone, Copy)] +#[derive(Clone)] #[unstable(feature = "core", reason = "will be replaced by range notation")] pub struct Range { diff --git a/src/libcore/lib.rs b/src/libcore/lib.rs index 1032c56fa22ad..353d4252dfb05 100644 --- a/src/libcore/lib.rs +++ b/src/libcore/lib.rs @@ -65,6 +65,8 @@ #![allow(unknown_features)] #![feature(int_uint)] #![feature(on_unimplemented)] #![deny(missing_docs)] +// NOTE(stage0) remove cfg_attr after a snapshot +#![cfg_attr(not(stage0), allow(unused_mut))] #[macro_use] mod macros; @@ -158,4 +160,6 @@ mod std { pub use marker; pub use ops; pub use option; + // for-loops + pub use iter; } diff --git a/src/libcore/num/mod.rs b/src/libcore/num/mod.rs index dd9cc553c7c8f..1be7a0fb066b5 100644 --- a/src/libcore/num/mod.rs +++ b/src/libcore/num/mod.rs @@ -1524,7 +1524,7 @@ macro_rules! from_str_radix_float_impl { let mut exp_info = None::<(char, uint)>; // Parse the integer part of the significand - for (i, c) in cs { + for (i, c) in cs.by_ref() { match c.to_digit(radix) { Some(digit) => { // shift significand one digit left @@ -1572,7 +1572,7 @@ macro_rules! from_str_radix_float_impl { // part of the significand if exp_info.is_none() { let mut power = 1.0; - for (i, c) in cs { + for (i, c) in cs.by_ref() { match c.to_digit(radix) { Some(digit) => { // Decrease power one order of magnitude diff --git a/src/libcore/slice.rs b/src/libcore/slice.rs index 40e66db3ae5b0..a368ddba9bc30 100644 --- a/src/libcore/slice.rs +++ b/src/libcore/slice.rs @@ -41,7 +41,6 @@ use cmp::Ordering::{Less, Equal, Greater}; use cmp; use default::Default; use iter::*; -use marker::Copy; use num::Int; use ops::{FnMut, self, Index}; #[cfg(stage0)] @@ -637,6 +636,22 @@ impl<'a, T> Default for &'a [T] { // Iterators // +impl<'a, T> IntoIterator for &'a [T] { + type Iter = Iter<'a, T>; + + fn into_iter(self) -> Iter<'a, T> { + self.iter() + } +} + +impl<'a, T> IntoIterator for &'a mut [T] { + type Iter = IterMut<'a, T>; + + fn into_iter(self) -> IterMut<'a, T> { + self.iter_mut() + } +} + // The shared definition of the `Iter` and `IterMut` iterators macro_rules! iterator { (struct $name:ident -> $ptr:ty, $elem:ty) => { @@ -784,8 +799,6 @@ impl<'a, T> Iter<'a, T> { } } -impl<'a,T> Copy for Iter<'a,T> {} - iterator!{struct Iter -> *const T, &'a T} #[stable(feature = "rust1", since = "1.0.0")] @@ -793,7 +806,7 @@ impl<'a, T> ExactSizeIterator 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> { *self } + fn clone(&self) -> Iter<'a, T> { Iter { ptr: self.ptr, end: self.end, marker: self.marker } } } #[unstable(feature = "core", reason = "trait is experimental")] diff --git a/src/libcore/str/mod.rs b/src/libcore/str/mod.rs index 8495a03747e7b..f545c56a060ca 100644 --- a/src/libcore/str/mod.rs +++ b/src/libcore/str/mod.rs @@ -18,6 +18,7 @@ use self::Searcher::{Naive, TwoWay, TwoWayLong}; +use clone::Clone; use cmp::{self, Eq}; use default::Default; use error::Error; @@ -279,7 +280,7 @@ Section: Iterators /// Iterator for the char (representing *Unicode Scalar Values*) of a string /// /// Created with the method `.chars()`. -#[derive(Clone, Copy)] +#[derive(Clone)] #[stable(feature = "rust1", since = "1.0.0")] pub struct Chars<'a> { iter: slice::Iter<'a, u8> @@ -1007,11 +1008,11 @@ fn run_utf8_validation_iterator(iter: &mut slice::Iter) let whole = iter.as_slice(); loop { // save the current thing we're pointing at. - let old = *iter; + let old = iter.clone(); // restore the iterator we had at the start of this codepoint. macro_rules! err { () => {{ - *iter = old; + *iter = old.clone(); return Err(Utf8Error::InvalidByte(whole.len() - iter.as_slice().len())) }}} diff --git a/src/libcoretest/iter.rs b/src/libcoretest/iter.rs index 8bcd4982fba5d..2590b20450218 100644 --- a/src/libcoretest/iter.rs +++ b/src/libcoretest/iter.rs @@ -366,32 +366,32 @@ fn test_iterator_size_hint() { let vi = v.iter(); assert_eq!(c.size_hint(), (uint::MAX, None)); - assert_eq!(vi.size_hint(), (10, Some(10))); - - assert_eq!(c.take(5).size_hint(), (5, Some(5))); - assert_eq!(c.skip(5).size_hint().1, None); - assert_eq!(c.take_while(|_| false).size_hint(), (0, None)); - assert_eq!(c.skip_while(|_| false).size_hint(), (0, None)); - assert_eq!(c.enumerate().size_hint(), (uint::MAX, None)); - assert_eq!(c.chain(vi.map(|&i| i)).size_hint(), (uint::MAX, None)); - assert_eq!(c.zip(vi).size_hint(), (10, Some(10))); - assert_eq!(c.scan(0i, |_,_| Some(0i)).size_hint(), (0, None)); - assert_eq!(c.filter(|_| false).size_hint(), (0, None)); - assert_eq!(c.map(|_| 0i).size_hint(), (uint::MAX, None)); + assert_eq!(vi.clone().size_hint(), (10, Some(10))); + + assert_eq!(c.clone().take(5).size_hint(), (5, Some(5))); + assert_eq!(c.clone().skip(5).size_hint().1, None); + assert_eq!(c.clone().take_while(|_| false).size_hint(), (0, None)); + assert_eq!(c.clone().skip_while(|_| false).size_hint(), (0, None)); + assert_eq!(c.clone().enumerate().size_hint(), (uint::MAX, None)); + assert_eq!(c.clone().chain(vi.clone().map(|&i| i)).size_hint(), (uint::MAX, None)); + assert_eq!(c.clone().zip(vi.clone()).size_hint(), (10, Some(10))); + assert_eq!(c.clone().scan(0i, |_,_| Some(0i)).size_hint(), (0, None)); + assert_eq!(c.clone().filter(|_| false).size_hint(), (0, None)); + assert_eq!(c.clone().map(|_| 0i).size_hint(), (uint::MAX, None)); assert_eq!(c.filter_map(|_| Some(0i)).size_hint(), (0, None)); - assert_eq!(vi.take(5).size_hint(), (5, Some(5))); - assert_eq!(vi.take(12).size_hint(), (10, Some(10))); - assert_eq!(vi.skip(3).size_hint(), (7, Some(7))); - assert_eq!(vi.skip(12).size_hint(), (0, Some(0))); - assert_eq!(vi.take_while(|_| false).size_hint(), (0, Some(10))); - assert_eq!(vi.skip_while(|_| false).size_hint(), (0, Some(10))); - assert_eq!(vi.enumerate().size_hint(), (10, Some(10))); - assert_eq!(vi.chain(v2.iter()).size_hint(), (13, Some(13))); - assert_eq!(vi.zip(v2.iter()).size_hint(), (3, Some(3))); - assert_eq!(vi.scan(0i, |_,_| Some(0i)).size_hint(), (0, Some(10))); - assert_eq!(vi.filter(|_| false).size_hint(), (0, Some(10))); - assert_eq!(vi.map(|&i| i+1).size_hint(), (10, Some(10))); + assert_eq!(vi.clone().take(5).size_hint(), (5, Some(5))); + assert_eq!(vi.clone().take(12).size_hint(), (10, Some(10))); + assert_eq!(vi.clone().skip(3).size_hint(), (7, Some(7))); + assert_eq!(vi.clone().skip(12).size_hint(), (0, Some(0))); + assert_eq!(vi.clone().take_while(|_| false).size_hint(), (0, Some(10))); + assert_eq!(vi.clone().skip_while(|_| false).size_hint(), (0, Some(10))); + assert_eq!(vi.clone().enumerate().size_hint(), (10, Some(10))); + assert_eq!(vi.clone().chain(v2.iter()).size_hint(), (13, Some(13))); + assert_eq!(vi.clone().zip(v2.iter()).size_hint(), (3, Some(3))); + assert_eq!(vi.clone().scan(0i, |_,_| Some(0i)).size_hint(), (0, Some(10))); + assert_eq!(vi.clone().filter(|_| false).size_hint(), (0, Some(10))); + assert_eq!(vi.clone().map(|&i| i+1).size_hint(), (10, Some(10))); assert_eq!(vi.filter_map(|_| Some(0i)).size_hint(), (0, Some(10))); } @@ -904,7 +904,7 @@ fn bench_multiple_take(b: &mut Bencher) { b.iter(|| { let n = it.next().unwrap(); for _ in 0u..n { - it.take(it.next().unwrap()).all(|_| true); + it.clone().take(it.next().unwrap()).all(|_| true); } }); } diff --git a/src/librand/lib.rs b/src/librand/lib.rs index 762581518505f..8c50550a6e84c 100644 --- a/src/librand/lib.rs +++ b/src/librand/lib.rs @@ -498,6 +498,8 @@ mod std { pub use core::{option, fmt}; // panic!() pub use core::clone; // derive Clone pub use core::marker; + // for-loops + pub use core::iter; } #[cfg(test)] diff --git a/src/librustc/lib.rs b/src/librustc/lib.rs index 580e55f78a9e5..a38e8bb45361e 100644 --- a/src/librustc/lib.rs +++ b/src/librustc/lib.rs @@ -41,6 +41,8 @@ #![feature(unicode)] #![feature(hash)] #![cfg_attr(test, feature(test))] +// NOTE(stage0) remove cfg_attr after a snapshot +#![cfg_attr(not(stage0), allow(unused_mut))] extern crate arena; extern crate flate; diff --git a/src/librustc/lint/builtin.rs b/src/librustc/lint/builtin.rs index f13814527cdfd..e594d462ff385 100644 --- a/src/librustc/lint/builtin.rs +++ b/src/librustc/lint/builtin.rs @@ -1163,6 +1163,7 @@ impl LintPass for UnusedParens { ast::MatchSource::Normal => (head, "`match` head expression", true), ast::MatchSource::IfLetDesugar { .. } => (head, "`if let` head expression", true), ast::MatchSource::WhileLetDesugar => (head, "`while let` head expression", true), + ast::MatchSource::ForLoopDesugar => (head, "`for` head expression", true), }, ast::ExprRet(Some(ref value)) => (value, "`return` value", false), ast::ExprAssign(_, ref value) => (value, "assigned value", false), diff --git a/src/librustc/middle/cfg/construct.rs b/src/librustc/middle/cfg/construct.rs index 6162f61fde1c7..0a575a31eadc0 100644 --- a/src/librustc/middle/cfg/construct.rs +++ b/src/librustc/middle/cfg/construct.rs @@ -263,43 +263,8 @@ impl<'a, 'tcx> CFGBuilder<'a, 'tcx> { self.tcx.sess.span_bug(expr.span, "non-desugared ExprWhileLet"); } - ast::ExprForLoop(ref pat, ref head, ref body, _) => { - // - // [pred] - // | - // v 1 - // [head] - // | - // v 2 - // [loopback] <--+ 7 - // | | - // v 3 | - // +------[cond] | - // | | | - // | v 5 | - // | [pat] | - // | | | - // | v 6 | - // v 4 [body] -----+ - // [expr] - // - // Note that `break` and `continue` statements - // may cause additional edges. - - let head = self.expr(&**head, pred); // 1 - let loopback = self.add_dummy_node(&[head]); // 2 - let cond = self.add_dummy_node(&[loopback]); // 3 - let expr_exit = self.add_node(expr.id, &[cond]); // 4 - self.loop_scopes.push(LoopScope { - loop_id: expr.id, - continue_index: loopback, - break_index: expr_exit, - }); - let pat = self.pat(&**pat, cond); // 5 - let body = self.block(&**body, pat); // 6 - self.add_contained_edge(body, loopback); // 7 - self.loop_scopes.pop(); - expr_exit + ast::ExprForLoop(..) => { + self.tcx.sess.span_bug(expr.span, "non-desugared ExprForLoop"); } ast::ExprLoop(ref body, _) => { diff --git a/src/librustc/middle/check_loop.rs b/src/librustc/middle/check_loop.rs index 623f3525d4a90..41ef55933cda2 100644 --- a/src/librustc/middle/check_loop.rs +++ b/src/librustc/middle/check_loop.rs @@ -45,10 +45,6 @@ impl<'a, 'v> Visitor<'v> for CheckLoopVisitor<'a> { ast::ExprLoop(ref b, _) => { self.with_context(Loop, |v| v.visit_block(&**b)); } - ast::ExprForLoop(_, ref e, ref b, _) => { - self.visit_expr(&**e); - self.with_context(Loop, |v| v.visit_block(&**b)); - } ast::ExprClosure(_, _, _, ref b) => { self.with_context(Closure, |v| v.visit_block(&**b)); } diff --git a/src/librustc/middle/check_match.rs b/src/librustc/middle/check_match.rs index fec7b51157d81..aded63336dcd5 100644 --- a/src/librustc/middle/check_match.rs +++ b/src/librustc/middle/check_match.rs @@ -221,21 +221,8 @@ fn check_expr(cx: &mut MatchCheckCtxt, ex: &ast::Expr) { .flat_map(|arm| arm.0.iter()) .map(|pat| vec![&**pat]) .collect(); - check_exhaustive(cx, ex.span, &matrix); + check_exhaustive(cx, ex.span, &matrix, source); }, - ast::ExprForLoop(ref pat, _, _, _) => { - let mut static_inliner = StaticInliner::new(cx.tcx); - is_refutable(cx, &*static_inliner.fold_pat((*pat).clone()), |uncovered_pat| { - span_err!(cx.tcx.sess, pat.span, E0297, - "refutable pattern in `for` loop binding: \ - `{}` not covered", - pat_to_string(uncovered_pat)); - }); - - // Check legality of move bindings. - check_legality_of_move_bindings(cx, false, slice::ref_slice(pat)); - check_legality_of_bindings_in_at_patterns(cx, &**pat); - } _ => () } } @@ -327,6 +314,14 @@ fn check_arms(cx: &MatchCheckCtxt, span_err!(cx.tcx.sess, span, E0165, "irrefutable while-let pattern"); }, + ast::MatchSource::ForLoopDesugar => { + // this is a bug, because on `match iter.next()` we cover + // `Some()` and `None`. It's impossible to have an unreachable + // pattern + // (see libsyntax/ext/expand.rs for the full expansion of a for loop) + cx.tcx.sess.span_bug(pat.span, "unreachable for-loop pattern") + }, + ast::MatchSource::Normal => { span_err!(cx.tcx.sess, pat.span, E0001, "unreachable pattern") }, @@ -351,7 +346,7 @@ fn raw_pat<'a>(p: &'a Pat) -> &'a Pat { } } -fn check_exhaustive(cx: &MatchCheckCtxt, sp: Span, matrix: &Matrix) { +fn check_exhaustive(cx: &MatchCheckCtxt, sp: Span, matrix: &Matrix, source: ast::MatchSource) { match is_useful(cx, matrix, &[DUMMY_WILD_PAT], ConstructWitness) { UsefulWithWitness(pats) => { let witness = match &pats[] { @@ -359,10 +354,29 @@ fn check_exhaustive(cx: &MatchCheckCtxt, sp: Span, matrix: &Matrix) { [] => DUMMY_WILD_PAT, _ => unreachable!() }; - span_err!(cx.tcx.sess, sp, E0004, - "non-exhaustive patterns: `{}` not covered", - pat_to_string(witness) - ); + match source { + ast::MatchSource::ForLoopDesugar => { + // `witness` has the form `Some()`, peel off the `Some` + let witness = match witness.node { + ast::PatEnum(_, Some(ref pats)) => match &pats[] { + [ref pat] => &**pat, + _ => unreachable!(), + }, + _ => unreachable!(), + }; + + span_err!(cx.tcx.sess, sp, E0297, + "refutable pattern in `for` loop binding: \ + `{}` not covered", + pat_to_string(witness)); + }, + _ => { + span_err!(cx.tcx.sess, sp, E0004, + "non-exhaustive patterns: `{}` not covered", + pat_to_string(witness) + ); + }, + } } NotUseful => { // This is good, wildcard pattern isn't reachable diff --git a/src/librustc/middle/expr_use_visitor.rs b/src/librustc/middle/expr_use_visitor.rs index 0d543ca7beb0c..a79e6fac0cc26 100644 --- a/src/librustc/middle/expr_use_visitor.rs +++ b/src/librustc/middle/expr_use_visitor.rs @@ -537,22 +537,8 @@ impl<'d,'t,'tcx,TYPER:mc::Typer<'tcx>> ExprUseVisitor<'d,'t,'tcx,TYPER> { self.tcx().sess.span_bug(expr.span, "non-desugared ExprWhileLet"); } - ast::ExprForLoop(ref pat, ref head, ref blk, _) => { - // The pattern lives as long as the block. - debug!("walk_expr for loop case: blk id={}", blk.id); - self.consume_expr(&**head); - - // Fetch the type of the value that the iteration yields to - // produce the pattern's categorized mutable type. - let pattern_type = return_if_err!(self.typer.node_ty(pat.id)); - let blk_scope = region::CodeExtent::from_node_id(blk.id); - let pat_cmt = self.mc.cat_rvalue(pat.id, - pat.span, - ty::ReScope(blk_scope), - pattern_type); - self.walk_irrefutable_pat(pat_cmt, &**pat); - - self.walk_block(&**blk); + ast::ExprForLoop(..) => { + self.tcx().sess.span_bug(expr.span, "non-desugared ExprForLoop"); } ast::ExprUnary(op, ref lhs) => { diff --git a/src/librustc/middle/lang_items.rs b/src/librustc/middle/lang_items.rs index 16d2c68ad60a9..29a615f2b4052 100644 --- a/src/librustc/middle/lang_items.rs +++ b/src/librustc/middle/lang_items.rs @@ -325,8 +325,6 @@ lets_do_this! { NonZeroItem, "non_zero", non_zero; - IteratorItem, "iterator", iterator; - StackExhaustedLangItem, "stack_exhausted", stack_exhausted; DebugTraitLangItem, "debug_trait", debug_trait; diff --git a/src/librustc/middle/liveness.rs b/src/librustc/middle/liveness.rs index f6a51004eb680..982bc41f06a84 100644 --- a/src/librustc/middle/liveness.rs +++ b/src/librustc/middle/liveness.rs @@ -135,8 +135,6 @@ enum LoopKind<'a> { LoopLoop, /// A `while` loop, with the given expression as condition. WhileLoop(&'a Expr), - /// A `for` loop, with the given pattern to bind. - ForLoop(&'a ast::Pat), } #[derive(Copy, PartialEq)] @@ -490,19 +488,8 @@ fn visit_expr(ir: &mut IrMaps, expr: &Expr) { ast::ExprWhileLet(..) => { ir.tcx.sess.span_bug(expr.span, "non-desugared ExprWhileLet"); } - ast::ExprForLoop(ref pat, _, _, _) => { - pat_util::pat_bindings(&ir.tcx.def_map, &**pat, |bm, p_id, sp, path1| { - debug!("adding local variable {} from for loop with bm {:?}", - p_id, bm); - let name = path1.node; - ir.add_live_node_for_node(p_id, VarDefNode(sp)); - ir.add_variable(Local(LocalInfo { - id: p_id, - ident: name - })); - }); - ir.add_live_node_for_node(expr.id, ExprNode(expr.span)); - visit::walk_expr(ir, expr); + ast::ExprForLoop(..) => { + ir.tcx.sess.span_bug(expr.span, "non-desugared ExprForLoop"); } ast::ExprBinary(op, _, _) if ast_util::lazy_binop(op.node) => { ir.add_live_node_for_node(expr.id, ExprNode(expr.span)); @@ -1034,9 +1021,8 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> { self.ir.tcx.sess.span_bug(expr.span, "non-desugared ExprWhileLet"); } - ast::ExprForLoop(ref pat, ref head, ref blk, _) => { - let ln = self.propagate_through_loop(expr, ForLoop(&**pat), &**blk, succ); - self.propagate_through_expr(&**head, ln) + ast::ExprForLoop(..) => { + self.ir.tcx.sess.span_bug(expr.span, "non-desugared ExprForLoop"); } // Note that labels have been resolved, so we don't need to look @@ -1373,7 +1359,6 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> { let cond_ln = match kind { LoopLoop => ln, - ForLoop(ref pat) => self.define_bindings_in_pat(*pat, ln), WhileLoop(ref cond) => self.propagate_through_expr(&**cond, ln), }; let body_ln = self.with_loop_nodes(expr.id, succ, ln, |this| { @@ -1386,9 +1371,6 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> { let new_cond_ln = match kind { LoopLoop => ln, - ForLoop(ref pat) => { - self.define_bindings_in_pat(*pat, ln) - } WhileLoop(ref cond) => { self.propagate_through_expr(&**cond, ln) } @@ -1476,14 +1458,6 @@ fn check_expr(this: &mut Liveness, expr: &Expr) { visit::walk_expr(this, expr); } - ast::ExprForLoop(ref pat, _, _, _) => { - this.pat_bindings(&**pat, |this, ln, var, sp, id| { - this.warn_about_unused(sp, id, ln, var); - }); - - visit::walk_expr(this, expr); - } - // no correctness conditions related to liveness ast::ExprCall(..) | ast::ExprMethodCall(..) | ast::ExprIf(..) | ast::ExprMatch(..) | ast::ExprWhile(..) | ast::ExprLoop(..) | @@ -1503,6 +1477,9 @@ fn check_expr(this: &mut Liveness, expr: &Expr) { ast::ExprWhileLet(..) => { this.ir.tcx.sess.span_bug(expr.span, "non-desugared ExprWhileLet"); } + ast::ExprForLoop(..) => { + this.ir.tcx.sess.span_bug(expr.span, "non-desugared ExprForLoop"); + } } } diff --git a/src/librustc/middle/mem_categorization.rs b/src/librustc/middle/mem_categorization.rs index 1be1bfa6730cd..7de6b70b15955 100644 --- a/src/librustc/middle/mem_categorization.rs +++ b/src/librustc/middle/mem_categorization.rs @@ -536,8 +536,7 @@ impl<'t,'tcx,TYPER:Typer<'tcx>> MemCategorizationContext<'t,TYPER> { ast::ExprBlock(..) | ast::ExprLoop(..) | ast::ExprMatch(..) | ast::ExprLit(..) | ast::ExprBreak(..) | ast::ExprMac(..) | ast::ExprAgain(..) | ast::ExprStruct(..) | ast::ExprRepeat(..) | - ast::ExprInlineAsm(..) | ast::ExprBox(..) | - ast::ExprForLoop(..) => { + ast::ExprInlineAsm(..) | ast::ExprBox(..) => { Ok(self.cat_rvalue_node(expr.id(), expr.span(), expr_ty)) } @@ -547,6 +546,9 @@ impl<'t,'tcx,TYPER:Typer<'tcx>> MemCategorizationContext<'t,TYPER> { ast::ExprWhileLet(..) => { self.tcx().sess.span_bug(expr.span, "non-desugared ExprWhileLet"); } + ast::ExprForLoop(..) => { + self.tcx().sess.span_bug(expr.span, "non-desugared ExprForLoop"); + } } } diff --git a/src/librustc/middle/region.rs b/src/librustc/middle/region.rs index 4e29e9b75e860..c70532dbb30cb 100644 --- a/src/librustc/middle/region.rs +++ b/src/librustc/middle/region.rs @@ -701,14 +701,6 @@ fn resolve_expr(visitor: &mut RegionResolutionVisitor, expr: &ast::Expr) { terminating(body.id); } - ast::ExprForLoop(ref _pat, ref _head, ref body, _) => { - terminating(body.id); - - // The variable parent of everything inside (most importantly, the - // pattern) is the body. - visitor.cx.var_parent = InnermostDeclaringBlock::Block(body.id); - } - ast::ExprMatch(..) => { visitor.cx.var_parent = InnermostDeclaringBlock::Match(expr.id); } diff --git a/src/librustc/middle/ty.rs b/src/librustc/middle/ty.rs index 44615f19d94aa..19b788a38e6f8 100644 --- a/src/librustc/middle/ty.rs +++ b/src/librustc/middle/ty.rs @@ -4493,9 +4493,6 @@ pub fn expr_kind(tcx: &ctxt, expr: &ast::Expr) -> ExprKind { // the index method invoked for `a[i]` always yields an `&T` ast::ExprIndex(..) => LvalueExpr, - // `for` loops are statements - ast::ExprForLoop(..) => RvalueStmtExpr, - // in the general case, result could be any type, use DPS _ => RvalueDpsExpr }; @@ -4582,6 +4579,10 @@ pub fn expr_kind(tcx: &ctxt, expr: &ast::Expr) -> ExprKind { tcx.sess.span_bug(expr.span, "non-desugared ExprWhileLet"); } + ast::ExprForLoop(..) => { + tcx.sess.span_bug(expr.span, "non-desugared ExprForLoop"); + } + ast::ExprLit(ref lit) if lit_is_str(&**lit) => { RvalueDpsExpr } @@ -4619,8 +4620,7 @@ pub fn expr_kind(tcx: &ctxt, expr: &ast::Expr) -> ExprKind { ast::ExprLoop(..) | ast::ExprAssign(..) | ast::ExprInlineAsm(..) | - ast::ExprAssignOp(..) | - ast::ExprForLoop(..) => { + ast::ExprAssignOp(..) => { RvalueStmtExpr } diff --git a/src/librustc/util/common.rs b/src/librustc/util/common.rs index cdaca497b904c..a433161d659e8 100644 --- a/src/librustc/util/common.rs +++ b/src/librustc/util/common.rs @@ -96,7 +96,7 @@ impl<'v, P> Visitor<'v> for LoopQueryVisitor

where P: FnMut(&ast::Expr_) -> b match e.node { // Skip inner loops, since a break in the inner loop isn't a // break inside the outer loop - ast::ExprLoop(..) | ast::ExprWhile(..) | ast::ExprForLoop(..) => {} + ast::ExprLoop(..) | ast::ExprWhile(..) => {} _ => visit::walk_expr(self, e) } } diff --git a/src/librustc/util/ppaux.rs b/src/librustc/util/ppaux.rs index 1be99a8e569f3..dd9a52aa70555 100644 --- a/src/librustc/util/ppaux.rs +++ b/src/librustc/util/ppaux.rs @@ -100,6 +100,7 @@ pub fn explain_region_and_span(cx: &ctxt, region: ty::Region) ast::ExprMethodCall(..) => "method call", ast::ExprMatch(_, _, ast::MatchSource::IfLetDesugar { .. }) => "if let", ast::ExprMatch(_, _, ast::MatchSource::WhileLetDesugar) => "while let", + ast::ExprMatch(_, _, ast::MatchSource::ForLoopDesugar) => "for", ast::ExprMatch(..) => "match", _ => "expression", }, diff --git a/src/librustc_back/svh.rs b/src/librustc_back/svh.rs index aef4f7a896ba2..3d7adc9934fb5 100644 --- a/src/librustc_back/svh.rs +++ b/src/librustc_back/svh.rs @@ -252,7 +252,6 @@ mod svh_visitor { SawExprStruct, SawExprRepeat, SawExprParen, - SawExprForLoop, } fn saw_expr<'a>(node: &'a Expr_) -> SawExprComponent<'a> { @@ -288,9 +287,9 @@ mod svh_visitor { ExprStruct(..) => SawExprStruct, ExprRepeat(..) => SawExprRepeat, ExprParen(..) => SawExprParen, - ExprForLoop(..) => SawExprForLoop, // just syntactic artifacts, expanded away by time of SVH. + ExprForLoop(..) => unreachable!(), ExprIfLet(..) => unreachable!(), ExprWhileLet(..) => unreachable!(), ExprMac(..) => unreachable!(), diff --git a/src/librustc_resolve/lib.rs b/src/librustc_resolve/lib.rs index 000426771a81a..89d36ef580101 100644 --- a/src/librustc_resolve/lib.rs +++ b/src/librustc_resolve/lib.rs @@ -68,7 +68,7 @@ use rustc::util::lev_distance::lev_distance; use syntax::ast::{Arm, BindByRef, BindByValue, BindingMode, Block, Crate, CrateNum}; use syntax::ast::{DefId, Expr, ExprAgain, ExprBreak, ExprField}; -use syntax::ast::{ExprClosure, ExprForLoop, ExprLoop, ExprWhile, ExprMethodCall}; +use syntax::ast::{ExprClosure, ExprLoop, ExprWhile, ExprMethodCall}; use syntax::ast::{ExprPath, ExprQPath, ExprStruct, FnDecl}; use syntax::ast::{ForeignItemFn, ForeignItemStatic, Generics}; use syntax::ast::{Ident, ImplItem, Item, ItemConst, ItemEnum, ItemExternCrate}; @@ -4562,39 +4562,6 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { }) } - ExprForLoop(ref pattern, ref head, ref body, optional_label) => { - self.resolve_expr(&**head); - - self.value_ribs.push(Rib::new(NormalRibKind)); - - self.resolve_pattern(&**pattern, - LocalIrrefutableMode, - &mut HashMap::new()); - - match optional_label { - None => {} - Some(label) => { - self.label_ribs - .push(Rib::new(NormalRibKind)); - let def_like = DlDef(DefLabel(expr.id)); - - { - let rib = self.label_ribs.last_mut().unwrap(); - let renamed = mtwt::resolve(label); - rib.bindings.insert(renamed, def_like); - } - } - } - - self.resolve_block(&**body); - - if optional_label.is_some() { - drop(self.label_ribs.pop()) - } - - self.value_ribs.pop(); - } - ExprBreak(Some(label)) | ExprAgain(Some(label)) => { let renamed = mtwt::resolve(label); match self.search_label(renamed) { diff --git a/src/librustc_trans/lib.rs b/src/librustc_trans/lib.rs index bb026e237df82..bee320c682922 100644 --- a/src/librustc_trans/lib.rs +++ b/src/librustc_trans/lib.rs @@ -41,6 +41,8 @@ #![feature(std_misc)] #![feature(unicode)] #![feature(hash)] +// NOTE(stage0) remove cfg_attr after a snapshot +#![cfg_attr(not(stage0), allow(unused_mut))] extern crate arena; extern crate flate; diff --git a/src/librustc_trans/trans/_match.rs b/src/librustc_trans/trans/_match.rs index 8d7eb5816c2b1..7074a970ba91c 100644 --- a/src/librustc_trans/trans/_match.rs +++ b/src/librustc_trans/trans/_match.rs @@ -1537,31 +1537,6 @@ pub fn store_arg<'blk, 'tcx>(mut bcx: Block<'blk, 'tcx>, } } -/// Generates code for the pattern binding in a `for` loop like -/// `for in { ... }`. -pub fn store_for_loop_binding<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, - pat: &ast::Pat, - llvalue: ValueRef, - body_scope: cleanup::ScopeId) - -> Block<'blk, 'tcx> { - let _icx = push_ctxt("match::store_for_loop_binding"); - - if simple_identifier(&*pat).is_some() && - bcx.sess().opts.debuginfo != FullDebugInfo { - // Generate nicer LLVM for the common case of a `for` loop pattern - // like `for x in blahblah { ... }`. - let binding_type = node_id_type(bcx, pat.id); - bcx.fcx.lllocals.borrow_mut().insert(pat.id, - Datum::new(llvalue, - binding_type, - Lvalue)); - return bcx - } - - // General path. Copy out the values that are used in the pattern. - bind_irrefutable_pat(bcx, pat, llvalue, body_scope) -} - fn mk_binding_alloca<'blk, 'tcx, A, F>(bcx: Block<'blk, 'tcx>, p_id: ast::NodeId, ident: &ast::Ident, diff --git a/src/librustc_trans/trans/controlflow.rs b/src/librustc_trans/trans/controlflow.rs index bea8a75997152..c4388603145fe 100644 --- a/src/librustc_trans/trans/controlflow.rs +++ b/src/librustc_trans/trans/controlflow.rs @@ -11,8 +11,6 @@ use llvm::ValueRef; use middle::def; use middle::lang_items::{PanicFnLangItem, PanicBoundsCheckFnLangItem}; -use trans::_match; -use trans::adt; use trans::base::*; use trans::build::*; use trans::callee; @@ -20,17 +18,12 @@ use trans::cleanup::CleanupMethods; use trans::cleanup; use trans::common::*; use trans::consts; -use trans::datum; use trans::debuginfo; use trans::debuginfo::{DebugLoc, ToDebugLoc}; use trans::expr; -use trans::meth; -use trans::type_::Type; use trans; use middle::ty; -use middle::ty::MethodCall; use util::ppaux::Repr; -use util::ppaux; use syntax::ast; use syntax::ast::Ident; @@ -259,135 +252,6 @@ pub fn trans_while<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, return next_bcx_in; } -/// Translates a `for` loop. -pub fn trans_for<'blk, 'tcx>(mut bcx: Block<'blk, 'tcx>, - loop_info: NodeIdAndSpan, - pat: &ast::Pat, - head: &ast::Expr, - body: &ast::Block) - -> Block<'blk, 'tcx> -{ - let _icx = push_ctxt("trans_for"); - - // bcx - // | - // loopback_bcx_in <-------+ - // | | - // loopback_bcx_out | - // | | | - // | body_bcx_in | - // cleanup_blk | | - // | body_bcx_out --+ - // next_bcx_in - - // Codegen the head to create the iterator value. - let iterator_datum = - unpack_datum!(bcx, expr::trans_to_lvalue(bcx, head, "for_head")); - let iterator_type = node_id_type(bcx, head.id); - debug!("iterator type is {}, datum type is {}", - ppaux::ty_to_string(bcx.tcx(), iterator_type), - ppaux::ty_to_string(bcx.tcx(), iterator_datum.ty)); - - let lliterator = load_ty(bcx, iterator_datum.val, iterator_datum.ty); - - // Create our basic blocks and set up our loop cleanups. - let next_bcx_in = bcx.fcx.new_id_block("for_exit", loop_info.id); - let loopback_bcx_in = bcx.fcx.new_id_block("for_loopback", head.id); - let body_bcx_in = bcx.fcx.new_id_block("for_body", body.id); - bcx.fcx.push_loop_cleanup_scope(loop_info.id, - [next_bcx_in, loopback_bcx_in]); - Br(bcx, loopback_bcx_in.llbb, DebugLoc::None); - let cleanup_llbb = bcx.fcx.normal_exit_block(loop_info.id, - cleanup::EXIT_BREAK); - - // Set up the method call (to `.next()`). - let method_call = MethodCall::expr(loop_info.id); - let method_type = (*loopback_bcx_in.tcx() - .method_map - .borrow())[method_call] - .ty; - let method_type = monomorphize_type(loopback_bcx_in, method_type); - let method_result_type = - ty::assert_no_late_bound_regions( // LB regions are instantiated in invoked methods - loopback_bcx_in.tcx(), &ty::ty_fn_ret(method_type)).unwrap(); - let option_cleanup_scope = body_bcx_in.fcx.push_custom_cleanup_scope(); - let option_cleanup_scope_id = cleanup::CustomScope(option_cleanup_scope); - - // Compile the method call (to `.next()`). - let mut loopback_bcx_out = loopback_bcx_in; - let option_datum = - unpack_datum!(loopback_bcx_out, - datum::lvalue_scratch_datum(loopback_bcx_out, - method_result_type, - "loop_option", - false, - option_cleanup_scope_id, - (), - |(), bcx, lloption| { - let Result { - bcx, - val: _ - } = callee::trans_call_inner(bcx, - Some(loop_info), - method_type, - |bcx, arg_cleanup_scope| { - meth::trans_method_callee( - bcx, - method_call, - None, - arg_cleanup_scope) - }, - callee::ArgVals(&[lliterator]), - Some(expr::SaveIn(lloption))); - bcx - })); - - // Check the discriminant; if the `None` case, exit the loop. - let option_representation = adt::represent_type(loopback_bcx_out.ccx(), - method_result_type); - let lldiscriminant = adt::trans_get_discr(loopback_bcx_out, - &*option_representation, - option_datum.val, - None); - let i1_type = Type::i1(loopback_bcx_out.ccx()); - let llcondition = Trunc(loopback_bcx_out, lldiscriminant, i1_type); - CondBr(loopback_bcx_out, llcondition, body_bcx_in.llbb, cleanup_llbb, DebugLoc::None); - - // Now we're in the body. Unpack the `Option` value into the programmer- - // supplied pattern. - let llpayload = adt::trans_field_ptr(body_bcx_in, - &*option_representation, - option_datum.val, - 1, - 0); - let binding_cleanup_scope = body_bcx_in.fcx.push_custom_cleanup_scope(); - let binding_cleanup_scope_id = - cleanup::CustomScope(binding_cleanup_scope); - let mut body_bcx_out = - _match::store_for_loop_binding(body_bcx_in, - pat, - llpayload, - binding_cleanup_scope_id); - - debuginfo::create_for_loop_var_metadata(body_bcx_in, pat); - - // Codegen the body. - body_bcx_out = trans_block(body_bcx_out, body, expr::Ignore); - body_bcx_out = - body_bcx_out.fcx - .pop_and_trans_custom_cleanup_scope(body_bcx_out, - binding_cleanup_scope); - body_bcx_out = - body_bcx_out.fcx - .pop_and_trans_custom_cleanup_scope(body_bcx_out, - option_cleanup_scope); - Br(body_bcx_out, loopback_bcx_in.llbb, DebugLoc::None); - - // Codegen cleanups and leave. - next_bcx_in.fcx.pop_loop_cleanup_scope(loop_info.id); - next_bcx_in -} - pub fn trans_loop<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, loop_expr: &ast::Expr, body: &ast::Block) diff --git a/src/librustc_trans/trans/debuginfo.rs b/src/librustc_trans/trans/debuginfo.rs index ce9af3162a089..4f9c97795e198 100644 --- a/src/librustc_trans/trans/debuginfo.rs +++ b/src/librustc_trans/trans/debuginfo.rs @@ -1053,48 +1053,6 @@ pub fn create_argument_metadata(bcx: Block, arg: &ast::Arg) { }) } -/// Creates debug information for the given for-loop variable. -/// -/// This function assumes that there's a datum for each pattern component of the -/// loop variable in `bcx.fcx.lllocals`. -/// Adds the created metadata nodes directly to the crate's IR. -pub fn create_for_loop_var_metadata(bcx: Block, pat: &ast::Pat) { - if bcx.unreachable.get() || - fn_should_be_ignored(bcx.fcx) || - bcx.sess().opts.debuginfo != FullDebugInfo { - return; - } - - let def_map = &bcx.tcx().def_map; - let locals = bcx.fcx.lllocals.borrow(); - - pat_util::pat_bindings(def_map, pat, |_, node_id, span, var_ident| { - let datum = match locals.get(&node_id) { - Some(datum) => datum, - None => { - bcx.sess().span_bug(span, - format!("no entry in lllocals table for {}", - node_id).as_slice()); - } - }; - - if unsafe { llvm::LLVMIsAAllocaInst(datum.val) } == ptr::null_mut() { - bcx.sess().span_bug(span, "debuginfo::create_for_loop_var_metadata() - \ - Referenced variable location is not an alloca!"); - } - - let scope_metadata = scope_metadata(bcx.fcx, node_id, span); - - declare_local(bcx, - var_ident.node, - datum.ty, - scope_metadata, - DirectVariable { alloca: datum.val }, - LocalVariable, - span); - }) -} - pub fn get_cleanup_debug_loc_for_ast_node<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, node_id: ast::NodeId, node_span: Span, @@ -3627,24 +3585,9 @@ fn create_scope_map(cx: &CrateContext, Found unexpanded while-let."); } - ast::ExprForLoop(ref pattern, ref head, ref body, _) => { - walk_expr(cx, &**head, scope_stack, scope_map); - - with_new_scope(cx, - exp.span, - scope_stack, - scope_map, - |cx, scope_stack, scope_map| { - scope_map.insert(exp.id, - scope_stack.last() - .unwrap() - .scope_metadata); - walk_pattern(cx, - &**pattern, - scope_stack, - scope_map); - walk_block(cx, &**body, scope_stack, scope_map); - }) + ast::ExprForLoop(..) => { + cx.sess().span_bug(exp.span, "debuginfo::create_scope_map() - \ + Found unexpanded for loop."); } ast::ExprMac(_) => { diff --git a/src/librustc_trans/trans/expr.rs b/src/librustc_trans/trans/expr.rs index 2b97e7b79648a..46726f78d04f5 100644 --- a/src/librustc_trans/trans/expr.rs +++ b/src/librustc_trans/trans/expr.rs @@ -927,13 +927,6 @@ fn trans_rvalue_stmt_unadjusted<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, ast::ExprWhile(ref cond, ref body, _) => { controlflow::trans_while(bcx, expr, &**cond, &**body) } - ast::ExprForLoop(ref pat, ref head, ref body, _) => { - controlflow::trans_for(bcx, - expr_info(expr), - &**pat, - &**head, - &**body) - } ast::ExprLoop(ref body, _) => { controlflow::trans_loop(bcx, expr, &**body) } diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index d78b819065a99..12bf507c05735 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -87,7 +87,6 @@ use check::_match::pat_ctxt; use fmt_macros::{Parser, Piece, Position}; use middle::{const_eval, def}; use middle::infer; -use middle::lang_items::IteratorItem; use middle::mem_categorization as mc; use middle::mem_categorization::McResult; use middle::pat_util::{self, pat_id_map}; @@ -2140,92 +2139,6 @@ fn try_index_step<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, }) } -/// Given the head of a `for` expression, looks up the `next` method in the -/// `Iterator` trait. Panics if the expression does not implement `next`. -/// -/// The return type of this function represents the concrete element type -/// `A` in the type `Iterator` that the method returns. -fn lookup_method_for_for_loop<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, - iterator_expr: &ast::Expr, - loop_id: ast::NodeId) - -> Ty<'tcx> { - let trait_did = match fcx.tcx().lang_items.require(IteratorItem) { - Ok(trait_did) => trait_did, - Err(ref err_string) => { - span_err!(fcx.tcx().sess, iterator_expr.span, E0233, - "{}", &err_string[]); - return fcx.tcx().types.err - } - }; - - let expr_type = fcx.expr_ty(&*iterator_expr); - let method = method::lookup_in_trait(fcx, - iterator_expr.span, - Some(&*iterator_expr), - token::intern("next"), - trait_did, - expr_type, - None); - - // Regardless of whether the lookup succeeds, check the method arguments - // so that we have *some* type for each argument. - let method_type = match method { - Some(ref method) => method.ty, - None => { - let true_expr_type = fcx.infcx().resolve_type_vars_if_possible(&expr_type); - - if !ty::type_is_error(true_expr_type) { - let ty_string = fcx.infcx().ty_to_string(true_expr_type); - span_err!(fcx.tcx().sess, iterator_expr.span, E0234, - "`for` loop expression has type `{}` which does \ - not implement the `Iterator` trait; \ - maybe try .iter()", ty_string); - } - fcx.tcx().types.err - } - }; - let return_type = check_method_argument_types(fcx, - iterator_expr.span, - method_type, - iterator_expr, - &[], - AutorefArgs::No, - DontTupleArguments, - NoExpectation); - - match method { - Some(method) => { - fcx.inh.method_map.borrow_mut().insert(MethodCall::expr(loop_id), - method); - - // We expect the return type to be `Option` or something like it. - // Grab the first parameter of its type substitution. - let return_type = match return_type { - ty::FnConverging(return_type) => - structurally_resolved_type(fcx, iterator_expr.span, return_type), - ty::FnDiverging => fcx.tcx().types.err - }; - match return_type.sty { - ty::ty_enum(_, ref substs) - if !substs.types.is_empty_in(subst::TypeSpace) => { - *substs.types.get(subst::TypeSpace, 0) - } - ty::ty_err => { - fcx.tcx().types.err - } - _ => { - span_err!(fcx.tcx().sess, iterator_expr.span, E0239, - "`next` method of the `Iterator` \ - trait has an unexpected type `{}`", - fcx.infcx().ty_to_string(return_type)); - fcx.tcx().types.err - } - } - } - None => fcx.tcx().types.err - } -} - fn check_method_argument_types<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, sp: Span, method_fn_ty: Ty<'tcx>, @@ -3762,22 +3675,8 @@ fn check_expr_with_unifier<'a, 'tcx, F>(fcx: &FnCtxt<'a, 'tcx>, ast::ExprWhileLet(..) => { tcx.sess.span_bug(expr.span, "non-desugared ExprWhileLet"); } - ast::ExprForLoop(ref pat, ref head, ref block, _) => { - check_expr(fcx, &**head); - let typ = lookup_method_for_for_loop(fcx, &**head, expr.id); - vtable::select_new_fcx_obligations(fcx); - - debug!("ExprForLoop each item has type {}", - fcx.infcx().resolve_type_vars_if_possible(&typ).repr(fcx.tcx())); - - let pcx = pat_ctxt { - fcx: fcx, - map: pat_id_map(&tcx.def_map, &**pat), - }; - _match::check_pat(&pcx, &**pat, typ); - - check_block_no_value(fcx, &**block); - fcx.write_nil(id); + ast::ExprForLoop(..) => { + tcx.sess.span_bug(expr.span, "non-desugared ExprForLoop"); } ast::ExprLoop(ref body, _) => { check_block_no_value(fcx, &**body); diff --git a/src/librustc_typeck/check/regionck.rs b/src/librustc_typeck/check/regionck.rs index 15602505d90d4..8b5ad1357004e 100644 --- a/src/librustc_typeck/check/regionck.rs +++ b/src/librustc_typeck/check/regionck.rs @@ -658,30 +658,6 @@ fn visit_expr(rcx: &mut Rcx, expr: &ast::Expr) { rcx.set_repeating_scope(repeating_scope); } - ast::ExprForLoop(ref pat, ref head, ref body, _) => { - constrain_bindings_in_pat(&**pat, rcx); - - { - let mc = mc::MemCategorizationContext::new(rcx.fcx); - let pat_ty = rcx.resolve_node_type(pat.id); - let pat_cmt = mc.cat_rvalue(pat.id, - pat.span, - ty::ReScope(CodeExtent::from_node_id(body.id)), - pat_ty); - link_pattern(rcx, mc, pat_cmt, &**pat); - } - - rcx.visit_expr(&**head); - type_of_node_must_outlive(rcx, - infer::AddrOf(expr.span), - head.id, - ty::ReScope(CodeExtent::from_node_id(expr.id))); - - let repeating_scope = rcx.set_repeating_scope(body.id); - rcx.visit_block(&**body); - rcx.set_repeating_scope(repeating_scope); - } - _ => { visit::walk_expr(rcx, expr); } diff --git a/src/librustc_typeck/lib.rs b/src/librustc_typeck/lib.rs index 31c9f9961260a..98f997c5990ba 100644 --- a/src/librustc_typeck/lib.rs +++ b/src/librustc_typeck/lib.rs @@ -84,6 +84,8 @@ This API is completely unstable and subject to change. #![feature(core)] #![feature(rustc_private)] #![feature(std_misc)] +// NOTE(stage0) remove cfg_attr after a snapshot +#![cfg_attr(not(stage0), allow(unused_mut))] #[macro_use] extern crate log; #[macro_use] extern crate syntax; diff --git a/src/librustdoc/lib.rs b/src/librustdoc/lib.rs index f8ba2dc2a7483..4e811844ea9b6 100644 --- a/src/librustdoc/lib.rs +++ b/src/librustdoc/lib.rs @@ -32,6 +32,8 @@ #![feature(test)] #![feature(unicode)] #![feature(hash)] +// NOTE(stage0) remove cfg_attr after a snapshot +#![cfg_attr(not(stage0), allow(unused_mut))] extern crate arena; extern crate getopts; diff --git a/src/libstd/collections/hash/map.rs b/src/libstd/collections/hash/map.rs index a291ec16a6244..b1c1dd1a9f65b 100644 --- a/src/libstd/collections/hash/map.rs +++ b/src/libstd/collections/hash/map.rs @@ -1772,7 +1772,7 @@ mod test_map { } }); - for _ in half {} + for _ in half.by_ref() {} DROP_VECTOR.with(|v| { let nk = (0u..100).filter(|&i| { diff --git a/src/libstd/collections/hash/table.rs b/src/libstd/collections/hash/table.rs index 9e6a45d8bf0b5..141c51d8363d8 100644 --- a/src/libstd/collections/hash/table.rs +++ b/src/libstd/collections/hash/table.rs @@ -15,7 +15,7 @@ use self::BucketState::*; use clone::Clone; use cmp; use hash::{Hash, Hasher}; -use iter::{Iterator, ExactSizeIterator, count}; +use iter::{Iterator, IteratorExt, ExactSizeIterator, count}; use marker::{Copy, Sized, self}; use mem::{min_align_of, size_of}; use mem; @@ -921,7 +921,7 @@ impl<'a, K, V> ExactSizeIterator for Drain<'a, K, V> { #[unsafe_destructor] impl<'a, K: 'a, V: 'a> Drop for Drain<'a, K, V> { fn drop(&mut self) { - for _ in *self {} + for _ in self.by_ref() {} } } diff --git a/src/libstd/lib.rs b/src/libstd/lib.rs index a016ba8fb0cd0..54e2eaf16ee10 100644 --- a/src/libstd/lib.rs +++ b/src/libstd/lib.rs @@ -123,6 +123,8 @@ #![feature(rand)] #![feature(hash)] #![cfg_attr(test, feature(test))] +// NOTE(stage0): remove cfg_attr after a snapshot +#![cfg_attr(not(stage0), allow(unused_mut))] // Don't link to std. We are std. #![no_std] @@ -310,4 +312,6 @@ mod std { pub use slice; pub use boxed; // used for vec![] + // for-loops + pub use iter; } diff --git a/src/libstd/path/windows.rs b/src/libstd/path/windows.rs index 88db27013ac83..98e0320cd14d2 100644 --- a/src/libstd/path/windows.rs +++ b/src/libstd/path/windows.rs @@ -557,7 +557,7 @@ impl GenericPath for Path { } (Some(a), Some(_)) => { comps.push(".."); - for _ in itb { + for _ in itb.by_ref() { comps.push(".."); } comps.push(a); diff --git a/src/libstd/sys/common/backtrace.rs b/src/libstd/sys/common/backtrace.rs index c3e125868293c..a71676c6bf229 100644 --- a/src/libstd/sys/common/backtrace.rs +++ b/src/libstd/sys/common/backtrace.rs @@ -54,7 +54,7 @@ pub fn demangle(writer: &mut Writer, s: &str) -> IoResult<()> { let mut chars = inner.chars(); while valid { let mut i = 0; - for c in chars { + for c in chars.by_ref() { if c.is_numeric() { i = i * 10 + c as uint - '0' as uint; } else { diff --git a/src/libsyntax/ast.rs b/src/libsyntax/ast.rs index 11068880b0e26..d7283db25a5f2 100644 --- a/src/libsyntax/ast.rs +++ b/src/libsyntax/ast.rs @@ -788,6 +788,7 @@ pub enum MatchSource { Normal, IfLetDesugar { contains_else_clause: bool }, WhileLetDesugar, + ForLoopDesugar, } #[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug, Copy)] diff --git a/src/libsyntax/ext/expand.rs b/src/libsyntax/ext/expand.rs index acf0fe7f6cde3..5736400313e95 100644 --- a/src/libsyntax/ext/expand.rs +++ b/src/libsyntax/ext/expand.rs @@ -225,11 +225,101 @@ pub fn expand_expr(e: P, fld: &mut MacroExpander) -> P { fld.cx.expr(span, ast::ExprLoop(loop_block, opt_ident)) } + // Desugar ExprForLoop + // From: `[opt_ident]: for in ` ast::ExprForLoop(pat, head, body, opt_ident) => { - let pat = fld.fold_pat(pat); + // to: + // + // match ::std::iter::IntoIterator::into_iter() { + // mut iter => { + // [opt_ident]: loop { + // match ::std::iter::Iterator::next(&mut iter) { + // ::std::option::Option::Some() => , + // ::std::option::Option::None => break + // } + // } + // } + // } + + // expand let head = fld.fold_expr(head); - let (body, opt_ident) = expand_loop_block(body, opt_ident, fld); - fld.cx.expr(span, ast::ExprForLoop(pat, head, body, opt_ident)) + + // create an hygienic ident + let iter = { + let ident = fld.cx.ident_of("iter"); + let new_ident = fresh_name(&ident); + let rename = (ident, new_ident); + let mut rename_list = vec![rename]; + let mut rename_fld = IdentRenamer{ renames: &mut rename_list }; + + rename_fld.fold_ident(ident) + }; + + let pat_span = pat.span; + // `:;std::option::Option::Some() => ` + let pat_arm = { + let body_expr = fld.cx.expr_block(body); + let some_pat = fld.cx.pat_some(pat_span, pat); + + fld.cx.arm(pat_span, vec![some_pat], body_expr) + }; + + // `::std::option::Option::None => break` + let break_arm = { + let break_expr = fld.cx.expr_break(span); + + fld.cx.arm(span, vec![fld.cx.pat_none(span)], break_expr) + }; + + // `match ::std::iter::Iterator::next(&mut iter) { ... }` + let match_expr = { + let next_path = { + let strs = vec![ + fld.cx.ident_of("std"), + fld.cx.ident_of("iter"), + fld.cx.ident_of("Iterator"), + fld.cx.ident_of("next"), + ]; + + fld.cx.path_global(span, strs) + }; + let ref_mut_iter = fld.cx.expr_mut_addr_of(span, fld.cx.expr_ident(span, iter)); + let next_expr = + fld.cx.expr_call(span, fld.cx.expr_path(next_path), vec![ref_mut_iter]); + let arms = vec![pat_arm, break_arm]; + + fld.cx.expr(pat_span, + ast::ExprMatch(next_expr, arms, ast::MatchSource::ForLoopDesugar)) + }; + + // `[opt_ident]: loop { ... }` + let loop_block = fld.cx.block_expr(match_expr); + let (loop_block, opt_ident) = expand_loop_block(loop_block, opt_ident, fld); + let loop_expr = fld.cx.expr(span, ast::ExprLoop(loop_block, opt_ident)); + + // `mut iter => { ... }` + let iter_arm = { + let iter_pat = + fld.cx.pat_ident_binding_mode(span, iter, ast::BindByValue(ast::MutMutable)); + fld.cx.arm(span, vec![iter_pat], loop_expr) + }; + + // `match ::std::iter::IntoIterator::into_iter() { ... }` + let into_iter_expr = { + let into_iter_path = { + let strs = vec![ + fld.cx.ident_of("std"), + fld.cx.ident_of("iter"), + fld.cx.ident_of("IntoIterator"), + fld.cx.ident_of("into_iter"), + ]; + + fld.cx.path_global(span, strs) + }; + + fld.cx.expr_call(span, fld.cx.expr_path(into_iter_path), vec![head]) + }; + fld.cx.expr_match(span, into_iter_expr, vec![iter_arm]) } ast::ExprClosure(capture_clause, opt_kind, fn_decl, block) => { diff --git a/src/libsyntax/lib.rs b/src/libsyntax/lib.rs index ff4c7b565cbbe..5b78d5b1405e7 100644 --- a/src/libsyntax/lib.rs +++ b/src/libsyntax/lib.rs @@ -39,6 +39,8 @@ #![feature(rustc_private)] #![feature(std_misc)] #![feature(unicode)] +// NOTE(stage0) remove cfg_attr after a snapshot +#![cfg_attr(not(stage0), allow(unused_mut))] extern crate arena; extern crate fmt_macros; diff --git a/src/libtest/lib.rs b/src/libtest/lib.rs index 8fea6bb539f57..4497832ba7ecd 100644 --- a/src/libtest/lib.rs +++ b/src/libtest/lib.rs @@ -44,6 +44,8 @@ #![feature(rustc_private)] #![feature(std_misc)] #![feature(hash)] +// NOTE(stage0): remove cfg_attr after a snapshot +#![cfg_attr(not(stage0), allow(unused_mut))] extern crate getopts; extern crate serialize; diff --git a/src/libunicode/lib.rs b/src/libunicode/lib.rs index 02f738c9d29e1..659d57b729214 100644 --- a/src/libunicode/lib.rs +++ b/src/libunicode/lib.rs @@ -84,4 +84,7 @@ mod std { pub use core::cmp; pub use core::fmt; pub use core::marker; + // for-loops + pub use core::iter; + pub use core::option; } diff --git a/src/libunicode/u_str.rs b/src/libunicode/u_str.rs index 370f59a5b2679..9a757c0c980dd 100644 --- a/src/libunicode/u_str.rs +++ b/src/libunicode/u_str.rs @@ -447,7 +447,7 @@ impl<'a> Iterator for Utf16Items<'a> { Some(Utf16Item::LoneSurrogate(u)) } else { // preserve state for rewinding. - let old = self.iter; + let old = self.iter.clone(); let u2 = match self.iter.next() { Some(u2) => *u2, @@ -457,7 +457,7 @@ impl<'a> Iterator for Utf16Items<'a> { if u2 < 0xDC00 || u2 > 0xDFFF { // not a trailing surrogate so we're not a valid // surrogate pair, so rewind to redecode u2 next time. - self.iter = old; + self.iter = old.clone(); return Some(Utf16Item::LoneSurrogate(u)) } diff --git a/src/test/auxiliary/issue-16643.rs b/src/test/auxiliary/issue-16643.rs index c3f7f2d1aa166..c5b3fceaf4a5f 100644 --- a/src/test/auxiliary/issue-16643.rs +++ b/src/test/auxiliary/issue-16643.rs @@ -15,7 +15,7 @@ pub struct TreeBuilder; impl TreeBuilder { pub fn process_token(&mut self) { match self { - _ => for _y in *self {} + _ => for _y in self.by_ref() {} } } } diff --git a/src/test/compile-fail/for-loop-bogosity.rs b/src/test/compile-fail/for-loop-bogosity.rs index fd920f923944d..6bc0e74a2eb58 100644 --- a/src/test/compile-fail/for-loop-bogosity.rs +++ b/src/test/compile-fail/for-loop-bogosity.rs @@ -24,7 +24,10 @@ pub fn main() { x: 1, y: 2, }; - for x in bogus { //~ ERROR has type `MyStruct` which does not implement the `Iterator` trait + for x in bogus { //~ ERROR `core::iter::Iterator` is not implemented for the type `MyStruct` + //~^ ERROR + //~^^ ERROR + // FIXME(#21528) not fulfilled obligation error should be reported once, not thrice drop(x); } } diff --git a/src/test/compile-fail/for-loop-hygiene.rs b/src/test/compile-fail/for-loop-hygiene.rs new file mode 100644 index 0000000000000..ff6f848ab598d --- /dev/null +++ b/src/test/compile-fail/for-loop-hygiene.rs @@ -0,0 +1,20 @@ +// 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// for-loops are expanded in the front end, and use an `iter` ident in their expansion. Check that +// `iter` is not accessible inside the for loop. + +#![allow(unstable)] + +fn main() { + for _ in 0..10 { + iter.next(); //~ error: unresolved name `iter` + } +} diff --git a/src/test/compile-fail/for-loop-refutable-pattern-error-message.rs b/src/test/compile-fail/for-loop-refutable-pattern-error-message.rs index c381fcf3efb06..fa55e7215c0b2 100644 --- a/src/test/compile-fail/for-loop-refutable-pattern-error-message.rs +++ b/src/test/compile-fail/for-loop-refutable-pattern-error-message.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. - fn main() { for &1is //~ ERROR refutable pattern in `for` loop binding diff --git a/src/test/compile-fail/issue-13853.rs b/src/test/compile-fail/issue-13853.rs index 509ca9b80f81f..251da2c6b3ee9 100644 --- a/src/test/compile-fail/issue-13853.rs +++ b/src/test/compile-fail/issue-13853.rs @@ -32,7 +32,7 @@ impl Node for Stuff { fn iterate>(graph: &G) { for node in graph.iter() { //~ ERROR does not implement any method in scope named - node.zomg(); + node.zomg(); //~ error: the type of this value must be known in this context } } diff --git a/src/test/compile-fail/issue-17999.rs b/src/test/compile-fail/issue-17999.rs index 99cb2ec2c02e3..f336fdbfbed95 100644 --- a/src/test/compile-fail/issue-17999.rs +++ b/src/test/compile-fail/issue-17999.rs @@ -9,6 +9,7 @@ // except according to those terms. #![deny(unused_variables)] +#![feature(core)] fn main() { for _ in 1is..101 { diff --git a/src/test/compile-fail/issue-20605.rs b/src/test/compile-fail/issue-20605.rs new file mode 100644 index 0000000000000..87b7616db8ed2 --- /dev/null +++ b/src/test/compile-fail/issue-20605.rs @@ -0,0 +1,19 @@ +// Copyright 2015 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +fn changer<'a>(mut things: Box>) { + for item in *things { *item = 0 } +//~^ ERROR the trait `core::marker::Sized` is not implemented for the type `core::iter::Iterator +//~^^ ERROR +//~^^^ ERROR +// FIXME(#21528) error should be reported once, not thrice +} + +fn main() {} diff --git a/src/test/compile-fail/issue-2150.rs b/src/test/compile-fail/issue-2150.rs index f18db94acf33f..68195985eec4b 100644 --- a/src/test/compile-fail/issue-2150.rs +++ b/src/test/compile-fail/issue-2150.rs @@ -11,6 +11,7 @@ #![deny(unreachable_code)] #![allow(unused_variables)] #![allow(dead_code)] +#![feature(core)] fn fail_len(v: Vec ) -> usize { let mut i = 3; diff --git a/src/test/compile-fail/liveness-unused.rs b/src/test/compile-fail/liveness-unused.rs index 6262783dd380e..ebcf46f7277d6 100644 --- a/src/test/compile-fail/liveness-unused.rs +++ b/src/test/compile-fail/liveness-unused.rs @@ -11,6 +11,7 @@ #![deny(unused_variables)] #![deny(unused_assignments)] #![allow(dead_code, non_camel_case_types)] +#![feature(core)] #![feature(os)] fn f1(x: isize) { diff --git a/src/test/compile-fail/range-1.rs b/src/test/compile-fail/range-1.rs index fdae5f7954692..fbc9ad99b7243 100644 --- a/src/test/compile-fail/range-1.rs +++ b/src/test/compile-fail/range-1.rs @@ -17,7 +17,10 @@ pub fn main() { // Float => does not implement iterator. for i in 0f32..42f32 {} - //~^ ERROR `for` loop expression has type `core::ops::Range` which does not implement + //~^ ERROR `core::iter::Iterator` is not implemented for the type `core::ops::Range` + //~^^ ERROR + //~^^^ ERROR + // FIXME(#21528) not fulfilled obligation error should be reported once, not thrice // Unsized type. let arr: &[_] = &[1us, 2, 3]; diff --git a/src/test/run-pass/for-loop-into-iterator.rs b/src/test/run-pass/for-loop-into-iterator.rs new file mode 100644 index 0000000000000..7564efbd9e56b --- /dev/null +++ b/src/test/run-pass/for-loop-into-iterator.rs @@ -0,0 +1,27 @@ +// 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// Test that for loops can do what RFC #235 claims + +fn main() { + let mut v = vec![1]; + + for x in &v { + assert_eq!(x, &1); + } + + for x in &mut v { + assert_eq!(x, &mut 1); + } + + for x in v { + assert_eq!(x, 1); + } +} diff --git a/src/test/run-pass/foreach-external-iterators-hashmap-break-restart.rs b/src/test/run-pass/foreach-external-iterators-hashmap-break-restart.rs index 4305ae956989e..7c71c8ea464db 100644 --- a/src/test/run-pass/foreach-external-iterators-hashmap-break-restart.rs +++ b/src/test/run-pass/foreach-external-iterators-hashmap-break-restart.rs @@ -27,7 +27,7 @@ pub fn main() { let mut i = h.iter(); - for (&k,&v) in i { + for (&k,&v) in i.by_ref() { x += k; y += v; break; diff --git a/src/test/run-pass/issue-21655.rs b/src/test/run-pass/issue-21655.rs new file mode 100644 index 0000000000000..b9b1e5f3337cd --- /dev/null +++ b/src/test/run-pass/issue-21655.rs @@ -0,0 +1,20 @@ +// Copyright 2015 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +fn test(it: &mut Iterator) { + for x in it { + assert_eq!(x, 1) + } +} + +fn main() { + let v = vec![1]; + test(&mut v.into_iter()) +}