Skip to content

Commit c7dd3c4

Browse files
committed
auto merge of #20578 : japaric/rust/no-more-bc, r=nmatsakis
This PR removes boxed closures from the language, the closure type syntax (`let f: |int| -> bool = /* ... */`) has been obsoleted. Move all your uses of closures to the new unboxed closure system (i.e. `Fn*` traits). [breaking-change] patterns - `lef f = || {}` This binding used to type check to a boxed closure. Now that boxed closures are gone, you need to annotate the "kind" of the unboxed closure, i.e. you need pick one of these: `|&:| {}`, `|&mut:| {}` or `|:| {}`. In the (near) future we'll have closure "kind" inference, so the compiler will infer which `Fn*` trait to use based on how the closure is used. Once this inference machinery is in place, we'll be able to remove the kind annotation from most closures. - `type Alias<'a> = |int|:'a -> bool` Use a trait object: `type Alias<'a> = Box<FnMut(int) -> bool + 'a>`. Use the `Fn*` trait that makes sense for your use case. - `fn foo(&self, f: |uint| -> bool)` In this case you can use either a trait object or an unboxed closure: ``` rust fn foo(&self, f: F) where F: FnMut(uint) -> bool; // or fn foo(&self, f: Box<FnMut(uint) -> bool>); ``` - `struct Struct<'a> { f: |uint|:'a -> bool }` Again, you can use either a trait object or an unboxed closure: ``` rust struct Struct<F> where F: FnMut(uint) -> bool { f: F } // or struct Struct<'a> { f: Box<FnMut(uint) -> bool + 'a> } ``` - Using `|x, y| f(x, y)` for closure "borrows" This comes up in recursive functions, consider the following (contrived) example: ``` rust fn foo(x: uint, f: |uint| -> bool) -> bool { //foo(x / 2, f) && f(x) // can't use this because `f` gets moved away in the `foo` call foo(x / 2, |x| f(x)) && f(x) // instead "borrow" `f` in the `foo` call } ``` If you attempt to do the same with unboxed closures you'll hit ""error: reached the recursion limit during monomorphization" (see #19596): ``` rust fn foo<F>(x: uint, mut f: F) -> bool where F: FnMut(uint) -> bool { foo(x / 2, |x| f(x)) && f(x) //~^ error: reached the recursion limit during monomorphization } ``` Instead you *should* be able to write this: ``` rust fn foo<F>(x: uint, mut f: F) -> bool where F: FnMut(uint) -> bool { foo(x / 2, &mut f) && f(x) //~^ error: the trait `FnMut` is not implemented for the type `&mut F` } ``` But as you see above `&mut F` doesn't implement the `FnMut` trait. `&mut F` *should* implement the `FnMut` and the above code *should* work, but due to a bug (see #18835) it doesn't (for now). You can work around the issue by rewriting the function to take `&mut F` instead of `F`: ``` rust fn foo<F>(x: uint, f: &mut F) -> bool where F: FnMut(uint) -> bool { foo(x / 2, f) && (*f)(x) } ``` This finally works! However writing `foo(0, &mut |x| x == 0)` is unergonomic. So you can use a private helper function to avoid this: ``` rust // public API function pub fn foo<F>(x: uint, mut f: F) -> bool where F: FnMut(uint) -> bool { foo_(x, &mut f) } // private helper function fn foo_<F>(x: uint, f: &mut F) -> bool where F: FnMut(uint) -> bool { foo_(x / 2, f) && (*f)(x) } ``` Closes #14798 --- There is more cleanup to do: like renaming functions/types from `unboxed_closure` to just `closure`, removing more dead code, simplify functions which now have unused arguments, update the documentation, etc. But that can be done in another PR. r? @nikomatsakis @aturon (You probably want to focus on the deleted/modified tests.) cc @eddyb
2 parents f11f3e7 + eb2506c commit c7dd3c4

File tree

331 files changed

+986
-2489
lines changed

Some content is hidden

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

331 files changed

+986
-2489
lines changed

src/compiletest/compiletest.rs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -339,8 +339,9 @@ pub fn is_test(config: &Config, testfile: &Path) -> bool {
339339
return valid;
340340
}
341341

342-
pub fn make_test(config: &Config, testfile: &Path, f: || -> test::TestFn)
343-
-> test::TestDescAndFn {
342+
pub fn make_test<F>(config: &Config, testfile: &Path, f: F) -> test::TestDescAndFn where
343+
F: FnOnce() -> test::TestFn,
344+
{
344345
test::TestDescAndFn {
345346
desc: test::TestDesc {
346347
name: make_test_name(config, testfile),

src/compiletest/header.rs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -220,7 +220,9 @@ pub fn is_test_ignored(config: &Config, testfile: &Path) -> bool {
220220
!val
221221
}
222222

223-
fn iter_header(testfile: &Path, it: |&str| -> bool) -> bool {
223+
fn iter_header<F>(testfile: &Path, mut it: F) -> bool where
224+
F: FnMut(&str) -> bool,
225+
{
224226
use std::io::{BufferedReader, File};
225227

226228
let mut rdr = BufferedReader::new(File::open(testfile).unwrap());

src/compiletest/runtest.rs

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1233,12 +1233,14 @@ enum TargetLocation {
12331233
ThisDirectory(Path),
12341234
}
12351235

1236-
fn make_compile_args(config: &Config,
1237-
props: &TestProps,
1238-
extras: Vec<String> ,
1239-
xform: |&Config, &Path| -> TargetLocation,
1240-
testfile: &Path)
1241-
-> ProcArgs {
1236+
fn make_compile_args<F>(config: &Config,
1237+
props: &TestProps,
1238+
extras: Vec<String> ,
1239+
xform: F,
1240+
testfile: &Path)
1241+
-> ProcArgs where
1242+
F: FnOnce(&Config, &Path) -> TargetLocation,
1243+
{
12421244
let xform_file = xform(config, testfile);
12431245
let target = if props.force_host {
12441246
config.host.as_slice()

src/doc/guide-testing.md

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -537,7 +537,8 @@ computation entirely. This could be done for the example above by adjusting the
537537
`b.iter` call to
538538

539539
```rust
540-
# struct X; impl X { fn iter<T>(&self, _: || -> T) {} } let b = X;
540+
# struct X;
541+
# impl X { fn iter<T, F>(&self, _: F) where F: FnMut() -> T {} } let b = X;
541542
b.iter(|| {
542543
// note lack of `;` (could also use an explicit `return`).
543544
range(0u, 1000).fold(0, |old, new| old ^ new)
@@ -552,7 +553,8 @@ argument as used.
552553
extern crate test;
553554

554555
# fn main() {
555-
# struct X; impl X { fn iter<T>(&self, _: || -> T) {} } let b = X;
556+
# struct X;
557+
# impl X { fn iter<T, F>(&self, _: F) where F: FnMut() -> T {} } let b = X;
556558
b.iter(|| {
557559
test::black_box(range(0u, 1000).fold(0, |old, new| old ^ new));
558560
});

src/doc/guide.md

Lines changed: 16 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -4232,7 +4232,7 @@ arguments, really powerful things are possible.
42324232
Let's make a closure:
42334233
42344234
```{rust}
4235-
let add_one = |x| { 1 + x };
4235+
let add_one = |&: x| { 1 + x };
42364236
42374237
println!("The sum of 5 plus 1 is {}.", add_one(5));
42384238
```
@@ -4244,8 +4244,8 @@ binding name and two parentheses, just like we would for a named function.
42444244
Let's compare syntax. The two are pretty close:
42454245
42464246
```{rust}
4247-
let add_one = |x: i32| -> i32 { 1 + x };
4248-
fn add_one (x: i32) -> i32 { 1 + x }
4247+
let add_one = |&: x: i32| -> i32 { 1 + x };
4248+
fn add_one (x: i32) -> i32 { 1 + x }
42494249
```
42504250
42514251
As you may have noticed, closures infer their argument and return types, so you
@@ -4258,9 +4258,9 @@ this:
42584258
42594259
```{rust}
42604260
fn main() {
4261-
let x = 5;
4261+
let x: i32 = 5;
42624262
4263-
let printer = || { println!("x is: {}", x); };
4263+
let printer = |&:| { println!("x is: {}", x); };
42644264
42654265
printer(); // prints "x is: 5"
42664266
}
@@ -4276,7 +4276,7 @@ defined. The closure borrows any variables it uses, so this will error:
42764276
fn main() {
42774277
let mut x = 5;
42784278
4279-
let printer = || { println!("x is: {}", x); };
4279+
let printer = |&:| { println!("x is: {}", x); };
42804280
42814281
x = 6; // error: cannot assign to `x` because it is borrowed
42824282
}
@@ -4298,12 +4298,12 @@ now. We'll talk about them more in the "Threads" section of the guide.
42984298
Closures are most useful as an argument to another function. Here's an example:
42994299
43004300
```{rust}
4301-
fn twice(x: i32, f: |i32| -> i32) -> i32 {
4301+
fn twice<F: Fn(i32) -> i32>(x: i32, f: F) -> i32 {
43024302
f(x) + f(x)
43034303
}
43044304
43054305
fn main() {
4306-
let square = |x: i32| { x * x };
4306+
let square = |&: x: i32| { x * x };
43074307
43084308
twice(5, square); // evaluates to 50
43094309
}
@@ -4312,15 +4312,15 @@ fn main() {
43124312
Let's break the example down, starting with `main`:
43134313
43144314
```{rust}
4315-
let square = |x: i32| { x * x };
4315+
let square = |&: x: i32| { x * x };
43164316
```
43174317
43184318
We've seen this before. We make a closure that takes an integer, and returns
43194319
its square.
43204320
43214321
```{rust}
4322-
# fn twice(x: i32, f: |i32| -> i32) -> i32 { f(x) + f(x) }
4323-
# let square = |x: i32| { x * x };
4322+
# fn twice<F: Fn(i32) -> i32>(x: i32, f: F) -> i32 { f(x) + f(x) }
4323+
# let square = |&: x: i32| { x * x };
43244324
twice(5, square); // evaluates to 50
43254325
```
43264326
@@ -4343,8 +4343,8 @@ how the `|i32| -> i32` syntax looks a lot like our definition of `square`
43434343
above, if we added the return type in:
43444344
43454345
```{rust}
4346-
let square = |x: i32| -> i32 { x * x };
4347-
// |i32| -> i32
4346+
let square = |&: x: i32| -> i32 { x * x };
4347+
// |i32| -> i32
43484348
```
43494349
43504350
This function takes an `i32` and returns an `i32`.
@@ -4358,7 +4358,7 @@ Finally, `twice` returns an `i32` as well.
43584358
Okay, let's look at the body of `twice`:
43594359
43604360
```{rust}
4361-
fn twice(x: i32, f: |i32| -> i32) -> i32 {
4361+
fn twice<F: Fn(i32) -> i32>(x: i32, f: F) -> i32 {
43624362
f(x) + f(x)
43634363
}
43644364
```
@@ -4376,7 +4376,7 @@ If we didn't want to give `square` a name, we could just define it inline.
43764376
This example is the same as the previous one:
43774377
43784378
```{rust}
4379-
fn twice(x: i32, f: |i32| -> i32) -> i32 {
4379+
fn twice<F: Fn(i32) -> i32>(x: i32, f: F) -> i32 {
43804380
f(x) + f(x)
43814381
}
43824382
@@ -4389,7 +4389,7 @@ A named function's name can be used wherever you'd use a closure. Another
43894389
way of writing the previous example:
43904390
43914391
```{rust}
4392-
fn twice(x: i32, f: |i32| -> i32) -> i32 {
4392+
fn twice<F: Fn(i32) -> i32>(x: i32, f: F) -> i32 {
43934393
f(x) + f(x)
43944394
}
43954395

src/doc/reference.md

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1563,7 +1563,7 @@ functions](#generic-functions).
15631563
trait Seq<T> {
15641564
fn len(&self) -> uint;
15651565
fn elt_at(&self, n: uint) -> T;
1566-
fn iter(&self, |T|);
1566+
fn iter<F>(&self, F) where F: Fn(T);
15671567
}
15681568
```
15691569

@@ -3218,7 +3218,7 @@ In this example, we define a function `ten_times` that takes a higher-order
32183218
function argument, and call it with a lambda expression as an argument.
32193219

32203220
```
3221-
fn ten_times(f: |int|) {
3221+
fn ten_times<F>(f: F) where F: Fn(int) {
32223222
let mut i = 0;
32233223
while i < 10 {
32243224
f(i);
@@ -3828,7 +3828,7 @@ fn add(x: int, y: int) -> int {
38283828
38293829
let mut x = add(5,7);
38303830
3831-
type Binop<'a> = |int,int|: 'a -> int;
3831+
type Binop = fn(int, int) -> int;
38323832
let bo: Binop = add;
38333833
x = bo(5,7);
38343834
```
@@ -3852,14 +3852,14 @@ An example of creating and calling a closure:
38523852
```rust
38533853
let captured_var = 10i;
38543854

3855-
let closure_no_args = || println!("captured_var={}", captured_var);
3855+
let closure_no_args = |&:| println!("captured_var={}", captured_var);
38563856

3857-
let closure_args = |arg: int| -> int {
3857+
let closure_args = |&: arg: int| -> int {
38583858
println!("captured_var={}, arg={}", captured_var, arg);
38593859
arg // Note lack of semicolon after 'arg'
38603860
};
38613861

3862-
fn call_closure(c1: ||, c2: |int| -> int) {
3862+
fn call_closure<F: Fn(), G: Fn(int) -> int>(c1: F, c2: G) {
38633863
c1();
38643864
c2(2);
38653865
}

src/libcollections/bit.rs

Lines changed: 0 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -164,21 +164,6 @@ pub struct Bitv {
164164
nbits: uint
165165
}
166166

167-
// NOTE(stage0): remove impl after a snapshot
168-
#[cfg(stage0)]
169-
// FIXME(Gankro): NopeNopeNopeNopeNope (wait for IndexGet to be a thing)
170-
impl Index<uint,bool> for Bitv {
171-
#[inline]
172-
fn index(&self, i: &uint) -> &bool {
173-
if self.get(*i).expect("index out of bounds") {
174-
&TRUE
175-
} else {
176-
&FALSE
177-
}
178-
}
179-
}
180-
181-
#[cfg(not(stage0))] // NOTE(stage0): remove cfg after a snapshot
182167
// FIXME(Gankro): NopeNopeNopeNopeNope (wait for IndexGet to be a thing)
183168
impl Index<uint> for Bitv {
184169
type Output = bool;

src/libcollections/btree/map.rs

Lines changed: 0 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -877,18 +877,6 @@ impl<K: Show, V: Show> Show for BTreeMap<K, V> {
877877
}
878878
}
879879

880-
// NOTE(stage0): remove impl after a snapshot
881-
#[cfg(stage0)]
882-
#[stable]
883-
impl<K: Ord, Sized? Q, V> Index<Q, V> for BTreeMap<K, V>
884-
where Q: BorrowFrom<K> + Ord
885-
{
886-
fn index(&self, key: &Q) -> &V {
887-
self.get(key).expect("no entry found for key")
888-
}
889-
}
890-
891-
#[cfg(not(stage0))] // NOTE(stage0): remove cfg after a snapshot
892880
#[stable]
893881
impl<K: Ord, Sized? Q, V> Index<Q> for BTreeMap<K, V>
894882
where Q: BorrowFrom<K> + Ord
@@ -900,18 +888,6 @@ impl<K: Ord, Sized? Q, V> Index<Q> for BTreeMap<K, V>
900888
}
901889
}
902890

903-
// NOTE(stage0): remove impl after a snapshot
904-
#[cfg(stage0)]
905-
#[stable]
906-
impl<K: Ord, Sized? Q, V> IndexMut<Q, V> for BTreeMap<K, V>
907-
where Q: BorrowFrom<K> + Ord
908-
{
909-
fn index_mut(&mut self, key: &Q) -> &mut V {
910-
self.get_mut(key).expect("no entry found for key")
911-
}
912-
}
913-
914-
#[cfg(not(stage0))] // NOTE(stage0): remove cfg after a snapshot
915891
#[stable]
916892
impl<K: Ord, Sized? Q, V> IndexMut<Q> for BTreeMap<K, V>
917893
where Q: BorrowFrom<K> + Ord

src/libcollections/ring_buf.rs

Lines changed: 0 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1360,17 +1360,6 @@ impl<S: Writer, A: Hash<S>> Hash<S> for RingBuf<A> {
13601360
}
13611361
}
13621362

1363-
// NOTE(stage0): remove impl after a snapshot
1364-
#[cfg(stage0)]
1365-
#[stable]
1366-
impl<A> Index<uint, A> for RingBuf<A> {
1367-
#[inline]
1368-
fn index<'a>(&'a self, i: &uint) -> &'a A {
1369-
self.get(*i).expect("Out of bounds access")
1370-
}
1371-
}
1372-
1373-
#[cfg(not(stage0))] // NOTE(stage0): remove cfg after a snapshot
13741363
#[stable]
13751364
impl<A> Index<uint> for RingBuf<A> {
13761365
type Output = A;
@@ -1381,17 +1370,6 @@ impl<A> Index<uint> for RingBuf<A> {
13811370
}
13821371
}
13831372

1384-
// NOTE(stage0): remove impl after a snapshot
1385-
#[cfg(stage0)]
1386-
#[stable]
1387-
impl<A> IndexMut<uint, A> for RingBuf<A> {
1388-
#[inline]
1389-
fn index_mut<'a>(&'a mut self, i: &uint) -> &'a mut A {
1390-
self.get_mut(*i).expect("Out of bounds access")
1391-
}
1392-
}
1393-
1394-
#[cfg(not(stage0))] // NOTE(stage0): remove cfg after a snapshot
13951373
#[stable]
13961374
impl<A> IndexMut<uint> for RingBuf<A> {
13971375
type Output = A;

src/libcollections/vec.rs

Lines changed: 0 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1190,17 +1190,6 @@ impl<S: hash::Writer, T: Hash<S>> Hash<S> for Vec<T> {
11901190
}
11911191
}
11921192

1193-
// NOTE(stage0): remove impl after a snapshot
1194-
#[cfg(stage0)]
1195-
#[experimental = "waiting on Index stability"]
1196-
impl<T> Index<uint,T> for Vec<T> {
1197-
#[inline]
1198-
fn index<'a>(&'a self, index: &uint) -> &'a T {
1199-
&self.as_slice()[*index]
1200-
}
1201-
}
1202-
1203-
#[cfg(not(stage0))] // NOTE(stage0): remove cfg after a snapshot
12041193
#[experimental = "waiting on Index stability"]
12051194
impl<T> Index<uint> for Vec<T> {
12061195
type Output = T;
@@ -1211,16 +1200,6 @@ impl<T> Index<uint> for Vec<T> {
12111200
}
12121201
}
12131202

1214-
// NOTE(stage0): remove impl after a snapshot
1215-
#[cfg(stage0)]
1216-
impl<T> IndexMut<uint,T> for Vec<T> {
1217-
#[inline]
1218-
fn index_mut<'a>(&'a mut self, index: &uint) -> &'a mut T {
1219-
&mut self.as_mut_slice()[*index]
1220-
}
1221-
}
1222-
1223-
#[cfg(not(stage0))] // NOTE(stage0): remove cfg after a snapshot
12241203
impl<T> IndexMut<uint> for Vec<T> {
12251204
type Output = T;
12261205

src/libcollections/vec_map.rs

Lines changed: 0 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -517,17 +517,6 @@ impl<V> Extend<(uint, V)> for VecMap<V> {
517517
}
518518
}
519519

520-
// NOTE(stage0): remove impl after a snapshot
521-
#[cfg(stage0)]
522-
#[stable]
523-
impl<V> Index<uint, V> for VecMap<V> {
524-
#[inline]
525-
fn index<'a>(&'a self, i: &uint) -> &'a V {
526-
self.get(i).expect("key not present")
527-
}
528-
}
529-
530-
#[cfg(not(stage0))] // NOTE(stage0): remove cfg after a snapshot
531520
impl<V> Index<uint> for VecMap<V> {
532521
type Output = V;
533522

@@ -537,17 +526,6 @@ impl<V> Index<uint> for VecMap<V> {
537526
}
538527
}
539528

540-
// NOTE(stage0): remove impl after a snapshot
541-
#[cfg(stage0)]
542-
#[stable]
543-
impl<V> IndexMut<uint, V> for VecMap<V> {
544-
#[inline]
545-
fn index_mut<'a>(&'a mut self, i: &uint) -> &'a mut V {
546-
self.get_mut(i).expect("key not present")
547-
}
548-
}
549-
550-
#[cfg(not(stage0))] // NOTE(stage0): remove cfg after a snapshot
551529
#[stable]
552530
impl<V> IndexMut<uint> for VecMap<V> {
553531
type Output = V;

0 commit comments

Comments
 (0)