diff --git a/src/librustc/middle/check_loop.rs b/src/librustc/middle/check_loop.rs index 41ef55933cda2..ea584407944ab 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 e40e04bdee86a..c0fabb2a3481d 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 1ae483be2696d..156ff43e2bab3 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 3ede6bbb965ef..c2a451b405bb5 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 000572cdd40a3..b8af91add9efb 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:Iterable`, but the impl specifies // `impl Iterable for Vec`, 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 + /// + /// 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 - { - 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 e5271cfde5a44..b9d2b9ec263ab 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 d87039cbaefc1..dd739059ed0dd 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 7758039e40a41..b0ce9641cf440 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 9e561fc883bb0..6901eb25b31fe 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) } 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 66bb299273d9f..172e105896c30 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 bed43a5c83882..df9e722569701 100644 --- a/src/librustc_trans/trans/expr.rs +++ b/src/librustc_trans/trans/expr.rs @@ -1094,7 +1094,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 808dbd4b31910..b2a676e878e63 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, 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>,Option) { + 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>, Option) { 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`. + 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 "::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> +{ + 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 07b67d543a87e..adf15fbf28a8f 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 d5baff3a0c4a3..9df0403794d7c 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 b52e01f9a7a76..f452c8488ce1c 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 52b1eb490cc25..f047a36c56095 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 d7283db25a5f2..34eeedeaa7650 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 ... or not, if these are hygienic. ExprLoop(P, Option), ExprMatch(P, Vec, MatchSource), - ExprClosure(CaptureClause, Option, P, P), + ExprClosure(CaptureClause, P, P), ExprBlock(P), ExprAssign(P, P), @@ -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 53787d71eef80..a85b87f47d6ee 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 2b3a72126831e..53c35ef34cd0d 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, blk: P) -> P { - 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, blk: P) -> P { 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) -> P { self.lambda(span, Vec::new(), blk) diff --git a/src/libsyntax/ext/deriving/rand.rs b/src/libsyntax/ext/deriving/rand.rs index 9fd5091e194dc..739c73a70b02b 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 6eacb34401894..77440914342fb 100644 --- a/src/libsyntax/ext/expand.rs +++ b/src/libsyntax/ext/expand.rs @@ -322,11 +322,10 @@ pub fn expand_expr(e: P, fld: &mut MacroExpander) -> P { 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 9012ec2114d07..07b6af651f610 100644 --- a/src/libsyntax/fold.rs +++ b/src/libsyntax/fold.rs @@ -1325,9 +1325,8 @@ pub fn noop_fold_expr(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 a3600506057af..60de6c909b78b 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 c3182602a4b89..2cb265033c399 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 { - 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) -> Ty_ { @@ -3047,7 +3052,7 @@ impl<'a> Parser<'a> { -> P { 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 { @@ -4529,30 +4534,29 @@ impl<'a> Parser<'a> { } // parse the |arg, arg| header on a lambda - fn parse_fn_block_decl(&mut self) -> (P, Option) { - let (optional_closure_kind, inputs_captures) = { + fn parse_fn_block_decl(&mut self) -> P { + 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 e6d895a49fcd7..ee8e207fa6c05 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) + 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 bd84306fe17e0..fbcfcaadf12b7 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 12555c550729c..7033f5caef6c6 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>(f: F) -> F { f } +fn to_fn_mut>(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 b0d546cd5c803..a1708e7f49728 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>(f: F) -> F { f } +fn to_fn_once>(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 2951c63828d5c..738755855c070 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>(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 69f7b46009c38..df4dab2552e7d 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>(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 c06082de3cd08..40d446b91a5a8 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>(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 5dfe7f0c71f14..4251be36ab438 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>(f: F) -> F { f } + fn test(_x: Box) {} 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 182c632d06261..2d55979491981 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>(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 1312b42fb82d4..224cbc2bef324 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>(f: F) -> F { f } +fn to_fn_mut>(f: F) -> F { f } +fn to_fn_once>(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 96c7948dcb046..650bb17bb7758 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>(f: F) -> F { f } +fn to_fn_mut>(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 8d3721f28db50..f430e9fc75902 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>(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 305dd33e5a05a..c2a2e5162ace0 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>(f: F) -> F { f } + fn call_itisize>(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 2ada0dd22e75f..0000000000000 --- 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 or the MIT license -// , 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 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 893003dd99722..3bd0273216de3 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(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 0cdd4d3889c06..0cd8c13a4e10a 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 } +struct A { a: Box } -fn foo() -> Box int + 'static> { +fn foo() -> Box 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 f2eddd84af832..8e3d44df798a7 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(); }