]> git.lizzy.rs Git - rust.git/blob - src/comp/middle/trans_impl.rs
1f3f43953667cd9a4c837a092c94bbd46375119c
[rust.git] / src / comp / middle / trans_impl.rs
1 import trans::*;
2 import trans_common::*;
3 import trans_build::*;
4 import option::{some, none};
5 import syntax::{ast, ast_util};
6 import metadata::csearch;
7 import back::link;
8 import lib::llvm::llvm;
9 import llvm::{ValueRef, TypeRef, LLVMGetParam};
10
11 fn trans_impl(cx: @local_ctxt, name: ast::ident, methods: [@ast::method],
12               id: ast::node_id, tps: [ast::ty_param]) {
13     let sub_cx = extend_path(cx, name);
14     for m in methods {
15         alt cx.ccx.item_ids.find(m.id) {
16           some(llfn) {
17             trans_fn(extend_path(sub_cx, m.ident), m.span, m.decl, m.body,
18                      llfn, impl_self(ty::node_id_to_monotype(cx.ccx.tcx, id)),
19                      tps + m.tps, m.id);
20           }
21         }
22     }
23 }
24
25 fn trans_self_arg(bcx: @block_ctxt, base: @ast::expr) -> result {
26     let tz = [], tr = [];
27     let basety = ty::expr_ty(bcx_tcx(bcx), base);
28     let {bcx, val} = trans_arg_expr(bcx, {mode: ast::by_ref, ty: basety},
29                                     T_ptr(type_of_or_i8(bcx, basety)), tz,
30                                     tr, base);
31     rslt(bcx, PointerCast(bcx, val, T_opaque_boxed_closure_ptr(bcx_ccx(bcx))))
32 }
33
34 fn trans_static_callee(bcx: @block_ctxt, e: @ast::expr, base: @ast::expr,
35                        did: ast::def_id) -> lval_maybe_callee {
36     let {bcx, val} = trans_self_arg(bcx, base);
37     {env: obj_env(val) with lval_static_fn(bcx, did, e.id)}
38 }
39
40 fn trans_dict_callee(bcx: @block_ctxt, e: @ast::expr, base: @ast::expr,
41                      iface_id: ast::def_id, n_method: uint,
42                      n_param: uint, n_bound: uint) -> lval_maybe_callee {
43     let tcx = bcx_tcx(bcx);
44     let {bcx, val} = trans_self_arg(bcx, base);
45     let dict = option::get(bcx.fcx.lltyparams[n_param].dicts)[n_bound];
46     let method = ty::iface_methods(tcx, iface_id)[n_method];
47     let fty = ty::expr_ty(tcx, e);
48     let bare_fn_ty = type_of_fn_from_ty(bcx_ccx(bcx), ast_util::dummy_sp(),
49                                         fty, *method.tps);
50     let {inputs: bare_inputs, output} = llfn_arg_tys(bare_fn_ty);
51     let fn_ty = T_fn([val_ty(dict)] + bare_inputs, output);
52     let vtable = PointerCast(bcx, Load(bcx, GEPi(bcx, dict, [0, 0])),
53                              T_ptr(T_array(T_ptr(fn_ty), n_method + 1u)));
54     let mptr = Load(bcx, GEPi(bcx, vtable, [0, n_method as int]));
55     let generic = none;
56     if vec::len(*method.tps) > 0u {
57         let tydescs = [], tis = [];
58         let tptys = ty::node_id_to_type_params(tcx, e.id);
59         for t in vec::tail_n(tptys, vec::len(tptys) - vec::len(*method.tps)) {
60             // TODO: Doesn't always escape.
61             let ti = none;
62             let td = get_tydesc(bcx, t, true, tps_normal, ti).result;
63             tis += [ti];
64             tydescs += [td.val];
65             bcx = td.bcx;
66         }
67         generic = some({item_type: fty,
68                         static_tis: tis,
69                         tydescs: tydescs,
70                         param_bounds: method.tps,
71                         origins: bcx_ccx(bcx).dict_map.find(e.id)});
72     }
73     {bcx: bcx, val: mptr, kind: owned,
74      env: dict_env(dict, val),
75      generic: generic}
76 }
77
78 fn llfn_arg_tys(ft: TypeRef) -> {inputs: [TypeRef], output: TypeRef} {
79     let out_ty = llvm::LLVMGetReturnType(ft);
80     let n_args = llvm::LLVMCountParamTypes(ft);
81     let args = vec::init_elt(0 as TypeRef, n_args);
82     unsafe { llvm::LLVMGetParamTypes(ft, vec::to_ptr(args)); }
83     {inputs: args, output: out_ty}
84 }
85
86 fn trans_wrapper(ccx: @crate_ctxt, pt: [ast::ident],
87                  extra_tps: [ty::param_bounds], m: @ast::method) -> ValueRef {
88     let real_fn = ccx.item_ids.get(m.id);
89     let {inputs: real_args, output: real_ret} =
90         llfn_arg_tys(llvm::LLVMGetElementType(val_ty(real_fn)));
91     let extra_ptrs = [];
92     for tp in extra_tps {
93         extra_ptrs += [T_ptr(ccx.tydesc_type)];
94         for bound in *tp {
95             alt bound {
96               ty::bound_iface(_) { extra_ptrs += [T_ptr(T_dict())]; }
97               _ {}
98             }
99         }
100     }
101     let env_ty = T_ptr(T_struct([T_ptr(T_i8())] + extra_ptrs));
102     let n_extra_ptrs = vec::len(extra_ptrs);
103
104     let wrap_args = [T_ptr(T_dict())] + vec::slice(real_args, 0u, 2u) +
105         vec::slice(real_args, 2u + vec::len(extra_ptrs), vec::len(real_args));
106     let llfn_ty = T_fn(wrap_args, real_ret);
107
108     let lcx = @{path: pt + ["wrapper", m.ident], module_path: [],
109                 obj_typarams: [], obj_fields: [], ccx: ccx};
110     let name = link::mangle_internal_name_by_path_and_seq(ccx, pt, m.ident);
111     let llfn = decl_internal_cdecl_fn(ccx.llmod, name, llfn_ty);
112     let fcx = new_fn_ctxt(lcx, ast_util::dummy_sp(), llfn);
113     let bcx = new_top_block_ctxt(fcx), lltop = bcx.llbb;
114
115     let dict = PointerCast(bcx, LLVMGetParam(llfn, 0u), env_ty);
116     // retptr, self
117     let args = [LLVMGetParam(llfn, 1u), LLVMGetParam(llfn, 2u)], i = 0u;
118     // saved tydescs/dicts
119     while i < n_extra_ptrs {
120         i += 1u;
121         args += [load_inbounds(bcx, dict, [0, i as int])];
122     }
123     // the rest of the parameters
124     let i = 3u, params_total = llvm::LLVMCountParamTypes(llfn_ty);
125     while i < params_total {
126         args += [LLVMGetParam(llfn, i)];
127         i += 1u;
128     }
129     Call(bcx, ccx.item_ids.get(m.id), args);
130     build_return(bcx);
131     finish_fn(fcx, lltop);
132     ret llfn;
133 }
134
135 fn dict_is_static(tcx: ty::ctxt, origin: typeck::dict_origin) -> bool {
136     alt origin {
137       typeck::dict_static(_, ts, origs) {
138         vec::all(ts, {|t| !ty::type_contains_params(tcx, t)}) &&
139         vec::all(*origs, {|o| dict_is_static(tcx, o)})
140       }
141       typeck::dict_param(_, _) { false }
142     }
143 }
144
145 fn get_dict(bcx: @block_ctxt, origin: typeck::dict_origin) -> result {
146     let ccx = bcx_ccx(bcx);
147     alt origin {
148       typeck::dict_static(impl_did, tys, sub_origins) {
149         if dict_is_static(ccx.tcx, origin) {
150             ret rslt(bcx, get_static_dict(bcx, origin));
151         }
152         let {bcx, ptrs} = get_dict_ptrs(bcx, origin);
153         let pty = T_ptr(T_i8()), dict_ty = T_array(pty, vec::len(ptrs));
154         let dict = alloca(bcx, dict_ty), i = 0;
155         for ptr in ptrs {
156             Store(bcx, PointerCast(bcx, ptr, pty), GEPi(bcx, dict, [0, i]));
157             i += 1;
158         }
159         dict = Call(bcx, ccx.upcalls.intern_dict,
160                     [C_uint(ccx, vec::len(ptrs)),
161                      PointerCast(bcx, dict, T_ptr(T_dict()))]);
162         rslt(bcx, dict)
163       }
164       typeck::dict_param(n_param, n_bound) {
165         rslt(bcx, option::get(bcx.fcx.lltyparams[n_param].dicts)[n_bound])
166       }
167     }
168 }
169
170 fn dict_id(tcx: ty::ctxt, origin: typeck::dict_origin) -> dict_id {
171     alt origin {
172       typeck::dict_static(did, ts, origs) {
173         let d_params = [], orig = 0u;
174         if vec::len(ts) == 0u { ret @{impl_def: did, params: d_params}; }
175         let impl_params = ty::lookup_item_type(tcx, did).bounds;
176         vec::iter2(ts, *impl_params) {|t, bounds|
177             d_params += [dict_param_ty(t)];
178             for bound in *bounds {
179                 alt bound {
180                   ty::bound_iface(_) {
181                     d_params += [dict_param_dict(dict_id(tcx, origs[orig]))];
182                     orig += 1u;
183                   }
184                 }
185             }
186         }
187         @{impl_def: did, params: d_params}
188       }
189     }
190 }
191
192 fn get_static_dict(bcx: @block_ctxt, origin: typeck::dict_origin)
193     -> ValueRef {
194     let ccx = bcx_ccx(bcx);
195     let id = dict_id(ccx.tcx, origin);
196     alt ccx.dicts.find(id) {
197       some(d) { ret d; }
198       none. {}
199     }
200     let ptrs = C_struct(get_dict_ptrs(bcx, origin).ptrs);
201     let name = ccx.names.next("dict");
202     let gvar = str::as_buf(name, {|buf|
203         llvm::LLVMAddGlobal(ccx.llmod, val_ty(ptrs), buf)
204     });
205     llvm::LLVMSetGlobalConstant(gvar, lib::llvm::True);
206     llvm::LLVMSetInitializer(gvar, ptrs);
207     llvm::LLVMSetLinkage(gvar,
208                          lib::llvm::LLVMInternalLinkage as llvm::Linkage);
209     let cast = llvm::LLVMConstPointerCast(gvar, T_ptr(T_dict()));
210     ccx.dicts.insert(id, cast);
211     cast
212 }
213
214 fn get_dict_ptrs(bcx: @block_ctxt, origin: typeck::dict_origin)
215     -> {bcx: @block_ctxt, ptrs: [ValueRef]} {
216     let ccx = bcx_ccx(bcx);
217     alt origin {
218       typeck::dict_static(impl_did, tys, sub_origins) {
219         let vtable = if impl_did.crate == ast::local_crate {
220             ccx.item_ids.get(impl_did.node)
221         } else {
222             let name = csearch::get_symbol(ccx.sess.get_cstore(), impl_did);
223             get_extern_const(ccx.externs, ccx.llmod, name, T_ptr(T_i8()))
224         };
225         let impl_params = ty::lookup_item_type(ccx.tcx, impl_did).bounds;
226         let ptrs = [vtable], origin = 0u, ti = none, bcx = bcx;
227         vec::iter2(*impl_params, tys) {|param, ty|
228             let rslt = get_tydesc(bcx, ty, true, tps_normal, ti).result;
229             ptrs += [rslt.val];
230             bcx = rslt.bcx;
231             for bound in *param {
232                 alt bound {
233                   ty::bound_iface(_) {
234                     let res = get_dict(bcx, sub_origins[origin]);
235                     ptrs += [res.val];
236                     bcx = res.bcx;
237                     origin += 1u;
238                   }
239                   _ {}
240                 }
241             }
242         }
243         {bcx: bcx, ptrs: ptrs}
244       }
245     }
246 }