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/libsyntax/parse | |
| 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/libsyntax/parse')
| -rw-r--r-- | src/libsyntax/parse/obsolete.rs | 5 | ||||
| -rw-r--r-- | src/libsyntax/parse/parser.rs | 40 |
2 files changed, 20 insertions, 25 deletions
diff --git a/src/libsyntax/parse/obsolete.rs b/src/libsyntax/parse/obsolete.rs index e1e456f880e..75b2c17b81b 100644 --- a/src/libsyntax/parse/obsolete.rs +++ b/src/libsyntax/parse/obsolete.rs @@ -34,6 +34,7 @@ pub enum ObsoleteSyntax { ObsoleteExternCrateRenaming, ObsoleteProcType, ObsoleteProcExpr, + ObsoleteClosureType, } pub trait ParserObsoleteMethods { @@ -94,6 +95,10 @@ impl<'a> ParserObsoleteMethods for parser::Parser<'a> { ObsoleteExternCrateRenaming => ( "`extern crate foo = bar` syntax", "write `extern crate bar as foo` instead" + ), + ObsoleteClosureType => ( + "`|uint| -> bool` closure type syntax", + "use unboxed closures instead, no type annotation needed" ) }; diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index cc67079e538..28c7293fc26 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -14,7 +14,7 @@ pub use self::PathParsingMode::*; use self::ItemOrViewItem::*; use abi; -use ast::{AssociatedType, BareFnTy, ClosureTy}; +use ast::{AssociatedType, BareFnTy}; use ast::{RegionTyParamBound, TraitTyParamBound, TraitBoundModifier}; use ast::{ProvidedMethod, Public, Unsafety}; use ast::{Mod, BiAdd, Arg, Arm, Attribute, BindByRef, BindByValue}; @@ -30,7 +30,6 @@ use ast::{ExprLit, ExprLoop, ExprMac, ExprRange}; use ast::{ExprMethodCall, ExprParen, ExprPath}; use ast::{ExprRepeat, ExprRet, ExprStruct, ExprTup, ExprUnary}; use ast::{ExprVec, ExprWhile, ExprWhileLet, ExprForLoop, Field, FnDecl}; -use ast::{Many}; use ast::{FnUnboxedClosureKind, FnMutUnboxedClosureKind}; use ast::{FnOnceUnboxedClosureKind}; use ast::{ForeignItem, ForeignItemStatic, ForeignItemFn, ForeignMod, FunctionRetTy}; @@ -55,7 +54,7 @@ use ast::{SelfExplicit, SelfRegion, SelfStatic, SelfValue}; use ast::{Delimited, SequenceRepetition, TokenTree, TraitItem, TraitRef}; use ast::{TtDelimited, TtSequence, TtToken}; use ast::{TupleVariantKind, Ty, Ty_, TypeBinding}; -use ast::{TypeField, TyFixedLengthVec, TyClosure, TyBareFn}; +use ast::{TypeField, TyFixedLengthVec, TyBareFn}; use ast::{TyTypeof, TyInfer, TypeMethod}; use ast::{TyParam, TyParamBound, TyParen, TyPath, TyPolyTraitRef, TyPtr, TyQPath}; use ast::{TyRptr, TyTup, TyU32, TyVec, UnUniq}; @@ -1227,38 +1226,29 @@ impl<'a> Parser<'a> { */ - let unsafety = self.parse_unsafety(); + let ty_closure_span = self.last_span; - let lifetime_defs = self.parse_legacy_lifetime_defs(lifetime_defs); + // To be helpful, parse the closure type as ever + let _ = self.parse_unsafety(); - let inputs = if self.eat(&token::OrOr) { - Vec::new() - } else { + let _ = self.parse_legacy_lifetime_defs(lifetime_defs); + + if !self.eat(&token::OrOr) { self.expect_or(); - let inputs = self.parse_seq_to_before_or( + let _ = self.parse_seq_to_before_or( &token::Comma, |p| p.parse_arg_general(false)); self.expect_or(); - inputs - }; + } - let bounds = self.parse_colon_then_ty_param_bounds(BoundParsingMode::Bare); + let _ = self.parse_colon_then_ty_param_bounds(BoundParsingMode::Bare); - let output = self.parse_ret_ty(); - let decl = P(FnDecl { - inputs: inputs, - output: output, - variadic: false - }); + let _ = self.parse_ret_ty(); - TyClosure(P(ClosureTy { - unsafety: unsafety, - onceness: Many, - bounds: bounds, - decl: decl, - lifetimes: lifetime_defs, - })) + self.obsolete(ty_closure_span, ObsoleteClosureType); + + TyInfer } pub fn parse_unsafety(&mut self) -> Unsafety { |
