diff --git a/src/libcollectionstest/btree/set.rs b/src/libcollectionstest/btree/set.rs index 488f0d756d329..234cd6e0fd21e 100644 --- a/src/libcollectionstest/btree/set.rs +++ b/src/libcollectionstest/btree/set.rs @@ -43,8 +43,6 @@ struct Counter<'a, 'b> { } impl<'a, 'b, 'c> FnMut<(&'c i32,)> for Counter<'a, 'b> { - type Output = bool; - extern "rust-call" fn call_mut(&mut self, (&x,): (&'c i32,)) -> bool { assert_eq!(x, self.expected[*self.i]); *self.i += 1; @@ -52,6 +50,14 @@ impl<'a, 'b, 'c> FnMut<(&'c i32,)> for Counter<'a, 'b> { } } +impl<'a, 'b, 'c> FnOnce<(&'c i32,)> for Counter<'a, 'b> { + type Output = bool; + + extern "rust-call" fn call_once(mut self, args: (&'c i32,)) -> bool { + self.call_mut(args) + } +} + fn check(a: &[i32], b: &[i32], expected: &[i32], f: F) where // FIXME Replace Counter with `Box _>` F: FnOnce(&BTreeSet, &BTreeSet, Counter) -> bool, diff --git a/src/libcore/ops.rs b/src/libcore/ops.rs index 6324e8fa87443..fc3f4b426d861 100644 --- a/src/libcore/ops.rs +++ b/src/libcore/ops.rs @@ -1136,6 +1136,7 @@ impl<'a, T: ?Sized> DerefMut for &'a mut T { #[lang="fn"] #[stable(feature = "rust1", since = "1.0.0")] #[rustc_paren_sugar] +#[cfg(stage0)] pub trait Fn { /// The returned type after the call operator is used. type Output; @@ -1144,10 +1145,21 @@ pub trait Fn { extern "rust-call" fn call(&self, args: Args) -> Self::Output; } +/// A version of the call operator that takes an immutable receiver. +#[lang="fn"] +#[stable(feature = "rust1", since = "1.0.0")] +#[rustc_paren_sugar] +#[cfg(not(stage0))] +pub trait Fn : FnMut { + /// This is called when the call operator is used. + extern "rust-call" fn call(&self, args: Args) -> Self::Output; +} + /// A version of the call operator that takes a mutable receiver. #[lang="fn_mut"] #[stable(feature = "rust1", since = "1.0.0")] #[rustc_paren_sugar] +#[cfg(stage0)] pub trait FnMut { /// The returned type after the call operator is used. type Output; @@ -1156,6 +1168,16 @@ pub trait FnMut { extern "rust-call" fn call_mut(&mut self, args: Args) -> Self::Output; } +/// A version of the call operator that takes a mutable receiver. +#[lang="fn_mut"] +#[stable(feature = "rust1", since = "1.0.0")] +#[rustc_paren_sugar] +#[cfg(not(stage0))] +pub trait FnMut : FnOnce { + /// This is called when the call operator is used. + extern "rust-call" fn call_mut(&mut self, args: Args) -> Self::Output; +} + /// A version of the call operator that takes a by-value receiver. #[lang="fn_once"] #[stable(feature = "rust1", since = "1.0.0")] @@ -1168,6 +1190,7 @@ pub trait FnOnce { extern "rust-call" fn call_once(self, args: Args) -> Self::Output; } +#[cfg(stage0)] impl FnMut for F where F : Fn { @@ -1178,6 +1201,7 @@ impl FnMut for F } } +#[cfg(stage0)] impl FnOnce for F where F : FnMut { diff --git a/src/libcore/str/mod.rs b/src/libcore/str/mod.rs index e8181395b5c1e..dd7144636dfb7 100644 --- a/src/libcore/str/mod.rs +++ b/src/libcore/str/mod.rs @@ -29,7 +29,7 @@ use iter::{Map, Iterator, IteratorExt, DoubleEndedIterator}; use marker::Sized; use mem; use num::Int; -use ops::{Fn, FnMut}; +use ops::{Fn, FnMut, FnOnce}; use option::Option::{self, None, Some}; use raw::{Repr, Slice}; use result::Result::{self, Ok, Err}; @@ -524,6 +524,7 @@ delegate_iter!{exact u8 : Bytes<'a>} #[derive(Copy, Clone)] struct BytesDeref; +#[cfg(stage0)] impl<'a> Fn<(&'a u8,)> for BytesDeref { type Output = u8; @@ -533,6 +534,32 @@ impl<'a> Fn<(&'a u8,)> for BytesDeref { } } +#[cfg(not(stage0))] +impl<'a> Fn<(&'a u8,)> for BytesDeref { + #[inline] + extern "rust-call" fn call(&self, (ptr,): (&'a u8,)) -> u8 { + *ptr + } +} + +#[cfg(not(stage0))] +impl<'a> FnMut<(&'a u8,)> for BytesDeref { + #[inline] + extern "rust-call" fn call_mut(&mut self, (ptr,): (&'a u8,)) -> u8 { + Fn::call(&*self, (ptr,)) + } +} + +#[cfg(not(stage0))] +impl<'a> FnOnce<(&'a u8,)> for BytesDeref { + type Output = u8; + + #[inline] + extern "rust-call" fn call_once(self, (ptr,): (&'a u8,)) -> u8 { + Fn::call(&self, (ptr,)) + } +} + /// An iterator over the substrings of a string, separated by `sep`. struct CharSplits<'a, P: Pattern<'a>> { /// The slice remaining to be iterated diff --git a/src/librustc/middle/traits/project.rs b/src/librustc/middle/traits/project.rs index 6b66d7227d300..b4f21492ca10b 100644 --- a/src/librustc/middle/traits/project.rs +++ b/src/librustc/middle/traits/project.rs @@ -789,10 +789,13 @@ fn confirm_callable_candidate<'cx,'tcx>( obligation.repr(tcx), fn_sig.repr(tcx)); + // the `Output` associated type is declared on `FnOnce` + let fn_once_def_id = tcx.lang_items.fn_once_trait().unwrap(); + // Note: we unwrap the binder here but re-create it below (1) let ty::Binder((trait_ref, ret_type)) = util::closure_trait_ref_and_return_type(tcx, - obligation.predicate.trait_ref.def_id, + fn_once_def_id, obligation.predicate.trait_ref.self_ty(), fn_sig, flag); diff --git a/src/librustc/middle/traits/select.rs b/src/librustc/middle/traits/select.rs index 7dfbccea0dccd..764e342a0c5af 100644 --- a/src/librustc/middle/traits/select.rs +++ b/src/librustc/middle/traits/select.rs @@ -1071,7 +1071,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { match self.closure_typer.closure_kind(closure_def_id) { Some(closure_kind) => { debug!("assemble_unboxed_candidates: closure_kind = {:?}", closure_kind); - if closure_kind == kind { + if closure_kind.extends(kind) { candidates.vec.push(ClosureCandidate(closure_def_id, substs.clone())); } } @@ -1090,10 +1090,8 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { candidates: &mut SelectionCandidateSet<'tcx>) -> Result<(),SelectionError<'tcx>> { - // We provide a `Fn` impl for fn pointers. There is no need to provide - // the other traits (e.g. `FnMut`) since those are provided by blanket - // impls. - if Some(obligation.predicate.def_id()) != self.tcx().lang_items.fn_trait() { + // We provide impl of all fn traits for fn pointers. + if self.tcx().lang_items.fn_trait_kind(obligation.predicate.def_id()).is_none() { return Ok(()); } diff --git a/src/librustc/middle/ty.rs b/src/librustc/middle/ty.rs index 99c35c6e54258..4b8c4ee88c05d 100644 --- a/src/librustc/middle/ty.rs +++ b/src/librustc/middle/ty.rs @@ -2461,8 +2461,11 @@ pub struct ItemSubsts<'tcx> { pub substs: Substs<'tcx>, } -#[derive(Clone, Copy, PartialEq, Eq, Debug, RustcEncodable, RustcDecodable)] +#[derive(Clone, Copy, PartialOrd, Ord, PartialEq, Eq, Debug, RustcEncodable, RustcDecodable)] pub enum ClosureKind { + // Warning: Ordering is significant here! The ordering is chosen + // because the trait Fn is a subtrait of FnMut and so in turn, and + // hence we order it so that Fn < FnMut < FnOnce. FnClosureKind, FnMutClosureKind, FnOnceClosureKind, @@ -2484,6 +2487,20 @@ impl ClosureKind { Err(err) => cx.sess.fatal(&err[..]), } } + + /// True if this a type that impls this closure kind + /// must also implement `other`. + pub fn extends(self, other: ty::ClosureKind) -> bool { + match (self, other) { + (FnClosureKind, FnClosureKind) => true, + (FnClosureKind, FnMutClosureKind) => true, + (FnClosureKind, FnOnceClosureKind) => true, + (FnMutClosureKind, FnMutClosureKind) => true, + (FnMutClosureKind, FnOnceClosureKind) => true, + (FnOnceClosureKind, FnOnceClosureKind) => true, + _ => false, + } + } } pub trait ClosureTyper<'tcx> { diff --git a/src/librustc_trans/trans/callee.rs b/src/librustc_trans/trans/callee.rs index cf36ec1f3ed96..07c94097e2df8 100644 --- a/src/librustc_trans/trans/callee.rs +++ b/src/librustc_trans/trans/callee.rs @@ -264,14 +264,29 @@ fn trans_fn_ref_with_substs_to_callee<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, /// but for the bare function type given. pub fn trans_fn_pointer_shim<'a, 'tcx>( ccx: &'a CrateContext<'a, 'tcx>, + closure_kind: ty::ClosureKind, bare_fn_ty: Ty<'tcx>) -> ValueRef { let _icx = push_ctxt("trans_fn_pointer_shim"); let tcx = ccx.tcx(); + // Normalize the type for better caching. let bare_fn_ty = common::erase_regions(tcx, &bare_fn_ty); - match ccx.fn_pointer_shims().borrow().get(&bare_fn_ty) { + + // If this is an impl of `Fn` or `FnMut` trait, the receiver is `&self`. + let is_by_ref = match closure_kind { + ty::FnClosureKind | ty::FnMutClosureKind => true, + ty::FnOnceClosureKind => false, + }; + let bare_fn_ty_maybe_ref = if is_by_ref { + ty::mk_imm_rptr(tcx, tcx.mk_region(ty::ReStatic), bare_fn_ty) + } else { + bare_fn_ty + }; + + // Check if we already trans'd this shim. + match ccx.fn_pointer_shims().borrow().get(&bare_fn_ty_maybe_ref) { Some(&llval) => { return llval; } None => { } } @@ -279,9 +294,6 @@ pub fn trans_fn_pointer_shim<'a, 'tcx>( debug!("trans_fn_pointer_shim(bare_fn_ty={})", bare_fn_ty.repr(tcx)); - // This is an impl of `Fn` trait, so receiver is `&self`. - let bare_fn_ty_ref = ty::mk_imm_rptr(tcx, tcx.mk_region(ty::ReStatic), bare_fn_ty); - // Construct the "tuply" version of `bare_fn_ty`. It takes two arguments: `self`, // which is the fn pointer, and `args`, which is the arguments tuple. let (opt_def_id, sig) = @@ -306,7 +318,7 @@ pub fn trans_fn_pointer_shim<'a, 'tcx>( unsafety: ast::Unsafety::Normal, abi: synabi::RustCall, sig: ty::Binder(ty::FnSig { - inputs: vec![bare_fn_ty_ref, + inputs: vec![bare_fn_ty_maybe_ref, tuple_input_ty], output: sig.output, variadic: false @@ -337,8 +349,11 @@ pub fn trans_fn_pointer_shim<'a, 'tcx>( let mut bcx = init_function(&fcx, false, sig.output); // the first argument (`self`) will be ptr to the the fn pointer - let llfnpointer = - Load(bcx, get_param(fcx.llfn, fcx.arg_pos(0) as u32)); + let llfnpointer = if is_by_ref { + Load(bcx, get_param(fcx.llfn, fcx.arg_pos(0) as u32)) + } else { + get_param(fcx.llfn, fcx.arg_pos(0) as u32) + }; // the remaining arguments will be the untupled values let llargs: Vec<_> = @@ -361,7 +376,7 @@ pub fn trans_fn_pointer_shim<'a, 'tcx>( finish_fn(&fcx, bcx, sig.output, DebugLoc::None); - ccx.fn_pointer_shims().borrow_mut().insert(bare_fn_ty, llfn); + ccx.fn_pointer_shims().borrow_mut().insert(bare_fn_ty_maybe_ref, llfn); llfn } diff --git a/src/librustc_trans/trans/closure.rs b/src/librustc_trans/trans/closure.rs index c1bc7219ad825..5a48b8e4bce1d 100644 --- a/src/librustc_trans/trans/closure.rs +++ b/src/librustc_trans/trans/closure.rs @@ -8,24 +8,27 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use back::link::mangle_internal_name_by_path_and_seq; -use llvm::ValueRef; +use arena::TypedArena; +use back::link::{self, mangle_internal_name_by_path_and_seq}; +use llvm::{ValueRef, get_param}; use middle::mem_categorization::Typer; use trans::adt; use trans::base::*; use trans::build::*; -use trans::cleanup::{CleanupMethods, ScopeId}; +use trans::callee::{self, ArgVals, Callee, TraitItem, MethodData}; +use trans::cleanup::{CleanupMethods, CustomScope, ScopeId}; use trans::common::*; -use trans::datum::{Datum, rvalue_scratch_datum}; -use trans::datum::{Rvalue, ByValue}; -use trans::debuginfo; +use trans::datum::{self, Datum, rvalue_scratch_datum, Rvalue, ByValue}; +use trans::debuginfo::{self, DebugLoc}; use trans::expr; use trans::monomorphize::{self, MonoId}; use trans::type_of::*; use middle::ty::{self, ClosureTyper}; use middle::subst::{Substs}; use session::config::FullDebugInfo; +use util::ppaux::Repr; +use syntax::abi::RustCall; use syntax::ast; use syntax::ast_util; @@ -239,11 +242,7 @@ pub fn trans_closure_expr<'a, 'tcx>(dest: Dest<'a, 'tcx>, // Create the closure. for (i, freevar) in freevars.iter().enumerate() { let datum = expr::trans_local_var(bcx, freevar.def); - let upvar_slot_dest = adt::trans_field_ptr(bcx, - &*repr, - dest_addr, - 0, - i); + let upvar_slot_dest = adt::trans_field_ptr(bcx, &*repr, dest_addr, 0, i); let upvar_id = ty::UpvarId { var_id: freevar.def.local_node_id(), closure_expr_id: id }; match tcx.upvar_capture(upvar_id).unwrap() { @@ -259,3 +258,186 @@ pub fn trans_closure_expr<'a, 'tcx>(dest: Dest<'a, 'tcx>, Some(bcx) } + +pub fn trans_closure_method<'a, 'tcx>(ccx: &'a CrateContext<'a, 'tcx>, + closure_def_id: ast::DefId, + substs: Substs<'tcx>, + node: ExprOrMethodCall, + param_substs: &'tcx Substs<'tcx>, + trait_closure_kind: ty::ClosureKind) + -> ValueRef +{ + // The substitutions should have no type parameters remaining + // after passing through fulfill_obligation + let llfn = callee::trans_fn_ref_with_substs(ccx, + closure_def_id, + node, + param_substs, + substs.clone()).val; + + // If the closure is a Fn closure, but a FnOnce is needed (etc), + // then adapt the self type + let closure_kind = ccx.tcx().closure_kind(closure_def_id); + trans_closure_adapter_shim(ccx, + closure_def_id, + substs, + closure_kind, + trait_closure_kind, + llfn) +} + +fn trans_closure_adapter_shim<'a, 'tcx>( + ccx: &'a CrateContext<'a, 'tcx>, + closure_def_id: ast::DefId, + substs: Substs<'tcx>, + llfn_closure_kind: ty::ClosureKind, + trait_closure_kind: ty::ClosureKind, + llfn: ValueRef) + -> ValueRef +{ + let _icx = push_ctxt("trans_closure_adapter_shim"); + let tcx = ccx.tcx(); + + debug!("trans_closure_adapter_shim(llfn_closure_kind={:?}, \ + trait_closure_kind={:?}, \ + llfn={})", + llfn_closure_kind, + trait_closure_kind, + ccx.tn().val_to_string(llfn)); + + match (llfn_closure_kind, trait_closure_kind) { + (ty::FnClosureKind, ty::FnClosureKind) | + (ty::FnMutClosureKind, ty::FnMutClosureKind) | + (ty::FnOnceClosureKind, ty::FnOnceClosureKind) => { + // No adapter needed. + llfn + } + (ty::FnClosureKind, ty::FnMutClosureKind) => { + // The closure fn `llfn` is a `fn(&self, ...)`. We want a + // `fn(&mut self, ...)`. In fact, at trans time, these are + // basically the same thing, so we can just return llfn. + llfn + } + (ty::FnClosureKind, ty::FnOnceClosureKind) | + (ty::FnMutClosureKind, ty::FnOnceClosureKind) => { + // The closure fn `llfn` is a `fn(&self, ...)` or `fn(&mut + // self, ...)`. We want a `fn(self, ...)`. We can produce + // this by doing something like: + // + // fn call_once(self, ...) { call_mut(&self, ...) } + // fn call_once(mut self, ...) { call_mut(&mut self, ...) } + // + // These are both the same at trans time. + trans_fn_once_adapter_shim(ccx, closure_def_id, substs, llfn) + } + _ => { + tcx.sess.bug(&format!("trans_closure_adapter_shim: cannot convert {:?} to {:?}", + llfn_closure_kind, + trait_closure_kind)); + } + } +} + +fn trans_fn_once_adapter_shim<'a, 'tcx>( + ccx: &'a CrateContext<'a, 'tcx>, + closure_def_id: ast::DefId, + substs: Substs<'tcx>, + llreffn: ValueRef) + -> ValueRef +{ + debug!("trans_fn_once_adapter_shim(closure_def_id={}, substs={}, llreffn={})", + closure_def_id.repr(ccx.tcx()), + substs.repr(ccx.tcx()), + ccx.tn().val_to_string(llreffn)); + + let tcx = ccx.tcx(); + let typer = NormalizingClosureTyper::new(tcx); + + // Find a version of the closure type. Substitute static for the + // region since it doesn't really matter. + let substs = tcx.mk_substs(substs); + let closure_ty = ty::mk_closure(tcx, closure_def_id, substs); + let ref_closure_ty = ty::mk_imm_rptr(tcx, tcx.mk_region(ty::ReStatic), closure_ty); + + // Make a version with the type of by-ref closure. + let ty::ClosureTy { unsafety, abi, mut sig } = typer.closure_type(closure_def_id, substs); + sig.0.inputs.insert(0, ref_closure_ty); // sig has no self type as of yet + let llref_bare_fn_ty = tcx.mk_bare_fn(ty::BareFnTy { unsafety: unsafety, + abi: abi, + sig: sig.clone() }); + let llref_fn_ty = ty::mk_bare_fn(tcx, None, llref_bare_fn_ty); + debug!("trans_fn_once_adapter_shim: llref_fn_ty={}", + llref_fn_ty.repr(tcx)); + + // Make a version of the closure type with the same arguments, but + // with argument #0 being by value. + assert_eq!(abi, RustCall); + sig.0.inputs[0] = closure_ty; + let llonce_bare_fn_ty = tcx.mk_bare_fn(ty::BareFnTy { unsafety: unsafety, + abi: abi, + sig: sig }); + let llonce_fn_ty = ty::mk_bare_fn(tcx, None, llonce_bare_fn_ty); + + // Create the by-value helper. + let function_name = link::mangle_internal_name_by_type_and_seq(ccx, llonce_fn_ty, "once_shim"); + let lloncefn = decl_internal_rust_fn(ccx, llonce_fn_ty, &function_name); + + let sig = ty::erase_late_bound_regions(tcx, &llonce_bare_fn_ty.sig); + let (block_arena, fcx): (TypedArena<_>, FunctionContext); + block_arena = TypedArena::new(); + fcx = new_fn_ctxt(ccx, + lloncefn, + ast::DUMMY_NODE_ID, + false, + sig.output, + substs, + None, + &block_arena); + let mut bcx = init_function(&fcx, false, sig.output); + + // the first argument (`self`) will be the (by value) closure env. + let self_scope = fcx.push_custom_cleanup_scope(); + let self_scope_id = CustomScope(self_scope); + let rvalue_mode = datum::appropriate_rvalue_mode(ccx, closure_ty); + let llself = get_param(lloncefn, fcx.arg_pos(0) as u32); + let env_datum = Datum::new(llself, closure_ty, Rvalue::new(rvalue_mode)); + let env_datum = unpack_datum!(bcx, + env_datum.to_lvalue_datum_in_scope(bcx, "self", + self_scope_id)); + + debug!("trans_fn_once_adapter_shim: env_datum={}", + bcx.val_to_string(env_datum.val)); + + // the remaining arguments will be packed up in a tuple. + let input_tys = match sig.inputs[1].sty { + ty::ty_tup(ref tys) => &**tys, + _ => bcx.sess().bug(&format!("trans_fn_once_adapter_shim: not rust-call! \ + closure_def_id={}", + closure_def_id.repr(tcx))) + }; + let llargs: Vec<_> = + input_tys.iter() + .enumerate() + .map(|(i, _)| get_param(lloncefn, fcx.arg_pos(i+1) as u32)) + .collect(); + + let dest = + fcx.llretslotptr.get().map( + |_| expr::SaveIn(fcx.get_ret_slot(bcx, sig.output, "ret_slot"))); + + let callee_data = TraitItem(MethodData { llfn: llreffn, + llself: env_datum.val }); + + bcx = callee::trans_call_inner(bcx, + DebugLoc::None, + llref_fn_ty, + |bcx, _| Callee { bcx: bcx, data: callee_data }, + ArgVals(&llargs), + dest).bcx; + + fcx.pop_custom_cleanup_scope(self_scope); + + finish_fn(&fcx, bcx, sig.output, DebugLoc::None); + + lloncefn +} diff --git a/src/librustc_trans/trans/meth.rs b/src/librustc_trans/trans/meth.rs index 4da17972c55fb..aa038f8ddca31 100644 --- a/src/librustc_trans/trans/meth.rs +++ b/src/librustc_trans/trans/meth.rs @@ -17,11 +17,13 @@ use middle::subst::Substs; use middle::subst::VecPerParamSpace; use middle::subst; use middle::traits; +use middle::ty::ClosureTyper; use trans::base::*; use trans::build::*; use trans::callee::*; use trans::callee; use trans::cleanup; +use trans::closure; use trans::common::*; use trans::consts; use trans::datum::*; @@ -358,19 +360,21 @@ fn trans_monomorphized_callee<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, traits::VtableClosure(closure_def_id, substs) => { // The substitutions should have no type parameters remaining // after passing through fulfill_obligation - let llfn = trans_fn_ref_with_substs(bcx.ccx(), - closure_def_id, - MethodCallKey(method_call), - bcx.fcx.param_substs, - substs).val; - + let trait_closure_kind = bcx.tcx().lang_items.fn_trait_kind(trait_id).unwrap(); + let llfn = closure::trans_closure_method(bcx.ccx(), + closure_def_id, + substs, + MethodCallKey(method_call), + bcx.fcx.param_substs, + trait_closure_kind); Callee { bcx: bcx, data: Fn(llfn), } } traits::VtableFnPointer(fn_ty) => { - let llfn = trans_fn_pointer_shim(bcx.ccx(), fn_ty); + let trait_closure_kind = bcx.tcx().lang_items.fn_trait_kind(trait_id).unwrap(); + let llfn = trans_fn_pointer_shim(bcx.ccx(), trait_closure_kind, fn_ty); Callee { bcx: bcx, data: Fn(llfn) } } traits::VtableObject(ref data) => { @@ -645,9 +649,6 @@ pub fn trans_object_shim<'a, 'tcx>( assert!(!fcx.needs_ret_allocas); - let sig = - ty::erase_late_bound_regions(bcx.tcx(), &fty.sig); - let dest = fcx.llretslotptr.get().map( |_| expr::SaveIn(fcx.get_ret_slot(bcx, sig.output, "ret_slot"))); @@ -714,17 +715,18 @@ pub fn get_vtable<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, emit_vtable_methods(ccx, id, substs, param_substs).into_iter() } traits::VtableClosure(closure_def_id, substs) => { - let llfn = trans_fn_ref_with_substs( - ccx, - closure_def_id, - ExprId(0), - param_substs, - substs).val; - + let trait_closure_kind = tcx.lang_items.fn_trait_kind(trait_ref.def_id()).unwrap(); + let llfn = closure::trans_closure_method(ccx, + closure_def_id, + substs, + ExprId(0), + param_substs, + trait_closure_kind); vec![llfn].into_iter() } traits::VtableFnPointer(bare_fn_ty) => { - vec![trans_fn_pointer_shim(ccx, bare_fn_ty)].into_iter() + let trait_closure_kind = tcx.lang_items.fn_trait_kind(trait_ref.def_id()).unwrap(); + vec![trans_fn_pointer_shim(ccx, trait_closure_kind, bare_fn_ty)].into_iter() } traits::VtableObject(ref data) => { // this would imply that the Self type being erased is diff --git a/src/librustc_typeck/astconv.rs b/src/librustc_typeck/astconv.rs index 28e7027b2124a..4f06346fb45cc 100644 --- a/src/librustc_typeck/astconv.rs +++ b/src/librustc_typeck/astconv.rs @@ -55,7 +55,7 @@ use middle::resolve_lifetime as rl; use middle::privacy::{AllPublic, LastMod}; use middle::subst::{FnSpace, TypeSpace, SelfSpace, Subst, Substs}; use middle::traits; -use middle::ty::{self, RegionEscape, ToPolyTraitRef, Ty}; +use middle::ty::{self, RegionEscape, Ty}; use rscope::{self, UnelidableRscope, RegionScope, ElidableRscope, ObjectLifetimeDefaultRscope, ShiftedRscope, BindingRscope}; use util::common::{ErrorReported, FN_OUTPUT_NAME}; @@ -608,24 +608,16 @@ pub fn instantiate_poly_trait_ref<'tcx>( poly_projections: &mut Vec>) -> ty::PolyTraitRef<'tcx> { - let mut projections = Vec::new(); - - // The trait reference introduces a binding level here, so - // we need to shift the `rscope`. It'd be nice if we could - // do away with this rscope stuff and work this knowledge - // into resolve_lifetimes, as we do with non-omitted - // lifetimes. Oh well, not there yet. - let shifted_rscope = ShiftedRscope::new(rscope); - - let trait_ref = instantiate_trait_ref(this, &shifted_rscope, - &ast_trait_ref.trait_ref, - None, self_ty, Some(&mut projections)); - - for projection in projections { - poly_projections.push(ty::Binder(projection)); - } - - ty::Binder(trait_ref) + let trait_ref = &ast_trait_ref.trait_ref; + let trait_def_id = trait_def_id(this, trait_ref); + ast_path_to_poly_trait_ref(this, + rscope, + trait_ref.path.span, + PathParamMode::Explicit, + trait_def_id, + self_ty, + trait_ref.path.segments.last().unwrap(), + poly_projections) } /// Instantiates the path for the given trait reference, assuming that it's @@ -634,31 +626,27 @@ pub fn instantiate_poly_trait_ref<'tcx>( /// /// If the `projections` argument is `None`, then assoc type bindings like `Foo` /// are disallowed. Otherwise, they are pushed onto the vector given. -pub fn instantiate_trait_ref<'tcx>( +pub fn instantiate_mono_trait_ref<'tcx>( this: &AstConv<'tcx>, rscope: &RegionScope, trait_ref: &ast::TraitRef, - impl_id: Option, - self_ty: Option>, - projections: Option<&mut Vec>>) + self_ty: Option>) -> Rc> { + let trait_def_id = trait_def_id(this, trait_ref); + ast_path_to_mono_trait_ref(this, + rscope, + trait_ref.path.span, + PathParamMode::Explicit, + trait_def_id, + self_ty, + trait_ref.path.segments.last().unwrap()) +} + +fn trait_def_id<'tcx>(this: &AstConv<'tcx>, trait_ref: &ast::TraitRef) -> ast::DefId { let path = &trait_ref.path; match ::lookup_full_def(this.tcx(), path.span, trait_ref.ref_id) { - def::DefTrait(trait_def_id) => { - let trait_ref = ast_path_to_trait_ref(this, - rscope, - path.span, - PathParamMode::Explicit, - trait_def_id, - self_ty, - path.segments.last().unwrap(), - projections); - if let Some(id) = impl_id { - this.tcx().impl_trait_refs.borrow_mut().insert(id, trait_ref.clone()); - } - trait_ref - } + def::DefTrait(trait_def_id) => trait_def_id, _ => { span_fatal!(this.tcx().sess, path.span, E0245, "`{}` is not a trait", path.user_string(this.tcx())); @@ -676,24 +664,17 @@ fn object_path_to_poly_trait_ref<'a,'tcx>( mut projections: &mut Vec>) -> ty::PolyTraitRef<'tcx> { - // we are introducing a binder here, so shift the - // anonymous regions depth to account for that - let shifted_rscope = ShiftedRscope::new(rscope); - - let mut tmp = Vec::new(); - let trait_ref = ty::Binder(ast_path_to_trait_ref(this, - &shifted_rscope, - span, - param_mode, - trait_def_id, - None, - trait_segment, - Some(&mut tmp))); - projections.extend(tmp.into_iter().map(ty::Binder)); - trait_ref + ast_path_to_poly_trait_ref(this, + rscope, + span, + param_mode, + trait_def_id, + None, + trait_segment, + projections) } -fn ast_path_to_trait_ref<'a,'tcx>( +fn ast_path_to_poly_trait_ref<'a,'tcx>( this: &AstConv<'tcx>, rscope: &RegionScope, span: Span, @@ -701,10 +682,78 @@ fn ast_path_to_trait_ref<'a,'tcx>( trait_def_id: ast::DefId, self_ty: Option>, trait_segment: &ast::PathSegment, - mut projections: Option<&mut Vec>>) - -> Rc> + poly_projections: &mut Vec>) + -> ty::PolyTraitRef<'tcx> +{ + // The trait reference introduces a binding level here, so + // we need to shift the `rscope`. It'd be nice if we could + // do away with this rscope stuff and work this knowledge + // into resolve_lifetimes, as we do with non-omitted + // lifetimes. Oh well, not there yet. + let shifted_rscope = &ShiftedRscope::new(rscope); + + let (substs, assoc_bindings) = + create_substs_for_ast_trait_ref(this, + shifted_rscope, + span, + param_mode, + trait_def_id, + self_ty, + trait_segment); + let poly_trait_ref = ty::Binder(Rc::new(ty::TraitRef::new(trait_def_id, substs))); + + { + let converted_bindings = + assoc_bindings + .iter() + .filter_map(|binding| { + // specify type to assert that error was already reported in Err case: + let predicate: Result<_, ErrorReported> = + ast_type_binding_to_poly_projection_predicate(this, + poly_trait_ref.clone(), + self_ty, + binding); + predicate.ok() // ok to ignore Err() because ErrorReported (see above) + }); + poly_projections.extend(converted_bindings); + } + + poly_trait_ref +} + +fn ast_path_to_mono_trait_ref<'a,'tcx>(this: &AstConv<'tcx>, + rscope: &RegionScope, + span: Span, + param_mode: PathParamMode, + trait_def_id: ast::DefId, + self_ty: Option>, + trait_segment: &ast::PathSegment) + -> Rc> { - debug!("ast_path_to_trait_ref {:?}", trait_segment); + let (substs, assoc_bindings) = + create_substs_for_ast_trait_ref(this, + rscope, + span, + param_mode, + trait_def_id, + self_ty, + trait_segment); + prohibit_projections(this.tcx(), &assoc_bindings); + Rc::new(ty::TraitRef::new(trait_def_id, substs)) +} + +fn create_substs_for_ast_trait_ref<'a,'tcx>(this: &AstConv<'tcx>, + rscope: &RegionScope, + span: Span, + param_mode: PathParamMode, + trait_def_id: ast::DefId, + self_ty: Option>, + trait_segment: &ast::PathSegment) + -> (&'tcx Substs<'tcx>, Vec>) +{ + debug!("create_substs_for_ast_trait_ref(trait_segment={:?})", + trait_segment); + let trait_def = match this.get_trait_def(span, trait_def_id) { Ok(trait_def) => trait_def, Err(ErrorReported) => { @@ -752,34 +801,16 @@ fn ast_path_to_trait_ref<'a,'tcx>( self_ty, types, regions); - let substs = this.tcx().mk_substs(substs); - let trait_ref = Rc::new(ty::TraitRef::new(trait_def_id, substs)); - - match projections { - None => { - prohibit_projections(this.tcx(), &assoc_bindings); - } - Some(ref mut v) => { - for binding in &assoc_bindings { - match ast_type_binding_to_projection_predicate(this, trait_ref.clone(), - self_ty, binding) { - Ok(pp) => { v.push(pp); } - Err(ErrorReported) => { } - } - } - } - } - - trait_ref + (this.tcx().mk_substs(substs), assoc_bindings) } -fn ast_type_binding_to_projection_predicate<'tcx>( +fn ast_type_binding_to_poly_projection_predicate<'tcx>( this: &AstConv<'tcx>, - mut trait_ref: Rc>, + mut trait_ref: ty::PolyTraitRef<'tcx>, self_ty: Option>, binding: &ConvertedBinding<'tcx>) - -> Result, ErrorReported> + -> Result, ErrorReported> { let tcx = this.tcx(); @@ -800,14 +831,14 @@ fn ast_type_binding_to_projection_predicate<'tcx>( // We want to produce `>::T == foo`. // Simple case: X is defined in the current trait. - if this.trait_defines_associated_type_named(trait_ref.def_id, binding.item_name) { - return Ok(ty::ProjectionPredicate { - projection_ty: ty::ProjectionTy { - trait_ref: trait_ref, + if this.trait_defines_associated_type_named(trait_ref.def_id(), binding.item_name) { + return Ok(ty::Binder(ty::ProjectionPredicate { // <-------------------+ + projection_ty: ty::ProjectionTy { // | + trait_ref: trait_ref.skip_binder().clone(), // Binder moved here --+ item_name: binding.item_name, }, ty: binding.ty, - }); + })); } // Otherwise, we have to walk through the supertraits to find @@ -820,17 +851,17 @@ fn ast_type_binding_to_projection_predicate<'tcx>( let dummy_self_ty = ty::mk_infer(tcx, ty::FreshTy(0)); if self_ty.is_none() { // if converting for an object type - let mut dummy_substs = trait_ref.substs.clone(); - assert!(dummy_substs.self_ty().is_none()); - dummy_substs.types.push(SelfSpace, dummy_self_ty); - trait_ref = Rc::new(ty::TraitRef::new(trait_ref.def_id, - tcx.mk_substs(dummy_substs))); + let mut dummy_substs = trait_ref.skip_binder().substs.clone(); // binder moved here -+ + assert!(dummy_substs.self_ty().is_none()); // | + dummy_substs.types.push(SelfSpace, dummy_self_ty); // | + trait_ref = ty::Binder(Rc::new(ty::TraitRef::new(trait_ref.def_id(), // <------------+ + tcx.mk_substs(dummy_substs)))); } - try!(this.ensure_super_predicates(binding.span, trait_ref.def_id)); + try!(this.ensure_super_predicates(binding.span, trait_ref.def_id())); let mut candidates: Vec = - traits::supertraits(tcx, trait_ref.to_poly_trait_ref()) + traits::supertraits(tcx, trait_ref.clone()) .filter(|r| this.trait_defines_associated_type_named(r.def_id(), binding.item_name)) .collect(); @@ -865,21 +896,13 @@ fn ast_type_binding_to_projection_predicate<'tcx>( } }; - if ty::binds_late_bound_regions(tcx, &candidate) { - span_err!(tcx.sess, binding.span, E0219, - "associated type `{}` defined in higher-ranked supertrait `{}`", - token::get_name(binding.item_name), - candidate.user_string(tcx)); - return Err(ErrorReported); - } - - Ok(ty::ProjectionPredicate { - projection_ty: ty::ProjectionTy { - trait_ref: candidate.0, + Ok(ty::Binder(ty::ProjectionPredicate { // <-------------------------+ + projection_ty: ty::ProjectionTy { // | + trait_ref: candidate.skip_binder().clone(), // binder is moved up here --+ item_name: binding.item_name, }, ty: binding.ty, - }) + })) } fn ast_path_to_ty<'tcx>( @@ -1134,14 +1157,14 @@ fn qpath_to_ty<'tcx>(this: &AstConv<'tcx>, debug!("qpath_to_ty: self_type={}", self_ty.repr(tcx)); - let trait_ref = ast_path_to_trait_ref(this, - rscope, - span, - param_mode, - trait_def_id, - Some(self_ty), - trait_segment, - None); + let trait_ref = + ast_path_to_mono_trait_ref(this, + rscope, + span, + param_mode, + trait_def_id, + Some(self_ty), + trait_segment); debug!("qpath_to_ty: trait_ref={}", trait_ref.repr(tcx)); diff --git a/src/librustc_typeck/check/closure.rs b/src/librustc_typeck/check/closure.rs index 32f91a175f3c3..d2a06fcf99091 100644 --- a/src/librustc_typeck/check/closure.rs +++ b/src/librustc_typeck/check/closure.rs @@ -16,6 +16,7 @@ use astconv; use middle::region; use middle::subst; use middle::ty::{self, ToPolyTraitRef, Ty}; +use std::cmp; use syntax::abi; use syntax::ast; use syntax::ast_util; @@ -109,15 +110,11 @@ fn deduce_expectations_from_expected_type<'a,'tcx>( ty::ty_trait(ref object_type) => { let proj_bounds = object_type.projection_bounds_with_self_ty(fcx.tcx(), fcx.tcx().types.err); - 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) - } + let sig = proj_bounds.iter() + .filter_map(|pb| deduce_sig_from_projection(fcx, pb)) + .next(); + let kind = fcx.tcx().lang_items.fn_trait_kind(object_type.principal_def_id()); + (sig, kind) } ty::ty_infer(ty::TyVar(vid)) => { deduce_expectations_from_obligations(fcx, vid) @@ -136,7 +133,7 @@ fn deduce_expectations_from_obligations<'a,'tcx>( let fulfillment_cx = fcx.inh.fulfillment_cx.borrow(); // Here `expected_ty` is known to be a type inference variable. - let expected_sig_and_kind = + let expected_sig = fulfillment_cx .pending_obligations() .iter() @@ -150,7 +147,7 @@ fn deduce_expectations_from_obligations<'a,'tcx>( 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)) + .and_then(|_| deduce_sig_from_projection(fcx, proj_predicate)) } _ => { None @@ -159,14 +156,10 @@ fn deduce_expectations_from_obligations<'a,'tcx>( }) .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`. + // like `F : Fn`. Note that due to subtyping we could encounter + // many viable options, so pick the most restrictive. let expected_kind = fulfillment_cx .pending_obligations() @@ -183,54 +176,61 @@ fn deduce_expectations_from_obligations<'a,'tcx>( .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(); + .fold(None, pick_most_restrictive_closure_kind); + + (expected_sig, expected_kind) +} - (None, expected_kind) +fn pick_most_restrictive_closure_kind(best: Option, + cur: ty::ClosureKind) + -> Option +{ + match best { + None => Some(cur), + Some(best) => Some(cmp::min(best, cur)) + } } /// Given a projection like "::Result == Y", we can deduce /// everything we need to know about a closure. -fn deduce_expectations_from_projection<'a,'tcx>( +fn deduce_sig_from_projection<'a,'tcx>( fcx: &FnCtxt<'a,'tcx>, projection: &ty::PolyProjectionPredicate<'tcx>) - -> Option<(ty::FnSig<'tcx>, ty::ClosureKind)> + -> Option> { let tcx = fcx.tcx(); - debug!("deduce_expectations_from_projection({})", + debug!("deduce_sig_from_projection({})", projection.repr(tcx)); let trait_ref = projection.to_poly_trait_ref(); - let kind = match tcx.lang_items.fn_trait_kind(trait_ref.def_id()) { - Some(k) => k, - None => { return None; } - }; - - debug!("found object type {:?}", kind); + if tcx.lang_items.fn_trait_kind(trait_ref.def_id()).is_none() { + return None; + } let arg_param_ty = *trait_ref.substs().types.get(subst::TypeSpace, 0); let arg_param_ty = fcx.infcx().resolve_type_vars_if_possible(&arg_param_ty); - debug!("arg_param_ty {}", arg_param_ty.repr(tcx)); + debug!("deduce_sig_from_projection: arg_param_ty {}", arg_param_ty.repr(tcx)); let input_tys = match arg_param_ty.sty { ty::ty_tup(ref tys) => { (*tys).clone() } _ => { return None; } }; - debug!("input_tys {}", input_tys.repr(tcx)); + debug!("deduce_sig_from_projection: input_tys {}", input_tys.repr(tcx)); let ret_param_ty = projection.0.ty; let ret_param_ty = fcx.infcx().resolve_type_vars_if_possible(&ret_param_ty); - debug!("ret_param_ty {}", ret_param_ty.repr(tcx)); + debug!("deduce_sig_from_projection: ret_param_ty {}", ret_param_ty.repr(tcx)); let fn_sig = ty::FnSig { inputs: input_tys, output: ty::FnConverging(ret_param_ty), variadic: false }; - debug!("fn_sig {}", fn_sig.repr(tcx)); + debug!("deduce_sig_from_projection: fn_sig {}", fn_sig.repr(tcx)); - return Some((fn_sig, kind)); + Some(fn_sig) } fn self_type_matches_expected_vid<'a,'tcx>( diff --git a/src/librustc_typeck/check/method/probe.rs b/src/librustc_typeck/check/method/probe.rs index bc581a6af4154..b95e0ce8cb3c5 100644 --- a/src/librustc_typeck/check/method/probe.rs +++ b/src/librustc_typeck/check/method/probe.rs @@ -725,7 +725,7 @@ impl<'a,'tcx> ProbeContext<'a,'tcx> { }; // this closure doesn't implement the right kind of `Fn` trait - if closure_kind != kind { + if !closure_kind.extends(kind) { continue; } diff --git a/src/librustc_typeck/collect.rs b/src/librustc_typeck/collect.rs index 97cc3ac7c48a7..8744df0e20249 100644 --- a/src/librustc_typeck/collect.rs +++ b/src/librustc_typeck/collect.rs @@ -784,14 +784,15 @@ fn convert_item(ccx: &CrateCtxt, it: &ast::Item) { &enum_definition.variants); }, ast::ItemDefaultImpl(_, ref ast_trait_ref) => { - let trait_ref = astconv::instantiate_trait_ref(&ccx.icx(&()), - &ExplicitRscope, - ast_trait_ref, - Some(it.id), - None, - None); + let trait_ref = + astconv::instantiate_mono_trait_ref(&ccx.icx(&()), + &ExplicitRscope, + ast_trait_ref, + None); ty::record_trait_has_default_impl(tcx, trait_ref.def_id); + + tcx.impl_trait_refs.borrow_mut().insert(it.id, trait_ref); } ast::ItemImpl(_, _, ref generics, @@ -890,13 +891,14 @@ fn convert_item(ccx: &CrateCtxt, it: &ast::Item) { } } - if let Some(ref trait_ref) = *opt_trait_ref { - astconv::instantiate_trait_ref(&ccx.icx(&ty_predicates), - &ExplicitRscope, - trait_ref, - Some(it.id), - Some(selfty), - None); + if let Some(ref ast_trait_ref) = *opt_trait_ref { + let trait_ref = + astconv::instantiate_mono_trait_ref(&ccx.icx(&ty_predicates), + &ExplicitRscope, + ast_trait_ref, + Some(selfty)); + + tcx.impl_trait_refs.borrow_mut().insert(it.id, trait_ref); } enforce_impl_ty_params_are_constrained(tcx, diff --git a/src/test/compile-fail/borrowck-overloaded-call.rs b/src/test/compile-fail/borrowck-overloaded-call.rs index 673c025e86345..93c37524bf565 100644 --- a/src/test/compile-fail/borrowck-overloaded-call.rs +++ b/src/test/compile-fail/borrowck-overloaded-call.rs @@ -18,26 +18,36 @@ struct SFn { } impl Fn<(isize,)> for SFn { - type Output = isize; - extern "rust-call" fn call(&self, (z,): (isize,)) -> isize { self.x * self.y * z } } +impl FnMut<(isize,)> for SFn { + extern "rust-call" fn call_mut(&mut self, args: (isize,)) -> isize { self.call(args) } +} + +impl FnOnce<(isize,)> for SFn { + type Output = isize; + extern "rust-call" fn call_once(self, args: (isize,)) -> isize { self.call(args) } +} + struct SFnMut { x: isize, y: isize, } impl FnMut<(isize,)> for SFnMut { - type Output = isize; - extern "rust-call" fn call_mut(&mut self, (z,): (isize,)) -> isize { self.x * self.y * z } } +impl FnOnce<(isize,)> for SFnMut { + type Output = isize; + extern "rust-call" fn call_once(mut self, args: (isize,)) -> isize { self.call_mut(args) } +} + struct SFnOnce { x: String, } diff --git a/src/test/compile-fail/coerce-unsafe-to-closure.rs b/src/test/compile-fail/coerce-unsafe-to-closure.rs index fe7635f065cdc..27b4a04054f07 100644 --- a/src/test/compile-fail/coerce-unsafe-to-closure.rs +++ b/src/test/compile-fail/coerce-unsafe-to-closure.rs @@ -10,5 +10,6 @@ fn main() { let x: Option<&[u8]> = Some("foo").map(std::mem::transmute); - //~^ ERROR: is not implemented for the type + //~^ ERROR E0277 + //~| ERROR E0277 } diff --git a/src/test/compile-fail/extern-wrong-value-type.rs b/src/test/compile-fail/extern-wrong-value-type.rs index db3373ea02772..d1abed9b2627c 100644 --- a/src/test/compile-fail/extern-wrong-value-type.rs +++ b/src/test/compile-fail/extern-wrong-value-type.rs @@ -18,5 +18,5 @@ fn main() { let _x: extern "C" fn() = f; // OK is_fn(f); //~^ ERROR the trait `core::ops::Fn<()>` is not implemented for the type `extern "C" fn() - //~| ERROR the trait `core::ops::Fn<()>` is not implemented for the type `extern "C" fn() + //~| ERROR the trait `core::ops::FnOnce<()>` is not implemented for the type `extern "C" fn() } diff --git a/src/test/compile-fail/feature-gate-unboxed-closures-manual-impls.rs b/src/test/compile-fail/feature-gate-unboxed-closures-manual-impls.rs index e5e5ddadafccf..d86c5d211dc5f 100644 --- a/src/test/compile-fail/feature-gate-unboxed-closures-manual-impls.rs +++ b/src/test/compile-fail/feature-gate-unboxed-closures-manual-impls.rs @@ -18,28 +18,21 @@ struct Foo; impl Fn<()> for Foo { //~^ ERROR angle-bracket notation is not stable when used with the `Fn` family of traits - type Output = (); - - extern "rust-call" fn call(&self, args: ()) -> () {} + extern "rust-call" fn call(self, args: ()) -> () {} } struct Foo1; -impl Fn() for Foo1 { +impl FnOnce() for Foo1 { //~^ ERROR associated type bindings are not allowed here - - extern "rust-call" fn call(&self, args: ()) -> () {} + extern "rust-call" fn call_once(self, args: ()) -> () {} } struct Bar; impl FnMut<()> for Bar { //~^ ERROR angle-bracket notation is not stable when used with the `Fn` family of traits - type Output = (); - extern "rust-call" fn call_mut(&self, args: ()) -> () {} } struct Baz; impl FnOnce<()> for Baz { //~^ ERROR angle-bracket notation is not stable when used with the `Fn` family of traits - type Output = (); - extern "rust-call" fn call_once(&self, args: ()) -> () {} } diff --git a/src/test/compile-fail/fn-trait-formatting.rs b/src/test/compile-fail/fn-trait-formatting.rs index 35c551931366d..6433255bd4d2f 100644 --- a/src/test/compile-fail/fn-trait-formatting.rs +++ b/src/test/compile-fail/fn-trait-formatting.rs @@ -35,5 +35,5 @@ fn main() { needs_fn(1); //~^ ERROR `core::ops::Fn<(isize,)>` - //~| ERROR `core::ops::Fn<(isize,)>` + //~| ERROR `core::ops::FnOnce<(isize,)>` } diff --git a/src/test/compile-fail/fn-variance-1.rs b/src/test/compile-fail/fn-variance-1.rs index 838e65e1d0574..8e1e88a92e452 100644 --- a/src/test/compile-fail/fn-variance-1.rs +++ b/src/test/compile-fail/fn-variance-1.rs @@ -17,9 +17,13 @@ fn apply(t: T, f: F) where F: FnOnce(T) { } fn main() { - apply(&3, takes_mut); //~ ERROR (values differ in mutability) apply(&3, takes_imm); + apply(&3, takes_mut); + //~^ ERROR (values differ in mutability) + //~| ERROR (values differ in mutability) apply(&mut 3, takes_mut); - apply(&mut 3, takes_imm); //~ ERROR (values differ in mutability) + apply(&mut 3, takes_imm); + //~^ ERROR (values differ in mutability) + //~| ERROR (values differ in mutability) } diff --git a/src/test/compile-fail/issue-15094.rs b/src/test/compile-fail/issue-15094.rs index 8f79022405ebe..3853434e128eb 100644 --- a/src/test/compile-fail/issue-15094.rs +++ b/src/test/compile-fail/issue-15094.rs @@ -16,11 +16,10 @@ struct Debuger { x: T } -impl ops::Fn<(),> for Debuger { +impl ops::FnOnce<(),> for Debuger { type Output = (); - - fn call(&self, _args: ()) { -//~^ ERROR `call` has an incompatible type for trait: expected "rust-call" fn, found "Rust" fn + fn call_once(self, _args: ()) { +//~^ ERROR `call_once` has an incompatible type for trait: expected "rust-call" fn, found "Rust" fn println!("{:?}", self.x); } } diff --git a/src/test/compile-fail/issue-20225.rs b/src/test/compile-fail/issue-20225.rs index e4bedbbb7e1e5..fe427e02451af 100644 --- a/src/test/compile-fail/issue-20225.rs +++ b/src/test/compile-fail/issue-20225.rs @@ -13,9 +13,19 @@ struct Foo; impl<'a, T> Fn<(&'a T,)> for Foo { + extern "rust-call" fn call(&self, (_,): (T,)) {} + //~^ ERROR: has an incompatible type for trait: expected &-ptr +} + +impl<'a, T> FnMut<(&'a T,)> for Foo { + extern "rust-call" fn call_mut(&mut self, (_,): (T,)) {} + //~^ ERROR: has an incompatible type for trait: expected &-ptr +} + +impl<'a, T> FnOnce<(&'a T,)> for Foo { type Output = (); - extern "rust-call" fn call(&self, (_,): (T,)) {} + extern "rust-call" fn call_once(self, (_,): (T,)) {} //~^ ERROR: has an incompatible type for trait: expected &-ptr } diff --git a/src/test/compile-fail/overloaded-calls-bad.rs b/src/test/compile-fail/overloaded-calls-bad.rs index 61752e62abdef..77ac97bc8b899 100644 --- a/src/test/compile-fail/overloaded-calls-bad.rs +++ b/src/test/compile-fail/overloaded-calls-bad.rs @@ -18,13 +18,18 @@ struct S { } impl FnMut<(isize,)> for S { - type Output = isize; - extern "rust-call" fn call_mut(&mut self, (z,): (isize,)) -> isize { self.x * self.y * z } } +impl FnOnce<(isize,)> for S { + type Output = isize; + extern "rust-call" fn call_once(mut self, (z,): (isize,)) -> isize { + 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 c4019fa22097a..ea47d67641209 100644 --- a/src/test/compile-fail/overloaded-calls-nontuple.rs +++ b/src/test/compile-fail/overloaded-calls-nontuple.rs @@ -18,12 +18,16 @@ struct S { } impl FnMut for S { - type Output = isize; extern "rust-call" fn call_mut(&mut self, z: isize) -> isize { self.x + self.y + z } } +impl FnOnce for S { + type Output = isize; + extern "rust-call" fn call_once(mut self, z: isize) -> isize { self.call_mut(z) } +} + fn main() { let mut s = S { x: 1, diff --git a/src/test/compile-fail/unboxed-closures-fnmut-as-fn.rs b/src/test/compile-fail/unboxed-closures-fnmut-as-fn.rs index 92e6affa4c202..93498ac7f8351 100644 --- a/src/test/compile-fail/unboxed-closures-fnmut-as-fn.rs +++ b/src/test/compile-fail/unboxed-closures-fnmut-as-fn.rs @@ -19,13 +19,17 @@ use std::ops::{Fn,FnMut,FnOnce}; struct S; impl FnMut<(isize,)> for S { - type Output = isize; - extern "rust-call" fn call_mut(&mut self, (x,): (isize,)) -> isize { x * x } } +impl FnOnce<(isize,)> for S { + type Output = isize; + + extern "rust-call" fn call_once(mut self, args: (isize,)) -> isize { self.call_mut(args) } +} + fn call_itisize>(f: &F, x: isize) -> isize { f.call((x,)) } @@ -33,5 +37,4 @@ fn call_itisize>(f: &F, x: isize) -> isize { fn main() { let x = call_it(&S, 22); //~^ ERROR not implemented - //~| ERROR not implemented } diff --git a/src/test/compile-fail/unboxed-closures-recursive-fn-using-fn-mut.rs b/src/test/compile-fail/unboxed-closures-recursive-fn-using-fn-mut.rs index 713b64b1349fc..2dcd7a97d8977 100644 --- a/src/test/compile-fail/unboxed-closures-recursive-fn-using-fn-mut.rs +++ b/src/test/compile-fail/unboxed-closures-recursive-fn-using-fn-mut.rs @@ -28,14 +28,19 @@ impl YCombinator { } impl R, A) -> R> FnMut<(A,)> for YCombinator { - type Output = R; - extern "rust-call" fn call_mut(&mut self, (arg,): (A,)) -> R { (self.func)(self, arg) //~^ ERROR cannot borrow `*self` as mutable more than once at a time } } +impl R, A) -> R> FnOnce<(A,)> for YCombinator { + type Output = R; + extern "rust-call" fn call_once(mut self, args: (A,)) -> R { + self.call_mut(args) + } +} + fn main() { let mut counter = 0; let factorial = |recur: &mut FnMut(u32) -> u32, arg: u32| -> u32 { diff --git a/src/test/compile-fail/unboxed-closures-unsafe-extern-fn.rs b/src/test/compile-fail/unboxed-closures-unsafe-extern-fn.rs index 23f7ee2b0101d..dc7c70ba649d8 100644 --- a/src/test/compile-fail/unboxed-closures-unsafe-extern-fn.rs +++ b/src/test/compile-fail/unboxed-closures-unsafe-extern-fn.rs @@ -27,11 +27,15 @@ fn a() { } fn b() { - let y = call_it_mut(&mut square, 22); //~ ERROR not implemented + let y = call_it_mut(&mut square, 22); + //~^ ERROR not implemented + //~| ERROR not implemented } fn c() { - let z = call_it_once(square, 22); //~ ERROR not implemented + let z = call_it_once(square, 22); + //~^ ERROR not implemented + //~| ERROR not implemented } fn main() { } diff --git a/src/test/compile-fail/unboxed-closures-wrong-abi.rs b/src/test/compile-fail/unboxed-closures-wrong-abi.rs index 40655f8a3cec4..cdcb435b65a6a 100644 --- a/src/test/compile-fail/unboxed-closures-wrong-abi.rs +++ b/src/test/compile-fail/unboxed-closures-wrong-abi.rs @@ -27,11 +27,15 @@ fn a() { } fn b() { - let y = call_it_mut(&mut square, 22); //~ ERROR not implemented + let y = call_it_mut(&mut square, 22); + //~^ ERROR not implemented + //~| ERROR not implemented } fn c() { - let z = call_it_once(square, 22); //~ ERROR not implemented + let z = call_it_once(square, 22); + //~^ ERROR not implemented + //~| ERROR not implemented } fn main() { } diff --git a/src/test/compile-fail/unboxed-closures-wrong-arg-type-extern-fn.rs b/src/test/compile-fail/unboxed-closures-wrong-arg-type-extern-fn.rs index ebcbdbbc006df..150bf36dcc286 100644 --- a/src/test/compile-fail/unboxed-closures-wrong-arg-type-extern-fn.rs +++ b/src/test/compile-fail/unboxed-closures-wrong-arg-type-extern-fn.rs @@ -28,11 +28,15 @@ fn a() { } fn b() { - let y = call_it_mut(&mut square, 22); //~ ERROR not implemented + let y = call_it_mut(&mut square, 22); + //~^ ERROR not implemented + //~| ERROR not implemented } fn c() { - let z = call_it_once(square, 22); //~ ERROR not implemented + let z = call_it_once(square, 22); + //~^ ERROR not implemented + //~| ERROR not implemented } fn main() { } diff --git a/src/test/run-pass/issue-13655.rs b/src/test/run-pass/issue-13655.rs index 81a8b29461c78..6c0e5edae72a6 100644 --- a/src/test/run-pass/issue-13655.rs +++ b/src/test/run-pass/issue-13655.rs @@ -14,7 +14,6 @@ use std::ops::Fn; struct Foo(T); impl Fn<()> for Foo { - type Output = T; extern "rust-call" fn call(&self, _: ()) -> T { match *self { Foo(t) => t @@ -22,6 +21,20 @@ impl Fn<()> for Foo { } } +impl FnMut<()> for Foo { + extern "rust-call" fn call_mut(&mut self, _: ()) -> T { + self.call(()) + } +} + +impl FnOnce<()> for Foo { + type Output = T; + + extern "rust-call" fn call_once(self, _: ()) -> T { + self.call(()) + } +} + fn main() { let t: u8 = 1; println!("{}", Foo(t)()); diff --git a/src/test/run-pass/issue-14958.rs b/src/test/run-pass/issue-14958.rs index 6335f79be6c7a..ab5a2f03ece8c 100644 --- a/src/test/run-pass/issue-14958.rs +++ b/src/test/run-pass/issue-14958.rs @@ -15,10 +15,18 @@ trait Foo { fn dummy(&self) { }} struct Bar; impl<'a> std::ops::Fn<(&'a (Foo+'a),)> for Bar { - type Output = (); extern "rust-call" fn call(&self, _: (&'a Foo,)) {} } +impl<'a> std::ops::FnMut<(&'a (Foo+'a),)> for Bar { + extern "rust-call" fn call_mut(&mut self, a: (&'a Foo,)) { self.call(a) } +} + +impl<'a> std::ops::FnOnce<(&'a (Foo+'a),)> for Bar { + type Output = (); + extern "rust-call" fn call_once(self, a: (&'a Foo,)) { self.call(a) } +} + struct Baz; impl Foo for Baz {} diff --git a/src/test/run-pass/issue-14959.rs b/src/test/run-pass/issue-14959.rs index 53d0f7dae0577..91ad7e03623fd 100644 --- a/src/test/run-pass/issue-14959.rs +++ b/src/test/run-pass/issue-14959.rs @@ -34,9 +34,21 @@ impl Alloy { } impl<'b> Fn<(&'b mut (Response+'b),)> for SendFile { + extern "rust-call" fn call(&self, (_res,): (&'b mut (Response+'b),)) {} +} + +impl<'b> FnMut<(&'b mut (Response+'b),)> for SendFile { + extern "rust-call" fn call_mut(&mut self, (_res,): (&'b mut (Response+'b),)) { + self.call((_res,)) + } +} + +impl<'b> FnOnce<(&'b mut (Response+'b),)> for SendFile { type Output = (); - extern "rust-call" fn call(&self, (_res,): (&'b mut (Response+'b),)) {} + extern "rust-call" fn call_once(self, (_res,): (&'b mut (Response+'b),)) { + self.call((_res,)) + } } impl Ingot for HelloWorld { diff --git a/src/test/run-pass/issue-16739.rs b/src/test/run-pass/issue-16739.rs index 389baecafd144..fda35d3e7f463 100644 --- a/src/test/run-pass/issue-16739.rs +++ b/src/test/run-pass/issue-16739.rs @@ -18,20 +18,36 @@ struct Foo { foo: u32 } impl FnMut<()> for Foo { - type Output = u32; extern "rust-call" fn call_mut(&mut self, _: ()) -> u32 { self.foo } } -impl FnMut<(u32,)> for Foo { +impl FnOnce<()> for Foo { type Output = u32; + extern "rust-call" fn call_once(mut self, _: ()) -> u32 { self.call_mut(()) } +} + +///////////////////////////////////////////////////////////////////////// + +impl FnMut<(u32,)> for Foo { extern "rust-call" fn call_mut(&mut self, (x,): (u32,)) -> u32 { self.foo + x } } -impl FnMut<(u32,u32)> for Foo { +impl FnOnce<(u32,)> for Foo { type Output = u32; + extern "rust-call" fn call_once(mut self, args: (u32,)) -> u32 { self.call_mut(args) } +} + +///////////////////////////////////////////////////////////////////////// + +impl FnMut<(u32,u32)> for Foo { extern "rust-call" fn call_mut(&mut self, (x, y): (u32, u32)) -> u32 { self.foo + x + y } } +impl FnOnce<(u32,u32)> for Foo { + type Output = u32; + extern "rust-call" fn call_once(mut self, args: (u32,u32)) -> u32 { self.call_mut(args) } +} + fn main() { let mut f = box Foo { foo: 42 } as Box u32>; assert_eq!(f.call_mut(()), 42); diff --git a/src/test/run-pass/issue-19982.rs b/src/test/run-pass/issue-19982.rs index 3082fc27a7dec..9a476f563eda7 100644 --- a/src/test/run-pass/issue-19982.rs +++ b/src/test/run-pass/issue-19982.rs @@ -14,9 +14,17 @@ struct Foo; impl<'a> Fn<(&'a (),)> for Foo { + extern "rust-call" fn call(&self, (_,): (&(),)) {} +} + +impl<'a> FnMut<(&'a (),)> for Foo { + extern "rust-call" fn call_mut(&mut self, (_,): (&(),)) {} +} + +impl<'a> FnOnce<(&'a (),)> for Foo { type Output = (); - extern "rust-call" fn call(&self, (_,): (&(),)) {} + extern "rust-call" fn call_once(self, (_,): (&(),)) {} } fn main() {} diff --git a/src/test/run-pass/overloaded-calls-param-vtables.rs b/src/test/run-pass/overloaded-calls-param-vtables.rs index 0ac9c97532bff..081e1417d5f45 100644 --- a/src/test/run-pass/overloaded-calls-param-vtables.rs +++ b/src/test/run-pass/overloaded-calls-param-vtables.rs @@ -19,13 +19,20 @@ use std::ops::Add; struct G(PhantomData); impl<'a, A: Add> Fn<(A,)> for G { - type Output = i32; - extern "rust-call" fn call(&self, (arg,): (A,)) -> i32 { arg.add(1) } } +impl<'a, A: Add> FnMut<(A,)> for G { + extern "rust-call" fn call_mut(&mut self, args: (A,)) -> i32 { self.call(args) } +} + +impl<'a, A: Add> FnOnce<(A,)> for G { + type Output = i32; + extern "rust-call" fn call_once(self, args: (A,)) -> i32 { self.call(args) } +} + fn main() { // ICE trigger (G(PhantomData))(1); diff --git a/src/test/run-pass/overloaded-calls-simple.rs b/src/test/run-pass/overloaded-calls-simple.rs index d18a91c545280..b20c80dc4c944 100644 --- a/src/test/run-pass/overloaded-calls-simple.rs +++ b/src/test/run-pass/overloaded-calls-simple.rs @@ -18,24 +18,38 @@ struct S1 { } impl FnMut<(i32,)> for S1 { - type Output = i32; extern "rust-call" fn call_mut(&mut self, (z,): (i32,)) -> i32 { self.x * self.y * z } } +impl FnOnce<(i32,)> for S1 { + type Output = i32; + extern "rust-call" fn call_once(mut self, args: (i32,)) -> i32 { + self.call_mut(args) + } +} + struct S2 { x: i32, y: i32, } impl Fn<(i32,)> for S2 { - type Output = i32; extern "rust-call" fn call(&self, (z,): (i32,)) -> i32 { self.x * self.y * z } } +impl FnMut<(i32,)> for S2 { + extern "rust-call" fn call_mut(&mut self, args: (i32,)) -> i32 { self.call(args) } +} + +impl FnOnce<(i32,)> for S2 { + type Output = i32; + extern "rust-call" fn call_once(self, args: (i32,)) -> i32 { self.call(args) } +} + struct S3 { x: i32, y: i32, diff --git a/src/test/run-pass/overloaded-calls-zero-args.rs b/src/test/run-pass/overloaded-calls-zero-args.rs index 78e84b9d55bca..245ff6df6145f 100644 --- a/src/test/run-pass/overloaded-calls-zero-args.rs +++ b/src/test/run-pass/overloaded-calls-zero-args.rs @@ -18,12 +18,16 @@ struct S { } impl FnMut<()> for S { - type Output = i32; extern "rust-call" fn call_mut(&mut self, (): ()) -> i32 { self.x * self.y } } +impl FnOnce<()> for S { + type Output = i32; + extern "rust-call" fn call_once(mut self, args: ()) -> i32 { self.call_mut(args) } +} + fn main() { let mut s = S { x: 3, diff --git a/src/test/run-pass/unboxed-closures-fn-as-fnmut-and-fnonce.rs b/src/test/run-pass/unboxed-closures-fn-as-fnmut-and-fnonce.rs index 0aab5be2877e1..aad190d0236c9 100644 --- a/src/test/run-pass/unboxed-closures-fn-as-fnmut-and-fnonce.rs +++ b/src/test/run-pass/unboxed-closures-fn-as-fnmut-and-fnonce.rs @@ -19,12 +19,20 @@ use std::ops::{Fn,FnMut,FnOnce}; struct S; impl Fn<(i32,)> for S { - type Output = i32; extern "rust-call" fn call(&self, (x,): (i32,)) -> i32 { x * x } } +impl FnMut<(i32,)> for S { + extern "rust-call" fn call_mut(&mut self, args: (i32,)) -> i32 { self.call(args) } +} + +impl FnOnce<(i32,)> for S { + type Output = i32; + extern "rust-call" fn call_once(self, args: (i32,)) -> i32 { self.call(args) } +} + fn call_iti32>(f: &F, x: i32) -> i32 { f(x) } diff --git a/src/test/run-pass/unboxed-closures-fnmut-as-fnonce.rs b/src/test/run-pass/unboxed-closures-fnmut-as-fnonce.rs index a8bb091893271..94be640636718 100644 --- a/src/test/run-pass/unboxed-closures-fnmut-as-fnonce.rs +++ b/src/test/run-pass/unboxed-closures-fnmut-as-fnonce.rs @@ -19,13 +19,17 @@ use std::ops::{FnMut,FnOnce}; struct S; impl FnMut<(i32,)> for S { - type Output = i32; - extern "rust-call" fn call_mut(&mut self, (x,): (i32,)) -> i32 { x * x } } +impl FnOnce<(i32,)> for S { + type Output = i32; + + extern "rust-call" fn call_once(mut self, args: (i32,)) -> i32 { self.call_mut(args) } +} + fn call_it_muti32>(f: &mut F, x: i32) -> i32 { f(x) } diff --git a/src/test/run-pass/unboxed-closures-infer-recursive-fn.rs b/src/test/run-pass/unboxed-closures-infer-recursive-fn.rs index 2d1ba7f39b27b..a2ab06049d63d 100644 --- a/src/test/run-pass/unboxed-closures-infer-recursive-fn.rs +++ b/src/test/run-pass/unboxed-closures-infer-recursive-fn.rs @@ -30,13 +30,20 @@ impl YCombinator { } impl R, A) -> R> Fn<(A,)> for YCombinator { - type Output = R; - extern "rust-call" fn call(&self, (arg,): (A,)) -> R { (self.func)(self, arg) } } +impl R, A) -> R> FnMut<(A,)> for YCombinator { + extern "rust-call" fn call_mut(&mut self, args: (A,)) -> R { self.call(args) } +} + +impl R, A) -> R> FnOnce<(A,)> for YCombinator { + type Output = R; + extern "rust-call" fn call_once(self, args: (A,)) -> R { self.call(args) } +} + fn main() { let factorial = |recur: &Fn(u32) -> u32, arg: u32| -> u32 { if arg == 0 {1} else {arg * recur(arg-1)} diff --git a/src/test/run-pass/unboxed-closures-manual-impl.rs b/src/test/run-pass/unboxed-closures-manual-impl.rs index f1b79a1829eab..439ec4af9ebfc 100644 --- a/src/test/run-pass/unboxed-closures-manual-impl.rs +++ b/src/test/run-pass/unboxed-closures-manual-impl.rs @@ -15,13 +15,17 @@ use std::ops::FnMut; struct S; impl FnMut<(i32,)> for S { - type Output = i32; - extern "rust-call" fn call_mut(&mut self, (x,): (i32,)) -> i32 { x * x } } +impl FnOnce<(i32,)> for S { + type Output = i32; + + extern "rust-call" fn call_once(mut self, args: (i32,)) -> i32 { self.call_mut(args) } +} + fn call_iti32>(mut f: F, x: i32) -> i32 { f(x) + 3 }