Skip to content

Commit 341e858

Browse files
committed
rollup merge of rust-lang#20790: japaric/for-loops
As per [RFC rust-lang#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 rust-lang#18424 closes rust-lang#18045
2 parents 1a51eb9 + b9a9030 commit 341e858

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

70 files changed

+588
-599
lines changed

src/doc/trpl/unsafe.md

+4
Original file line numberDiff line numberDiff line change
@@ -576,6 +576,10 @@ extern fn panic_fmt(args: &core::fmt::Arguments,
576576
#[lang = "eh_personality"] extern fn eh_personality() {}
577577
# #[start] fn start(argc: isize, argv: *const *const u8) -> isize { 0 }
578578
# fn main() {}
579+
# mod std { // for-loops
580+
# pub use core::iter;
581+
# pub use core::option;
582+
# }
579583
```
580584

581585
Note that there is one extra lang item here which differs from the examples

src/libcollections/binary_heap.rs

+17-1
Original file line numberDiff line numberDiff line change
@@ -153,7 +153,7 @@
153153
use core::prelude::*;
154154

155155
use core::default::Default;
156-
use core::iter::FromIterator;
156+
use core::iter::{FromIterator, IntoIterator};
157157
use core::mem::{zeroed, replace, swap};
158158
use core::ptr;
159159

@@ -655,6 +655,22 @@ impl<T: Ord> FromIterator<T> for BinaryHeap<T> {
655655
}
656656
}
657657

658+
impl<T: Ord> IntoIterator for BinaryHeap<T> {
659+
type Iter = IntoIter<T>;
660+
661+
fn into_iter(self) -> IntoIter<T> {
662+
self.into_iter()
663+
}
664+
}
665+
666+
impl<'a, T> IntoIterator for &'a BinaryHeap<T> where T: Ord {
667+
type Iter = Iter<'a, T>;
668+
669+
fn into_iter(self) -> Iter<'a, T> {
670+
self.iter()
671+
}
672+
}
673+
658674
#[stable(feature = "rust1", since = "1.0.0")]
659675
impl<T: Ord> Extend<T> for BinaryHeap<T> {
660676
fn extend<Iter: Iterator<Item=T>>(&mut self, mut iter: Iter) {

src/libcollections/bit.rs

+16-1
Original file line numberDiff line numberDiff line change
@@ -89,7 +89,7 @@ use core::fmt;
8989
use core::hash;
9090
use core::iter::RandomAccessIterator;
9191
use core::iter::{Chain, Enumerate, Repeat, Skip, Take, repeat, Cloned};
92-
use core::iter::{self, FromIterator};
92+
use core::iter::{self, FromIterator, IntoIterator};
9393
use core::num::Int;
9494
use core::ops::Index;
9595
use core::slice;
@@ -1070,6 +1070,14 @@ impl<'a> RandomAccessIterator for Iter<'a> {
10701070
}
10711071
}
10721072

1073+
impl<'a> IntoIterator for &'a Bitv {
1074+
type Iter = Iter<'a>;
1075+
1076+
fn into_iter(self) -> Iter<'a> {
1077+
self.iter()
1078+
}
1079+
}
1080+
10731081
/// An implementation of a set using a bit vector as an underlying
10741082
/// representation for holding unsigned numerical elements.
10751083
///
@@ -1873,6 +1881,13 @@ impl<'a> Iterator for SymmetricDifference<'a> {
18731881
#[inline] fn size_hint(&self) -> (uint, Option<uint>) { self.0.size_hint() }
18741882
}
18751883

1884+
impl<'a> IntoIterator for &'a BitvSet {
1885+
type Iter = SetIter<'a>;
1886+
1887+
fn into_iter(self) -> SetIter<'a> {
1888+
self.iter()
1889+
}
1890+
}
18761891

18771892
#[cfg(test)]
18781893
mod tests {

src/libcollections/btree/map.rs

+25-1
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ use core::cmp::Ordering;
2424
use core::default::Default;
2525
use core::fmt::Debug;
2626
use core::hash::{Hash, Hasher};
27-
use core::iter::{Map, FromIterator};
27+
use core::iter::{Map, FromIterator, IntoIterator};
2828
use core::ops::{Index, IndexMut};
2929
use core::{iter, fmt, mem};
3030
use Bound::{self, Included, Excluded, Unbounded};
@@ -478,6 +478,30 @@ impl<K: Ord, V> BTreeMap<K, V> {
478478
}
479479
}
480480

481+
impl<K, V> IntoIterator for BTreeMap<K, V> {
482+
type Iter = IntoIter<K, V>;
483+
484+
fn into_iter(self) -> IntoIter<K, V> {
485+
self.into_iter()
486+
}
487+
}
488+
489+
impl<'a, K, V> IntoIterator for &'a BTreeMap<K, V> {
490+
type Iter = Iter<'a, K, V>;
491+
492+
fn into_iter(self) -> Iter<'a, K, V> {
493+
self.iter()
494+
}
495+
}
496+
497+
impl<'a, K, V> IntoIterator for &'a mut BTreeMap<K, V> {
498+
type Iter = IterMut<'a, K, V>;
499+
500+
fn into_iter(mut self) -> IterMut<'a, K, V> {
501+
self.iter_mut()
502+
}
503+
}
504+
481505
/// A helper enum useful for deciding whether to continue a loop since we can't
482506
/// return from a closure
483507
enum Continuation<A, B> {

src/libcollections/btree/node.rs

+4-4
Original file line numberDiff line numberDiff line change
@@ -271,7 +271,7 @@ impl<T> DoubleEndedIterator for RawItems<T> {
271271
#[unsafe_destructor]
272272
impl<T> Drop for RawItems<T> {
273273
fn drop(&mut self) {
274-
for _ in *self {}
274+
for _ in self.by_ref() {}
275275
}
276276
}
277277

@@ -1374,9 +1374,9 @@ impl<K, V> Drop for MoveTraversalImpl<K, V> {
13741374
fn drop(&mut self) {
13751375
// We need to cleanup the stored values manually, as the RawItems destructor would run
13761376
// after our deallocation.
1377-
for _ in self.keys {}
1378-
for _ in self.vals {}
1379-
for _ in self.edges {}
1377+
for _ in self.keys.by_ref() {}
1378+
for _ in self.vals.by_ref() {}
1379+
for _ in self.edges.by_ref() {}
13801380

13811381
let (alignment, size) =
13821382
calculate_allocation_generic::<K, V>(self.capacity, self.is_leaf);

src/libcollections/btree/set.rs

+17-1
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ use core::cmp::Ordering::{self, Less, Greater, Equal};
1818
use core::default::Default;
1919
use core::fmt::Debug;
2020
use core::fmt;
21-
use core::iter::{Peekable, Map, FromIterator};
21+
use core::iter::{Peekable, Map, FromIterator, IntoIterator};
2222
use core::ops::{BitOr, BitAnd, BitXor, Sub};
2323

2424
use btree_map::{BTreeMap, Keys};
@@ -480,6 +480,22 @@ impl<T: Ord> FromIterator<T> for BTreeSet<T> {
480480
}
481481
}
482482

483+
impl<T> IntoIterator for BTreeSet<T> {
484+
type Iter = IntoIter<T>;
485+
486+
fn into_iter(self) -> IntoIter<T> {
487+
self.into_iter()
488+
}
489+
}
490+
491+
impl<'a, T> IntoIterator for &'a BTreeSet<T> {
492+
type Iter = Iter<'a, T>;
493+
494+
fn into_iter(self) -> Iter<'a, T> {
495+
self.iter()
496+
}
497+
}
498+
483499
#[stable(feature = "rust1", since = "1.0.0")]
484500
impl<T: Ord> Extend<T> for BTreeSet<T> {
485501
#[inline]

src/libcollections/dlist.rs

+25-1
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ use core::cmp::Ordering;
2828
use core::default::Default;
2929
use core::fmt;
3030
use core::hash::{Writer, Hasher, Hash};
31-
use core::iter::{self, FromIterator};
31+
use core::iter::{self, FromIterator, IntoIterator};
3232
use core::mem;
3333
use core::ptr;
3434

@@ -830,6 +830,30 @@ impl<A> FromIterator<A> for DList<A> {
830830
}
831831
}
832832

833+
impl<T> IntoIterator for DList<T> {
834+
type Iter = IntoIter<T>;
835+
836+
fn into_iter(self) -> IntoIter<T> {
837+
self.into_iter()
838+
}
839+
}
840+
841+
impl<'a, T> IntoIterator for &'a DList<T> {
842+
type Iter = Iter<'a, T>;
843+
844+
fn into_iter(self) -> Iter<'a, T> {
845+
self.iter()
846+
}
847+
}
848+
849+
impl<'a, T> IntoIterator for &'a mut DList<T> {
850+
type Iter = IterMut<'a, T>;
851+
852+
fn into_iter(mut self) -> IterMut<'a, T> {
853+
self.iter_mut()
854+
}
855+
}
856+
833857
#[stable(feature = "rust1", since = "1.0.0")]
834858
impl<A> Extend<A> for DList<A> {
835859
fn extend<T: Iterator<Item=A>>(&mut self, mut iterator: T) {

src/libcollections/enum_set.rs

+9-1
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@
1616
use core::prelude::*;
1717
use core::fmt;
1818
use core::num::Int;
19-
use core::iter::FromIterator;
19+
use core::iter::{FromIterator, IntoIterator};
2020
use core::ops::{Sub, BitOr, BitAnd, BitXor};
2121

2222
// FIXME(contentions): implement union family of methods? (general design may be wrong here)
@@ -256,6 +256,14 @@ impl<E:CLike> FromIterator<E> for EnumSet<E> {
256256
}
257257
}
258258

259+
impl<'a, E> IntoIterator for &'a EnumSet<E> where E: CLike {
260+
type Iter = Iter<E>;
261+
262+
fn into_iter(self) -> Iter<E> {
263+
self.iter()
264+
}
265+
}
266+
259267
impl<E:CLike> Extend<E> for EnumSet<E> {
260268
fn extend<I: Iterator<Item=E>>(&mut self, mut iterator: I) {
261269
for element in iterator {

src/libcollections/lib.rs

+4
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,8 @@
3434
#![feature(unicode)]
3535
#![feature(hash)]
3636
#![cfg_attr(test, feature(test))]
37+
// NOTE(stage0): remove after a snapshot
38+
#![cfg_attr(not(stage0), allow(unused_mut))]
3739

3840
#[macro_use]
3941
extern crate core;
@@ -114,6 +116,8 @@ mod std {
114116
pub use core::marker; // derive(Copy)
115117
pub use core::hash; // derive(Hash)
116118
pub use core::ops; // RangeFull
119+
// for-loops
120+
pub use core::iter;
117121
}
118122

119123
#[cfg(test)]

src/libcollections/ring_buf.rs

+26-2
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ use core::prelude::*;
1919
use core::cmp::Ordering;
2020
use core::default::Default;
2121
use core::fmt;
22-
use core::iter::{self, repeat, FromIterator, RandomAccessIterator};
22+
use core::iter::{self, repeat, FromIterator, IntoIterator, RandomAccessIterator};
2323
use core::marker;
2424
use core::mem;
2525
use core::num::{Int, UnsignedInt};
@@ -1510,7 +1510,7 @@ pub struct Drain<'a, T: 'a> {
15101510
#[stable(feature = "rust1", since = "1.0.0")]
15111511
impl<'a, T: 'a> Drop for Drain<'a, T> {
15121512
fn drop(&mut self) {
1513-
for _ in *self {}
1513+
for _ in self.by_ref() {}
15141514
self.inner.head = 0;
15151515
self.inner.tail = 0;
15161516
}
@@ -1609,6 +1609,30 @@ impl<A> FromIterator<A> for RingBuf<A> {
16091609
}
16101610
}
16111611

1612+
impl<T> IntoIterator for RingBuf<T> {
1613+
type Iter = IntoIter<T>;
1614+
1615+
fn into_iter(self) -> IntoIter<T> {
1616+
self.into_iter()
1617+
}
1618+
}
1619+
1620+
impl<'a, T> IntoIterator for &'a RingBuf<T> {
1621+
type Iter = Iter<'a, T>;
1622+
1623+
fn into_iter(self) -> Iter<'a, T> {
1624+
self.iter()
1625+
}
1626+
}
1627+
1628+
impl<'a, T> IntoIterator for &'a mut RingBuf<T> {
1629+
type Iter = IterMut<'a, T>;
1630+
1631+
fn into_iter(mut self) -> IterMut<'a, T> {
1632+
self.iter_mut()
1633+
}
1634+
}
1635+
16121636
#[stable(feature = "rust1", since = "1.0.0")]
16131637
impl<A> Extend<A> for RingBuf<A> {
16141638
fn extend<T: Iterator<Item=A>>(&mut self, mut iterator: T) {

src/libcollections/slice.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -1958,7 +1958,7 @@ mod tests {
19581958
let mut amt = 0;
19591959
let mut it = v.permutations();
19601960
let (min_size, max_opt) = it.size_hint();
1961-
for _perm in it {
1961+
for _perm in it.by_ref() {
19621962
amt += 1;
19631963
}
19641964
assert_eq!(amt, it.swaps.swaps_made);

src/libcollections/str.rs

+3-3
Original file line numberDiff line numberDiff line change
@@ -199,7 +199,7 @@ impl<'a> Iterator for Decompositions<'a> {
199199
}
200200

201201
if !self.sorted {
202-
for ch in self.iter {
202+
for ch in self.iter.by_ref() {
203203
let buffer = &mut self.buffer;
204204
let sorted = &mut self.sorted;
205205
{
@@ -279,7 +279,7 @@ impl<'a> Iterator for Recompositions<'a> {
279279
loop {
280280
match self.state {
281281
Composing => {
282-
for ch in self.iter {
282+
for ch in self.iter.by_ref() {
283283
let ch_class = unicode::char::canonical_combining_class(ch);
284284
if self.composee.is_none() {
285285
if ch_class != 0 {
@@ -2154,7 +2154,7 @@ mod tests {
21542154
let s = "ศไทย中华Việt Nam";
21552155
let mut it = s.chars();
21562156
it.next();
2157-
assert!(it.zip(it.clone()).all(|(x,y)| x == y));
2157+
assert!(it.clone().zip(it).all(|(x,y)| x == y));
21582158
}
21592159

21602160
#[test]

0 commit comments

Comments
 (0)