about summary refs log tree commit diff
diff options
context:
space:
mode:
-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();
 }