about summary refs log tree commit diff
path: root/src/libstd
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2015-01-05 23:51:00 +0000
committerbors <bors@rust-lang.org>2015-01-05 23:51:00 +0000
commitc7dd3c4d69aee1c4ad8cc220c194b176bba2ab62 (patch)
tree437b342261834278ef6b45fde186c5944eb4819e /src/libstd
parentf11f3e7baeba3f5acf08cc6fbfee559c00e9f96e (diff)
parenteb2506cc1bcf2011d4e8ce99ff7cf74c2c1d1493 (diff)
downloadrust-c7dd3c4d69aee1c4ad8cc220c194b176bba2ab62.tar.gz
rust-c7dd3c4d69aee1c4ad8cc220c194b176bba2ab62.zip
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 
Diffstat (limited to 'src/libstd')
-rw-r--r--src/libstd/collections/hash/map.rs26
-rw-r--r--src/libstd/io/fs.rs8
-rw-r--r--src/libstd/io/net/ip.rs19
3 files changed, 15 insertions, 38 deletions
diff --git a/src/libstd/collections/hash/map.rs b/src/libstd/collections/hash/map.rs
index a6532707f3e..c35be86420d 100644
--- a/src/libstd/collections/hash/map.rs
+++ b/src/libstd/collections/hash/map.rs
@@ -1226,19 +1226,6 @@ impl<K: Eq + Hash<S>, V, S, H: Hasher<S> + Default> Default for HashMap<K, V, H>
     }
 }
 
-// NOTE(stage0): remove impl after a snapshot
-#[cfg(stage0)]
-#[stable]
-impl<K: Hash<S> + Eq, Sized? Q, V, S, H: Hasher<S>> Index<Q, V> for HashMap<K, V, H>
-    where Q: BorrowFrom<K> + Hash<S> + Eq
-{
-    #[inline]
-    fn index<'a>(&'a self, index: &Q) -> &'a V {
-        self.get(index).expect("no entry found for key")
-    }
-}
-
-#[cfg(not(stage0))]  // NOTE(stage0): remove cfg after a snapshot
 #[stable]
 impl<K: Hash<S> + Eq, Sized? Q, V, S, H: Hasher<S>> Index<Q> for HashMap<K, V, H>
     where Q: BorrowFrom<K> + Hash<S> + Eq
@@ -1251,19 +1238,6 @@ impl<K: Hash<S> + Eq, Sized? Q, V, S, H: Hasher<S>> Index<Q> for HashMap<K, V, H
     }
 }
 
-// NOTE(stage0): remove impl after a snapshot
-#[cfg(stage0)]
-#[stable]
-impl<K: Hash<S> + Eq, Sized? Q, V, S, H: Hasher<S>> IndexMut<Q, V> for HashMap<K, V, H>
-    where Q: BorrowFrom<K> + Hash<S> + Eq
-{
-    #[inline]
-    fn index_mut<'a>(&'a mut self, index: &Q) -> &'a mut V {
-        self.get_mut(index).expect("no entry found for key")
-    }
-}
-
-#[cfg(not(stage0))]  // NOTE(stage0): remove cfg after a snapshot
 #[stable]
 impl<K: Hash<S> + Eq, Sized? Q, V, S, H: Hasher<S>> IndexMut<Q> for HashMap<K, V, H>
     where Q: BorrowFrom<K> + Hash<S> + Eq
diff --git a/src/libstd/io/fs.rs b/src/libstd/io/fs.rs
index 5cb79d41db9..4691c06c1de 100644
--- a/src/libstd/io/fs.rs
+++ b/src/libstd/io/fs.rs
@@ -518,14 +518,16 @@ pub fn rmdir(path: &Path) -> IoResult<()> {
 /// use std::io;
 ///
 /// // one possible implementation of fs::walk_dir only visiting files
-/// fn visit_dirs(dir: &Path, cb: |&Path|) -> io::IoResult<()> {
+/// fn visit_dirs<F>(dir: &Path, cb: &mut F) -> io::IoResult<()> where
+///     F: FnMut(&Path),
+/// {
 ///     if dir.is_dir() {
 ///         let contents = try!(fs::readdir(dir));
 ///         for entry in contents.iter() {
 ///             if entry.is_dir() {
-///                 try!(visit_dirs(entry, |p| cb(p)));
+///                 try!(visit_dirs(entry, cb));
 ///             } else {
-///                 cb(entry);
+///                 (*cb)(entry);
 ///             }
 ///         }
 ///         Ok(())
diff --git a/src/libstd/io/net/ip.rs b/src/libstd/io/net/ip.rs
index 52b589b5f24..d398b61fe64 100644
--- a/src/libstd/io/net/ip.rs
+++ b/src/libstd/io/net/ip.rs
@@ -17,11 +17,12 @@
 
 pub use self::IpAddr::*;
 
+use boxed::Box;
 use fmt;
 use io::{self, IoResult, IoError};
 use io::net;
 use iter::{Iterator, IteratorExt};
-use ops::FnOnce;
+use ops::{FnOnce, FnMut};
 use option::Option;
 use option::Option::{None, Some};
 use result::Result::{Ok, Err};
@@ -120,10 +121,10 @@ impl<'a> Parser<'a> {
     }
 
     // Return result of first successful parser
-    fn read_or<T>(&mut self, parsers: &mut [|&mut Parser| -> Option<T>])
+    fn read_or<T>(&mut self, parsers: &mut [Box<FnMut(&mut Parser) -> Option<T>>])
                -> Option<T> {
         for pf in parsers.iter_mut() {
-            match self.read_atomically(|p: &mut Parser| (*pf)(p)) {
+            match self.read_atomically(|p: &mut Parser| pf.call_mut((p,))) {
                 Some(r) => return Some(r),
                 None => {}
             }
@@ -320,22 +321,22 @@ impl<'a> Parser<'a> {
     }
 
     fn read_ip_addr(&mut self) -> Option<IpAddr> {
-        let ipv4_addr = |p: &mut Parser| p.read_ipv4_addr();
-        let ipv6_addr = |p: &mut Parser| p.read_ipv6_addr();
-        self.read_or(&mut [ipv4_addr, ipv6_addr])
+        let ipv4_addr = |&mut: p: &mut Parser| p.read_ipv4_addr();
+        let ipv6_addr = |&mut: p: &mut Parser| p.read_ipv6_addr();
+        self.read_or(&mut [box ipv4_addr, box ipv6_addr])
     }
 
     fn read_socket_addr(&mut self) -> Option<SocketAddr> {
         let ip_addr = |&: p: &mut Parser| {
-            let ipv4_p = |p: &mut Parser| p.read_ip_addr();
-            let ipv6_p = |p: &mut Parser| {
+            let ipv4_p = |&mut: p: &mut Parser| p.read_ip_addr();
+            let ipv6_p = |&mut: p: &mut Parser| {
                 let open_br = |&: p: &mut Parser| p.read_given_char('[');
                 let ip_addr = |&: p: &mut Parser| p.read_ipv6_addr();
                 let clos_br = |&: p: &mut Parser| p.read_given_char(']');
                 p.read_seq_3::<char, IpAddr, char, _, _, _>(open_br, ip_addr, clos_br)
                         .map(|t| match t { (_, ip, _) => ip })
             };
-            p.read_or(&mut [ipv4_p, ipv6_p])
+            p.read_or(&mut [box ipv4_p, box ipv6_p])
         };
         let colon = |&: p: &mut Parser| p.read_given_char(':');
         let port  = |&: p: &mut Parser| p.read_number(10, 5, 0x10000).map(|n| n as u16);