2012-10-22 19:57:10 -05:00
|
|
|
// Translation of automatically-derived trait implementations. This handles
|
|
|
|
// enums and structs only; other types cannot be automatically derived.
|
|
|
|
|
2012-10-26 20:23:45 -05:00
|
|
|
use lib::llvm::llvm;
|
|
|
|
use middle::trans::base::{finish_fn, get_insn_ctxt, get_item_val};
|
|
|
|
use middle::trans::base::{new_fn_ctxt, sub_block, top_scope_block};
|
|
|
|
use middle::trans::build::{Br, CondBr, GEPi, Load, PointerCast, Store};
|
|
|
|
use middle::trans::build::{ValueRef};
|
|
|
|
use middle::trans::callee;
|
|
|
|
use middle::trans::callee::{ArgVals, Callee, DontAutorefArg, Method};
|
|
|
|
use middle::trans::callee::{MethodData};
|
|
|
|
use middle::trans::common;
|
|
|
|
use middle::trans::common::{C_bool, T_ptr, block, crate_ctxt};
|
|
|
|
use middle::trans::expr::SaveIn;
|
|
|
|
use middle::trans::type_of::type_of;
|
|
|
|
use middle::typeck::method_static;
|
|
|
|
use syntax::ast;
|
|
|
|
use syntax::ast::{def_id, ident, node_id, ty_param};
|
2012-10-22 19:57:10 -05:00
|
|
|
use syntax::ast_map::path;
|
2012-10-26 20:23:45 -05:00
|
|
|
use syntax::ast_util;
|
|
|
|
use syntax::ast_util::local_def;
|
2012-10-22 19:57:10 -05:00
|
|
|
|
|
|
|
/// The main "translation" pass for automatically-derived impls. Generates
|
|
|
|
/// code for monomorphic methods only. Other methods will be generated when
|
|
|
|
/// they are invoked with specific type parameters; see
|
|
|
|
/// `trans::base::lval_static_fn()` or `trans::base::monomorphic_fn()`.
|
|
|
|
pub fn trans_deriving_impl(ccx: @crate_ctxt, _path: path, _name: ident,
|
2012-10-26 20:23:45 -05:00
|
|
|
tps: ~[ty_param], id: node_id) {
|
2012-10-22 19:57:10 -05:00
|
|
|
let _icx = ccx.insn_ctxt("deriving::trans_deriving_impl");
|
|
|
|
if tps.len() > 0 { return; }
|
|
|
|
|
2012-10-26 20:23:45 -05:00
|
|
|
let impl_def_id = local_def(id);
|
|
|
|
let self_ty = ty::lookup_item_type(ccx.tcx, impl_def_id);
|
|
|
|
let method_dids = ccx.tcx.automatically_derived_methods_for_impl.get(
|
|
|
|
impl_def_id);
|
|
|
|
|
|
|
|
for method_dids.each |method_did| {
|
|
|
|
let llfn = get_item_val(ccx, method_did.node);
|
|
|
|
match ty::get(self_ty.ty).sty {
|
|
|
|
ty::ty_class(*) => {
|
|
|
|
trans_deriving_struct_method(ccx, llfn, impl_def_id,
|
|
|
|
self_ty.ty);
|
|
|
|
}
|
|
|
|
_ => {
|
|
|
|
ccx.tcx.sess.unimpl(~"translation of non-struct deriving \
|
|
|
|
method");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
fn trans_deriving_struct_method(ccx: @crate_ctxt, llfn: ValueRef,
|
|
|
|
impl_did: def_id, self_ty: ty::t) {
|
|
|
|
let _icx = ccx.insn_ctxt("trans_deriving_struct_method");
|
|
|
|
let fcx = new_fn_ctxt(ccx, ~[], llfn, None);
|
|
|
|
let top_bcx = top_scope_block(fcx, None);
|
|
|
|
let lltop = top_bcx.llbb;
|
|
|
|
let mut bcx = top_bcx;
|
|
|
|
|
|
|
|
let llselfty = type_of(ccx, self_ty);
|
|
|
|
let llselfval = PointerCast(bcx, fcx.llenv, T_ptr(llselfty));
|
|
|
|
let llotherval = llvm::LLVMGetParam(llfn, 2);
|
|
|
|
|
|
|
|
let struct_field_tys;
|
|
|
|
match ty::get(self_ty).sty {
|
|
|
|
ty::ty_class(struct_id, ref struct_substs) => {
|
|
|
|
struct_field_tys = ty::class_items_as_fields(
|
|
|
|
ccx.tcx, struct_id, struct_substs);
|
|
|
|
}
|
|
|
|
_ => {
|
|
|
|
ccx.tcx.sess.bug(~"passed non-struct to \
|
|
|
|
trans_deriving_struct_method");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Iterate over every element of the struct.
|
|
|
|
for ccx.tcx.deriving_struct_methods.get(impl_did).eachi
|
|
|
|
|i, derived_method_info| {
|
|
|
|
let target_method_def_id;
|
|
|
|
match *derived_method_info {
|
|
|
|
method_static(did) => target_method_def_id = did,
|
|
|
|
_ => fail ~"derived method didn't resolve to a static method"
|
|
|
|
}
|
|
|
|
|
|
|
|
let fn_expr_ty =
|
|
|
|
ty::lookup_item_type(ccx.tcx, target_method_def_id).ty;
|
|
|
|
|
|
|
|
let llselfval = GEPi(bcx, llselfval, [0, 0, i]);
|
|
|
|
let llotherval = GEPi(bcx, llotherval, [0, 0, i]);
|
|
|
|
|
|
|
|
// XXX: Cross-crate won't work!
|
|
|
|
let llfn = get_item_val(ccx, target_method_def_id.node);
|
|
|
|
let cb: &fn(block) -> Callee = |block| {
|
|
|
|
Callee {
|
|
|
|
bcx: block,
|
|
|
|
data: Method(MethodData {
|
|
|
|
llfn: llfn,
|
|
|
|
llself: llselfval,
|
|
|
|
self_ty: struct_field_tys[i].mt.ty,
|
|
|
|
self_mode: ast::by_copy
|
|
|
|
})
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
bcx = callee::trans_call_inner(bcx,
|
|
|
|
None,
|
|
|
|
fn_expr_ty,
|
|
|
|
ty::mk_bool(ccx.tcx),
|
|
|
|
cb,
|
|
|
|
ArgVals(~[llotherval]),
|
|
|
|
SaveIn(fcx.llretptr),
|
|
|
|
DontAutorefArg);
|
|
|
|
|
|
|
|
// Return immediately if the call returned false.
|
|
|
|
let next_block = sub_block(top_bcx, ~"next");
|
|
|
|
let llcond = Load(bcx, fcx.llretptr);
|
|
|
|
CondBr(bcx, llcond, next_block.llbb, fcx.llreturn);
|
|
|
|
bcx = next_block;
|
|
|
|
}
|
|
|
|
|
|
|
|
Store(bcx, C_bool(true), fcx.llretptr);
|
|
|
|
Br(bcx, fcx.llreturn);
|
|
|
|
|
|
|
|
finish_fn(fcx, lltop);
|
2012-10-22 19:57:10 -05:00
|
|
|
}
|
|
|
|
|