diff options
| author | bors <bors@rust-lang.org> | 2015-01-05 23:51:00 +0000 |
|---|---|---|
| committer | bors <bors@rust-lang.org> | 2015-01-05 23:51:00 +0000 |
| commit | c7dd3c4d69aee1c4ad8cc220c194b176bba2ab62 (patch) | |
| tree | 437b342261834278ef6b45fde186c5944eb4819e /src/libstd | |
| parent | f11f3e7baeba3f5acf08cc6fbfee559c00e9f96e (diff) | |
| parent | eb2506cc1bcf2011d4e8ce99ff7cf74c2c1d1493 (diff) | |
| download | rust-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.rs | 26 | ||||
| -rw-r--r-- | src/libstd/io/fs.rs | 8 | ||||
| -rw-r--r-- | src/libstd/io/net/ip.rs | 19 |
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); |
