rollup merge of #20790: japaric/for-loops

As per [RFC #235][rfc], you can now do:

[rfc]: https://github.com/rust-lang/rfcs/blob/master/text/0235-collections-conventions.md#intoiterator-and-iterable

``` rust
let mut v = vec![1];

// iterate over immutable references
for x in &v {
    assert_eq!(x, &1);
}

// iterate over mutable references
for x in &mut v {
    assert_eq!(x, &mut 1);
}

// iterate over values, this consumes `v`
for x in v {
    assert_eq!(x, 1);
}
```

[breaking-change]s

For loops now "consume" (move) the iterator, this breaks iterating over mutable references to iterators, and also breaks multiple iterations over the same iterator:

``` rust
fn foo(mut it: &mut Iter) {  // `Iter` implements `Iterator`
    for x in it { .. }  //~ error: `&mut Iter` doesn't implement Iterator
}

fn bar() {
    for x in it { .. }  //~ note: `it` moved here
    for x in it { .. }  //~ error: `it` has been moved
}
```

Both cases can be fixed using the `by_ref()` adapter to create an iterator from the mutable reference:

``` rust
fn foo(mut it: &mut Iter) {
    for x in it.by_ref() { .. }
}

fn bar() {
    for x in it.by_ref() { .. }
    for x in it { .. }
}
```

This PR also makes iterator non-implicitly copyable, as this was source of subtle bugs in the libraries. You can still use `clone()` to explictly copy the iterator.

Finally, since the for loops are implemented in the frontend and use global paths to `IntoIterator`, `Iterator` and `Option` variants, users of the `core` crate will have to use add an `std` module to the root of their crate to be able to use for loops:

``` rust
#![no_std]

extern crate core;

fn main() {
    for x in 0..10 {}
}

#[doc(hidden)]
mod std {
    // these imports are needed to use for-loops
    pub use core::iter;
    pub use core::option;
}
```

---

r? @nikomatsakis @aturon
cc #18424
closes #18045
This commit is contained in:
Alex Crichton 2015-01-30 12:02:44 -08:00
commit 341e858bd8
70 changed files with 587 additions and 598 deletions

View file

@ -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

View file

@ -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 @@ fn from_iter<Iter: Iterator<Item=T>>(iter: Iter) -> BinaryHeap<T> {
}
}
impl<T: Ord> IntoIterator for BinaryHeap<T> {
type Iter = IntoIter<T>;
fn into_iter(self) -> IntoIter<T> {
self.into_iter()
}
}
impl<'a, T> IntoIterator for &'a BinaryHeap<T> 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<T: Ord> Extend<T> for BinaryHeap<T> {
fn extend<Iter: Iterator<Item=T>>(&mut self, mut iter: Iter) {

View file

@ -89,7 +89,7 @@
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 @@ fn idx(&mut self, index: uint) -> Option<bool> {
}
}
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<uint>) { 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 {

View file

@ -24,7 +24,7 @@
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 @@ pub fn remove<Q: ?Sized>(&mut self, key: &Q) -> Option<V> where Q: BorrowFrom<K>
}
}
impl<K, V> IntoIterator for BTreeMap<K, V> {
type Iter = IntoIter<K, V>;
fn into_iter(self) -> IntoIter<K, V> {
self.into_iter()
}
}
impl<'a, K, V> IntoIterator for &'a BTreeMap<K, V> {
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<K, V> {
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<A, B> {

View file

@ -271,7 +271,7 @@ fn next_back(&mut self) -> Option<T> {
#[unsafe_destructor]
impl<T> Drop for RawItems<T> {
fn drop(&mut self) {
for _ in *self {}
for _ in self.by_ref() {}
}
}
@ -1374,9 +1374,9 @@ impl<K, V> Drop for MoveTraversalImpl<K, V> {
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::<K, V>(self.capacity, self.is_leaf);

View file

@ -18,7 +18,7 @@
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 @@ fn from_iter<Iter: Iterator<Item=T>>(iter: Iter) -> BTreeSet<T> {
}
}
impl<T> IntoIterator for BTreeSet<T> {
type Iter = IntoIter<T>;
fn into_iter(self) -> IntoIter<T> {
self.into_iter()
}
}
impl<'a, T> IntoIterator for &'a BTreeSet<T> {
type Iter = Iter<'a, T>;
fn into_iter(self) -> Iter<'a, T> {
self.iter()
}
}
#[stable(feature = "rust1", since = "1.0.0")]
impl<T: Ord> Extend<T> for BTreeSet<T> {
#[inline]

View file

@ -28,7 +28,7 @@
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 @@ fn from_iter<T: Iterator<Item=A>>(iterator: T) -> DList<A> {
}
}
impl<T> IntoIterator for DList<T> {
type Iter = IntoIter<T>;
fn into_iter(self) -> IntoIter<T> {
self.into_iter()
}
}
impl<'a, T> IntoIterator for &'a DList<T> {
type Iter = Iter<'a, T>;
fn into_iter(self) -> Iter<'a, T> {
self.iter()
}
}
impl<'a, T> IntoIterator for &'a mut DList<T> {
type Iter = IterMut<'a, T>;
fn into_iter(mut self) -> IterMut<'a, T> {
self.iter_mut()
}
}
#[stable(feature = "rust1", since = "1.0.0")]
impl<A> Extend<A> for DList<A> {
fn extend<T: Iterator<Item=A>>(&mut self, mut iterator: T) {

View file

@ -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 @@ fn from_iter<I:Iterator<Item=E>>(iterator: I) -> EnumSet<E> {
}
}
impl<'a, E> IntoIterator for &'a EnumSet<E> where E: CLike {
type Iter = Iter<E>;
fn into_iter(self) -> Iter<E> {
self.iter()
}
}
impl<E:CLike> Extend<E> for EnumSet<E> {
fn extend<I: Iterator<Item=E>>(&mut self, mut iterator: I) {
for element in iterator {

View file

@ -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)]

View file

@ -19,7 +19,7 @@
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 @@ fn from_iter<T: Iterator<Item=A>>(iterator: T) -> RingBuf<A> {
}
}
impl<T> IntoIterator for RingBuf<T> {
type Iter = IntoIter<T>;
fn into_iter(self) -> IntoIter<T> {
self.into_iter()
}
}
impl<'a, T> IntoIterator for &'a RingBuf<T> {
type Iter = Iter<'a, T>;
fn into_iter(self) -> Iter<'a, T> {
self.iter()
}
}
impl<'a, T> IntoIterator for &'a mut RingBuf<T> {
type Iter = IterMut<'a, T>;
fn into_iter(mut self) -> IterMut<'a, T> {
self.iter_mut()
}
}
#[stable(feature = "rust1", since = "1.0.0")]
impl<A> Extend<A> for RingBuf<A> {
fn extend<T: Iterator<Item=A>>(&mut self, mut iterator: T) {

View file

@ -1958,7 +1958,7 @@ fn test_permutations() {
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);

View file

@ -199,7 +199,7 @@ fn next(&mut self) -> Option<char> {
}
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 @@ fn next(&mut self) -> Option<char> {
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 @@ fn test_iterator_clone() {
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]

View file

@ -56,7 +56,7 @@
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;
use core::ptr;
use core::raw::Slice as RawSlice;
use core::slice;
use core::uint;
/// A growable list type, written `Vec<T>` but pronounced 'vector.'
@ -1404,6 +1405,30 @@ fn from_iter<I:Iterator<Item=T>>(mut iterator: I) -> Vec<T> {
}
}
impl<T> IntoIterator for Vec<T> {
type Iter = IntoIter<T>;
fn into_iter(self) -> IntoIter<T> {
self.into_iter()
}
}
impl<'a, T> IntoIterator for &'a Vec<T> {
type Iter = slice::Iter<'a, T>;
fn into_iter(self) -> slice::Iter<'a, T> {
self.iter()
}
}
impl<'a, T> IntoIterator for &'a mut Vec<T> {
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<T> Extend<T> for Vec<T> {
#[inline]
@ -1623,7 +1648,7 @@ impl<T> IntoIter<T> {
#[unstable(feature = "collections")]
pub fn into_inner(mut self) -> Vec<T> {
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<T> Drop for IntoIter<T> {
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 @@ fn drop(&mut self) {
// so we can use #[unsafe_no_drop_flag].
// destroy the remaining elements
for _x in *self {}
for _x in self.by_ref() {}
}
}

View file

@ -19,7 +19,7 @@
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 @@ fn from_iter<Iter: Iterator<Item=(uint, V)>>(iter: Iter) -> VecMap<V> {
}
}
impl<T> IntoIterator for VecMap<T> {
type Iter = IntoIter<T>;
fn into_iter(self) -> IntoIter<T> {
self.into_iter()
}
}
impl<'a, T> IntoIterator for &'a VecMap<T> {
type Iter = Iter<'a, T>;
fn into_iter(self) -> Iter<'a, T> {
self.iter()
}
}
impl<'a, T> IntoIterator for &'a mut VecMap<T> {
type Iter = IterMut<'a, T>;
fn into_iter(mut self) -> IterMut<'a, T> {
self.iter_mut()
}
}
#[stable(feature = "rust1", since = "1.0.0")]
impl<V> Extend<(uint, V)> for VecMap<V> {
fn extend<Iter: Iterator<Item=(uint, V)>>(&mut self, mut iter: Iter) {

View file

@ -18,12 +18,14 @@
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 @@ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
}
}
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<A, B> PartialEq<[B; $N]> for [A; $N] where A: PartialEq<B> {
#[inline]

View file

@ -122,6 +122,22 @@ pub trait FromIterator<A> {
fn from_iter<T: Iterator<Item=A>>(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<I> 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<A> {
@ -178,7 +194,7 @@ fn last(mut self) -> Option<Self::Item> {
#[inline]
#[stable(feature = "rust1", since = "1.0.0")]
fn nth(&mut self, mut n: usize) -> Option<Self::Item> {
for x in *self {
for x in self.by_ref() {
if n == 0 { return Some(x) }
n -= 1;
}
@ -475,7 +491,7 @@ fn flat_map<B, U, F>(self, f: F) -> FlatMap<Self::Item, B, Self, U, F> where
/// fn process<U: Iterator<Item=isize>>(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 @@ fn all<F>(mut self, mut f: F) -> bool where F: FnMut(Self::Item) -> bool {
#[inline]
#[stable(feature = "rust1", since = "1.0.0")]
fn any<F>(&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 @@ fn any<F>(&mut self, mut f: F) -> bool where F: FnMut(Self::Item) -> bool {
fn find<P>(&mut self, mut predicate: P) -> Option<Self::Item> 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 @@ fn position<P>(&mut self, mut predicate: P) -> Option<usize> where
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<T, D, I> ExactSizeIterator for Cloned<I> 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<I> {
@ -1647,7 +1663,7 @@ impl<A, I, P> Iterator for Filter<A, I, P> where I: Iterator<Item=A>, P: FnMut(&
#[inline]
fn next(&mut self) -> Option<A> {
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<A, B, I, F> Iterator for FilterMap<A, B, I, F> where
#[inline]
fn next(&mut self) -> Option<B> {
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 @@ fn idx(&mut self, index: usize) -> Option<(usize, <I as Iterator>::Item)> {
/// 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<T, I> where I: Iterator<Item=T> {
iter: I,
peeked: Option<T>,
@ -1897,7 +1912,7 @@ impl<A, I, P> Iterator for SkipWhile<A, I, P> where I: Iterator<Item=A>, P: FnMu
#[inline]
fn next(&mut self) -> Option<A> {
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<A, B, I, U, F> Iterator for FlatMap<A, B, I, U, F> where
fn next(&mut self) -> Option<B> {
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 @@ fn size_hint(&self) -> (usize, Option<usize>) {
/// An infinite iterator starting at `start` and advancing by `step` with each
/// iteration
#[derive(Clone, Copy)]
#[derive(Clone)]
#[unstable(feature = "core",
reason = "may be renamed or replaced by range notation adapaters")]
pub struct Counter<A> {
@ -2520,7 +2535,7 @@ fn size_hint(&self) -> (usize, Option<usize>) {
}
/// 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<A> {

View file

@ -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;
}

View file

@ -1524,7 +1524,7 @@ fn from_str_radix(src: &str, radix: uint) -> Option<$T> {
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 @@ fn from_str_radix(src: &str, radix: uint) -> Option<$T> {
// 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

View file

@ -41,7 +41,6 @@
use cmp;
use default::Default;
use iter::*;
use marker::Copy;
use num::Int;
use ops::{FnMut, self, Index};
#[cfg(stage0)]
@ -637,6 +636,22 @@ fn default() -> &'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 @@ pub fn as_slice(&self) -> &'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")]

View file

@ -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 @@ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
/// 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<u8>)
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()))
}}}

View file

@ -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!(vi.clone().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!(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);
}
});
}

View file

@ -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)]

View file

@ -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;

View file

@ -1163,6 +1163,7 @@ fn check_expr(&mut self, cx: &Context, e: &ast::Expr) {
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),

View file

@ -263,43 +263,8 @@ fn expr(&mut self, expr: &ast::Expr, pred: CFGIndex) -> CFGIndex {
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, _) => {

View file

@ -45,10 +45,6 @@ fn visit_expr(&mut self, e: &ast::Expr) {
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));
}

View file

@ -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(<head>)` 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!()
};
match source {
ast::MatchSource::ForLoopDesugar => {
// `witness` has the form `Some(<head>)`, 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

View file

@ -537,22 +537,8 @@ pub fn walk_expr(&mut self, expr: &ast::Expr) {
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) => {

View file

@ -325,8 +325,6 @@ pub fn collect_language_items(krate: &ast::Crate,
NonZeroItem, "non_zero", non_zero;
IteratorItem, "iterator", iterator;
StackExhaustedLangItem, "stack_exhausted", stack_exhausted;
DebugTraitLangItem, "debug_trait", debug_trait;

View file

@ -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 @@ fn propagate_through_expr(&mut self, expr: &Expr, succ: LiveNode)
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 @@ fn propagate_through_loop(&mut self,
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 @@ fn propagate_through_loop(&mut self,
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");
}
}
}

View file

@ -536,8 +536,7 @@ pub fn cat_expr_unadjusted(&self, expr: &ast::Expr) -> McResult<cmt<'tcx>> {
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 @@ pub fn cat_expr_unadjusted(&self, expr: &ast::Expr) -> McResult<cmt<'tcx>> {
ast::ExprWhileLet(..) => {
self.tcx().sess.span_bug(expr.span, "non-desugared ExprWhileLet");
}
ast::ExprForLoop(..) => {
self.tcx().sess.span_bug(expr.span, "non-desugared ExprForLoop");
}
}
}

View file

@ -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);
}

View file

@ -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
}

View file

@ -96,7 +96,7 @@ fn visit_expr(&mut self, e: &ast::Expr) {
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)
}
}

View file

@ -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",
},

View file

@ -252,7 +252,6 @@ pub enum SawExprComponent<'a> {
SawExprStruct,
SawExprRepeat,
SawExprParen,
SawExprForLoop,
}
fn saw_expr<'a>(node: &'a Expr_) -> SawExprComponent<'a> {
@ -288,9 +287,9 @@ fn saw_expr<'a>(node: &'a Expr_) -> SawExprComponent<'a> {
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!(),

View file

@ -68,7 +68,7 @@
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 @@ fn resolve_expr(&mut self, expr: &Expr) {
})
}
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) {

View file

@ -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;

View file

@ -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 <pat> in <expr> { ... }`.
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,

View file

@ -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;
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)

View file

@ -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 walk_expr(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(_) => {

View file

@ -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)
}

View file

@ -87,7 +87,6 @@
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<A>` 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_struct_fields_on_error(fcx: &FnCtxt,
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);

View file

@ -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);
}

View file

@ -84,6 +84,8 @@
#![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;

View file

@ -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;

View file

@ -1772,7 +1772,7 @@ fn test_move_iter_drops() {
}
});
for _ in half {}
for _ in half.by_ref() {}
DROP_VECTOR.with(|v| {
let nk = (0u..100).filter(|&i| {

View file

@ -15,7 +15,7 @@
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 @@ fn len(&self) -> usize { self.table.size() }
#[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() {}
}
}

View file

@ -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;
}

View file

@ -557,7 +557,7 @@ fn comp_requires_verbatim(s: &str) -> bool {
}
(Some(a), Some(_)) => {
comps.push("..");
for _ in itb {
for _ in itb.by_ref() {
comps.push("..");
}
comps.push(a);

View file

@ -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 {

View file

@ -788,6 +788,7 @@ pub enum MatchSource {
Normal,
IfLetDesugar { contains_else_clause: bool },
WhileLetDesugar,
ForLoopDesugar,
}
#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug, Copy)]

View file

@ -225,11 +225,101 @@ pub fn expand_expr(e: P<ast::Expr>, fld: &mut MacroExpander) -> P<ast::Expr> {
fld.cx.expr(span, ast::ExprLoop(loop_block, opt_ident))
}
// Desugar ExprForLoop
// From: `[opt_ident]: for <pat> in <head> <body>`
ast::ExprForLoop(pat, head, body, opt_ident) => {
let pat = fld.fold_pat(pat);
// to:
//
// match ::std::iter::IntoIterator::into_iter(<head>) {
// mut iter => {
// [opt_ident]: loop {
// match ::std::iter::Iterator::next(&mut iter) {
// ::std::option::Option::Some(<pat>) => <body>,
// ::std::option::Option::None => break
// }
// }
// }
// }
// expand <head>
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(<pat>) => <body>`
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(<head>) { ... }`
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) => {

View file

@ -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;

View file

@ -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;

View file

@ -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;
}

View file

@ -447,7 +447,7 @@ fn next(&mut self) -> Option<Utf16Item> {
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 @@ fn next(&mut self) -> Option<Utf16Item> {
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))
}

View file

@ -15,7 +15,7 @@
impl<H> TreeBuilder<H> {
pub fn process_token(&mut self) {
match self {
_ => for _y in *self {}
_ => for _y in self.by_ref() {}
}
}
}

View file

@ -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);
}
}

View file

@ -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 <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.
// 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`
}
}

View file

@ -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

View file

@ -32,7 +32,7 @@ fn zomg() {
fn iterate<N: Node, G: Graph<N>>(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
}
}

View file

@ -9,6 +9,7 @@
// except according to those terms.
#![deny(unused_variables)]
#![feature(core)]
fn main() {
for _ in 1is..101 {

View file

@ -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 <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.
fn changer<'a>(mut things: Box<Iterator<Item=&'a mut u8>>) {
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() {}

View file

@ -11,6 +11,7 @@
#![deny(unreachable_code)]
#![allow(unused_variables)]
#![allow(dead_code)]
#![feature(core)]
fn fail_len(v: Vec<isize> ) -> usize {
let mut i = 3;

View file

@ -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) {

View file

@ -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<f32>` which does not implement
//~^ ERROR `core::iter::Iterator` is not implemented for the type `core::ops::Range<f32>`
//~^^ ERROR
//~^^^ ERROR
// FIXME(#21528) not fulfilled obligation error should be reported once, not thrice
// Unsized type.
let arr: &[_] = &[1us, 2, 3];

View file

@ -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 <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 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);
}
}

View file

@ -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;

View file

@ -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 <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.
fn test(it: &mut Iterator<Item=i32>) {
for x in it {
assert_eq!(x, 1)
}
}
fn main() {
let v = vec![1];
test(&mut v.into_iter())
}