about summary refs log tree commit diff
diff options
context:
space:
mode:
authorAlex Crichton <alex@alexcrichton.com>2015-02-03 15:36:07 -0800
committerAlex Crichton <alex@alexcrichton.com>2015-02-03 20:11:20 -0800
commit74f7e0693909a45f9159c6d2ef72b42fcb4f1bac (patch)
tree4a275ef4606878200f7a1e7ee57cf9fa1bb75b16
parent1d921f557d6d9e509ce0d696d7b2178628989935 (diff)
parent8ddcb06b1d021560bfe641c0dbc452a04e80388e (diff)
rollup merge of #21899: nikomatsakis/closure-unify-anyhow
This *almost* completes the job for #16440. The idea is that even if we do not know whether some closure type `C` implements `Fn` or `FnMut` (etc), we still know its argument and return types. So if we see an obligation `C : Fn(_0)`, we can unify `_0` with those argument types while still considering the obligation ambiguous and unsatisfied. This helps to make a lot of progress with type inference even before closure kind inference is done.

As part of this PR, the explicit `:` syntax is removed from the AST and completely ignored. We still infer the closure kind based on the expected type if that is available. There are several reasons for this. First, deciding the closure kind earlier is always better, as it allows us to make more progress. Second, this retains a (admittedly obscure) way for users to manually specify the closure kind, which is useful for writing tests if nothing else. Finally, there are still some cases where inference can fail, so it may be useful to have this manual override. (The expectation is that we will eventually revisit an explicit syntax for specifying the closure kind, but it will not be `:` and may be some sort of generalization of the `||` syntax to handle other traits as well.)

This commit does not *quite* fix #16640 because a snapshot is still needed to enable the obsolete syntax errors for explicit `&mut:` and friends.

r? @eddyb as he reviewed the prior patch in this direction
-rw-r--r--src/librustc/middle/check_loop.rs2
-rw-r--r--src/librustc/middle/liveness.rs2
-rw-r--r--src/librustc/middle/mem_categorization.rs2
-rw-r--r--src/librustc/middle/traits/project.rs75
-rw-r--r--src/librustc/middle/traits/select.rs82
-rw-r--r--src/librustc_borrowck/borrowck/mod.rs2
-rw-r--r--src/librustc_resolve/lib.rs2
-rw-r--r--src/librustc_trans/save/mod.rs2
-rw-r--r--src/librustc_trans/trans/base.rs2
-rw-r--r--src/librustc_trans/trans/debuginfo.rs4
-rw-r--r--src/librustc_trans/trans/expr.rs2
-rw-r--r--src/librustc_typeck/check/closure.rs151
-rw-r--r--src/librustc_typeck/check/mod.rs4
-rw-r--r--src/librustc_typeck/check/regionck.rs2
-rw-r--r--src/librustc_typeck/check/upvar.rs2
-rw-r--r--src/librustc_typeck/check/writeback.rs2
-rw-r--r--src/libsyntax/ast.rs10
-rw-r--r--src/libsyntax/ast_map/blocks.rs2
-rw-r--r--src/libsyntax/ext/build.rs4
-rw-r--r--src/libsyntax/ext/deriving/rand.rs2
-rw-r--r--src/libsyntax/ext/expand.rs3
-rw-r--r--src/libsyntax/fold.rs3
-rw-r--r--src/libsyntax/parse/obsolete.rs5
-rw-r--r--src/libsyntax/parse/parser.rs62
-rw-r--r--src/libsyntax/print/pprust.rs19
-rw-r--r--src/libsyntax/visit.rs2
-rw-r--r--src/test/compile-fail/borrow-immutable-upvar-mutation.rs18
-rw-r--r--src/test/compile-fail/borrowck-move-by-capture.rs11
-rw-r--r--src/test/compile-fail/cannot-mutate-captured-non-mut-var.rs8
-rw-r--r--src/test/compile-fail/issue-11925.rs6
-rw-r--r--src/test/compile-fail/issue-12127.rs7
-rw-r--r--src/test/compile-fail/moves-based-on-type-move-out-of-closure-env-issue-1965.rs6
-rw-r--r--src/test/compile-fail/unboxed-closer-non-implicit-copyable.rs4
-rw-r--r--src/test/compile-fail/unboxed-closure-illegal-move.rs16
-rw-r--r--src/test/compile-fail/unboxed-closures-mutate-upvar.rs29
-rw-r--r--src/test/compile-fail/unboxed-closures-static-call-wrong-trait.rs4
-rw-r--r--src/test/compile-fail/unboxed-closures-vtable-mismatch.rs4
-rw-r--r--src/test/compile-fail/unboxed-closures-wrong-trait.rs23
-rw-r--r--src/test/run-pass/closure-inference.rs4
-rw-r--r--src/test/run-pass/last-use-in-cap-clause.rs4
-rw-r--r--src/test/run-pass/unboxed-closures-zero-args.rs4
41 files changed, 349 insertions, 249 deletions
diff --git a/src/librustc/middle/check_loop.rs b/src/librustc/middle/check_loop.rs
index 41ef55933cd..ea584407944 100644
--- a/src/librustc/middle/check_loop.rs
+++ b/src/librustc/middle/check_loop.rs
@@ -45,7 +45,7 @@ impl<'a, 'v> Visitor<'v> for CheckLoopVisitor<'a> {
             ast::ExprLoop(ref b, _) => {
                 self.with_context(Loop, |v| v.visit_block(&**b));
             }
-            ast::ExprClosure(_, _, _, ref b) => {
+            ast::ExprClosure(_, _, ref b) => {
                 self.with_context(Closure, |v| v.visit_block(&**b));
             }
             ast::ExprBreak(_) => self.require_loop("break", e.span),
diff --git a/src/librustc/middle/liveness.rs b/src/librustc/middle/liveness.rs
index e40e04bdee8..c0fabb2a348 100644
--- a/src/librustc/middle/liveness.rs
+++ b/src/librustc/middle/liveness.rs
@@ -959,7 +959,7 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> {
               self.propagate_through_expr(&**e, succ)
           }
 
-          ast::ExprClosure(_, _, _, ref blk) => {
+          ast::ExprClosure(_, _, ref blk) => {
               debug!("{} is an ExprClosure",
                      expr_to_string(expr));
 
diff --git a/src/librustc/middle/mem_categorization.rs b/src/librustc/middle/mem_categorization.rs
index 1ae483be269..156ff43e2ba 100644
--- a/src/librustc/middle/mem_categorization.rs
+++ b/src/librustc/middle/mem_categorization.rs
@@ -739,7 +739,7 @@ impl<'t,'tcx,TYPER:Typer<'tcx>> MemCategorizationContext<'t,TYPER> {
             };
 
             match fn_expr.node {
-                ast::ExprClosure(_, _, _, ref body) => body.id,
+                ast::ExprClosure(_, _, ref body) => body.id,
                 _ => unreachable!()
             }
         };
diff --git a/src/librustc/middle/traits/project.rs b/src/librustc/middle/traits/project.rs
index 3ede6bbb965..c2a451b405b 100644
--- a/src/librustc/middle/traits/project.rs
+++ b/src/librustc/middle/traits/project.rs
@@ -80,37 +80,23 @@ pub fn poly_project_and_unify_type<'cx,'tcx>(
            obligation.repr(selcx.tcx()));
 
     let infcx = selcx.infcx();
-    let result = infcx.try(|snapshot| {
+    infcx.try(|snapshot| {
         let (skol_predicate, skol_map) =
             infcx.skolemize_late_bound_regions(&obligation.predicate, snapshot);
 
         let skol_obligation = obligation.with(skol_predicate);
         match project_and_unify_type(selcx, &skol_obligation) {
-            Ok(Some(obligations)) => {
+            Ok(result) => {
                 match infcx.leak_check(&skol_map, snapshot) {
-                    Ok(()) => Ok(infcx.plug_leaks(skol_map, snapshot, &obligations)),
-                    Err(e) => Err(Some(MismatchedProjectionTypes { err: e })),
+                    Ok(()) => Ok(infcx.plug_leaks(skol_map, snapshot, &result)),
+                    Err(e) => Err(MismatchedProjectionTypes { err: e }),
                 }
             }
-            Ok(None) => {
-                // Signal ambiguity using Err just so that infcx.try()
-                // rolls back the snapshot. We adapt below.
-                Err(None)
-            }
             Err(e) => {
-                Err(Some(e))
+                Err(e)
             }
         }
-    });
-
-    // Above, we use Err(None) to signal ambiguity so that the
-    // snapshot will be rolled back. But here, we want to translate to
-    // Ok(None). Kind of weird.
-    match result {
-        Ok(obligations) => Ok(Some(obligations)),
-        Err(None) => Ok(None),
-        Err(Some(e)) => Err(e),
-    }
+    })
 }
 
 /// Evaluates constraints of the form:
@@ -132,7 +118,10 @@ fn project_and_unify_type<'cx,'tcx>(
                                             obligation.cause.clone(),
                                             obligation.recursion_depth) {
             Some(n) => n,
-            None => { return Ok(None); }
+            None => {
+                consider_unification_despite_ambiguity(selcx, obligation);
+                return Ok(None);
+            }
         };
 
     debug!("project_and_unify_type: normalized_ty={} obligations={}",
@@ -147,6 +136,50 @@ fn project_and_unify_type<'cx,'tcx>(
     }
 }
 
+fn consider_unification_despite_ambiguity<'cx,'tcx>(selcx: &mut SelectionContext<'cx,'tcx>,
+                                                    obligation: &ProjectionObligation<'tcx>) {
+    debug!("consider_unification_despite_ambiguity(obligation={})",
+           obligation.repr(selcx.tcx()));
+
+    let def_id = obligation.predicate.projection_ty.trait_ref.def_id;
+    match selcx.tcx().lang_items.fn_trait_kind(def_id) {
+        Some(_) => { }
+        None => { return; }
+    }
+
+    let infcx = selcx.infcx();
+    let self_ty = obligation.predicate.projection_ty.trait_ref.self_ty();
+    let self_ty = infcx.shallow_resolve(self_ty);
+    debug!("consider_unification_despite_ambiguity: self_ty.sty={:?}",
+           self_ty.sty);
+    match self_ty.sty {
+        ty::ty_closure(closure_def_id, _, substs) => {
+            let closure_typer = selcx.closure_typer();
+            let closure_type = closure_typer.closure_type(closure_def_id, substs);
+            let ty::Binder((_, ret_type)) =
+                util::closure_trait_ref_and_return_type(infcx.tcx,
+                                                        def_id,
+                                                        self_ty,
+                                                        &closure_type.sig,
+                                                        util::TupleArgumentsFlag::No);
+            let (ret_type, _) =
+                infcx.replace_late_bound_regions_with_fresh_var(
+                    obligation.cause.span,
+                    infer::AssocTypeProjection(obligation.predicate.projection_ty.item_name),
+                    &ty::Binder(ret_type));
+            debug!("consider_unification_despite_ambiguity: ret_type={:?}",
+                   ret_type.repr(selcx.tcx()));
+            let origin = infer::RelateOutputImplTypes(obligation.cause.span);
+            let obligation_ty = obligation.predicate.ty;
+            match infer::mk_eqty(infcx, true, origin, obligation_ty, ret_type) {
+                Ok(()) => { }
+                Err(_) => { /* ignore errors */ }
+            }
+        }
+        _ => { }
+    }
+}
+
 /// Normalizes any associated type projections in `value`, replacing
 /// them with a fully resolved type where possible. The return value
 /// combines the normalized result and any additional obligations that
diff --git a/src/librustc/middle/traits/select.rs b/src/librustc/middle/traits/select.rs
index 000572cdd40..b8af91add9e 100644
--- a/src/librustc/middle/traits/select.rs
+++ b/src/librustc/middle/traits/select.rs
@@ -233,9 +233,8 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
     //    is `Vec<Foo>:Iterable<Bar>`, but the impl specifies
     //    `impl<T> Iterable<T> for Vec<T>`, than an error would result.
 
-    /// Evaluates whether the obligation can be satisfied. Returns an indication of whether the
-    /// obligation can be satisfied and, if so, by what means. Never affects surrounding typing
-    /// environment.
+    /// Attempts to satisfy the obligation. If successful, this will affect the surrounding
+    /// type environment by performing unification.
     pub fn select(&mut self, obligation: &TraitObligation<'tcx>)
                   -> SelectionResult<'tcx, Selection<'tcx>> {
         debug!("select({})", obligation.repr(self.tcx()));
@@ -243,11 +242,68 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
 
         let stack = self.push_stack(None, obligation);
         match try!(self.candidate_from_obligation(&stack)) {
-            None => Ok(None),
+            None => {
+                self.consider_unification_despite_ambiguity(obligation);
+                Ok(None)
+            }
             Some(candidate) => Ok(Some(try!(self.confirm_candidate(obligation, candidate)))),
         }
     }
 
+    /// In the particular case of unboxed closure obligations, we can
+    /// sometimes do some amount of unification for the
+    /// argument/return types even though we can't yet fully match obligation.
+    /// The particular case we are interesting in is an obligation of the form:
+    ///
+    ///    C : FnFoo<A>
+    ///
+    /// where `C` is an unboxed closure type and `FnFoo` is one of the
+    /// `Fn` traits. Because we know that users cannot write impls for closure types
+    /// themselves, the only way that `C : FnFoo` can fail to match is under two
+    /// conditions:
+    ///
+    /// 1. The closure kind for `C` is not yet known, because inference isn't complete.
+    /// 2. The closure kind for `C` *is* known, but doesn't match what is needed.
+    ///    For example, `C` may be a `FnOnce` closure, but a `Fn` closure is needed.
+    ///
+    /// In either case, we always know what argument types are
+    /// expected by `C`, no matter what kind of `Fn` trait it
+    /// eventually matches. So we can go ahead and unify the argument
+    /// types, even though the end result is ambiguous.
+    ///
+    /// Note that this is safe *even if* the trait would never be
+    /// matched (case 2 above). After all, in that case, an error will
+    /// result, so it kind of doesn't matter what we do --- unifying
+    /// the argument types can only be helpful to the user, because
+    /// once they patch up the kind of closure that is expected, the
+    /// argment types won't really change.
+    fn consider_unification_despite_ambiguity(&mut self, obligation: &TraitObligation<'tcx>) {
+        // Is this a `C : FnFoo(...)` trait reference for some trait binding `FnFoo`?
+        match self.tcx().lang_items.fn_trait_kind(obligation.predicate.0.def_id()) {
+            Some(_) => { }
+            None => { return; }
+        }
+
+        // Is the self-type a closure type? We ignore bindings here
+        // because if it is a closure type, it must be a closure type from
+        // within this current fn, and hence none of the higher-ranked
+        // lifetimes can appear inside the self-type.
+        let self_ty = self.infcx.shallow_resolve(obligation.self_ty());
+        let (closure_def_id, substs) = match self_ty.sty {
+            ty::ty_closure(id, _, ref substs) => (id, substs.clone()),
+            _ => { return; }
+        };
+        assert!(!substs.has_escaping_regions());
+
+        let closure_trait_ref = self.closure_trait_ref(obligation, closure_def_id, substs);
+        match self.confirm_poly_trait_refs(obligation.cause.clone(),
+                                           obligation.predicate.to_poly_trait_ref(),
+                                           closure_trait_ref) {
+            Ok(()) => { }
+            Err(_) => { /* Silently ignore errors. */ }
+        }
+    }
+
     ///////////////////////////////////////////////////////////////////////////
     // EVALUATION
     //
@@ -1003,7 +1059,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
                                    candidates: &mut SelectionCandidateSet<'tcx>)
                                    -> Result<(),SelectionError<'tcx>>
     {
-        let kind = match self.fn_family_trait_kind(obligation.predicate.0.def_id()) {
+        let kind = match self.tcx().lang_items.fn_trait_kind(obligation.predicate.0.def_id()) {
             Some(k) => k,
             None => { return Ok(()); }
         };
@@ -2303,22 +2359,6 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
         impl_obligations
     }
 
-    fn fn_family_trait_kind(&self,
-                            trait_def_id: ast::DefId)
-                            -> Option<ty::ClosureKind>
-    {
-        let tcx = self.tcx();
-        if Some(trait_def_id) == tcx.lang_items.fn_trait() {
-            Some(ty::FnClosureKind)
-        } else if Some(trait_def_id) == tcx.lang_items.fn_mut_trait() {
-            Some(ty::FnMutClosureKind)
-        } else if Some(trait_def_id) == tcx.lang_items.fn_once_trait() {
-            Some(ty::FnOnceClosureKind)
-        } else {
-            None
-        }
-    }
-
     #[allow(unused_comparisons)]
     fn derived_cause(&self,
                      obligation: &TraitObligation<'tcx>,
diff --git a/src/librustc_borrowck/borrowck/mod.rs b/src/librustc_borrowck/borrowck/mod.rs
index e5271cfde5a..b9d2b9ec263 100644
--- a/src/librustc_borrowck/borrowck/mod.rs
+++ b/src/librustc_borrowck/borrowck/mod.rs
@@ -324,7 +324,7 @@ pub fn closure_to_block(closure_id: ast::NodeId,
                         tcx: &ty::ctxt) -> ast::NodeId {
     match tcx.map.get(closure_id) {
         ast_map::NodeExpr(expr) => match expr.node {
-            ast::ExprClosure(_, _, _, ref block) => {
+            ast::ExprClosure(_, _, ref block) => {
                 block.id
             }
             _ => {
diff --git a/src/librustc_resolve/lib.rs b/src/librustc_resolve/lib.rs
index d87039cbaef..dd739059ed0 100644
--- a/src/librustc_resolve/lib.rs
+++ b/src/librustc_resolve/lib.rs
@@ -4521,7 +4521,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
                 visit::walk_expr(self, expr);
             }
 
-            ExprClosure(_, _, ref fn_decl, ref block) => {
+            ExprClosure(_, ref fn_decl, ref block) => {
                 self.resolve_function(ClosureRibKind(expr.id),
                                       Some(&**fn_decl), NoTypeParameters,
                                       &**block);
diff --git a/src/librustc_trans/save/mod.rs b/src/librustc_trans/save/mod.rs
index 7758039e40a..b0ce9641cf4 100644
--- a/src/librustc_trans/save/mod.rs
+++ b/src/librustc_trans/save/mod.rs
@@ -1394,7 +1394,7 @@ impl<'l, 'tcx, 'v> Visitor<'v> for DxrVisitor<'l, 'tcx> {
                                                       type, found {:?}", ty)[]),
                 }
             },
-            ast::ExprClosure(_, _, ref decl, ref body) => {
+            ast::ExprClosure(_, ref decl, ref body) => {
                 if generated_code(body.span) {
                     return
                 }
diff --git a/src/librustc_trans/trans/base.rs b/src/librustc_trans/trans/base.rs
index 9e561fc883b..6901eb25b31 100644
--- a/src/librustc_trans/trans/base.rs
+++ b/src/librustc_trans/trans/base.rs
@@ -1340,7 +1340,7 @@ fn build_cfg(tcx: &ty::ctxt, id: ast::NodeId) -> (ast::NodeId, Option<cfg::CFG>)
         }
         Some(ast_map::NodeExpr(e)) => {
             match e.node {
-                ast::ExprClosure(_, _, _, ref blk) => {
+                ast::ExprClosure(_, _, ref blk) => {
                     blk
                 }
                 _ => tcx.sess.bug("unexpected expr variant in has_nested_returns")
diff --git a/src/librustc_trans/trans/debuginfo.rs b/src/librustc_trans/trans/debuginfo.rs
index 0ced4066f62..c6b70e1a1ab 100644
--- a/src/librustc_trans/trans/debuginfo.rs
+++ b/src/librustc_trans/trans/debuginfo.rs
@@ -1283,7 +1283,7 @@ pub fn create_function_debug_context<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
         }
         ast_map::NodeExpr(ref expr) => {
             match expr.node {
-                ast::ExprClosure(_, _, ref fn_decl, ref top_level_block) => {
+                ast::ExprClosure(_, ref fn_decl, ref top_level_block) => {
                     let name = format!("fn{}", token::gensym("fn"));
                     let name = token::str_to_ident(&name[]);
                     (name, &**fn_decl,
@@ -3595,7 +3595,7 @@ fn create_scope_map(cx: &CrateContext,
                 })
             }
 
-            ast::ExprClosure(_, _, ref decl, ref block) => {
+            ast::ExprClosure(_, ref decl, ref block) => {
                 with_new_scope(cx,
                                block.span,
                                scope_stack,
diff --git a/src/librustc_trans/trans/expr.rs b/src/librustc_trans/trans/expr.rs
index 689d0c231b5..44eb5b190e1 100644
--- a/src/librustc_trans/trans/expr.rs
+++ b/src/librustc_trans/trans/expr.rs
@@ -1095,7 +1095,7 @@ fn trans_rvalue_dps_unadjusted<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
         ast::ExprVec(..) | ast::ExprRepeat(..) => {
             tvec::trans_fixed_vstore(bcx, expr, dest)
         }
-        ast::ExprClosure(_, _, ref decl, ref body) => {
+        ast::ExprClosure(_, ref decl, ref body) => {
             closure::trans_closure_expr(bcx, &**decl, &**body, expr.id, dest)
         }
         ast::ExprCall(ref f, ref args) => {
diff --git a/src/librustc_typeck/check/closure.rs b/src/librustc_typeck/check/closure.rs
index 808dbd4b319..b2a676e878e 100644
--- a/src/librustc_typeck/check/closure.rs
+++ b/src/librustc_typeck/check/closure.rs
@@ -25,7 +25,6 @@ use util::ppaux::Repr;
 pub fn check_expr_closure<'a,'tcx>(fcx: &FnCtxt<'a,'tcx>,
                                    expr: &ast::Expr,
                                    _capture: ast::CaptureClause,
-                                   opt_kind: Option<ast::ClosureKind>,
                                    decl: &'tcx ast::FnDecl,
                                    body: &'tcx ast::Block,
                                    expected: Expectation<'tcx>) {
@@ -33,38 +32,14 @@ pub fn check_expr_closure<'a,'tcx>(fcx: &FnCtxt<'a,'tcx>,
            expr.repr(fcx.tcx()),
            expected.repr(fcx.tcx()));
 
-    let expected_sig_and_kind = expected.to_option(fcx).and_then(|ty| {
-        deduce_expectations_from_expected_type(fcx, ty)
-    });
-
-    match opt_kind {
-        None => {
-            // If users didn't specify what sort of closure they want,
-            // examine the expected type. For now, if we see explicit
-            // evidence than an unboxed closure is desired, we'll use
-            // that. Otherwise, we leave it unspecified, to be filled
-            // in by upvar inference.
-            match expected_sig_and_kind {
-                None => { // don't have information about the kind, request explicit annotation
-                    check_closure(fcx, expr, None, decl, body, None);
-                },
-                Some((sig, kind)) => {
-                    check_closure(fcx, expr, Some(kind), decl, body, Some(sig));
-                }
-            }
-        }
-
-        Some(kind) => {
-            let kind = match kind {
-                ast::FnClosureKind => ty::FnClosureKind,
-                ast::FnMutClosureKind => ty::FnMutClosureKind,
-                ast::FnOnceClosureKind => ty::FnOnceClosureKind,
-            };
-
-            let expected_sig = expected_sig_and_kind.map(|t| t.0);
-            check_closure(fcx, expr, Some(kind), decl, body, expected_sig);
-        }
-    }
+    // It's always helpful for inference if we know the kind of
+    // closure sooner rather than later, so first examine the expected
+    // type, and see if can glean a closure kind from there.
+    let (expected_sig,expected_kind) = match expected.to_option(fcx) {
+        Some(ty) => deduce_expectations_from_expected_type(fcx, ty),
+        None => (None, None)
+    };
+    check_closure(fcx, expr, expected_kind, decl, body, expected_sig)
 }
 
 fn check_closure<'a,'tcx>(fcx: &FnCtxt<'a,'tcx>,
@@ -133,21 +108,30 @@ fn check_closure<'a,'tcx>(fcx: &FnCtxt<'a,'tcx>,
 fn deduce_expectations_from_expected_type<'a,'tcx>(
     fcx: &FnCtxt<'a,'tcx>,
     expected_ty: Ty<'tcx>)
-    -> Option<(ty::FnSig<'tcx>,ty::ClosureKind)>
+    -> (Option<ty::FnSig<'tcx>>,Option<ty::ClosureKind>)
 {
+    debug!("deduce_expectations_from_expected_type(expected_ty={})",
+           expected_ty.repr(fcx.tcx()));
+
     match expected_ty.sty {
         ty::ty_trait(ref object_type) => {
             let proj_bounds = object_type.projection_bounds_with_self_ty(fcx.tcx(),
                                                                          fcx.tcx().types.err);
-            proj_bounds.iter()
-                       .filter_map(|pb| deduce_expectations_from_projection(fcx, pb))
-                       .next()
+            let expectations =
+                proj_bounds.iter()
+                           .filter_map(|pb| deduce_expectations_from_projection(fcx, pb))
+                           .next();
+
+            match expectations {
+                Some((sig, kind)) => (Some(sig), Some(kind)),
+                None => (None, None)
+            }
         }
         ty::ty_infer(ty::TyVar(vid)) => {
             deduce_expectations_from_obligations(fcx, vid)
         }
         _ => {
-            None
+            (None, None)
         }
     }
 }
@@ -155,33 +139,61 @@ fn deduce_expectations_from_expected_type<'a,'tcx>(
 fn deduce_expectations_from_obligations<'a,'tcx>(
     fcx: &FnCtxt<'a,'tcx>,
     expected_vid: ty::TyVid)
-    -> Option<(ty::FnSig<'tcx>, ty::ClosureKind)>
+    -> (Option<ty::FnSig<'tcx>>, Option<ty::ClosureKind>)
 {
     let fulfillment_cx = fcx.inh.fulfillment_cx.borrow();
     // Here `expected_ty` is known to be a type inference variable.
 
-    fulfillment_cx.pending_obligations()
-                  .iter()
-                  .filter_map(|obligation| {
-                      match obligation.predicate {
-                          ty::Predicate::Projection(ref proj_predicate) => {
-                              let trait_ref = proj_predicate.to_poly_trait_ref();
-                              let self_ty = fcx.infcx().shallow_resolve(trait_ref.self_ty());
-                              match self_ty.sty {
-                                  ty::ty_infer(ty::TyVar(v)) if expected_vid == v => {
-                                      deduce_expectations_from_projection(fcx, proj_predicate)
-                                  }
-                                  _ => {
-                                      None
-                                  }
-                              }
-                          }
-                          _ => {
-                              None
-                          }
-                      }
-                  })
-                  .next()
+    let expected_sig_and_kind =
+        fulfillment_cx
+        .pending_obligations()
+        .iter()
+        .filter_map(|obligation| {
+            debug!("deduce_expectations_from_obligations: obligation.predicate={}",
+                   obligation.predicate.repr(fcx.tcx()));
+
+            match obligation.predicate {
+                // Given a Projection predicate, we can potentially infer
+                // the complete signature.
+                ty::Predicate::Projection(ref proj_predicate) => {
+                    let trait_ref = proj_predicate.to_poly_trait_ref();
+                    self_type_matches_expected_vid(fcx, trait_ref, expected_vid)
+                        .and_then(|_| deduce_expectations_from_projection(fcx, proj_predicate))
+                }
+                _ => {
+                    None
+                }
+            }
+        })
+        .next();
+
+    match expected_sig_and_kind {
+        Some((sig, kind)) => { return (Some(sig), Some(kind)); }
+        None => { }
+    }
+
+    // Even if we can't infer the full signature, we may be able to
+    // infer the kind. This can occur if there is a trait-reference
+    // like `F : Fn<A>`.
+    let expected_kind =
+        fulfillment_cx
+        .pending_obligations()
+        .iter()
+        .filter_map(|obligation| {
+            let opt_trait_ref = match obligation.predicate {
+                ty::Predicate::Projection(ref data) => Some(data.to_poly_trait_ref()),
+                ty::Predicate::Trait(ref data) => Some(data.to_poly_trait_ref()),
+                ty::Predicate::Equate(..) => None,
+                ty::Predicate::RegionOutlives(..) => None,
+                ty::Predicate::TypeOutlives(..) => None,
+            };
+            opt_trait_ref
+                .and_then(|trait_ref| self_type_matches_expected_vid(fcx, trait_ref, expected_vid))
+                .and_then(|trait_ref| fcx.tcx().lang_items.fn_trait_kind(trait_ref.def_id()))
+        })
+        .next();
+
+    (None, expected_kind)
 }
 
 /// Given a projection like "<F as Fn(X)>::Result == Y", we can deduce
@@ -229,3 +241,20 @@ fn deduce_expectations_from_projection<'a,'tcx>(
     return Some((fn_sig, kind));
 }
 
+fn self_type_matches_expected_vid<'a,'tcx>(
+    fcx: &FnCtxt<'a,'tcx>,
+    trait_ref: ty::PolyTraitRef<'tcx>,
+    expected_vid: ty::TyVid)
+    -> Option<ty::PolyTraitRef<'tcx>>
+{
+    let self_ty = fcx.infcx().shallow_resolve(trait_ref.self_ty());
+    debug!("self_type_matches_expected_vid(trait_ref={}, self_ty={})",
+           trait_ref.repr(fcx.tcx()),
+           self_ty.repr(fcx.tcx()));
+    match self_ty.sty {
+        ty::ty_infer(ty::TyVar(v)) if expected_vid == v => Some(trait_ref),
+        _ => None,
+    }
+}
+
+
diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs
index 07b67d543a8..adf15fbf28a 100644
--- a/src/librustc_typeck/check/mod.rs
+++ b/src/librustc_typeck/check/mod.rs
@@ -3736,8 +3736,8 @@ fn check_expr_with_unifier<'a, 'tcx, F>(fcx: &FnCtxt<'a, 'tcx>,
       ast::ExprMatch(ref discrim, ref arms, match_src) => {
         _match::check_match(fcx, expr, &**discrim, arms.as_slice(), expected, match_src);
       }
-      ast::ExprClosure(capture, opt_kind, ref decl, ref body) => {
-          closure::check_expr_closure(fcx, expr, capture, opt_kind, &**decl, &**body, expected);
+      ast::ExprClosure(capture, ref decl, ref body) => {
+          closure::check_expr_closure(fcx, expr, capture, &**decl, &**body, expected);
       }
       ast::ExprBlock(ref b) => {
         check_block_with_expected(fcx, &**b, expected);
diff --git a/src/librustc_typeck/check/regionck.rs b/src/librustc_typeck/check/regionck.rs
index d5baff3a0c4..9df0403794d 100644
--- a/src/librustc_typeck/check/regionck.rs
+++ b/src/librustc_typeck/check/regionck.rs
@@ -638,7 +638,7 @@ fn visit_expr(rcx: &mut Rcx, expr: &ast::Expr) {
             visit::walk_expr(rcx, expr);
         }
 
-        ast::ExprClosure(_, _, _, ref body) => {
+        ast::ExprClosure(_, _, ref body) => {
             check_expr_fn_block(rcx, expr, &**body);
         }
 
diff --git a/src/librustc_typeck/check/upvar.rs b/src/librustc_typeck/check/upvar.rs
index b52e01f9a7a..f452c8488ce 100644
--- a/src/librustc_typeck/check/upvar.rs
+++ b/src/librustc_typeck/check/upvar.rs
@@ -83,7 +83,7 @@ struct SeedBorrowKind<'a,'tcx:'a> {
 impl<'a, 'tcx, 'v> Visitor<'v> for SeedBorrowKind<'a, 'tcx> {
     fn visit_expr(&mut self, expr: &ast::Expr) {
         match expr.node {
-            ast::ExprClosure(cc, _, _, ref body) => {
+            ast::ExprClosure(cc, _, ref body) => {
                 self.check_closure(expr, cc, &**body);
             }
 
diff --git a/src/librustc_typeck/check/writeback.rs b/src/librustc_typeck/check/writeback.rs
index 52b1eb490cc..f047a36c560 100644
--- a/src/librustc_typeck/check/writeback.rs
+++ b/src/librustc_typeck/check/writeback.rs
@@ -118,7 +118,7 @@ impl<'cx, 'tcx, 'v> Visitor<'v> for WritebackCx<'cx, 'tcx> {
                                     MethodCall::expr(e.id));
 
         match e.node {
-            ast::ExprClosure(_, _, ref decl, _) => {
+            ast::ExprClosure(_, ref decl, _) => {
                 for input in &decl.inputs {
                     let _ = self.visit_node_id(ResolvingExpr(e.span),
                                                input.id);
diff --git a/src/libsyntax/ast.rs b/src/libsyntax/ast.rs
index d7283db25a5..34eeedeaa76 100644
--- a/src/libsyntax/ast.rs
+++ b/src/libsyntax/ast.rs
@@ -48,7 +48,6 @@ pub use self::TraitItem::*;
 pub use self::Ty_::*;
 pub use self::TyParamBound::*;
 pub use self::UintTy::*;
-pub use self::ClosureKind::*;
 pub use self::UnOp::*;
 pub use self::UnsafeSource::*;
 pub use self::VariantKind::*;
@@ -736,7 +735,7 @@ pub enum Expr_ {
     // FIXME #6993: change to Option<Name> ... or not, if these are hygienic.
     ExprLoop(P<Block>, Option<Ident>),
     ExprMatch(P<Expr>, Vec<Arm>, MatchSource),
-    ExprClosure(CaptureClause, Option<ClosureKind>, P<FnDecl>, P<Block>),
+    ExprClosure(CaptureClause, P<FnDecl>, P<Block>),
     ExprBlock(P<Block>),
 
     ExprAssign(P<Expr>, P<Expr>),
@@ -1687,13 +1686,6 @@ impl ForeignItem_ {
     }
 }
 
-#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug, Copy)]
-pub enum ClosureKind {
-    FnClosureKind,
-    FnMutClosureKind,
-    FnOnceClosureKind,
-}
-
 /// The data we save and restore about an inlined item or method.  This is not
 /// part of the AST that we parse from a file, but it becomes part of the tree
 /// that we trans.
diff --git a/src/libsyntax/ast_map/blocks.rs b/src/libsyntax/ast_map/blocks.rs
index 53787d71eef..a85b87f47d6 100644
--- a/src/libsyntax/ast_map/blocks.rs
+++ b/src/libsyntax/ast_map/blocks.rs
@@ -218,7 +218,7 @@ impl<'a> FnLikeNode<'a> {
                 }
             }
             ast_map::NodeExpr(e) => match e.node {
-                ast::ExprClosure(_, _, ref decl, ref block) =>
+                ast::ExprClosure(_, ref decl, ref block) =>
                     closure(ClosureParts::new(&**decl, &**block, e.id, e.span)),
                 _ => panic!("expr FnLikeNode that is not fn-like"),
             },
diff --git a/src/libsyntax/ext/build.rs b/src/libsyntax/ext/build.rs
index 2b3a7212683..53c35ef34cd 100644
--- a/src/libsyntax/ext/build.rs
+++ b/src/libsyntax/ext/build.rs
@@ -876,14 +876,14 @@ impl<'a> AstBuilder for ExtCtxt<'a> {
 
     fn lambda_fn_decl(&self, span: Span,
                       fn_decl: P<ast::FnDecl>, blk: P<ast::Block>) -> P<ast::Expr> {
-        self.expr(span, ast::ExprClosure(ast::CaptureByRef, None, fn_decl, blk))
+        self.expr(span, ast::ExprClosure(ast::CaptureByRef, fn_decl, blk))
     }
     fn lambda(&self, span: Span, ids: Vec<ast::Ident>, blk: P<ast::Block>) -> P<ast::Expr> {
         let fn_decl = self.fn_decl(
             ids.iter().map(|id| self.arg(span, *id, self.ty_infer(span))).collect(),
             self.ty_infer(span));
 
-        self.expr(span, ast::ExprClosure(ast::CaptureByRef, None, fn_decl, blk))
+        self.expr(span, ast::ExprClosure(ast::CaptureByRef, fn_decl, blk))
     }
     fn lambda0(&self, span: Span, blk: P<ast::Block>) -> P<ast::Expr> {
         self.lambda(span, Vec::new(), blk)
diff --git a/src/libsyntax/ext/deriving/rand.rs b/src/libsyntax/ext/deriving/rand.rs
index 9fd5091e194..739c73a70b0 100644
--- a/src/libsyntax/ext/deriving/rand.rs
+++ b/src/libsyntax/ext/deriving/rand.rs
@@ -66,7 +66,7 @@ fn rand_substructure(cx: &mut ExtCtxt, trait_span: Span, substr: &Substructure)
         cx.ident_of("Rand"),
         cx.ident_of("rand")
     );
-    let mut rand_call = |&mut: cx: &mut ExtCtxt, span| {
+    let rand_call = |&: cx: &mut ExtCtxt, span| {
         cx.expr_call_global(span,
                             rand_ident.clone(),
                             vec!(rng.clone()))
diff --git a/src/libsyntax/ext/expand.rs b/src/libsyntax/ext/expand.rs
index 6eacb344018..77440914342 100644
--- a/src/libsyntax/ext/expand.rs
+++ b/src/libsyntax/ext/expand.rs
@@ -322,11 +322,10 @@ pub fn expand_expr(e: P<ast::Expr>, fld: &mut MacroExpander) -> P<ast::Expr> {
             fld.cx.expr_match(span, into_iter_expr, vec![iter_arm])
         }
 
-        ast::ExprClosure(capture_clause, opt_kind, fn_decl, block) => {
+        ast::ExprClosure(capture_clause, fn_decl, block) => {
             let (rewritten_fn_decl, rewritten_block)
                 = expand_and_rename_fn_decl_and_block(fn_decl, block, fld);
             let new_node = ast::ExprClosure(capture_clause,
-                                            opt_kind,
                                             rewritten_fn_decl,
                                             rewritten_block);
             P(ast::Expr{id:id, node: new_node, span: fld.new_span(span)})
diff --git a/src/libsyntax/fold.rs b/src/libsyntax/fold.rs
index 9012ec2114d..07b6af651f6 100644
--- a/src/libsyntax/fold.rs
+++ b/src/libsyntax/fold.rs
@@ -1325,9 +1325,8 @@ pub fn noop_fold_expr<T: Folder>(Expr {id, node, span}: Expr, folder: &mut T) ->
                         arms.move_map(|x| folder.fold_arm(x)),
                         source)
             }
-            ExprClosure(capture_clause, opt_kind, decl, body) => {
+            ExprClosure(capture_clause, decl, body) => {
                 ExprClosure(capture_clause,
-                            opt_kind,
                             folder.fold_fn_decl(decl),
                             folder.fold_block(body))
             }
diff --git a/src/libsyntax/parse/obsolete.rs b/src/libsyntax/parse/obsolete.rs
index a3600506057..60de6c909b7 100644
--- a/src/libsyntax/parse/obsolete.rs
+++ b/src/libsyntax/parse/obsolete.rs
@@ -27,6 +27,7 @@ pub enum ObsoleteSyntax {
     ProcType,
     ProcExpr,
     ClosureType,
+    ClosureKind,
 }
 
 pub trait ParserObsoleteMethods {
@@ -65,6 +66,10 @@ impl<'a> ParserObsoleteMethods for parser::Parser<'a> {
                 "`|usize| -> bool` closure type syntax",
                 "use unboxed closures instead, no type annotation needed"
             ),
+            ObsoleteSyntax::ClosureKind => (
+                "`:`, `&mut:`, or `&:` syntax",
+                "rely on inference instead"
+            ),
             ObsoleteSyntax::Sized => (
                 "`Sized? T` syntax for removing the `Sized` bound",
                 "write `T: ?Sized` instead"
diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs
index c3182602a4b..2cb265033c3 100644
--- a/src/libsyntax/parse/parser.rs
+++ b/src/libsyntax/parse/parser.rs
@@ -28,8 +28,6 @@ use ast::{ExprLit, ExprLoop, ExprMac, ExprRange};
 use ast::{ExprMethodCall, ExprParen, ExprPath, ExprQPath};
 use ast::{ExprRepeat, ExprRet, ExprStruct, ExprTup, ExprUnary};
 use ast::{ExprVec, ExprWhile, ExprWhileLet, ExprForLoop, Field, FnDecl};
-use ast::{FnClosureKind, FnMutClosureKind};
-use ast::{FnOnceClosureKind};
 use ast::{ForeignItem, ForeignItemStatic, ForeignItemFn, ForeignMod, FunctionRetTy};
 use ast::{Ident, Inherited, ImplItem, Item, Item_, ItemStatic};
 use ast::{ItemEnum, ItemFn, ItemForeignMod, ItemImpl, ItemConst};
@@ -57,7 +55,7 @@ use ast::{TyFixedLengthVec, TyBareFn};
 use ast::{TyTypeof, TyInfer, TypeMethod};
 use ast::{TyParam, TyParamBound, TyParen, TyPath, TyPolyTraitRef, TyPtr, TyQPath};
 use ast::{TyRptr, TyTup, TyU32, TyVec, UnUniq};
-use ast::{TypeImplItem, TypeTraitItem, Typedef, ClosureKind};
+use ast::{TypeImplItem, TypeTraitItem, Typedef,};
 use ast::{UnnamedField, UnsafeBlock};
 use ast::{ViewPath, ViewPathGlob, ViewPathList, ViewPathSimple};
 use ast::{Visibility, WhereClause};
@@ -1139,29 +1137,36 @@ impl<'a> Parser<'a> {
         TyInfer
     }
 
-    /// Parses an optional closure kind (`&:`, `&mut:`, or `:`).
-    pub fn parse_optional_closure_kind(&mut self) -> Option<ClosureKind> {
-        if self.check(&token::BinOp(token::And)) &&
-                self.look_ahead(1, |t| t.is_keyword(keywords::Mut)) &&
-                self.look_ahead(2, |t| *t == token::Colon) {
+    /// Parses an obsolete closure kind (`&:`, `&mut:`, or `:`).
+    pub fn parse_obsolete_closure_kind(&mut self) {
+        // let lo = self.span.lo;
+        if
+            self.check(&token::BinOp(token::And)) &&
+            self.look_ahead(1, |t| t.is_keyword(keywords::Mut)) &&
+            self.look_ahead(2, |t| *t == token::Colon)
+        {
             self.bump();
             self.bump();
             self.bump();
-            return Some(FnMutClosureKind)
-        }
-
-        if self.token == token::BinOp(token::And) &&
-                    self.look_ahead(1, |t| *t == token::Colon) {
+        } else if
+            self.token == token::BinOp(token::And) &&
+            self.look_ahead(1, |t| *t == token::Colon)
+        {
             self.bump();
             self.bump();
-            return Some(FnClosureKind)
-        }
-
-        if self.eat(&token::Colon) {
-            return Some(FnOnceClosureKind)
+            return;
+        } else if
+            self.eat(&token::Colon)
+        {
+            /* nothing */
+        } else {
+            return;
         }
 
-        return None
+        // SNAP 474b324
+        // Enable these obsolete errors after snapshot:
+        // let span = mk_sp(lo, self.span.hi);
+        // self.obsolete(span, ObsoleteSyntax::ClosureKind);
     }
 
     pub fn parse_ty_bare_fn_or_ty_closure(&mut self, lifetime_defs: Vec<LifetimeDef>) -> Ty_ {
@@ -3047,7 +3052,7 @@ impl<'a> Parser<'a> {
                              -> P<Expr>
     {
         let lo = self.span.lo;
-        let (decl, optional_closure_kind) = self.parse_fn_block_decl();
+        let decl = self.parse_fn_block_decl();
         let body = self.parse_expr();
         let fakeblock = P(ast::Block {
             id: ast::DUMMY_NODE_ID,
@@ -3060,7 +3065,7 @@ impl<'a> Parser<'a> {
         self.mk_expr(
             lo,
             fakeblock.span.hi,
-            ExprClosure(capture_clause, optional_closure_kind, decl, fakeblock))
+            ExprClosure(capture_clause, decl, fakeblock))
     }
 
     pub fn parse_else_expr(&mut self) -> P<Expr> {
@@ -4529,30 +4534,29 @@ impl<'a> Parser<'a> {
     }
 
     // parse the |arg, arg| header on a lambda
-    fn parse_fn_block_decl(&mut self) -> (P<FnDecl>, Option<ClosureKind>) {
-        let (optional_closure_kind, inputs_captures) = {
+    fn parse_fn_block_decl(&mut self) -> P<FnDecl> {
+        let inputs_captures = {
             if self.eat(&token::OrOr) {
-                (None, Vec::new())
+                Vec::new()
             } else {
                 self.expect(&token::BinOp(token::Or));
-                let optional_closure_kind =
-                    self.parse_optional_closure_kind();
+                self.parse_obsolete_closure_kind();
                 let args = self.parse_seq_to_before_end(
                     &token::BinOp(token::Or),
                     seq_sep_trailing_allowed(token::Comma),
                     |p| p.parse_fn_block_arg()
                 );
                 self.bump();
-                (optional_closure_kind, args)
+                args
             }
         };
         let output = self.parse_ret_ty();
 
-        (P(FnDecl {
+        P(FnDecl {
             inputs: inputs_captures,
             output: output,
             variadic: false
-        }), optional_closure_kind)
+        })
     }
 
     /// Parses the `(arg, arg) -> return_type` header on a procedure.
diff --git a/src/libsyntax/print/pprust.rs b/src/libsyntax/print/pprust.rs
index e6d895a49fc..ee8e207fa6c 100644
--- a/src/libsyntax/print/pprust.rs
+++ b/src/libsyntax/print/pprust.rs
@@ -11,11 +11,9 @@
 pub use self::AnnNode::*;
 
 use abi;
-use ast::{self, FnClosureKind, FnMutClosureKind};
-use ast::{FnOnceClosureKind};
+use ast;
 use ast::{MethodImplItem, RegionTyParamBound, TraitTyParamBound, TraitBoundModifier};
 use ast::{RequiredMethod, ProvidedMethod, TypeImplItem, TypeTraitItem};
-use ast::{ClosureKind};
 use ast_util;
 use owned_slice::OwnedSlice;
 use attr::{AttrMetaMethods, AttributeMethods};
@@ -350,7 +348,7 @@ pub fn method_to_string(p: &ast::Method) -> String {
 }
 
 pub fn fn_block_to_string(p: &ast::FnDecl) -> String {
-    $to_string(|s| s.print_fn_block_args(p, None))
+    $to_string(|s| s.print_fn_block_args(p))
 }
 
 pub fn path_to_string(p: &ast::Path) -> String {
@@ -1747,10 +1745,10 @@ impl<'a> State<'a> {
                 }
                 try!(self.bclose_(expr.span, indent_unit));
             }
-            ast::ExprClosure(capture_clause, opt_kind, ref decl, ref body) => {
+            ast::ExprClosure(capture_clause, ref decl, ref body) => {
                 try!(self.print_capture_clause(capture_clause));
 
-                try!(self.print_fn_block_args(&**decl, opt_kind));
+                try!(self.print_fn_block_args(&**decl));
                 try!(space(&mut self.s));
 
                 if !body.stmts.is_empty() || !body.expr.is_some() {
@@ -2350,16 +2348,9 @@ impl<'a> State<'a> {
 
     pub fn print_fn_block_args(
             &mut self,
-            decl: &ast::FnDecl,
-            closure_kind: Option<ClosureKind>)
+            decl: &ast::FnDecl)
             -> IoResult<()> {
         try!(word(&mut self.s, "|"));
-        match closure_kind {
-            None => {}
-            Some(FnClosureKind) => try!(self.word_space("&:")),
-            Some(FnMutClosureKind) => try!(self.word_space("&mut:")),
-            Some(FnOnceClosureKind) => try!(self.word_space(":")),
-        }
         try!(self.print_fn_args(decl, None));
         try!(word(&mut self.s, "|"));
 
diff --git a/src/libsyntax/visit.rs b/src/libsyntax/visit.rs
index bd84306fe17..fbcfcaadf12 100644
--- a/src/libsyntax/visit.rs
+++ b/src/libsyntax/visit.rs
@@ -836,7 +836,7 @@ pub fn walk_expr<'v, V: Visitor<'v>>(visitor: &mut V, expression: &'v Expr) {
                 visitor.visit_arm(arm)
             }
         }
-        ExprClosure(_, _, ref function_declaration, ref body) => {
+        ExprClosure(_, ref function_declaration, ref body) => {
             visitor.visit_fn(FkFnBlock,
                              &**function_declaration,
                              &**body,
diff --git a/src/test/compile-fail/borrow-immutable-upvar-mutation.rs b/src/test/compile-fail/borrow-immutable-upvar-mutation.rs
index 12555c55072..7033f5caef6 100644
--- a/src/test/compile-fail/borrow-immutable-upvar-mutation.rs
+++ b/src/test/compile-fail/borrow-immutable-upvar-mutation.rs
@@ -8,34 +8,38 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-#![feature(unboxed_closures, overloaded_calls)]
+#![feature(unboxed_closures)]
 
 // Tests that we can't assign to or mutably borrow upvars from `Fn`
 // closures (issue #17780)
 
 fn set(x: &mut usize) { *x = 5; }
 
+fn to_fn<A,F:Fn<A>>(f: F) -> F { f }
+fn to_fn_mut<A,F:FnMut<A>>(f: F) -> F { f }
+
 fn main() {
     // By-ref captures
     {
         let mut x = 0us;
-        let _f = |&:| x = 42; //~ ERROR cannot assign
+        let _f = to_fn(|| x = 42); //~ ERROR cannot assign
 
         let mut y = 0us;
-        let _g = |&:| set(&mut y); //~ ERROR cannot borrow
+        let _g = to_fn(|| set(&mut y)); //~ ERROR cannot borrow
 
         let mut z = 0us;
-        let _h = |&mut:| { set(&mut z); |&:| z = 42; }; //~ ERROR cannot assign
+        let _h = to_fn_mut(|| { set(&mut z); to_fn(|| z = 42); }); //~ ERROR cannot assign
     }
+
     // By-value captures
     {
         let mut x = 0us;
-        let _f = move |&:| x = 42; //~ ERROR cannot assign
+        let _f = to_fn(move || x = 42); //~ ERROR cannot assign
 
         let mut y = 0us;
-        let _g = move |&:| set(&mut y); //~ ERROR cannot borrow
+        let _g = to_fn(move || set(&mut y)); //~ ERROR cannot borrow
 
         let mut z = 0us;
-        let _h = move |&mut:| { set(&mut z); move |&:| z = 42; }; //~ ERROR cannot assign
+        let _h = to_fn_mut(move || { set(&mut z); to_fn(move || z = 42); }); //~ ERROR cannot assign
     }
 }
diff --git a/src/test/compile-fail/borrowck-move-by-capture.rs b/src/test/compile-fail/borrowck-move-by-capture.rs
index b0d546cd5c8..a1708e7f497 100644
--- a/src/test/compile-fail/borrowck-move-by-capture.rs
+++ b/src/test/compile-fail/borrowck-move-by-capture.rs
@@ -8,11 +8,14 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-#![feature(box_syntax)]
+#![feature(box_syntax,unboxed_closures)]
+
+fn to_fn_mut<A,F:FnMut<A>>(f: F) -> F { f }
+fn to_fn_once<A,F:FnOnce<A>>(f: F) -> F { f }
 
 pub fn main() {
     let bar = box 3;
-    let _g = |&mut:| {
-        let _h = move |:| -> isize { *bar }; //~ ERROR cannot move out of captured outer variable
-    };
+    let _g = to_fn_mut(|| {
+        let _h = to_fn_once(move || -> isize { *bar }); //~ ERROR cannot move out of
+    });
 }
diff --git a/src/test/compile-fail/cannot-mutate-captured-non-mut-var.rs b/src/test/compile-fail/cannot-mutate-captured-non-mut-var.rs
index 2951c63828d..738755855c0 100644
--- a/src/test/compile-fail/cannot-mutate-captured-non-mut-var.rs
+++ b/src/test/compile-fail/cannot-mutate-captured-non-mut-var.rs
@@ -8,12 +8,16 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
+#![feature(unboxed_closures)]
+
+fn to_fn_once<A,F:FnOnce<A>>(f: F) -> F { f }
+
 fn main() {
     let x = 1;
-    move|:| { x = 2; };
+    to_fn_once(move|:| { x = 2; });
     //~^ ERROR: cannot assign to immutable captured outer variable
 
     let s = std::old_io::stdin();
-    move|:| { s.read_to_end(); };
+    to_fn_once(move|:| { s.read_to_end(); });
     //~^ ERROR: cannot borrow immutable captured outer variable
 }
diff --git a/src/test/compile-fail/issue-11925.rs b/src/test/compile-fail/issue-11925.rs
index 69f7b46009c..df4dab2552e 100644
--- a/src/test/compile-fail/issue-11925.rs
+++ b/src/test/compile-fail/issue-11925.rs
@@ -8,12 +8,14 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-#![feature(box_syntax)]
+#![feature(box_syntax, unboxed_closures)]
+
+fn to_fn_once<A,F:FnOnce<A>>(f: F) -> F { f }
 
 fn main() {
     let r = {
         let x = box 42;
-        let f = move|:| &x; //~ ERROR: `x` does not live long enough
+        let f = to_fn_once(move|| &x); //~ ERROR: `x` does not live long enough
         f()
     };
 
diff --git a/src/test/compile-fail/issue-12127.rs b/src/test/compile-fail/issue-12127.rs
index c06082de3cd..40d446b91a5 100644
--- a/src/test/compile-fail/issue-12127.rs
+++ b/src/test/compile-fail/issue-12127.rs
@@ -8,14 +8,15 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-#![feature(box_syntax)]
+#![feature(box_syntax, unboxed_closures)]
 
+fn to_fn_once<A,F:FnOnce<A>>(f: F) -> F { f }
 fn do_it(x: &isize) { }
 
 fn main() {
     let x = box 22;
-    let f = move|:| do_it(&*x);
-    (move|:| {
+    let f = to_fn_once(move|| do_it(&*x));
+    to_fn_once(move|| {
         f();
         f();
         //~^ ERROR: use of moved value: `f`
diff --git a/src/test/compile-fail/moves-based-on-type-move-out-of-closure-env-issue-1965.rs b/src/test/compile-fail/moves-based-on-type-move-out-of-closure-env-issue-1965.rs
index 5dfe7f0c71f..4251be36ab4 100644
--- a/src/test/compile-fail/moves-based-on-type-move-out-of-closure-env-issue-1965.rs
+++ b/src/test/compile-fail/moves-based-on-type-move-out-of-closure-env-issue-1965.rs
@@ -8,13 +8,15 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-#![feature(box_syntax)]
+#![feature(box_syntax, unboxed_closures)]
 
 use std::usize;
 
+fn to_fn<A,F:Fn<A>>(f: F) -> F { f }
+
 fn test(_x: Box<usize>) {}
 
 fn main() {
     let i = box 3;
-    let _f = |&:| test(i); //~ ERROR cannot move out
+    let _f = to_fn(|| test(i)); //~ ERROR cannot move out
 }
diff --git a/src/test/compile-fail/unboxed-closer-non-implicit-copyable.rs b/src/test/compile-fail/unboxed-closer-non-implicit-copyable.rs
index 182c632d062..2d559794919 100644
--- a/src/test/compile-fail/unboxed-closer-non-implicit-copyable.rs
+++ b/src/test/compile-fail/unboxed-closer-non-implicit-copyable.rs
@@ -10,8 +10,10 @@
 
 #![feature(unboxed_closures)]
 
+fn to_fn_once<A,F:FnOnce<A>>(f: F) -> F { f }
+
 fn main() {
-    let f = move|:| ();
+    let f = to_fn_once(move|| ());
     f();
     f(); //~ ERROR use of moved value
 }
diff --git a/src/test/compile-fail/unboxed-closure-illegal-move.rs b/src/test/compile-fail/unboxed-closure-illegal-move.rs
index 1312b42fb82..224cbc2bef3 100644
--- a/src/test/compile-fail/unboxed-closure-illegal-move.rs
+++ b/src/test/compile-fail/unboxed-closure-illegal-move.rs
@@ -15,31 +15,35 @@
 // if the upvar is captured by ref or the closure takes self by
 // reference.
 
+fn to_fn<A,F:Fn<A>>(f: F) -> F { f }
+fn to_fn_mut<A,F:FnMut<A>>(f: F) -> F { f }
+fn to_fn_once<A,F:FnOnce<A>>(f: F) -> F { f }
+
 fn main() {
     // By-ref cases
     {
         let x = box 0us;
-        let f = |&:| drop(x); //~ ERROR cannot move
+        let f = to_fn(|| drop(x)); //~ ERROR cannot move
     }
     {
         let x = box 0us;
-        let f = |&mut:| drop(x); //~ ERROR cannot move
+        let f = to_fn_mut(|| drop(x)); //~ ERROR cannot move
     }
     {
         let x = box 0us;
-        let f = |:| drop(x); // OK -- FnOnce
+        let f = to_fn_once(|| drop(x)); // OK -- FnOnce
     }
     // By-value cases
     {
         let x = box 0us;
-        let f = move |&:| drop(x); //~ ERROR cannot move
+        let f = to_fn(move || drop(x)); //~ ERROR cannot move
     }
     {
         let x = box 0us;
-        let f = move |&mut:| drop(x); //~ ERROR cannot move
+        let f = to_fn_mut(move || drop(x)); //~ ERROR cannot move
     }
     {
         let x = box 0us;
-        let f = move |:| drop(x); // this one is ok
+        let f = to_fn_once(move || drop(x)); // this one is ok
     }
 }
diff --git a/src/test/compile-fail/unboxed-closures-mutate-upvar.rs b/src/test/compile-fail/unboxed-closures-mutate-upvar.rs
index 96c7948dcb0..650bb17bb77 100644
--- a/src/test/compile-fail/unboxed-closures-mutate-upvar.rs
+++ b/src/test/compile-fail/unboxed-closures-mutate-upvar.rs
@@ -12,51 +12,56 @@
 // as `mut` through a closure. Also test that we CAN mutate a moved copy,
 // unless this is a `Fn` closure. Issue #16749.
 
+#![feature(unboxed_closures)]
+
 use std::mem;
 
+fn to_fn<A,F:Fn<A>>(f: F) -> F { f }
+fn to_fn_mut<A,F:FnMut<A>>(f: F) -> F { f }
+
 fn a() {
     let n = 0u8;
-    let mut f = |&mut:| { //~ ERROR closure cannot assign
+    let mut f = to_fn_mut(|| { //~ ERROR closure cannot assign
         n += 1;
-    };
+    });
 }
 
 fn b() {
     let mut n = 0u8;
-    let mut f = |&mut:| {
+    let mut f = to_fn_mut(|| {
         n += 1; // OK
-    };
+    });
 }
 
 fn c() {
     let n = 0u8;
-    let mut f = move |&mut:| {
+    let mut f = to_fn_mut(move || {
         // If we just did a straight-forward desugaring, this would
         // compile, but we do something a bit more subtle, and hence
         // we get an error.
         n += 1; //~ ERROR cannot assign
-    };
+    });
 }
 
 fn d() {
     let mut n = 0u8;
-    let mut f = move |&mut:| {
+    let mut f = to_fn_mut(move || {
         n += 1; // OK
-    };
+    });
 }
 
 fn e() {
     let n = 0u8;
-    let mut f = move |&:| {
+    let mut f = to_fn(move || {
         n += 1; //~ ERROR cannot assign
-    };
+    });
 }
 
 fn f() {
     let mut n = 0u8;
-    let mut f = move |&:| {
+    let mut f = to_fn(move || {
         n += 1; //~ ERROR cannot assign
-    };
+    });
 }
 
 fn main() { }
diff --git a/src/test/compile-fail/unboxed-closures-static-call-wrong-trait.rs b/src/test/compile-fail/unboxed-closures-static-call-wrong-trait.rs
index 8d3721f28db..f430e9fc759 100644
--- a/src/test/compile-fail/unboxed-closures-static-call-wrong-trait.rs
+++ b/src/test/compile-fail/unboxed-closures-static-call-wrong-trait.rs
@@ -10,8 +10,10 @@
 
 #![feature(unboxed_closures)]
 
+fn to_fn_mut<A,F:FnMut<A>>(f: F) -> F { f }
+
 fn main() {
-    let mut_ = |&mut: x| x;
+    let mut_ = to_fn_mut(|x| x);
     mut_.call((0, )); //~ ERROR does not implement any method in scope named `call`
 }
 
diff --git a/src/test/compile-fail/unboxed-closures-vtable-mismatch.rs b/src/test/compile-fail/unboxed-closures-vtable-mismatch.rs
index 305dd33e5a0..c2a2e5162ac 100644
--- a/src/test/compile-fail/unboxed-closures-vtable-mismatch.rs
+++ b/src/test/compile-fail/unboxed-closures-vtable-mismatch.rs
@@ -12,12 +12,14 @@
 
 use std::ops::FnMut;
 
+fn to_fn_mut<A,F:FnMut<A>>(f: F) -> F { f }
+
 fn call_it<F:FnMut(isize,isize)->isize>(y: isize, mut f: F) -> isize {
     f(2, y)
 }
 
 pub fn main() {
-    let f = |&mut: x: usize, y: isize| -> isize { (x as isize) + y };
+    let f = to_fn_mut(|x: usize, y: isize| -> isize { (x as isize) + y });
     let z = call_it(3, f);
     //~^ ERROR type mismatch
     //~| ERROR type mismatch
diff --git a/src/test/compile-fail/unboxed-closures-wrong-trait.rs b/src/test/compile-fail/unboxed-closures-wrong-trait.rs
deleted file mode 100644
index 2ada0dd22e7..00000000000
--- a/src/test/compile-fail/unboxed-closures-wrong-trait.rs
+++ /dev/null
@@ -1,23 +0,0 @@
-// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
-// file at the top-level directory of this distribution and at
-// http://rust-lang.org/COPYRIGHT.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-#![feature(lang_items, overloaded_calls, unboxed_closures)]
-
-fn c<F:Fn(isize, isize) -> isize>(f: F) -> isize {
-    f(5, 6)
-}
-
-fn main() {
-    let z: isize = 7;
-    assert_eq!(c(|&mut: x: isize, y| x + y + z), 10);
-    //~^ ERROR not implemented
-    //~| ERROR not implemented
-}
-
diff --git a/src/test/run-pass/closure-inference.rs b/src/test/run-pass/closure-inference.rs
index 893003dd997..3bd0273216d 100644
--- a/src/test/run-pass/closure-inference.rs
+++ b/src/test/run-pass/closure-inference.rs
@@ -9,11 +9,11 @@
 // except according to those terms.
 
 
-fn foo(i: int) -> int { i + 1 }
+fn foo(i: isize) -> isize { i + 1 }
 
 fn apply<A, F>(f: F, v: A) -> A where F: FnOnce(A) -> A { f(v) }
 
 pub fn main() {
-    let f = {|: i| foo(i)};
+    let f = {|i| foo(i)};
     assert_eq!(apply(f, 2), 3);
 }
diff --git a/src/test/run-pass/last-use-in-cap-clause.rs b/src/test/run-pass/last-use-in-cap-clause.rs
index 0cdd4d3889c..0cd8c13a4e1 100644
--- a/src/test/run-pass/last-use-in-cap-clause.rs
+++ b/src/test/run-pass/last-use-in-cap-clause.rs
@@ -14,9 +14,9 @@
 #![feature(box_syntax)]
 #![feature(unboxed_closures)]
 
-struct A { a: Box<int> }
+struct A { a: Box<isize> }
 
-fn foo() -> Box<FnMut() -> int + 'static> {
+fn foo() -> Box<FnMut() -> isize + 'static> {
     let k = box 22;
     let _u = A {a: k.clone()};
     let result  = |&mut:| 22;
diff --git a/src/test/run-pass/unboxed-closures-zero-args.rs b/src/test/run-pass/unboxed-closures-zero-args.rs
index f2eddd84af8..8e3d44df798 100644
--- a/src/test/run-pass/unboxed-closures-zero-args.rs
+++ b/src/test/run-pass/unboxed-closures-zero-args.rs
@@ -11,7 +11,7 @@
 #![feature(unboxed_closures)]
 
 fn main() {
-    let mut zero = |&mut:| {};
-    let () = zero.call_mut(());
+    let mut zero = || {};
+    let () = zero();
 }