diff --git a/src/libcore/ops.rs b/src/libcore/ops.rs index 718d311999552..23c730992314e 100644 --- a/src/libcore/ops.rs +++ b/src/libcore/ops.rs @@ -848,7 +848,7 @@ pub trait DerefMut: Deref { /// A version of the call operator that takes an immutable receiver. #[lang="fn"] -pub trait Fn { +pub trait Fn : FnMut { /// This is called when the call operator is used. #[rust_call_abi_hack] fn call(&self, args: Args) -> Result; @@ -856,7 +856,7 @@ pub trait Fn { /// A version of the call operator that takes a mutable receiver. #[lang="fn_mut"] -pub trait FnMut { +pub trait FnMut : FnOnce { /// This is called when the call operator is used. #[rust_call_abi_hack] fn call_mut(&mut self, args: Args) -> Result; @@ -872,6 +872,28 @@ pub trait FnOnce { macro_rules! def_fn_mut( ($($args:ident)*) => ( + impl + FnOnce<($($args,)*),Result> + for extern "Rust" fn($($args: $args,)*) -> Result { + #[rust_call_abi_hack] + #[allow(non_snake_case)] + fn call_once(self, args: ($($args,)*)) -> Result { + let ($($args,)*) = args; + self($($args,)*) + } + } + + impl + Fn<($($args,)*),Result> + for extern "Rust" fn($($args: $args,)*) -> Result { + #[rust_call_abi_hack] + #[allow(non_snake_case)] + fn call(&self, args: ($($args,)*)) -> Result { + let ($($args,)*) = args; + (*self)($($args,)*) + } + } + impl FnMut<($($args,)*),Result> for extern "Rust" fn($($args: $args,)*) -> Result { diff --git a/src/librustc/middle/astencode.rs b/src/librustc/middle/astencode.rs index f40d6d47281c1..4525f77d94821 100644 --- a/src/librustc/middle/astencode.rs +++ b/src/librustc/middle/astencode.rs @@ -1332,6 +1332,7 @@ fn encode_side_tables_for_id(ecx: &e::EncodeContext, rbml_w.id(id); rbml_w.tag(c::tag_table_val, |rbml_w| { rbml_w.emit_closure_type(ecx, &unboxed_closure.closure_type); + rbml_w.emit_def_id(unboxed_closure.expr_id); encode_unboxed_closure_kind(rbml_w, unboxed_closure.kind) }) }) @@ -1750,6 +1751,7 @@ impl<'a> rbml_decoder_decoder_helpers for reader::Decoder<'a> { dcx.tcx, |s, a| this.convert_def_id(dcx, s, a))) }).unwrap(); + let expr_id = self.read_def_id(dcx); let variants = [ "FnUnboxedClosureKind", "FnMutUnboxedClosureKind", @@ -1765,6 +1767,7 @@ impl<'a> rbml_decoder_decoder_helpers for reader::Decoder<'a> { }).unwrap(); ty::UnboxedClosure { closure_type: closure_type, + expr_id: expr_id, kind: kind, } } diff --git a/src/librustc/middle/borrowck/mod.rs b/src/librustc/middle/borrowck/mod.rs index d3d6e7508f077..b51c9345a4e2c 100644 --- a/src/librustc/middle/borrowck/mod.rs +++ b/src/librustc/middle/borrowck/mod.rs @@ -282,7 +282,7 @@ pub fn closure_to_block(closure_id: ast::NodeId, ast_map::NodeExpr(expr) => match expr.node { ast::ExprProc(_, ref block) | ast::ExprFnBlock(_, _, ref block) | - ast::ExprUnboxedFn(_, _, _, ref block) => { block.id } + ast::ExprUnboxedFn(_, _, _, _, ref block) => { block.id } _ => fail!("encountered non-closure id: {}", closure_id) }, _ => fail!("encountered non-expr id: {}", closure_id) diff --git a/src/librustc/middle/check_loop.rs b/src/librustc/middle/check_loop.rs index 3abf49bdfb292..fbb8a33bfd6bb 100644 --- a/src/librustc/middle/check_loop.rs +++ b/src/librustc/middle/check_loop.rs @@ -49,7 +49,7 @@ impl<'a, 'v> Visitor<'v> for CheckLoopVisitor<'a> { } ast::ExprFnBlock(_, _, ref b) | ast::ExprProc(_, ref b) | - ast::ExprUnboxedFn(_, _, _, ref b) => { + ast::ExprUnboxedFn(_, _, _, _, 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 b6893a6a3b419..2dd6dfcccb5c3 100644 --- a/src/librustc/middle/liveness.rs +++ b/src/librustc/middle/liveness.rs @@ -961,7 +961,7 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> { ExprFnBlock(_, _, ref blk) | ExprProc(_, ref blk) | - ExprUnboxedFn(_, _, _, ref blk) => { + ExprUnboxedFn(_, _, _, _, ref blk) => { debug!("{} is an ExprFnBlock, ExprProc, or ExprUnboxedFn", expr_to_string(expr)); diff --git a/src/librustc/middle/mem_categorization.rs b/src/librustc/middle/mem_categorization.rs index 3b831dd6847a1..5c5ac6da5debb 100644 --- a/src/librustc/middle/mem_categorization.rs +++ b/src/librustc/middle/mem_categorization.rs @@ -580,10 +580,21 @@ impl<'t,'tcx,TYPER:Typer<'tcx>> MemCategorizationContext<'t,TYPER> { } } ty::ty_unboxed_closure(closure_id, _) => { - let unboxed_closures = self.typer - .unboxed_closures() - .borrow(); - let kind = unboxed_closures.get(&closure_id).kind; + assert!(closure_id.krate == ast::LOCAL_CRATE); + let kind = match self.typer + .tcx() + .map + .expect_expr(closure_id.node) + .node { + ast::ExprUnboxedFn(_, kind, _, _, _) => { + ty::UnboxedClosureKind::from_ast_kind(kind) + } + _ => { + self.typer.tcx().sess.bug("didn't find unboxed \ + fn with appropriate \ + type in AST map") + } + }; let onceness = match kind { ty::FnUnboxedClosureKind | ty::FnMutUnboxedClosureKind => ast::Many, diff --git a/src/librustc/middle/resolve.rs b/src/librustc/middle/resolve.rs index 2c18c450eb6b5..585e8dda38ec3 100644 --- a/src/librustc/middle/resolve.rs +++ b/src/librustc/middle/resolve.rs @@ -5815,7 +5815,7 @@ impl<'a> Resolver<'a> { Some(&**fn_decl), NoTypeParameters, &**block); } - ExprUnboxedFn(capture_clause, _, ref fn_decl, ref block) => { + ExprUnboxedFn(capture_clause, _, _, ref fn_decl, ref block) => { self.capture_mode_map.borrow_mut().insert(expr.id, capture_clause); self.resolve_function(ClosureRibKind(expr.id, block.id), Some(&**fn_decl), NoTypeParameters, diff --git a/src/librustc/middle/traits/select.rs b/src/librustc/middle/traits/select.rs index 63fbeb797c4d4..f4c51e76e4717 100644 --- a/src/librustc/middle/traits/select.rs +++ b/src/librustc/middle/traits/select.rs @@ -32,6 +32,7 @@ use std::cell::RefCell; use std::collections::hashmap::HashMap; use std::rc::Rc; use syntax::ast; +use syntax::ast_util; use util::ppaux::Repr; pub struct SelectionContext<'cx, 'tcx:'cx> { @@ -543,6 +544,8 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { * unboxed closure type. */ + debug!("assemble_unboxed_candidates()"); + let closure_def_id = match ty::get(skol_obligation_self_ty).sty { ty::ty_unboxed_closure(id, _) => id, _ => { return Ok(()); } @@ -564,22 +567,34 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { _ => continue, }; - // Check to see whether the argument and return types match. - let closure_kind = match self.typer.unboxed_closures().borrow().find(&closure_def_id) { - Some(closure) => closure.kind, - None => { - self.tcx().sess.span_bug( - obligation.cause.span, - format!("No entry for unboxed closure: {}", - closure_def_id.repr(self.tcx())).as_slice()); - } - }; + // Check to see whether the closure could implement this trait. + assert!(closure_def_id.krate == ast::LOCAL_CRATE); + let auxiliary_closure_id = + match self.tcx().map.expect_expr(closure_def_id.node).node { + ast::ExprUnboxedFn(_, _, ref ids, _, _) => { + ast_util::local_def( + kind.select_auxiliary_unboxed_closure_id(&**ids)) + } + _ => { + self.tcx().sess.span_bug( + obligation.cause.span, + "unboxed fn didn't map to an expr") + } + }; + + debug!("assemble_unboxed_candidates(kind={})", kind); - if closure_kind != kind { - continue; + // Check to see whether the argument and return types match. + if !self.typer + .unboxed_closures() + .borrow() + .contains_key(&auxiliary_closure_id) { + // Not compatible with this trait. + continue } - candidates.push(MatchedUnboxedClosureCandidate(closure_def_id)); + candidates.push(MatchedUnboxedClosureCandidate( + auxiliary_closure_id)); } Ok(()) @@ -1067,7 +1082,9 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { } MatchedUnboxedClosureCandidate(closure_def_id) => { - try!(self.confirm_unboxed_closure_candidate(obligation, closure_def_id)); + try!(self.confirm_unboxed_closure_candidate( + obligation, + closure_def_id)); Ok(Some(VtableUnboxedClosure(closure_def_id))) } } @@ -1148,11 +1165,11 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { Ok(vtable_impl) } - fn confirm_unboxed_closure_candidate(&mut self, - obligation: &Obligation, - closure_def_id: ast::DefId) - -> Result<(),SelectionError> - { + fn confirm_unboxed_closure_candidate( + &mut self, + obligation: &Obligation, + closure_def_id: ast::DefId) + -> Result<(),SelectionError> { debug!("confirm_unboxed_closure_candidate({},{})", obligation.repr(self.tcx()), closure_def_id.repr(self.tcx())); diff --git a/src/librustc/middle/trans/base.rs b/src/librustc/middle/trans/base.rs index cac6a8bbfed4c..59695a9e9c2c1 100644 --- a/src/librustc/middle/trans/base.rs +++ b/src/librustc/middle/trans/base.rs @@ -211,6 +211,11 @@ pub fn decl_fn(ccx: &CrateContext, name: &str, cc: llvm::CallConv, llfn } +pub enum FunctionType { + NormalFunctionType(ty::t), + UnboxedClosureFunctionType(ast::DefId), +} + // only use this for foreign function ABIs and glue, use `decl_rust_fn` for Rust functions pub fn decl_cdecl_fn(ccx: &CrateContext, name: &str, @@ -236,7 +241,11 @@ pub fn get_extern_fn(ccx: &CrateContext, f } -fn get_extern_rust_fn(ccx: &CrateContext, fn_ty: ty::t, name: &str, did: ast::DefId) -> ValueRef { +fn get_extern_rust_fn(ccx: &CrateContext, + fn_ty: FunctionType, + name: &str, + did: ast::DefId) + -> ValueRef { match ccx.externs().borrow().find_equiv(&name) { Some(n) => return *n, None => () @@ -253,13 +262,14 @@ fn get_extern_rust_fn(ccx: &CrateContext, fn_ty: ty::t, name: &str, did: ast::De } pub fn self_type_for_unboxed_closure(ccx: &CrateContext, - closure_id: ast::DefId) + auxiliary_id: ast::DefId, + expr_id: ast::DefId) -> ty::t { let unboxed_closure_type = ty::mk_unboxed_closure(ccx.tcx(), - closure_id, + expr_id, ty::ReStatic); let unboxed_closures = ccx.tcx().unboxed_closures.borrow(); - let unboxed_closure = unboxed_closures.get(&closure_id); + let unboxed_closure = unboxed_closures.get(&auxiliary_id); match unboxed_closure.kind { ty::FnUnboxedClosureKind => { ty::mk_imm_rptr(ccx.tcx(), ty::ReStatic, unboxed_closure_type) @@ -277,26 +287,37 @@ pub fn kind_for_unboxed_closure(ccx: &CrateContext, closure_id: ast::DefId) unboxed_closures.get(&closure_id).kind } -pub fn decl_rust_fn(ccx: &CrateContext, fn_ty: ty::t, name: &str) -> ValueRef { - let (inputs, output, abi, env) = match ty::get(fn_ty).sty { - ty::ty_bare_fn(ref f) => { - (f.sig.inputs.clone(), f.sig.output, f.abi, None) - } - ty::ty_closure(ref f) => { - (f.sig.inputs.clone(), f.sig.output, f.abi, Some(Type::i8p(ccx))) +pub fn decl_rust_fn(ccx: &CrateContext, fn_ty: FunctionType, name: &str) + -> ValueRef { + let (inputs, output, abi, env) = match fn_ty { + NormalFunctionType(fn_ty) => { + match ty::get(fn_ty).sty { + ty::ty_bare_fn(ref f) => { + (f.sig.inputs.clone(), f.sig.output, f.abi, None) + } + ty::ty_closure(ref f) => { + (f.sig.inputs.clone(), + f.sig.output, + f.abi, + Some(Type::i8p(ccx))) + } + _ => fail!("expected closure or fn"), + } } - ty::ty_unboxed_closure(closure_did, _) => { + UnboxedClosureFunctionType(closure_did) => { let unboxed_closures = ccx.tcx().unboxed_closures.borrow(); let unboxed_closure = unboxed_closures.get(&closure_did); let function_type = unboxed_closure.closure_type.clone(); - let self_type = self_type_for_unboxed_closure(ccx, closure_did); + let self_type = self_type_for_unboxed_closure( + ccx, + closure_did, + unboxed_closure.expr_id); let llenvironment_type = type_of_explicit_arg(ccx, self_type); (function_type.sig.inputs.clone(), function_type.sig.output, RustCall, Some(llenvironment_type)) } - _ => fail!("expected closure or fn") }; let llfty = type_of_rust_fn(ccx, env, inputs.as_slice(), output, abi); @@ -311,7 +332,10 @@ pub fn decl_rust_fn(ccx: &CrateContext, fn_ty: ty::t, name: &str) -> ValueRef { llfn } -pub fn decl_internal_rust_fn(ccx: &CrateContext, fn_ty: ty::t, name: &str) -> ValueRef { +pub fn decl_internal_rust_fn(ccx: &CrateContext, + fn_ty: FunctionType, + name: &str) + -> ValueRef { let llfn = decl_rust_fn(ccx, fn_ty, name); llvm::SetLinkage(llfn, llvm::InternalLinkage); llfn @@ -950,7 +974,10 @@ pub fn trans_external_path(ccx: &CrateContext, did: ast::DefId, t: ty::t) -> Val match fn_ty.abi.for_target(ccx.sess().targ_cfg.os, ccx.sess().targ_cfg.arch) { Some(Rust) | Some(RustCall) => { - get_extern_rust_fn(ccx, t, name.as_slice(), did) + get_extern_rust_fn(ccx, + NormalFunctionType(t), + name.as_slice(), + did) } Some(RustIntrinsic) => { ccx.sess().bug("unexpected intrinsic in trans_external_path") @@ -962,7 +989,10 @@ pub fn trans_external_path(ccx: &CrateContext, did: ast::DefId, t: ty::t) -> Val } } ty::ty_closure(_) => { - get_extern_rust_fn(ccx, t, name.as_slice(), did) + get_extern_rust_fn(ccx, + NormalFunctionType(t), + name.as_slice(), + did) } _ => { let llty = type_of(ccx, t); @@ -993,7 +1023,7 @@ pub fn invoke<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, let attributes = if is_lang_item { llvm::AttrBuilder::new() } else { - get_fn_llvm_attributes(bcx.ccx(), fn_ty) + get_fn_llvm_attributes(bcx.ccx(), NormalFunctionType(fn_ty)) }; match bcx.opt_node_id { @@ -1397,7 +1427,7 @@ fn has_nested_returns(tcx: &ty::ctxt, id: ast::NodeId) -> bool { match e.node { ast::ExprFnBlock(_, _, ref blk) | ast::ExprProc(_, ref blk) | - ast::ExprUnboxedFn(_, _, _, ref blk) => { + ast::ExprUnboxedFn(_, _, _, _, ref blk) => { let mut explicit = CheckForNestedReturnsVisitor::explicit(); let mut implicit = CheckForNestedReturnsVisitor::implicit(); visit::walk_expr(&mut explicit, e); @@ -2342,26 +2372,32 @@ fn register_fn(ccx: &CrateContext, _ => fail!("expected bare rust fn") }; - let llfn = decl_rust_fn(ccx, node_type, sym.as_slice()); + let llfn = decl_rust_fn(ccx, + NormalFunctionType(node_type), + sym.as_slice()); finish_register_fn(ccx, sp, sym, node_id, llfn); llfn } -pub fn get_fn_llvm_attributes(ccx: &CrateContext, fn_ty: ty::t) +pub fn get_fn_llvm_attributes(ccx: &CrateContext, fn_ty: FunctionType) -> llvm::AttrBuilder { use middle::ty::{BrAnon, ReLateBound}; - let (fn_sig, abi, has_env) = match ty::get(fn_ty).sty { - ty::ty_closure(ref f) => (f.sig.clone(), f.abi, true), - ty::ty_bare_fn(ref f) => (f.sig.clone(), f.abi, false), - ty::ty_unboxed_closure(closure_did, _) => { + let (fn_sig, abi, has_env) = match fn_ty { + NormalFunctionType(fn_ty) => { + match ty::get(fn_ty).sty { + ty::ty_closure(ref f) => (f.sig.clone(), f.abi, true), + ty::ty_bare_fn(ref f) => (f.sig.clone(), f.abi, false), + _ => ccx.sess().bug("expected closure or function."), + } + } + UnboxedClosureFunctionType(closure_did) => { let unboxed_closures = ccx.tcx().unboxed_closures.borrow(); let ref function_type = unboxed_closures.get(&closure_did) .closure_type; (function_type.sig.clone(), RustCall, true) } - _ => ccx.sess().bug("expected closure or function.") }; @@ -2373,8 +2409,8 @@ pub fn get_fn_llvm_attributes(ccx: &CrateContext, fn_ty: ty::t) // These have an odd calling convention, so we need to manually // unpack the input ty's - let input_tys = match ty::get(fn_ty).sty { - ty::ty_unboxed_closure(_, _) => { + let input_tys = match fn_ty { + UnboxedClosureFunctionType(..) => { assert!(abi == RustCall); match ty::get(fn_sig.inputs[0]).sty { @@ -2383,16 +2419,22 @@ pub fn get_fn_llvm_attributes(ccx: &CrateContext, fn_ty: ty::t) _ => ccx.sess().bug("expected tuple'd inputs") } }, - ty::ty_bare_fn(_) if abi == RustCall => { - let inputs = vec![fn_sig.inputs[0]]; - - match ty::get(fn_sig.inputs[1]).sty { - ty::ty_nil => inputs, - ty::ty_tup(ref t_in) => inputs.append(t_in.as_slice()), - _ => ccx.sess().bug("expected tuple'd inputs") + NormalFunctionType(fn_ty) => { + match ty::get(fn_ty).sty { + ty::ty_bare_fn(_) if abi == RustCall => { + let inputs = vec![fn_sig.inputs[0]]; + + match ty::get(fn_sig.inputs[1]).sty { + ty::ty_nil => inputs, + ty::ty_tup(ref t_in) => { + inputs.append(t_in.as_slice()) + } + _ => ccx.sess().bug("expected tuple'd inputs") + } + } + _ => fn_sig.inputs.clone() } } - _ => fn_sig.inputs.clone() }; // A function pointer is called without the declaration diff --git a/src/librustc/middle/trans/callee.rs b/src/librustc/middle/trans/callee.rs index 53c13f5628455..db72a38da1dec 100644 --- a/src/librustc/middle/trans/callee.rs +++ b/src/librustc/middle/trans/callee.rs @@ -286,7 +286,7 @@ pub fn trans_unboxing_shim(bcx: Block, link::mangle_internal_name_by_path_and_seq(path, "unboxing_shim") }); let llfn = decl_internal_rust_fn(ccx, - boxed_function_type, + NormalFunctionType(boxed_function_type), function_name.as_slice()); let block_arena = TypedArena::new(); diff --git a/src/librustc/middle/trans/closure.rs b/src/librustc/middle/trans/closure.rs index fa8c6b8b4482f..9c7b34f195b99 100644 --- a/src/librustc/middle/trans/closure.rs +++ b/src/librustc/middle/trans/closure.rs @@ -302,7 +302,8 @@ fn load_unboxed_closure_environment<'blk, 'tcx>( bcx: Block<'blk, 'tcx>, arg_scope_id: ScopeId, freevars: &Vec, - closure_id: ast::DefId) + auxiliary_id: ast::DefId, + expr_id: ast::DefId) -> Block<'blk, 'tcx> { let _icx = push_ctxt("closure::load_environment"); @@ -311,8 +312,10 @@ fn load_unboxed_closure_environment<'blk, 'tcx>( } // Special case for small by-value selfs. - let self_type = self_type_for_unboxed_closure(bcx.ccx(), closure_id); - let kind = kind_for_unboxed_closure(bcx.ccx(), closure_id); + let self_type = self_type_for_unboxed_closure(bcx.ccx(), + auxiliary_id, + expr_id); + let kind = kind_for_unboxed_closure(bcx.ccx(), auxiliary_id); let llenv = if kind == ty::FnOnceUnboxedClosureKind && !arg_is_indirect(bcx.ccx(), self_type) { let datum = rvalue_scratch_datum(bcx, @@ -381,7 +384,9 @@ pub fn trans_expr_fn<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, let s = tcx.map.with_path(id, |path| { mangle_internal_name_by_path_and_seq(path, "closure") }); - let llfn = decl_internal_rust_fn(ccx, fty, s.as_slice()); + let llfn = decl_internal_rust_fn(ccx, + NormalFunctionType(fty), + s.as_slice()); // set an inline hint for all closures set_inline_hint(llfn); @@ -431,14 +436,13 @@ pub fn get_or_create_declaration_if_unboxed_closure(ccx: &CrateContext, None => {} } - let function_type = ty::mk_unboxed_closure(ccx.tcx(), - closure_id, - ty::ReStatic); let symbol = ccx.tcx().map.with_path(closure_id.node, |path| { mangle_internal_name_by_path_and_seq(path, "unboxed_closure") }); - let llfn = decl_internal_rust_fn(ccx, function_type, symbol.as_slice()); + let llfn = decl_internal_rust_fn(ccx, + UnboxedClosureFunctionType(closure_id), + symbol.as_slice()); // set an inline hint for all closures set_inline_hint(llfn); @@ -456,46 +460,63 @@ pub fn trans_unboxed_closure<'blk, 'tcx>( mut bcx: Block<'blk, 'tcx>, decl: &ast::FnDecl, body: &ast::Block, - id: ast::NodeId, + expr_id: ast::NodeId, + auxiliary_ids: &ast::AuxiliaryUnboxedClosureIds, dest: expr::Dest) -> Block<'blk, 'tcx> { let _icx = push_ctxt("closure::trans_unboxed_closure"); debug!("trans_unboxed_closure()"); - let closure_id = ast_util::local_def(id); - let llfn = get_or_create_declaration_if_unboxed_closure( - bcx.ccx(), - closure_id).unwrap(); - - let unboxed_closures = bcx.tcx().unboxed_closures.borrow(); - let function_type = unboxed_closures.get(&closure_id) - .closure_type - .clone(); - let function_type = ty::mk_closure(bcx.tcx(), function_type); + // FIXME(pcwalton): We probably want to not eagerly generate unboxed + // closure bodies and only do so lazily for the traits that matter. let freevars: Vec = - ty::with_freevars(bcx.tcx(), id, |fv| fv.iter().map(|&fv| fv).collect()); + ty::with_freevars(bcx.tcx(), + expr_id, + |fv| fv.iter().map(|&fv| fv).collect()); let freevars_ptr = &freevars; - trans_closure(bcx.ccx(), - decl, - body, - llfn, - bcx.fcx.param_substs, - id, - [], - ty::ty_fn_args(function_type), - ty::ty_fn_ret(function_type), - ty::ty_fn_abi(function_type), - true, - IsUnboxedClosure, - |bcx, arg_scope| { - load_unboxed_closure_environment(bcx, - arg_scope, - freevars_ptr, - closure_id) - }); + for &auxiliary_id in [ + auxiliary_ids.fn_id, + auxiliary_ids.fn_mut_id, + auxiliary_ids.fn_once_id + ].iter() { + let auxiliary_id = ast_util::local_def(auxiliary_id); + let unboxed_closures = bcx.tcx().unboxed_closures.borrow(); + let unboxed_closure = match unboxed_closures.find(&auxiliary_id) { + None => continue, + Some(unboxed_closure) => unboxed_closure, + }; + + let llfn = get_or_create_declaration_if_unboxed_closure( + bcx.ccx(), + auxiliary_id).unwrap(); + + let function_type = unboxed_closure.closure_type.clone(); + let function_type = ty::mk_closure(bcx.tcx(), function_type); + + trans_closure(bcx.ccx(), + decl, + body, + llfn, + bcx.fcx.param_substs, + expr_id, + [], + ty::ty_fn_args(function_type), + ty::ty_fn_ret(function_type), + ty::ty_fn_abi(function_type), + true, + IsUnboxedClosure, + |bcx, arg_scope| { + load_unboxed_closure_environment( + bcx, + arg_scope, + freevars_ptr, + auxiliary_id, + ast_util::local_def(expr_id)) + }); + } // Don't hoist this to the top of the function. It's perfectly legitimate // to have a zero-size unboxed closure (in which case dest will be @@ -508,7 +529,7 @@ pub fn trans_unboxed_closure<'blk, 'tcx>( } }; - let repr = adt::represent_type(bcx.ccx(), node_id_type(bcx, id)); + let repr = adt::represent_type(bcx.ccx(), node_id_type(bcx, expr_id)); // Create the closure. for (i, freevar) in freevars_ptr.iter().enumerate() { @@ -564,9 +585,11 @@ pub fn get_wrapper_for_bare_fn(ccx: &CrateContext, mangle_internal_name_by_path_and_seq(path, "as_closure") }); let llfn = if is_local { - decl_internal_rust_fn(ccx, closure_ty, name.as_slice()) + decl_internal_rust_fn(ccx, + NormalFunctionType(closure_ty), + name.as_slice()) } else { - decl_rust_fn(ccx, closure_ty, name.as_slice()) + decl_rust_fn(ccx, NormalFunctionType(closure_ty), name.as_slice()) }; ccx.closure_bare_wrapper_cache().borrow_mut().insert(fn_ptr, llfn); diff --git a/src/librustc/middle/trans/debuginfo.rs b/src/librustc/middle/trans/debuginfo.rs index 1980d67fc4714..5f2eb9fd3f9ad 100644 --- a/src/librustc/middle/trans/debuginfo.rs +++ b/src/librustc/middle/trans/debuginfo.rs @@ -1158,7 +1158,11 @@ pub fn create_function_debug_context(cx: &CrateContext, match expr.node { ast::ExprFnBlock(_, ref fn_decl, ref top_level_block) | ast::ExprProc(ref fn_decl, ref top_level_block) | - ast::ExprUnboxedFn(_, _, ref fn_decl, ref top_level_block) => { + ast::ExprUnboxedFn(_, + _, + _, + ref fn_decl, + ref top_level_block) => { let name = format!("fn{}", token::gensym("fn")); let name = token::str_to_ident(name.as_slice()); (name, &**fn_decl, @@ -3566,7 +3570,7 @@ fn populate_scope_map(cx: &CrateContext, ast::ExprFnBlock(_, ref decl, ref block) | ast::ExprProc(ref decl, ref block) | - ast::ExprUnboxedFn(_, _, ref decl, ref block) => { + ast::ExprUnboxedFn(_, _, _, ref decl, ref block) => { with_new_scope(cx, block.span, scope_stack, diff --git a/src/librustc/middle/trans/expr.rs b/src/librustc/middle/trans/expr.rs index 75c28477414a9..d2dbdef154a07 100644 --- a/src/librustc/middle/trans/expr.rs +++ b/src/librustc/middle/trans/expr.rs @@ -1041,8 +1041,13 @@ fn trans_rvalue_dps_unadjusted<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, expr_to_string(expr), expr_ty.repr(tcx)); closure::trans_expr_fn(bcx, store, &**decl, &**body, expr.id, dest) } - ast::ExprUnboxedFn(_, _, ref decl, ref body) => { - closure::trans_unboxed_closure(bcx, &**decl, &**body, expr.id, dest) + ast::ExprUnboxedFn(_, _, ref ids, ref decl, ref body) => { + closure::trans_unboxed_closure(bcx, + &**decl, + &**body, + expr.id, + &**ids, + dest) } ast::ExprCall(ref f, ref args) => { if bcx.tcx().is_method_call(expr.id) { diff --git a/src/librustc/middle/trans/foreign.rs b/src/librustc/middle/trans/foreign.rs index 9cff7261806dd..4c8858f9d18fd 100644 --- a/src/librustc/middle/trans/foreign.rs +++ b/src/librustc/middle/trans/foreign.rs @@ -13,7 +13,7 @@ use back::{link}; use llvm::{ValueRef, CallConv, Linkage, get_param}; use llvm; use middle::weak_lang_items; -use middle::trans::base::push_ctxt; +use middle::trans::base::{NormalFunctionType, push_ctxt}; use middle::trans::base; use middle::trans::build::*; use middle::trans::cabi; @@ -639,7 +639,9 @@ pub fn trans_rust_fn_with_foreign_abi(ccx: &CrateContext, ccx.tcx().map.path_to_string(id), id, t.repr(tcx)); - let llfn = base::decl_internal_rust_fn(ccx, t, ps.as_slice()); + let llfn = base::decl_internal_rust_fn(ccx, + NormalFunctionType(t), + ps.as_slice()); base::set_llvm_fn_attrs(attrs, llfn); base::trans_fn(ccx, decl, body, llfn, param_substs, id, []); llfn @@ -809,7 +811,8 @@ pub fn trans_rust_fn_with_foreign_abi(ccx: &CrateContext, // Perform the call itself debug!("calling llrustfn = {}, t = {}", ccx.tn().val_to_string(llrustfn), t.repr(ccx.tcx())); - let attributes = base::get_fn_llvm_attributes(ccx, t); + let attributes = base::get_fn_llvm_attributes(ccx, + NormalFunctionType(t)); let llrust_ret_val = builder.call(llrustfn, llrust_args.as_slice(), Some(attributes)); // Get the return value where the foreign fn expects it. diff --git a/src/librustc/middle/trans/meth.rs b/src/librustc/middle/trans/meth.rs index 85c43f3f28114..5babb059fc52d 100644 --- a/src/librustc/middle/trans/meth.rs +++ b/src/librustc/middle/trans/meth.rs @@ -571,15 +571,15 @@ pub fn get_vtable(bcx: Block, nested: _ }) => { emit_vtable_methods(bcx, id, substs).into_iter() } - traits::VtableUnboxedClosure(closure_def_id) => { + traits::VtableUnboxedClosure(auxiliary_def_id) => { let callee_substs = get_callee_substitutions_for_unboxed_closure( bcx, - closure_def_id); + auxiliary_def_id); let mut llfn = trans_fn_ref_with_substs( bcx, - closure_def_id, + auxiliary_def_id, ExprId(0), callee_substs.clone()); @@ -588,14 +588,14 @@ pub fn get_vtable(bcx: Block, .unboxed_closures .borrow(); let closure_info = - unboxed_closures.find(&closure_def_id) + unboxed_closures.find(&auxiliary_def_id) .expect("get_vtable(): didn't find \ unboxed closure"); if closure_info.kind == ty::FnOnceUnboxedClosureKind { // Untuple the arguments and create an unboxing shim. let mut new_inputs = vec![ ty::mk_unboxed_closure(bcx.tcx(), - closure_def_id, + closure_info.expr_id, ty::ReStatic) ]; match ty::get(closure_info.closure_type @@ -630,7 +630,7 @@ pub fn get_vtable(bcx: Block, llfn = trans_unboxing_shim(bcx, llfn, &closure_type, - closure_def_id, + auxiliary_def_id, callee_substs); } } diff --git a/src/librustc/middle/trans/monomorphize.rs b/src/librustc/middle/trans/monomorphize.rs index 12a2815cfef34..63fb724b4fc44 100644 --- a/src/librustc/middle/trans/monomorphize.rs +++ b/src/librustc/middle/trans/monomorphize.rs @@ -14,9 +14,9 @@ use llvm::ValueRef; use llvm; use middle::subst; use middle::subst::Subst; -use middle::trans::base::{set_llvm_fn_attrs, set_inline_hint}; -use middle::trans::base::{trans_enum_variant, push_ctxt, get_item_val}; -use middle::trans::base::{trans_fn, decl_internal_rust_fn}; +use middle::trans::base::{NormalFunctionType, decl_internal_rust_fn}; +use middle::trans::base::{get_item_val, push_ctxt, set_inline_hint}; +use middle::trans::base::{set_llvm_fn_attrs, trans_enum_variant, trans_fn}; use middle::trans::base; use middle::trans::common::*; use middle::trans::foreign; @@ -141,7 +141,9 @@ pub fn monomorphic_fn(ccx: &CrateContext, let lldecl = if abi != abi::Rust { foreign::decl_rust_fn_with_foreign_abi(ccx, mono_ty, s.as_slice()) } else { - decl_internal_rust_fn(ccx, mono_ty, s.as_slice()) + decl_internal_rust_fn(ccx, + NormalFunctionType(mono_ty), + s.as_slice()) }; ccx.monomorphized().borrow_mut().insert(hash_id.take().unwrap(), lldecl); diff --git a/src/librustc/middle/trans/reflect.rs b/src/librustc/middle/trans/reflect.rs index 03550299fbdf5..ea6d1a50e24ae 100644 --- a/src/librustc/middle/trans/reflect.rs +++ b/src/librustc/middle/trans/reflect.rs @@ -339,7 +339,7 @@ impl<'a, 'blk, 'tcx> Reflector<'a, 'blk, 'tcx> { let fn_ty = ty::mk_ctor_fn(ccx.tcx(), ast::DUMMY_NODE_ID, [opaqueptrty], ty::mk_u64()); let llfdecl = decl_internal_rust_fn(ccx, - fn_ty, + NormalFunctionType(fn_ty), sym.as_slice()); let arena = TypedArena::new(); let empty_param_substs = param_substs::empty(); diff --git a/src/librustc/middle/ty.rs b/src/librustc/middle/ty.rs index 5ecf7c0d48d18..73acbccc4e880 100644 --- a/src/librustc/middle/ty.rs +++ b/src/librustc/middle/ty.rs @@ -1438,9 +1438,11 @@ pub struct UnboxedClosure { pub closure_type: ClosureTy, /// The kind of unboxed closure this is. pub kind: UnboxedClosureKind, + /// The ID of the expression. + pub expr_id: ast::DefId, } -#[deriving(Clone, PartialEq, Eq)] +#[deriving(Clone, PartialEq, Eq, Show)] pub enum UnboxedClosureKind { FnUnboxedClosureKind, FnMutUnboxedClosureKind, @@ -1448,6 +1450,29 @@ pub enum UnboxedClosureKind { } impl UnboxedClosureKind { + pub fn from_ast_kind(ast_kind: ast::UnboxedClosureKind) + -> UnboxedClosureKind { + match ast_kind { + ast::FnUnboxedClosureKind => FnUnboxedClosureKind, + ast::FnMutUnboxedClosureKind => FnMutUnboxedClosureKind, + ast::FnOnceUnboxedClosureKind => FnOnceUnboxedClosureKind, + } + } + + pub fn from_trait_did(cx: &ctxt, trait_did: ast::DefId) + -> UnboxedClosureKind { + if Some(trait_did) == cx.lang_items.fn_trait() { + FnUnboxedClosureKind + } else if Some(trait_did) == cx.lang_items.fn_mut_trait() { + FnMutUnboxedClosureKind + } else if Some(trait_did) == cx.lang_items.fn_once_trait() { + FnOnceUnboxedClosureKind + } else { + cx.sess.bug("UnboxedClosureKind::from_trait_did(): not an \ + unboxed closure trait") + } + } + pub fn trait_did(&self, cx: &ctxt) -> ast::DefId { let result = match *self { FnUnboxedClosureKind => cx.lang_items.require(FnTraitLangItem), @@ -1463,6 +1488,44 @@ impl UnboxedClosureKind { Err(err) => cx.sess.fatal(err.as_slice()), } } + + pub fn is_compatible_with(self, bound: UnboxedClosureKind) -> bool { + match (self, bound) { + (FnOnceUnboxedClosureKind, _) | + (FnMutUnboxedClosureKind, FnUnboxedClosureKind) | + (FnMutUnboxedClosureKind, FnMutUnboxedClosureKind) | + (FnUnboxedClosureKind, FnUnboxedClosureKind) => true, + _ => false, + } + } + + pub fn select_auxiliary_unboxed_closure_id( + self, + ids: &ast::AuxiliaryUnboxedClosureIds) + -> ast::NodeId { + match self { + FnUnboxedClosureKind => ids.fn_id, + FnMutUnboxedClosureKind => ids.fn_mut_id, + FnOnceUnboxedClosureKind => ids.fn_once_id, + } + } +} + +pub fn auxiliary_def_id_for_unboxed_closure(tcx: &ctxt, expr_id: ast::NodeId) + -> ast::DefId { + let expr = tcx.map.expect_expr(expr_id); + match expr.node { + ast::ExprUnboxedFn(_, kind, ref ids, _, _) => { + let kind = UnboxedClosureKind::from_ast_kind(kind); + ast_util::local_def(kind.select_auxiliary_unboxed_closure_id( + &**ids)) + } + _ => { + tcx.sess.span_bug(expr.span, + "auxiliary_def_id_for_unboxed_closure(): ID \ + passed in wasn't that of an unboxed fn") + } + } } pub fn mk_ctxt<'tcx>(s: Session, diff --git a/src/librustc/middle/typeck/check/method.rs b/src/librustc/middle/typeck/check/method.rs index 7d28a63d93578..a983be70ef639 100644 --- a/src/librustc/middle/typeck/check/method.rs +++ b/src/librustc/middle/typeck/check/method.rs @@ -474,9 +474,9 @@ impl<'a, 'tcx> LookupContext<'a, 'tcx> { ty_param(p) => { self.push_inherent_candidates_from_param(self_ty, restrict_to, p); } - ty_unboxed_closure(closure_did, _) => { + ty_unboxed_closure(closure_expr_did, _) => { self.push_unboxed_closure_call_candidates_if_applicable( - closure_did); + closure_expr_did); } _ => { /* No bound methods in these types */ } } @@ -526,7 +526,8 @@ impl<'a, 'tcx> LookupContext<'a, 'tcx> { fn push_unboxed_closure_call_candidate_if_applicable( &mut self, trait_did: DefId, - closure_did: DefId, + closure_expr_did: DefId, + closure_auxiliary_did: DefId, closure_function_type: &ClosureTy) { let trait_item = ty::trait_items(self.tcx(), trait_did).get(0) .clone(); @@ -550,9 +551,10 @@ impl<'a, 'tcx> LookupContext<'a, 'tcx> { let closure_region = self.fcx.infcx().next_region_var(infer::MiscVariable(self.span)); - let unboxed_closure_type = ty::mk_unboxed_closure(self.tcx(), - closure_did, - closure_region); + let unboxed_closure_type = ty::mk_unboxed_closure( + self.tcx(), + closure_expr_did, + closure_region); self.extension_candidates.push(Candidate { rcvr_match_condition: RcvrMatchesIfSubtype(unboxed_closure_type), @@ -561,31 +563,36 @@ impl<'a, 'tcx> LookupContext<'a, 'tcx> { vec![], *self.fcx.infcx().next_ty_vars(1).get(0)), method_ty: method, - origin: MethodStaticUnboxedClosure(closure_did), + origin: MethodStaticUnboxedClosure(closure_auxiliary_did), }); } fn push_unboxed_closure_call_candidates_if_applicable( &mut self, - closure_did: DefId) { - match self.tcx().unboxed_closures.borrow().find(&closure_did) { + closure_expr_did: DefId) { + let auxiliary_did = ty::auxiliary_def_id_for_unboxed_closure( + self.tcx(), + closure_expr_did.node); + match self.tcx().unboxed_closures.borrow().find(&auxiliary_did) { None => {} // Fall through to try inherited. Some(closure) => { let tcx = self.tcx(); self.push_unboxed_closure_call_candidate_if_applicable( closure.kind.trait_did(tcx), - closure_did, + closure_expr_did, + auxiliary_did, &closure.closure_type); return } } - match self.fcx.inh.unboxed_closures.borrow().find(&closure_did) { + match self.fcx.inh.unboxed_closures.borrow().find(&auxiliary_did) { Some(closure) => { let tcx = self.tcx(); self.push_unboxed_closure_call_candidate_if_applicable( closure.kind.trait_did(tcx), - closure_did, + closure_expr_did, + auxiliary_did, &closure.closure_type); return } diff --git a/src/librustc/middle/typeck/check/mod.rs b/src/librustc/middle/typeck/check/mod.rs index c7be2430cc98d..a584e7e82688f 100644 --- a/src/librustc/middle/typeck/check/mod.rs +++ b/src/librustc/middle/typeck/check/mod.rs @@ -2117,11 +2117,11 @@ fn try_overloaded_call<'a>(fcx: &FnCtxt, _ => {} } - // Try `FnOnce`, then `FnMut`, then `Fn`. + // Try `Fn`, then `FnMut`, then `FnOnce`. for &(maybe_function_trait, method_name) in [ - (fcx.tcx().lang_items.fn_once_trait(), token::intern("call_once")), + (fcx.tcx().lang_items.fn_trait(), token::intern("call")), (fcx.tcx().lang_items.fn_mut_trait(), token::intern("call_mut")), - (fcx.tcx().lang_items.fn_trait(), token::intern("call")) + (fcx.tcx().lang_items.fn_once_trait(), token::intern("call_once")) ].iter() { let function_trait = match maybe_function_trait { None => continue, @@ -3290,6 +3290,7 @@ fn check_expr_with_unifier(fcx: &FnCtxt, fn check_unboxed_closure(fcx: &FnCtxt, expr: &ast::Expr, kind: ast::UnboxedClosureKind, + ids: &ast::AuxiliaryUnboxedClosureIds, decl: &ast::FnDecl, body: &ast::Block) { let mut fn_ty = astconv::ty_of_closure( @@ -3320,6 +3321,9 @@ fn check_expr_with_unifier(fcx: &FnCtxt, local_def(expr.id), region); fcx.write_ty(expr.id, closure_type); + fcx.write_ty(ids.fn_id, closure_type); + fcx.write_ty(ids.fn_mut_id, closure_type); + fcx.write_ty(ids.fn_once_id, closure_type); check_fn(fcx.ccx, ast::NormalFn, @@ -3344,15 +3348,38 @@ fn check_expr_with_unifier(fcx: &FnCtxt, ast::FnOnceUnboxedClosureKind => ty::FnOnceUnboxedClosureKind, }; - let unboxed_closure = ty::UnboxedClosure { - closure_type: fn_ty, - kind: kind, - }; - fcx.inh .unboxed_closures .borrow_mut() - .insert(local_def(expr.id), unboxed_closure); + .insert(local_def(ids.fn_once_id), + ty::UnboxedClosure { + closure_type: fn_ty.clone(), + expr_id: ast_util::local_def(expr.id), + kind: ty::FnOnceUnboxedClosureKind, + }); + if kind == ty::FnUnboxedClosureKind || + kind == ty::FnMutUnboxedClosureKind { + fcx.inh + .unboxed_closures + .borrow_mut() + .insert(local_def(ids.fn_mut_id), + ty::UnboxedClosure { + closure_type: fn_ty.clone(), + expr_id: ast_util::local_def(expr.id), + kind: ty::FnMutUnboxedClosureKind, + }); + } + if kind == ty::FnUnboxedClosureKind { + fcx.inh + .unboxed_closures + .borrow_mut() + .insert(local_def(ids.fn_id), + ty::UnboxedClosure { + closure_type: fn_ty, + expr_id: ast_util::local_def(expr.id), + kind: ty::FnUnboxedClosureKind, + }); + } } fn check_expr_fn(fcx: &FnCtxt, @@ -4124,10 +4151,11 @@ fn check_expr_with_unifier(fcx: &FnCtxt, &**body, expected); } - ast::ExprUnboxedFn(_, kind, ref decl, ref body) => { + ast::ExprUnboxedFn(_, kind, ref ids, ref decl, ref body) => { check_unboxed_closure(fcx, expr, kind, + &**ids, &**decl, &**body); } diff --git a/src/librustc/middle/typeck/check/regionck.rs b/src/librustc/middle/typeck/check/regionck.rs index d45155c2ccd12..73de0c0d71407 100644 --- a/src/librustc/middle/typeck/check/regionck.rs +++ b/src/librustc/middle/typeck/check/regionck.rs @@ -733,7 +733,7 @@ fn visit_expr(rcx: &mut Rcx, expr: &ast::Expr) { ast::ExprFnBlock(_, _, ref body) | ast::ExprProc(_, ref body) | - ast::ExprUnboxedFn(_, _, _, ref body) => { + ast::ExprUnboxedFn(_, _, _, _, ref body) => { check_expr_fn_block(rcx, expr, &**body); } diff --git a/src/librustc/middle/typeck/check/writeback.rs b/src/librustc/middle/typeck/check/writeback.rs index f734aa09e4a12..9532893b83aa1 100644 --- a/src/librustc/middle/typeck/check/writeback.rs +++ b/src/librustc/middle/typeck/check/writeback.rs @@ -121,13 +121,21 @@ impl<'cx, 'tcx, 'v> Visitor<'v> for WritebackCx<'cx, 'tcx> { match e.node { ast::ExprFnBlock(_, ref decl, _) | - ast::ExprProc(ref decl, _) | - ast::ExprUnboxedFn(_, _, ref decl, _) => { + ast::ExprProc(ref decl, _) => { for input in decl.inputs.iter() { let _ = self.visit_node_id(ResolvingExpr(e.span), input.id); } } + ast::ExprUnboxedFn(_, _, ref ids, ref decl, _) => { + for input in decl.inputs.iter() { + let _ = self.visit_node_id(ResolvingExpr(e.span), + input.id); + } + self.visit_node_id(ResolvingExpr(e.span), ids.fn_id); + self.visit_node_id(ResolvingExpr(e.span), ids.fn_mut_id); + self.visit_node_id(ResolvingExpr(e.span), ids.fn_once_id); + } _ => {} } @@ -213,6 +221,7 @@ impl<'cx, 'tcx> WritebackCx<'cx, 'tcx> { ResolvingUnboxedClosure(*def_id)); let unboxed_closure = ty::UnboxedClosure { closure_type: closure_ty, + expr_id: unboxed_closure.expr_id, kind: unboxed_closure.kind, }; self.fcx diff --git a/src/libsyntax/ast.rs b/src/libsyntax/ast.rs index 38d8136c1a13c..073e85d0671e3 100644 --- a/src/libsyntax/ast.rs +++ b/src/libsyntax/ast.rs @@ -501,6 +501,13 @@ pub enum UnsafeSource { UserProvided, } +#[deriving(Clone, PartialEq, Eq, Encodable, Decodable, Hash, Show)] +pub struct AuxiliaryUnboxedClosureIds { + pub fn_id: NodeId, + pub fn_mut_id: NodeId, + pub fn_once_id: NodeId, +} + #[deriving(Clone, PartialEq, Eq, Encodable, Decodable, Hash, Show)] pub struct Expr { pub id: NodeId, @@ -531,7 +538,11 @@ pub enum Expr_ { ExprMatch(P, Vec), ExprFnBlock(CaptureClause, P, P), ExprProc(P, P), - ExprUnboxedFn(CaptureClause, UnboxedClosureKind, P, P), + ExprUnboxedFn(CaptureClause, + UnboxedClosureKind, + P, + P, + P), ExprBlock(P), ExprAssign(P, P), diff --git a/src/libsyntax/fold.rs b/src/libsyntax/fold.rs index 91a339a73f7af..bb34254bfc007 100644 --- a/src/libsyntax/fold.rs +++ b/src/libsyntax/fold.rs @@ -1233,11 +1233,16 @@ pub fn noop_fold_expr(Expr {id, node, span}: Expr, folder: &mut T) -> ExprProc(folder.fold_fn_decl(decl), folder.fold_block(body)) } - ExprUnboxedFn(capture_clause, kind, decl, body) => { + ExprUnboxedFn(capture_clause, kind, ids, decl, body) => { ExprUnboxedFn(capture_clause, - kind, - folder.fold_fn_decl(decl), - folder.fold_block(body)) + kind, + P(AuxiliaryUnboxedClosureIds { + fn_id: folder.new_id(ids.fn_id), + fn_mut_id: folder.new_id(ids.fn_mut_id), + fn_once_id: folder.new_id(ids.fn_once_id), + }), + folder.fold_fn_decl(decl), + folder.fold_block(body)) } ExprBlock(blk) => ExprBlock(folder.fold_block(blk)), ExprAssign(el, er) => { diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index cbc710821f937..a14724f191921 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -11,7 +11,7 @@ #![macro_escape] use abi; -use ast::{AssociatedType, BareFnTy, ClosureTy}; +use ast::{AssociatedType, AuxiliaryUnboxedClosureIds, BareFnTy, ClosureTy}; use ast::{RegionTyParamBound, TraitTyParamBound}; use ast::{ProvidedMethod, Public, FnStyle}; use ast::{Mod, BiAdd, Arg, Arm, Attribute, BindByRef, BindByValue}; @@ -2893,10 +2893,16 @@ impl<'a> Parser<'a> { match optional_unboxed_closure_kind { Some(unboxed_closure_kind) => { + let ids = P(AuxiliaryUnboxedClosureIds { + fn_id: ast::DUMMY_NODE_ID, + fn_mut_id: ast::DUMMY_NODE_ID, + fn_once_id: ast::DUMMY_NODE_ID, + }); self.mk_expr(lo, fakeblock.span.hi, ExprUnboxedFn(capture_clause, unboxed_closure_kind, + ids, decl, fakeblock)) } diff --git a/src/libsyntax/print/pprust.rs b/src/libsyntax/print/pprust.rs index 1fbd4af8627a9..5acd098f435a8 100644 --- a/src/libsyntax/print/pprust.rs +++ b/src/libsyntax/print/pprust.rs @@ -1552,7 +1552,11 @@ impl<'a> State<'a> { // empty box to satisfy the close. try!(self.ibox(0)); } - ast::ExprUnboxedFn(capture_clause, kind, ref decl, ref body) => { + ast::ExprUnboxedFn(capture_clause, + kind, + _, + ref decl, + ref body) => { try!(self.print_capture_clause(capture_clause)); // in do/for blocks we don't want to show an empty diff --git a/src/libsyntax/visit.rs b/src/libsyntax/visit.rs index 3b2ed30b76d89..26ce9e242509b 100644 --- a/src/libsyntax/visit.rs +++ b/src/libsyntax/visit.rs @@ -749,7 +749,7 @@ pub fn walk_expr<'v, V: Visitor<'v>>(visitor: &mut V, expression: &'v Expr) { expression.span, expression.id) } - ExprUnboxedFn(_, _, ref function_declaration, ref body) => { + ExprUnboxedFn(_, _, _, ref function_declaration, ref body) => { visitor.visit_fn(FkFnBlock, &**function_declaration, &**body, diff --git a/src/test/compile-fail/borrowck-overloaded-call.rs b/src/test/compile-fail/borrowck-overloaded-call.rs index f134c2aa09bd5..ae73c4c4a9056 100644 --- a/src/test/compile-fail/borrowck-overloaded-call.rs +++ b/src/test/compile-fail/borrowck-overloaded-call.rs @@ -23,6 +23,18 @@ impl Fn<(int,),int> for SFn { } } +impl FnMut<(int,),int> for SFn { + extern "rust-call" fn call_mut(&mut self, (z,): (int,)) -> int { + self.call((z,)) + } +} + +impl FnOnce<(int,),int> for SFn { + extern "rust-call" fn call_once(self, (z,): (int,)) -> int { + self.call((z,)) + } +} + struct SFnMut { x: int, y: int, @@ -34,6 +46,12 @@ impl FnMut<(int,),int> for SFnMut { } } +impl FnOnce<(int,),int> for SFnMut { + extern "rust-call" fn call_once(mut self, (z,): (int,)) -> int { + self.call_mut((z,)) + } +} + struct SFnOnce { x: String, } diff --git a/src/test/compile-fail/issue-15094.rs b/src/test/compile-fail/issue-15094.rs index c9e47b74d515d..c4704d3552ae8 100644 --- a/src/test/compile-fail/issue-15094.rs +++ b/src/test/compile-fail/issue-15094.rs @@ -16,6 +16,16 @@ struct Shower { x: T } +impl ops::FnOnce<(), ()> for Shower { + extern "rust-call" fn call_once(self, _args: ()) { + } +} + +impl ops::FnMut<(), ()> for Shower { + extern "rust-call" fn call_mut(&mut self, _args: ()) { + } +} + impl ops::Fn<(), ()> for Shower { fn call(&self, _args: ()) { //~^ ERROR `call` has an incompatible type for trait: expected "rust-call" fn, found "Rust" fn diff --git a/src/test/compile-fail/overloaded-calls-bad.rs b/src/test/compile-fail/overloaded-calls-bad.rs index cc01c0b3c9f1c..bf9d7f29c9106 100644 --- a/src/test/compile-fail/overloaded-calls-bad.rs +++ b/src/test/compile-fail/overloaded-calls-bad.rs @@ -23,6 +23,12 @@ impl FnMut<(int,),int> for S { } } +impl FnOnce<(int,),int> for S { + extern "rust-call" fn call_once(mut self, (z,): (int,)) -> int { + self.call_mut((z,)) + } +} + fn main() { let mut s = S { x: 3, diff --git a/src/test/compile-fail/overloaded-calls-nontuple.rs b/src/test/compile-fail/overloaded-calls-nontuple.rs index ee2fe3522470a..8c686abd7847a 100644 --- a/src/test/compile-fail/overloaded-calls-nontuple.rs +++ b/src/test/compile-fail/overloaded-calls-nontuple.rs @@ -23,6 +23,12 @@ impl FnMut for S { } } +impl FnOnce for S { + extern "rust-call" fn call_once(mut self, z: int) -> int { + self.call_mut(z) + } +} + fn main() { let mut s = S { x: 1, diff --git a/src/test/compile-fail/unboxed-closures-wrong-trait.rs b/src/test/compile-fail/unboxed-closures-wrong-trait.rs index 97ad64a77baf4..e8d00ca1bc99e 100644 --- a/src/test/compile-fail/unboxed-closures-wrong-trait.rs +++ b/src/test/compile-fail/unboxed-closures-wrong-trait.rs @@ -10,13 +10,13 @@ #![feature(lang_items, overloaded_calls, unboxed_closures)] -fn c int>(f: F) -> int { +fn c int>(f: F) -> int { f(5, 6) } fn main() { let z: int = 7; - assert_eq!(c(|&: x: int, y| x + y + z), 10); + assert_eq!(c(|&mut : x: int, y| x + y + z), 10); //~^ ERROR not implemented } diff --git a/src/test/run-pass/fn-trait-sugar.rs b/src/test/run-pass/fn-trait-sugar.rs index b0947f46a86ae..1bbe3733fe22c 100644 --- a/src/test/run-pass/fn-trait-sugar.rs +++ b/src/test/run-pass/fn-trait-sugar.rs @@ -15,6 +15,12 @@ use std::ops::FnMut; struct S; +impl FnOnce<(int,),int> for S { + extern "rust-call" fn call_once(mut self, (x,): (int,)) -> int { + self.call_mut((x,)) + } +} + impl FnMut<(int,),int> for S { extern "rust-call" fn call_mut(&mut self, (x,): (int,)) -> int { x * x diff --git a/src/test/run-pass/issue-14958.rs b/src/test/run-pass/issue-14958.rs index c2bd8c5b3e50c..f50d44f86303c 100644 --- a/src/test/run-pass/issue-14958.rs +++ b/src/test/run-pass/issue-14958.rs @@ -14,6 +14,14 @@ trait Foo {} struct Bar; +impl<'a> std::ops::FnOnce<(&'a Foo+'a,), ()> for Bar { + extern "rust-call" fn call_once(self, _: (&'a Foo,)) {} +} + +impl<'a> std::ops::FnMut<(&'a Foo+'a,), ()> for Bar { + extern "rust-call" fn call_mut(&mut self, _: (&'a Foo,)) {} +} + impl<'a> std::ops::Fn<(&'a Foo+'a,), ()> for Bar { extern "rust-call" fn call(&self, _: (&'a Foo,)) {} } diff --git a/src/test/run-pass/issue-14959.rs b/src/test/run-pass/issue-14959.rs index 74b9df9b88d87..89c0c287364ce 100644 --- a/src/test/run-pass/issue-14959.rs +++ b/src/test/run-pass/issue-14959.rs @@ -33,6 +33,14 @@ impl Alloy { } } +impl<'a, 'b> FnOnce<(&'b mut Response+'b,),()> for SendFile<'a> { + extern "rust-call" fn call_once(self, (_res,): (&'b mut Response+'b,)) {} +} + +impl<'a, 'b> FnMut<(&'b mut Response+'b,),()> for SendFile<'a> { + extern "rust-call" fn call_mut(&mut self, (_res,): (&'b mut Response+'b,)) {} +} + impl<'a, 'b> Fn<(&'b mut Response+'b,),()> for SendFile<'a> { extern "rust-call" fn call(&self, (_res,): (&'b mut Response+'b,)) {} } diff --git a/src/test/run-pass/overloaded-calls-param-vtables.rs b/src/test/run-pass/overloaded-calls-param-vtables.rs index 6f870f0afd52c..74418e790ee62 100644 --- a/src/test/run-pass/overloaded-calls-param-vtables.rs +++ b/src/test/run-pass/overloaded-calls-param-vtables.rs @@ -16,6 +16,18 @@ use std::ops::Fn; struct G; +impl<'a, A: Add> FnOnce<(A,), int> for G { + extern "rust-call" fn call_once(self, (arg,): (A,)) -> int { + self.call((arg,)) + } +} + +impl<'a, A: Add> FnMut<(A,), int> for G { + extern "rust-call" fn call_mut(&mut self, (arg,): (A,)) -> int { + self.call((arg,)) + } +} + impl<'a, A: Add> Fn<(A,), int> for G { extern "rust-call" fn call(&self, (arg,): (A,)) -> int { arg.add(&1) diff --git a/src/test/run-pass/overloaded-calls-simple.rs b/src/test/run-pass/overloaded-calls-simple.rs index 76c7e60116f80..dab3b9ee7f9b4 100644 --- a/src/test/run-pass/overloaded-calls-simple.rs +++ b/src/test/run-pass/overloaded-calls-simple.rs @@ -17,6 +17,12 @@ struct S1 { y: int, } +impl FnOnce<(int,),int> for S1 { + extern "rust-call" fn call_once(mut self, (z,): (int,)) -> int { + self.call_mut((z,)) + } +} + impl FnMut<(int,),int> for S1 { extern "rust-call" fn call_mut(&mut self, (z,): (int,)) -> int { self.x * self.y * z @@ -28,6 +34,18 @@ struct S2 { y: int, } +impl FnOnce<(int,),int> for S2 { + extern "rust-call" fn call_once(self, (z,): (int,)) -> int { + self.call((z,)) + } +} + +impl FnMut<(int,),int> for S2 { + extern "rust-call" fn call_mut(&mut self, (z,): (int,)) -> int { + self.call((z,)) + } +} + impl Fn<(int,),int> for S2 { extern "rust-call" fn call(&self, (z,): (int,)) -> int { self.x * self.y * z diff --git a/src/test/run-pass/overloaded-calls-zero-args.rs b/src/test/run-pass/overloaded-calls-zero-args.rs index b868c8c96b5fb..6a97ca90a657a 100644 --- a/src/test/run-pass/overloaded-calls-zero-args.rs +++ b/src/test/run-pass/overloaded-calls-zero-args.rs @@ -17,6 +17,12 @@ struct S { y: int, } +impl FnOnce<(),int> for S { + extern "rust-call" fn call_once(mut self, (): ()) -> int { + self.call_mut(()) + } +} + impl FnMut<(),int> for S { extern "rust-call" fn call_mut(&mut self, (): ()) -> int { self.x * self.y diff --git a/src/test/run-pass/unboxed-closure-trait-hierarchy.rs b/src/test/run-pass/unboxed-closure-trait-hierarchy.rs new file mode 100644 index 0000000000000..999e14a55b369 --- /dev/null +++ b/src/test/run-pass/unboxed-closure-trait-hierarchy.rs @@ -0,0 +1,25 @@ +// 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(overloaded_calls, unboxed_closures)] + +fn foo(f: F) -> int where F: FnOnce(int) -> int { + f(1i) +} + +fn bar(mut f: F) -> int where F: FnMut(int) -> int { + f(1i) +} + +fn main() { + assert_eq!(foo(|&mut: x: int| x + 3), 4i); + assert_eq!(bar(|&: x: int| x + 7), 8i); +} +