|
1 | 1 | // Translation of automatically-derived trait implementations. This handles
|
2 | 2 | // enums and structs only; other types cannot be automatically derived.
|
3 | 3 |
|
4 |
| -use middle::trans::base::get_insn_ctxt; |
5 |
| -use middle::trans::common::crate_ctxt; |
6 |
| -use syntax::ast::{ident, node_id, ty_param}; |
| 4 | +use lib::llvm::llvm; |
| 5 | +use middle::trans::base::{finish_fn, get_insn_ctxt, get_item_val}; |
| 6 | +use middle::trans::base::{new_fn_ctxt, sub_block, top_scope_block}; |
| 7 | +use middle::trans::build::{Br, CondBr, GEPi, Load, PointerCast, Store}; |
| 8 | +use middle::trans::build::{ValueRef}; |
| 9 | +use middle::trans::callee; |
| 10 | +use middle::trans::callee::{ArgVals, Callee, DontAutorefArg, Method}; |
| 11 | +use middle::trans::callee::{MethodData}; |
| 12 | +use middle::trans::common; |
| 13 | +use middle::trans::common::{C_bool, T_ptr, block, crate_ctxt}; |
| 14 | +use middle::trans::expr::SaveIn; |
| 15 | +use middle::trans::type_of::type_of; |
| 16 | +use middle::typeck::method_static; |
| 17 | +use syntax::ast; |
| 18 | +use syntax::ast::{def_id, ident, node_id, ty_param}; |
7 | 19 | use syntax::ast_map::path;
|
| 20 | +use syntax::ast_util; |
| 21 | +use syntax::ast_util::local_def; |
8 | 22 |
|
9 | 23 | /// The main "translation" pass for automatically-derived impls. Generates
|
10 | 24 | /// code for monomorphic methods only. Other methods will be generated when
|
11 | 25 | /// they are invoked with specific type parameters; see
|
12 | 26 | /// `trans::base::lval_static_fn()` or `trans::base::monomorphic_fn()`.
|
13 | 27 | pub fn trans_deriving_impl(ccx: @crate_ctxt, _path: path, _name: ident,
|
14 |
| - tps: ~[ty_param], _self_ty: Option<ty::t>, |
15 |
| - _id: node_id) { |
| 28 | + tps: ~[ty_param], id: node_id) { |
16 | 29 | let _icx = ccx.insn_ctxt("deriving::trans_deriving_impl");
|
17 | 30 | if tps.len() > 0 { return; }
|
18 | 31 |
|
19 |
| - // XXX: Unimplemented. |
| 32 | + let impl_def_id = local_def(id); |
| 33 | + let self_ty = ty::lookup_item_type(ccx.tcx, impl_def_id); |
| 34 | + let method_dids = ccx.tcx.automatically_derived_methods_for_impl.get( |
| 35 | + impl_def_id); |
| 36 | + |
| 37 | + for method_dids.each |method_did| { |
| 38 | + let llfn = get_item_val(ccx, method_did.node); |
| 39 | + match ty::get(self_ty.ty).sty { |
| 40 | + ty::ty_class(*) => { |
| 41 | + trans_deriving_struct_method(ccx, llfn, impl_def_id, |
| 42 | + self_ty.ty); |
| 43 | + } |
| 44 | + _ => { |
| 45 | + ccx.tcx.sess.unimpl(~"translation of non-struct deriving \ |
| 46 | + method"); |
| 47 | + } |
| 48 | + } |
| 49 | + } |
| 50 | +} |
| 51 | + |
| 52 | +fn trans_deriving_struct_method(ccx: @crate_ctxt, llfn: ValueRef, |
| 53 | + impl_did: def_id, self_ty: ty::t) { |
| 54 | + let _icx = ccx.insn_ctxt("trans_deriving_struct_method"); |
| 55 | + let fcx = new_fn_ctxt(ccx, ~[], llfn, None); |
| 56 | + let top_bcx = top_scope_block(fcx, None); |
| 57 | + let lltop = top_bcx.llbb; |
| 58 | + let mut bcx = top_bcx; |
| 59 | + |
| 60 | + let llselfty = type_of(ccx, self_ty); |
| 61 | + let llselfval = PointerCast(bcx, fcx.llenv, T_ptr(llselfty)); |
| 62 | + let llotherval = llvm::LLVMGetParam(llfn, 2); |
| 63 | + |
| 64 | + let struct_field_tys; |
| 65 | + match ty::get(self_ty).sty { |
| 66 | + ty::ty_class(struct_id, ref struct_substs) => { |
| 67 | + struct_field_tys = ty::class_items_as_fields( |
| 68 | + ccx.tcx, struct_id, struct_substs); |
| 69 | + } |
| 70 | + _ => { |
| 71 | + ccx.tcx.sess.bug(~"passed non-struct to \ |
| 72 | + trans_deriving_struct_method"); |
| 73 | + } |
| 74 | + } |
| 75 | + |
| 76 | + // Iterate over every element of the struct. |
| 77 | + for ccx.tcx.deriving_struct_methods.get(impl_did).eachi |
| 78 | + |i, derived_method_info| { |
| 79 | + let target_method_def_id; |
| 80 | + match *derived_method_info { |
| 81 | + method_static(did) => target_method_def_id = did, |
| 82 | + _ => fail ~"derived method didn't resolve to a static method" |
| 83 | + } |
| 84 | + |
| 85 | + let fn_expr_ty = |
| 86 | + ty::lookup_item_type(ccx.tcx, target_method_def_id).ty; |
| 87 | + |
| 88 | + let llselfval = GEPi(bcx, llselfval, [0, 0, i]); |
| 89 | + let llotherval = GEPi(bcx, llotherval, [0, 0, i]); |
| 90 | + |
| 91 | + // XXX: Cross-crate won't work! |
| 92 | + let llfn = get_item_val(ccx, target_method_def_id.node); |
| 93 | + let cb: &fn(block) -> Callee = |block| { |
| 94 | + Callee { |
| 95 | + bcx: block, |
| 96 | + data: Method(MethodData { |
| 97 | + llfn: llfn, |
| 98 | + llself: llselfval, |
| 99 | + self_ty: struct_field_tys[i].mt.ty, |
| 100 | + self_mode: ast::by_copy |
| 101 | + }) |
| 102 | + } |
| 103 | + }; |
| 104 | + |
| 105 | + bcx = callee::trans_call_inner(bcx, |
| 106 | + None, |
| 107 | + fn_expr_ty, |
| 108 | + ty::mk_bool(ccx.tcx), |
| 109 | + cb, |
| 110 | + ArgVals(~[llotherval]), |
| 111 | + SaveIn(fcx.llretptr), |
| 112 | + DontAutorefArg); |
| 113 | + |
| 114 | + // Return immediately if the call returned false. |
| 115 | + let next_block = sub_block(top_bcx, ~"next"); |
| 116 | + let llcond = Load(bcx, fcx.llretptr); |
| 117 | + CondBr(bcx, llcond, next_block.llbb, fcx.llreturn); |
| 118 | + bcx = next_block; |
| 119 | + } |
| 120 | + |
| 121 | + Store(bcx, C_bool(true), fcx.llretptr); |
| 122 | + Br(bcx, fcx.llreturn); |
| 123 | + |
| 124 | + finish_fn(fcx, lltop); |
20 | 125 | }
|
21 | 126 |
|
0 commit comments