Opt-in built-in traits allowed one to explicitly implement both `Drop`
and `Copy` for a type. This can theoretically make some sense, but the
current implementation means it is codegened totally incorrectly which
can lead to memory unsafety, so this feature is disabled for now.
Fixes#20126.
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
The first few commits in the PR are just general refactoring. I was intending them for some other code I didn't get around to writing yet, but might as well land them now.
cc @japaric
Fixes#19541
This commit moves the libserialize crate (and will force the hand of the
rustc-serialize crate) to not require the `old_orphan_check` feature gate as
well as using associated types wherever possible. Concretely, the following
changes were made:
* The error type of `Encoder` and `Decoder` is now an associated type, meaning
that these traits have no type parameters.
* The `Encoder` and `Decoder` type parameters on the `Encodable` and `Decodable`
traits have moved to the corresponding method of the trait. This movement
alleviates the dependency on `old_orphan_check` but implies that
implementations can no longer be specialized for the type of encoder/decoder
being implemented.
Due to the trait definitions changing, this is a:
[breaking-change]
This commit moves the libserialize crate (and will force the hand of the
rustc-serialize crate) to not require the `old_orphan_check` feature gate as
well as using associated types wherever possible. Concretely, the following
changes were made:
* The error type of `Encoder` and `Decoder` is now an associated type, meaning
that these traits have no type parameters.
* The `Encoder` and `Decoder` type parameters on the `Encodable` and `Decodable`
traits have moved to the corresponding method of the trait. This movement
alleviates the dependency on `old_orphan_check` but implies that
implementations can no longer be specialized for the type of encoder/decoder
being implemented.
Due to the trait definitions changing, this is a:
[breaking-change]