mirror of
https://github.com/rust-lang/rust.git
synced 2024-10-31 22:41:50 +00:00
Purge the hack that allows FnOnce
to be used with a by-value self method. Besides being yucky, it will cause problems if we try to make all traits implement themselves, which would make a lot of things in life easier. Also, it was inextricably linked to Box
, which was not the intention. We can work around its absence, so better to reimplement it later in a more thorough fashion.
This commit is contained in:
parent
d61338172f
commit
698db04a8d
@ -19,8 +19,7 @@ pub use self::CalleeData::*;
|
||||
pub use self::CallArgs::*;
|
||||
|
||||
use arena::TypedArena;
|
||||
use back::abi;
|
||||
use back::link;
|
||||
use back::{abi,link};
|
||||
use session;
|
||||
use llvm::{ValueRef, get_param};
|
||||
use llvm;
|
||||
@ -357,153 +356,6 @@ pub fn trans_fn_pointer_shim<'a, 'tcx>(
|
||||
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>,
|
||||
llshimmedfn: ValueRef,
|
||||
fty: &ty::BareFnTy<'tcx>,
|
||||
method_id: ast::DefId,
|
||||
substs: &subst::Substs<'tcx>)
|
||||
-> ValueRef {
|
||||
let _icx = push_ctxt("trans_unboxing_shim");
|
||||
let ccx = bcx.ccx();
|
||||
let tcx = bcx.tcx();
|
||||
|
||||
let fty = fty.subst(tcx, substs);
|
||||
|
||||
// Transform the self type to `Box<self_type>`.
|
||||
let self_type = fty.sig.inputs[0];
|
||||
let boxed_self_type = ty::mk_uniq(tcx, self_type);
|
||||
let boxed_function_type = ty::FnSig {
|
||||
inputs: fty.sig.inputs.iter().enumerate().map(|(i, typ)| {
|
||||
if i == 0 {
|
||||
boxed_self_type
|
||||
} else {
|
||||
*typ
|
||||
}
|
||||
}).collect(),
|
||||
output: fty.sig.output,
|
||||
variadic: false,
|
||||
};
|
||||
let boxed_function_type = ty::BareFnTy {
|
||||
fn_style: fty.fn_style,
|
||||
abi: fty.abi,
|
||||
sig: boxed_function_type,
|
||||
};
|
||||
let boxed_function_type = ty::mk_bare_fn(tcx, boxed_function_type);
|
||||
let function_type = match fty.abi {
|
||||
synabi::RustCall => {
|
||||
// We're passing through to a RustCall ABI function, but
|
||||
// because the shim will already perform untupling, we
|
||||
// need to pretend the shimmed function does not use
|
||||
// RustCall so the untupled arguments can be passed
|
||||
// through verbatim. This is kind of ugly.
|
||||
let fake_ty = ty::FnSig {
|
||||
inputs: type_of::untuple_arguments_if_necessary(ccx,
|
||||
fty.sig.inputs.as_slice(),
|
||||
fty.abi),
|
||||
output: fty.sig.output,
|
||||
variadic: false,
|
||||
};
|
||||
let fake_ty = ty::BareFnTy {
|
||||
fn_style: fty.fn_style,
|
||||
abi: synabi::Rust,
|
||||
sig: fake_ty,
|
||||
};
|
||||
ty::mk_bare_fn(tcx, fake_ty)
|
||||
}
|
||||
_ => {
|
||||
ty::mk_bare_fn(tcx, fty)
|
||||
}
|
||||
};
|
||||
|
||||
let function_name = ty::with_path(tcx, method_id, |path| {
|
||||
link::mangle_internal_name_by_path_and_seq(path, "unboxing_shim")
|
||||
});
|
||||
let llfn = decl_internal_rust_fn(ccx,
|
||||
boxed_function_type,
|
||||
function_name.as_slice());
|
||||
|
||||
let block_arena = TypedArena::new();
|
||||
let empty_param_substs = Substs::trans_empty();
|
||||
let return_type = ty::ty_fn_ret(boxed_function_type);
|
||||
let fcx = new_fn_ctxt(ccx,
|
||||
llfn,
|
||||
ast::DUMMY_NODE_ID,
|
||||
false,
|
||||
return_type,
|
||||
&empty_param_substs,
|
||||
None,
|
||||
&block_arena);
|
||||
let mut bcx = init_function(&fcx, false, return_type);
|
||||
|
||||
// Create the substituted versions of the self type.
|
||||
let arg_scope = fcx.push_custom_cleanup_scope();
|
||||
let arg_scope_id = cleanup::CustomScope(arg_scope);
|
||||
let boxed_self_type = ty::ty_fn_args(boxed_function_type)[0];
|
||||
let arg_types = ty::ty_fn_args(function_type);
|
||||
let self_type = arg_types[0];
|
||||
let boxed_self_kind = arg_kind(&fcx, boxed_self_type);
|
||||
|
||||
// Create a datum for self.
|
||||
let llboxedself = get_param(fcx.llfn, fcx.arg_pos(0) as u32);
|
||||
let llboxedself = Datum::new(llboxedself,
|
||||
boxed_self_type,
|
||||
boxed_self_kind);
|
||||
let boxed_self =
|
||||
unpack_datum!(bcx,
|
||||
llboxedself.to_lvalue_datum_in_scope(bcx,
|
||||
"boxedself",
|
||||
arg_scope_id));
|
||||
|
||||
// This `Load` is needed because lvalue data are always by-ref.
|
||||
let llboxedself = Load(bcx, boxed_self.val);
|
||||
|
||||
let llself = if type_is_immediate(ccx, self_type) {
|
||||
let llboxedself = Load(bcx, llboxedself);
|
||||
immediate_rvalue(llboxedself, self_type)
|
||||
} else {
|
||||
let llself = rvalue_scratch_datum(bcx, self_type, "self");
|
||||
memcpy_ty(bcx, llself.val, llboxedself, self_type);
|
||||
llself
|
||||
};
|
||||
|
||||
// Make sure we don't free the box twice!
|
||||
boxed_self.kind.post_store(bcx, boxed_self.val, boxed_self_type);
|
||||
|
||||
// Schedule a cleanup to free the box.
|
||||
fcx.schedule_free_value(arg_scope_id,
|
||||
llboxedself,
|
||||
cleanup::HeapExchange,
|
||||
self_type);
|
||||
|
||||
// Now call the function.
|
||||
let mut llshimmedargs = vec!(llself.val);
|
||||
for i in range(1, arg_types.len()) {
|
||||
llshimmedargs.push(get_param(fcx.llfn, fcx.arg_pos(i) as u32));
|
||||
}
|
||||
assert!(!fcx.needs_ret_allocas);
|
||||
let dest = fcx.llretslotptr.get().map(|_|
|
||||
expr::SaveIn(fcx.get_ret_slot(bcx, return_type, "ret_slot"))
|
||||
);
|
||||
bcx = trans_call_inner(bcx,
|
||||
None,
|
||||
function_type,
|
||||
|bcx, _| {
|
||||
Callee {
|
||||
bcx: bcx,
|
||||
data: Fn(llshimmedfn),
|
||||
}
|
||||
},
|
||||
ArgVals(llshimmedargs.as_slice()),
|
||||
dest).bcx;
|
||||
|
||||
bcx = fcx.pop_and_trans_custom_cleanup_scope(bcx, arg_scope);
|
||||
finish_fn(&fcx, bcx, return_type);
|
||||
|
||||
llfn
|
||||
}
|
||||
|
||||
/// Translates a reference to a fn/method item, monomorphizing and
|
||||
/// inlining as it goes.
|
||||
///
|
||||
|
@ -550,68 +550,12 @@ pub fn get_vtable<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
|
||||
emit_vtable_methods(bcx, id, substs).into_iter()
|
||||
}
|
||||
traits::VtableUnboxedClosure(closure_def_id, substs) => {
|
||||
// Look up closure type
|
||||
let self_ty = ty::node_id_to_type(bcx.tcx(), closure_def_id.node);
|
||||
// Apply substitutions from closure param environment.
|
||||
// The substitutions should have no type parameters
|
||||
// remaining after passing through fulfill_obligation
|
||||
let self_ty = self_ty.subst(bcx.tcx(), &substs);
|
||||
|
||||
let mut llfn = trans_fn_ref_with_substs(
|
||||
let llfn = trans_fn_ref_with_substs(
|
||||
bcx,
|
||||
closure_def_id,
|
||||
ExprId(0),
|
||||
substs.clone());
|
||||
|
||||
{
|
||||
let unboxed_closures = bcx.tcx()
|
||||
.unboxed_closures
|
||||
.borrow();
|
||||
let closure_info =
|
||||
unboxed_closures.get(&closure_def_id)
|
||||
.expect("get_vtable(): didn't find \
|
||||
unboxed closure");
|
||||
if closure_info.kind == ty::FnOnceUnboxedClosureKind {
|
||||
// Untuple the arguments and create an unboxing shim.
|
||||
let (new_inputs, new_output) = match self_ty.sty {
|
||||
ty::ty_unboxed_closure(_, _, ref substs) => {
|
||||
let mut new_inputs = vec![self_ty.clone()];
|
||||
match closure_info.closure_type.sig.inputs[0].sty {
|
||||
ty::ty_tup(ref elements) => {
|
||||
for element in elements.iter() {
|
||||
new_inputs.push(element.subst(bcx.tcx(), substs));
|
||||
}
|
||||
}
|
||||
_ => {
|
||||
bcx.tcx().sess.bug("get_vtable(): closure \
|
||||
type wasn't a tuple")
|
||||
}
|
||||
}
|
||||
(new_inputs,
|
||||
closure_info.closure_type.sig.output.subst(bcx.tcx(), substs))
|
||||
},
|
||||
_ => bcx.tcx().sess.bug("get_vtable(): def wasn't an unboxed closure")
|
||||
};
|
||||
|
||||
let closure_type = ty::BareFnTy {
|
||||
fn_style: closure_info.closure_type.fn_style,
|
||||
abi: Rust,
|
||||
sig: ty::FnSig {
|
||||
inputs: new_inputs,
|
||||
output: new_output,
|
||||
variadic: false,
|
||||
},
|
||||
};
|
||||
debug!("get_vtable(): closure type is {}",
|
||||
closure_type.repr(bcx.tcx()));
|
||||
llfn = trans_unboxing_shim(bcx,
|
||||
llfn,
|
||||
&closure_type,
|
||||
closure_def_id,
|
||||
&substs);
|
||||
}
|
||||
}
|
||||
|
||||
(vec!(llfn)).into_iter()
|
||||
}
|
||||
traits::VtableFnPointer(bare_fn_ty) => {
|
||||
@ -701,18 +645,15 @@ fn emit_vtable_methods<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
|
||||
token::get_name(name));
|
||||
Some(C_null(Type::nil(ccx).ptr_to())).into_iter()
|
||||
} else {
|
||||
let mut fn_ref = trans_fn_ref_with_substs(
|
||||
let fn_ref = trans_fn_ref_with_substs(
|
||||
bcx,
|
||||
m_id,
|
||||
ExprId(0),
|
||||
substs.clone());
|
||||
if m.explicit_self == ty::ByValueExplicitSelfCategory {
|
||||
fn_ref = trans_unboxing_shim(bcx,
|
||||
fn_ref,
|
||||
&m.fty,
|
||||
m_id,
|
||||
&substs);
|
||||
}
|
||||
|
||||
// currently, at least, by-value self is not object safe
|
||||
assert!(m.explicit_self != ty::ByValueExplicitSelfCategory);
|
||||
|
||||
Some(fn_ref).into_iter()
|
||||
}
|
||||
}
|
||||
|
@ -315,23 +315,6 @@ impl<'a,'tcx> ProbeContext<'a,'tcx> {
|
||||
get_method_index(tcx, &*new_trait_ref,
|
||||
trait_ref.clone(), method_num);
|
||||
|
||||
// FIXME Hacky. By-value `self` methods in objects ought to be
|
||||
// just a special case of passing ownership of a DST value
|
||||
// as a parameter. *But* we currently hack them in and tie them to
|
||||
// the particulars of the `Box` type. So basically for a `fn foo(self,...)`
|
||||
// method invoked on an object, we don't want the receiver type to be
|
||||
// `TheTrait`, but rather `Box<TheTrait>`. Yuck.
|
||||
let mut m = m;
|
||||
match m.explicit_self {
|
||||
ty::ByValueExplicitSelfCategory => {
|
||||
let mut n = (*m).clone();
|
||||
let self_ty = n.fty.sig.inputs[0];
|
||||
n.fty.sig.inputs[0] = ty::mk_uniq(tcx, self_ty);
|
||||
m = Rc::new(n);
|
||||
}
|
||||
_ => { }
|
||||
}
|
||||
|
||||
let xform_self_ty =
|
||||
this.xform_self_ty(&m, &new_trait_ref.substs);
|
||||
|
||||
|
@ -149,14 +149,6 @@ pub fn check_object_safety<'tcx>(tcx: &ty::ctxt<'tcx>,
|
||||
fn check_object_safety_inner<'tcx>(tcx: &ty::ctxt<'tcx>,
|
||||
object_trait: &ty::TraitRef<'tcx>,
|
||||
span: Span) {
|
||||
// Skip the fn_once lang item trait since only the compiler should call
|
||||
// `call_once` which is the method which takes self by value. What could go
|
||||
// wrong?
|
||||
match tcx.lang_items.fn_once_trait() {
|
||||
Some(def_id) if def_id == object_trait.def_id => return,
|
||||
_ => {}
|
||||
}
|
||||
|
||||
let trait_items = ty::trait_items(tcx, object_trait.def_id);
|
||||
|
||||
let mut errors = Vec::new();
|
||||
|
@ -11,29 +11,29 @@
|
||||
#![feature(unboxed_closures)]
|
||||
|
||||
// Test that unboxing shim for calling rust-call ABI methods through a
|
||||
// trait box works and does not cause an ICE
|
||||
// trait box works and does not cause an ICE.
|
||||
|
||||
struct Foo { foo: uint }
|
||||
|
||||
impl FnOnce<(), uint> for Foo {
|
||||
extern "rust-call" fn call_once(self, _: ()) -> uint { self.foo }
|
||||
impl FnMut<(), uint> for Foo {
|
||||
extern "rust-call" fn call_mut(&mut self, _: ()) -> uint { self.foo }
|
||||
}
|
||||
|
||||
impl FnOnce<(uint,), uint> for Foo {
|
||||
extern "rust-call" fn call_once(self, (x,): (uint,)) -> uint { self.foo + x }
|
||||
impl FnMut<(uint,), uint> for Foo {
|
||||
extern "rust-call" fn call_mut(&mut self, (x,): (uint,)) -> uint { self.foo + x }
|
||||
}
|
||||
|
||||
impl FnOnce<(uint, uint), uint> for Foo {
|
||||
extern "rust-call" fn call_once(self, (x, y): (uint, uint)) -> uint { self.foo + x + y }
|
||||
impl FnMut<(uint, uint), uint> for Foo {
|
||||
extern "rust-call" fn call_mut(&mut self, (x, y): (uint, uint)) -> uint { self.foo + x + y }
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let f = box Foo { foo: 42 } as Box<FnOnce<(), uint>>;
|
||||
assert_eq!(f.call_once(()), 42);
|
||||
let mut f = box Foo { foo: 42 } as Box<FnMut<(), uint>>;
|
||||
assert_eq!(f.call_mut(()), 42);
|
||||
|
||||
let f = box Foo { foo: 40 } as Box<FnOnce<(uint,), uint>>;
|
||||
assert_eq!(f.call_once((2,)), 42);
|
||||
let mut f = box Foo { foo: 40 } as Box<FnMut<(uint,), uint>>;
|
||||
assert_eq!(f.call_mut((2,)), 42);
|
||||
|
||||
let f = box Foo { foo: 40 } as Box<FnOnce<(uint, uint), uint>>;
|
||||
assert_eq!(f.call_once((1, 1)), 42);
|
||||
let mut f = box Foo { foo: 40 } as Box<FnMut<(uint, uint), uint>>;
|
||||
assert_eq!(f.call_mut((1, 1)), 42);
|
||||
}
|
||||
|
@ -1,19 +0,0 @@
|
||||
// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <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.
|
||||
|
||||
// Test that we don't ICE due to encountering unsubstituted type
|
||||
// parameters when untupling FnOnce parameters during translation of
|
||||
// an unboxing shim.
|
||||
|
||||
#![feature(unboxed_closures)]
|
||||
|
||||
fn main() {
|
||||
let _: Box<FnOnce<(),()>> = box move |&mut:| {};
|
||||
}
|
@ -14,26 +14,26 @@
|
||||
#![feature(unboxed_closures)]
|
||||
|
||||
fn main(){
|
||||
fn bar<'a, T:'a> (t: T) -> Box<FnOnce<(),T> + 'a> {
|
||||
box move |:| t
|
||||
fn bar<'a, T:Clone+'a> (t: T) -> Box<FnMut<(),T> + 'a> {
|
||||
box move |&mut:| t.clone()
|
||||
}
|
||||
|
||||
let f = bar(42u);
|
||||
assert_eq!(f.call_once(()), 42);
|
||||
let mut f = bar(42u);
|
||||
assert_eq!(f.call_mut(()), 42);
|
||||
|
||||
let f = bar("forty-two");
|
||||
assert_eq!(f.call_once(()), "forty-two");
|
||||
let mut f = bar("forty-two");
|
||||
assert_eq!(f.call_mut(()), "forty-two");
|
||||
|
||||
let x = 42u;
|
||||
let f = bar(&x);
|
||||
assert_eq!(f.call_once(()), &x);
|
||||
let mut f = bar(&x);
|
||||
assert_eq!(f.call_mut(()), &x);
|
||||
|
||||
#[deriving(Show, PartialEq)]
|
||||
#[deriving(Clone, Show, PartialEq)]
|
||||
struct Foo(uint, &'static str);
|
||||
|
||||
impl Copy for Foo {}
|
||||
|
||||
let x = Foo(42, "forty-two");
|
||||
let f = bar(x);
|
||||
assert_eq!(f.call_once(()), x);
|
||||
let mut f = bar(x);
|
||||
assert_eq!(f.call_mut(()), x);
|
||||
}
|
||||
|
@ -13,7 +13,16 @@
|
||||
#![feature(unboxed_closures)]
|
||||
|
||||
fn main() {
|
||||
let task: Box<FnOnce(int) -> int> = box |: x| x;
|
||||
task.call_once((0i, ));
|
||||
let task: Box<Fn(int) -> int> = box |&: x| x;
|
||||
task.call((0i, ));
|
||||
|
||||
let mut task: Box<FnMut(int) -> int> = box |&mut: x| x;
|
||||
task.call_mut((0i, ));
|
||||
|
||||
call(|:x| x, 22);
|
||||
}
|
||||
|
||||
fn call<F:FnOnce(int) -> int>(f: F, x: int) -> int {
|
||||
f.call_once((x,))
|
||||
}
|
||||
|
||||
|
@ -1,19 +0,0 @@
|
||||
// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <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.
|
||||
|
||||
#![feature(unboxed_closures)]
|
||||
|
||||
use std::ops::FnOnce;
|
||||
|
||||
fn main() {
|
||||
let task: Box<FnOnce(int) -> int> = box |: x| x;
|
||||
assert!(task.call_once((1234i,)) == 1234i);
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user