mirror of
https://github.com/rust-lang/rust.git
synced 2025-01-26 06:35:27 +00:00
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.
This commit is contained in:
parent
207a508411
commit
39221a013f
@ -833,48 +833,52 @@ impl<F,A,R> FnOnce<A,R> for F
|
||||
}
|
||||
}
|
||||
|
||||
#[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)
|
||||
}
|
||||
}
|
||||
|
||||
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,)*)
|
||||
}
|
||||
impl<Result> Fn<(),Result> for extern "Rust" fn() -> Result {
|
||||
#[allow(non_snake_case)]
|
||||
extern "rust-call" fn call(&self, _args: ()) -> Result {
|
||||
(*self)()
|
||||
}
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
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)
|
||||
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,)*)
|
||||
}
|
||||
}
|
||||
)
|
||||
)
|
||||
|
||||
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 @@ impl<'tcx, N> Vtable<'tcx, 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 @@ impl<'tcx, N> Vtable<'tcx, N> {
|
||||
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 @@ use super::{SelectionError, Unimplemented, Overflow,
|
||||
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 middle::ty_fold::TypeFoldable;
|
||||
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 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
||||
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 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
||||
/// 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 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
||||
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 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
||||
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 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
||||
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 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
||||
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 @@ impl<'tcx> Repr<'tcx> for Candidate<'tcx> {
|
||||
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 @@ impl<'tcx, N:Repr<'tcx>> Repr<'tcx> for super::Vtable<'tcx, N> {
|
||||
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 @@ impl<'tcx, N: TypeFoldable<'tcx>> TypeFoldable<'tcx> for traits::Vtable<'tcx, N>
|
||||
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
|
||||
}
|
||||
|
28
src/test/compile-fail/unboxed-closures-unsafe-extern-fn.rs
Normal file
28
src/test/compile-fail/unboxed-closures-unsafe-extern-fn.rs
Normal file
@ -0,0 +1,28 @@
|
||||
// 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
|
||||
}
|
||||
|
28
src/test/compile-fail/unboxed-closures-wrong-abi.rs
Normal file
28
src/test/compile-fail/unboxed-closures-wrong-abi.rs
Normal file
@ -0,0 +1,28 @@
|
||||
// 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
|
||||
}
|
||||
|
@ -0,0 +1,29 @@
|
||||
// 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
|
||||
}
|
||||
|
45
src/test/run-pass/unboxed-closures-extern-fn-hr.rs
Normal file
45
src/test/run-pass/unboxed-closures-extern-fn-hr.rs
Normal file
@ -0,0 +1,45 @@
|
||||
// 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)]
|
||||
|
Loading…
Reference in New Issue
Block a user