提交 39221a01 编写于 作者: N Niko Matsakis

Implement the `Fn` trait for bare fn pointers in the compiler rather than...

Implement the `Fn` trait for bare fn pointers in the compiler rather than doing it using hard-coded impls. This means that it works also for more complex fn types involving bound regions. Fixes #19126.
上级 207a5084
......@@ -833,48 +833,52 @@ extern "rust-call" fn call_once(mut self, args: A) -> R {
}
}
impl<Result> Fn<(),Result> for extern "Rust" fn() -> Result {
#[allow(non_snake_case)]
extern "rust-call" fn call(&self, _args: ()) -> Result {
(*self)()
#[cfg(stage0)]
mod fn_impls {
use super::Fn;
impl<Result> Fn<(),Result> for extern "Rust" fn() -> Result {
#[allow(non_snake_case)]
extern "rust-call" fn call(&self, _args: ()) -> Result {
(*self)()
}
}
}
impl<Result,A0> Fn<(A0,),Result> for extern "Rust" fn(A0) -> Result {
#[allow(non_snake_case)]
extern "rust-call" fn call(&self, args: (A0,)) -> Result {
let (a0,) = args;
(*self)(a0)
impl<Result,A0> Fn<(A0,),Result> for extern "Rust" fn(A0) -> Result {
#[allow(non_snake_case)]
extern "rust-call" fn call(&self, args: (A0,)) -> Result {
let (a0,) = args;
(*self)(a0)
}
}
}
macro_rules! def_fn(
($($args:ident)*) => (
impl<Result$(,$args)*>
Fn<($($args,)*),Result>
for extern "Rust" fn($($args: $args,)*) -> Result {
#[allow(non_snake_case)]
extern "rust-call" fn call(&self, args: ($($args,)*)) -> Result {
let ($($args,)*) = args;
(*self)($($args,)*)
macro_rules! def_fn(
($($args:ident)*) => (
impl<Result$(,$args)*>
Fn<($($args,)*),Result>
for extern "Rust" fn($($args: $args,)*) -> Result {
#[allow(non_snake_case)]
extern "rust-call" fn call(&self, args: ($($args,)*)) -> Result {
let ($($args,)*) = args;
(*self)($($args,)*)
}
}
}
)
)
)
def_fn!(A0 A1)
def_fn!(A0 A1 A2)
def_fn!(A0 A1 A2 A3)
def_fn!(A0 A1 A2 A3 A4)
def_fn!(A0 A1 A2 A3 A4 A5)
def_fn!(A0 A1 A2 A3 A4 A5 A6)
def_fn!(A0 A1 A2 A3 A4 A5 A6 A7)
def_fn!(A0 A1 A2 A3 A4 A5 A6 A7 A8)
def_fn!(A0 A1 A2 A3 A4 A5 A6 A7 A8 A9)
def_fn!(A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 A10)
def_fn!(A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 A10 A11)
def_fn!(A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 A10 A11 A12)
def_fn!(A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 A10 A11 A12 A13)
def_fn!(A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 A10 A11 A12 A13 A14)
def_fn!(A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 A10 A11 A12 A13 A14 A15)
def_fn!(A0 A1)
def_fn!(A0 A1 A2)
def_fn!(A0 A1 A2 A3)
def_fn!(A0 A1 A2 A3 A4)
def_fn!(A0 A1 A2 A3 A4 A5)
def_fn!(A0 A1 A2 A3 A4 A5 A6)
def_fn!(A0 A1 A2 A3 A4 A5 A6 A7)
def_fn!(A0 A1 A2 A3 A4 A5 A6 A7 A8)
def_fn!(A0 A1 A2 A3 A4 A5 A6 A7 A8 A9)
def_fn!(A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 A10)
def_fn!(A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 A10 A11)
def_fn!(A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 A10 A11 A12)
def_fn!(A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 A10 A11 A12 A13)
def_fn!(A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 A10 A11 A12 A13 A14)
def_fn!(A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 A10 A11 A12 A13 A14 A15)
}
......@@ -167,18 +167,21 @@ pub enum Vtable<'tcx, N> {
/// Vtable identifying a particular impl.
VtableImpl(VtableImplData<'tcx, N>),
/// Vtable automatically generated for an unboxed closure. The def
/// ID is the ID of the closure expression. This is a `VtableImpl`
/// in spirit, but the impl is generated by the compiler and does
/// not appear in the source.
VtableUnboxedClosure(ast::DefId, subst::Substs<'tcx>),
/// Successful resolution to an obligation provided by the caller
/// for some type parameter.
VtableParam(VtableParamData<'tcx>),
/// Successful resolution for a builtin trait.
VtableBuiltin(VtableBuiltinData<N>),
/// Vtable automatically generated for an unboxed closure. The def
/// ID is the ID of the closure expression. This is a `VtableImpl`
/// in spirit, but the impl is generated by the compiler and does
/// not appear in the source.
VtableUnboxedClosure(ast::DefId, subst::Substs<'tcx>),
/// Same as above, but for a fn pointer type with the given signature.
VtableFnPointer(ty::Ty<'tcx>),
}
/// Identifies a particular impl in the source, along with a set of
......@@ -322,6 +325,7 @@ impl<'tcx, N> Vtable<'tcx, N> {
pub fn iter_nested(&self) -> Items<N> {
match *self {
VtableImpl(ref i) => i.iter_nested(),
VtableFnPointer(..) => (&[]).iter(),
VtableUnboxedClosure(..) => (&[]).iter(),
VtableParam(_) => (&[]).iter(),
VtableBuiltin(ref i) => i.iter_nested(),
......@@ -331,6 +335,7 @@ pub fn iter_nested(&self) -> Items<N> {
pub fn map_nested<M>(&self, op: |&N| -> M) -> Vtable<'tcx, M> {
match *self {
VtableImpl(ref i) => VtableImpl(i.map_nested(op)),
VtableFnPointer(ref sig) => VtableFnPointer((*sig).clone()),
VtableUnboxedClosure(d, ref s) => VtableUnboxedClosure(d, s.clone()),
VtableParam(ref p) => VtableParam((*p).clone()),
VtableBuiltin(ref i) => VtableBuiltin(i.map_nested(op)),
......@@ -340,6 +345,7 @@ pub fn map_nested<M>(&self, op: |&N| -> M) -> Vtable<'tcx, M> {
pub fn map_move_nested<M>(self, op: |N| -> M) -> Vtable<'tcx, M> {
match self {
VtableImpl(i) => VtableImpl(i.map_move_nested(op)),
VtableFnPointer(sig) => VtableFnPointer(sig),
VtableUnboxedClosure(d, s) => VtableUnboxedClosure(d, s),
VtableParam(p) => VtableParam(p),
VtableBuiltin(i) => VtableBuiltin(i.map_move_nested(op)),
......
......@@ -22,7 +22,7 @@
OutputTypeParameterMismatch};
use super::{Selection};
use super::{SelectionResult};
use super::{VtableBuiltin, VtableImpl, VtableParam, VtableUnboxedClosure};
use super::{VtableBuiltin, VtableImpl, VtableParam, VtableUnboxedClosure, VtableFnPointer};
use super::{VtableImplData, VtableParamData, VtableBuiltinData};
use super::{util};
......@@ -36,7 +36,7 @@
use std::cell::RefCell;
use std::collections::hash_map::HashMap;
use std::rc::Rc;
use syntax::ast;
use syntax::{abi, ast};
use util::common::ErrorReported;
use util::ppaux::Repr;
......@@ -131,7 +131,15 @@ enum Candidate<'tcx> {
BuiltinCandidate(ty::BuiltinBound),
ParamCandidate(VtableParamData<'tcx>),
ImplCandidate(ast::DefId),
/// Implementation of a `Fn`-family trait by one of the
/// anonymous types generated for a `||` expression.
UnboxedClosureCandidate(/* closure */ ast::DefId, Substs<'tcx>),
/// Implementation of a `Fn`-family trait by one of the anonymous
/// types generated for a fn pointer type (e.g., `fn(int)->int`)
FnPointerCandidate,
ErrorCandidate,
}
......@@ -917,7 +925,8 @@ fn assemble_candidates<'o>(&mut self,
None => {
// For the time being, we ignore user-defined impls for builtin-bounds.
// (And unboxed candidates only apply to the Fn/FnMut/etc traits.)
try!(self.assemble_unboxed_candidates(obligation, &mut candidates));
try!(self.assemble_unboxed_closure_candidates(obligation, &mut candidates));
try!(self.assemble_fn_pointer_candidates(obligation, &mut candidates));
try!(self.assemble_candidates_from_impls(obligation, &mut candidates));
}
}
......@@ -968,20 +977,14 @@ fn assemble_candidates_from_caller_bounds(&mut self,
/// Note: the type parameters on an unboxed closure candidate are modeled as *output* type
/// parameters and hence do not affect whether this trait is a match or not. They will be
/// unified during the confirmation step.
fn assemble_unboxed_candidates(&mut self,
obligation: &Obligation<'tcx>,
candidates: &mut CandidateSet<'tcx>)
-> Result<(),SelectionError<'tcx>>
fn assemble_unboxed_closure_candidates(&mut self,
obligation: &Obligation<'tcx>,
candidates: &mut CandidateSet<'tcx>)
-> Result<(),SelectionError<'tcx>>
{
let tcx = self.tcx();
let kind = if Some(obligation.trait_ref.def_id) == tcx.lang_items.fn_trait() {
ty::FnUnboxedClosureKind
} else if Some(obligation.trait_ref.def_id) == tcx.lang_items.fn_mut_trait() {
ty::FnMutUnboxedClosureKind
} else if Some(obligation.trait_ref.def_id) == tcx.lang_items.fn_once_trait() {
ty::FnOnceUnboxedClosureKind
} else {
return Ok(()); // not a fn trait, ignore
let kind = match self.fn_family_trait_kind(obligation.trait_ref.def_id) {
Some(k) => k,
None => { return Ok(()); }
};
let self_ty = self.infcx.shallow_resolve(obligation.self_ty());
......@@ -1015,6 +1018,42 @@ fn assemble_unboxed_candidates(&mut self,
Ok(())
}
/// Implement one of the `Fn()` family for a fn pointer.
fn assemble_fn_pointer_candidates(&mut self,
obligation: &Obligation<'tcx>,
candidates: &mut CandidateSet<'tcx>)
-> Result<(),SelectionError<'tcx>>
{
// We provide a `Fn` impl for fn pointers (but not e.g. `FnMut`).
if Some(obligation.trait_ref.def_id) != self.tcx().lang_items.fn_trait() {
return Ok(());
}
let self_ty = self.infcx.shallow_resolve(obligation.self_ty());
match self_ty.sty {
ty::ty_infer(..) => {
candidates.ambiguous = true; // could wind up being a fn() type
}
// provide an impl, but only for suitable `fn` pointers
ty::ty_bare_fn(ty::BareFnTy {
fn_style: ast::NormalFn,
abi: abi::Rust,
sig: ty::FnSig {
inputs: _,
output: ty::FnConverging(_),
variadic: false
}
}) => {
candidates.vec.push(FnPointerCandidate);
}
_ => { }
}
Ok(())
}
/// Search for impls that might apply to `obligation`.
fn assemble_candidates_from_impls(&mut self,
obligation: &Obligation<'tcx>,
......@@ -1551,6 +1590,12 @@ fn confirm_candidate(&mut self,
try!(self.confirm_unboxed_closure_candidate(obligation, closure_def_id, &substs));
Ok(VtableUnboxedClosure(closure_def_id, substs))
}
FnPointerCandidate => {
let fn_type =
try!(self.confirm_fn_pointer_candidate(obligation));
Ok(VtableFnPointer(fn_type))
}
}
}
......@@ -1646,6 +1691,51 @@ fn vtable_impl(&mut self,
nested: impl_obligations }
}
fn confirm_fn_pointer_candidate(&mut self,
obligation: &Obligation<'tcx>)
-> Result<ty::Ty<'tcx>,SelectionError<'tcx>>
{
debug!("confirm_fn_pointer_candidate({})",
obligation.repr(self.tcx()));
let self_ty = self.infcx.shallow_resolve(obligation.self_ty());
let sig = match self_ty.sty {
ty::ty_bare_fn(ty::BareFnTy {
fn_style: ast::NormalFn,
abi: abi::Rust,
ref sig
}) => {
(*sig).clone()
}
_ => {
self.tcx().sess.span_bug(
obligation.cause.span,
format!("Fn pointer candidate for inappropriate self type: {}",
self_ty.repr(self.tcx())).as_slice());
}
};
let arguments_tuple = ty::mk_tup(self.tcx(), sig.inputs.to_vec());
let output_type = sig.output.unwrap();
let substs =
Substs::new_trait(
vec![arguments_tuple, output_type],
vec![],
vec![],
self_ty);
let trait_ref = Rc::new(ty::TraitRef {
def_id: obligation.trait_ref.def_id,
substs: substs,
});
let () =
try!(self.confirm(obligation.cause,
obligation.trait_ref.clone(),
trait_ref));
Ok(self_ty)
}
fn confirm_unboxed_closure_candidate(&mut self,
obligation: &Obligation<'tcx>,
closure_def_id: ast::DefId,
......@@ -1964,6 +2054,22 @@ fn impl_obligations(&self,
util::obligations_for_generics(self.tcx(), cause, recursion_depth,
&bounds, &impl_substs.types)
}
fn fn_family_trait_kind(&self,
trait_def_id: ast::DefId)
-> Option<ty::UnboxedClosureKind>
{
let tcx = self.tcx();
if Some(trait_def_id) == tcx.lang_items.fn_trait() {
Some(ty::FnUnboxedClosureKind)
} else if Some(trait_def_id) == tcx.lang_items.fn_mut_trait() {
Some(ty::FnMutUnboxedClosureKind)
} else if Some(trait_def_id) == tcx.lang_items.fn_once_trait() {
Some(ty::FnOnceUnboxedClosureKind)
} else {
None
}
}
}
impl<'tcx> Repr<'tcx> for Candidate<'tcx> {
......@@ -1972,7 +2078,10 @@ fn repr(&self, tcx: &ty::ctxt<'tcx>) -> String {
ErrorCandidate => format!("ErrorCandidate"),
BuiltinCandidate(b) => format!("BuiltinCandidate({})", b),
UnboxedClosureCandidate(c, ref s) => {
format!("MatchedUnboxedClosureCandidate({},{})", c, s.repr(tcx))
format!("UnboxedClosureCandidate({},{})", c, s.repr(tcx))
}
FnPointerCandidate => {
format!("FnPointerCandidate")
}
ParamCandidate(ref a) => format!("ParamCandidate({})", a.repr(tcx)),
ImplCandidate(a) => format!("ImplCandidate({})", a.repr(tcx)),
......
......@@ -302,6 +302,10 @@ fn repr(&self, tcx: &ty::ctxt<'tcx>) -> String {
d.repr(tcx),
s.repr(tcx)),
super::VtableFnPointer(ref d) =>
format!("VtableFnPointer({})",
d.repr(tcx)),
super::VtableParam(ref v) =>
format!("VtableParam({})", v.repr(tcx)),
......
......@@ -466,6 +466,9 @@ fn fold_with<F:TypeFolder<'tcx>>(&self, folder: &mut F) -> traits::Vtable<'tcx,
traits::VtableUnboxedClosure(d, ref s) => {
traits::VtableUnboxedClosure(d, s.fold_with(folder))
}
traits::VtableFnPointer(ref d) => {
traits::VtableFnPointer(d.fold_with(folder))
}
traits::VtableParam(ref p) => traits::VtableParam(p.fold_with(folder)),
traits::VtableBuiltin(ref d) => traits::VtableBuiltin(d.fold_with(folder)),
}
......
......@@ -995,9 +995,9 @@ pub fn invoke<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
}
if need_invoke(bcx) {
debug!("invoking {} at {}", llfn, bcx.llbb);
debug!("invoking {} at {}", bcx.val_to_string(llfn), bcx.llbb);
for &llarg in llargs.iter() {
debug!("arg: {}", llarg);
debug!("arg: {}", bcx.val_to_string(llarg));
}
let normal_bcx = bcx.fcx.new_temp_block("normal-return");
let landing_pad = bcx.fcx.get_landing_pad();
......@@ -1015,9 +1015,9 @@ pub fn invoke<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
Some(attributes));
return (llresult, normal_bcx);
} else {
debug!("calling {} at {}", llfn, bcx.llbb);
debug!("calling {} at {}", bcx.val_to_string(llfn), bcx.llbb);
for &llarg in llargs.iter() {
debug!("arg: {}", llarg);
debug!("arg: {}", bcx.val_to_string(llarg));
}
match call_info {
......
......@@ -242,6 +242,112 @@ fn trans_fn_ref_with_substs_to_callee<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
}
}
/// Translates an adapter that implements the `Fn` trait for a fn
/// pointer. This is basically the equivalent of something like:
///
/// ```rust
/// impl<'a> Fn(&'a int) -> &'a int for fn(&int) -> &int {
/// extern "rust-abi" fn call(&self, args: (&'a int,)) -> &'a int {
/// (*self)(args.0)
/// }
/// }
/// ```
///
/// but for the bare function type given.
pub fn trans_fn_pointer_shim<'a, 'tcx>(
ccx: &'a CrateContext<'a, 'tcx>,
bare_fn_ty: Ty<'tcx>)
-> ValueRef
{
let _icx = push_ctxt("trans_fn_pointer_shim");
let tcx = ccx.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, 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 (input_tys, output_ty) =
match bare_fn_ty.sty {
ty::ty_bare_fn(ty::BareFnTy { fn_style: ast::NormalFn,
abi: synabi::Rust,
sig: ty::FnSig { inputs: ref input_tys,
output: output_ty,
variadic: false }}) =>
{
(input_tys, output_ty)
}
_ => {
tcx.sess.bug(format!("trans_fn_pointer_shim invoked on invalid type: {}",
bare_fn_ty.repr(tcx)).as_slice());
}
};
let tuple_input_ty = ty::mk_tup(tcx, input_tys.to_vec());
let tuple_fn_ty = ty::mk_bare_fn(tcx,
ty::BareFnTy { fn_style: ast::NormalFn,
abi: synabi::RustCall,
sig: ty::FnSig {
inputs: vec![bare_fn_ty_ref,
tuple_input_ty],
output: output_ty,
variadic: false
}});
debug!("tuple_fn_ty: {}", tuple_fn_ty.repr(tcx));
//
let function_name =
link::mangle_internal_name_by_type_and_seq(ccx, bare_fn_ty,
"fn_pointer_shim");
let llfn =
decl_internal_rust_fn(ccx,
tuple_fn_ty,
function_name.as_slice());
//
let block_arena = TypedArena::new();
let empty_substs = Substs::trans_empty();
let fcx = new_fn_ctxt(ccx,
llfn,
ast::DUMMY_NODE_ID,
false,
output_ty,
&empty_substs,
None,
&block_arena);
let mut bcx = init_function(&fcx, false, output_ty);
// 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));
// the remaining arguments will be the untupled values
let llargs: Vec<_> =
input_tys.iter()
.enumerate()
.map(|(i, _)| get_param(fcx.llfn, fcx.arg_pos(i+1) as u32))
.collect();
assert!(!fcx.needs_ret_allocas);
let dest = fcx.llretslotptr.get().map(|_|
expr::SaveIn(fcx.get_ret_slot(bcx, output_ty, "ret_slot"))
);
bcx = trans_call_inner(bcx,
None,
bare_fn_ty,
|bcx, _| Callee { bcx: bcx, data: Fn(llfnpointer) },
ArgVals(llargs.as_slice()),
dest).bcx;
finish_fn(&fcx, bcx, output_ty);
llfn
}
/// Translates the adapter that deconstructs a `Box<Trait>` object into
/// `Trait` so that a by-value self method can be called.
pub fn trans_unboxing_shim<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
......
......@@ -368,9 +368,15 @@ fn trans_monomorphized_callee<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
data: Fn(llfn),
}
}
_ => {
bcx.tcx().sess.bug(
"vtable_param left in monomorphized function's vtable substs");
traits::VtableFnPointer(fn_ty) => {
let llfn = trans_fn_pointer_shim(bcx.ccx(), fn_ty);
Callee { bcx: bcx, data: Fn(llfn) }
}
traits::VtableBuiltin(..) |
traits::VtableParam(..) => {
bcx.sess().bug(
format!("resolved vtable bad vtable {} in trans",
vtable.repr(bcx.tcx())).as_slice());
}
}
}
......@@ -609,6 +615,10 @@ pub fn get_vtable<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
(vec!(llfn)).into_iter()
}
traits::VtableFnPointer(bare_fn_ty) => {
let llfn = vec![trans_fn_pointer_shim(bcx.ccx(), bare_fn_ty)];
llfn.into_iter()
}
traits::VtableParam(..) => {
bcx.sess().bug(
format!("resolved vtable for {} to bad vtable {} in trans",
......
......@@ -11,8 +11,6 @@
fn main() {
return
{ return () } //~ ERROR the type of this value must be known in this context
() //~^ ERROR the type of this value must be known in this context
//~^^ ERROR notation; the first type parameter for the function trait is neither a tuple nor unit
//~^^^ ERROR overloaded calls are experimental
()
;
}
......@@ -17,6 +17,4 @@
fn main() {
(return)((),());
//~^ ERROR the type of this value must be known
//~^^ ERROR the type of this value must be known
//~^^^ ERROR cannot use call notation
}
// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
// Tests that unsafe extern fn pointers do not implement any Fn traits.
#![feature(unboxed_closures)]
use std::ops::{Fn,FnMut,FnOnce};
unsafe fn square(x: &int) -> int { (*x) * (*x) }
fn call_it<F:Fn(&int)->int>(_: &F, _: int) -> int { 0 }
fn call_it_mut<F:FnMut(&int)->int>(_: &mut F, _: int) -> int { 0 }
fn call_it_once<F:FnOnce(&int)->int>(_: F, _: int) -> int { 0 }
fn main() {
let x = call_it(&square, 22); //~ ERROR not implemented
let y = call_it_mut(&mut square, 22); //~ ERROR not implemented
let z = call_it_once(square, 22); //~ ERROR not implemented
}
// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
// Tests that unsafe extern fn pointers do not implement any Fn traits.
#![feature(unboxed_closures)]
use std::ops::{Fn,FnMut,FnOnce};
extern "C" fn square(x: &int) -> int { (*x) * (*x) }
fn call_it<F:Fn(&int)->int>(_: &F, _: int) -> int { 0 }
fn call_it_mut<F:FnMut(&int)->int>(_: &mut F, _: int) -> int { 0 }
fn call_it_once<F:FnOnce(&int)->int>(_: F, _: int) -> int { 0 }
fn main() {
let x = call_it(&square, 22); //~ ERROR not implemented
let y = call_it_mut(&mut square, 22); //~ ERROR not implemented
let z = call_it_once(square, 22); //~ ERROR not implemented
}
// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
// Tests that unsafe extern fn pointers do not implement any Fn traits.
#![feature(unboxed_closures)]
use std::ops::{Fn,FnMut,FnOnce};
unsafe fn square(x: int) -> int { x * x }
// note: argument type here is `int`, not `&int`
fn call_it<F:Fn(&int)->int>(_: &F, _: int) -> int { 0 }
fn call_it_mut<F:FnMut(&int)->int>(_: &mut F, _: int) -> int { 0 }
fn call_it_once<F:FnOnce(&int)->int>(_: F, _: int) -> int { 0 }
fn main() {
let x = call_it(&square, 22); //~ ERROR not implemented
let y = call_it_mut(&mut square, 22); //~ ERROR not implemented
let z = call_it_once(square, 22); //~ ERROR not implemented
}
// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
// Checks that higher-ranked extern fn pointers implement the full range of Fn traits.
#![feature(unboxed_closures)]
use std::ops::{Fn,FnMut,FnOnce};
fn square(x: &int) -> int { (*x) * (*x) }
fn call_it<F:Fn(&int)->int>(f: &F, x: int) -> int {
(*f)(&x)
}
fn call_it_boxed(f: &Fn(&int) -> int, x: int) -> int {
f.call((&x,))
}
fn call_it_mut<F:FnMut(&int)->int>(f: &mut F, x: int) -> int {
(*f)(&x)
}
fn call_it_once<F:FnOnce(&int)->int>(f: F, x: int) -> int {
f(&x)
}
fn main() {
let x = call_it(&square, 22);
let x1 = call_it_boxed(&square, 22);
let y = call_it_mut(&mut square, 22);
let z = call_it_once(square, 22);
assert_eq!(x, square(&22));
assert_eq!(x1, square(&22));
assert_eq!(y, square(&22));
assert_eq!(z, square(&22));
}
......@@ -8,7 +8,7 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.
// Checks that extern fn points implement the full range of Fn traits.
// Checks that extern fn pointers implement the full range of Fn traits.
#![feature(unboxed_closures)]
#![feature(unboxed_closures)]
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册