]>
Commit | Line | Data |
---|---|---|
1a4d82fc JJ |
1 | // Copyright 2012 The Rust Project Developers. See the COPYRIGHT |
2 | // file at the top-level directory of this distribution and at | |
3 | // http://rust-lang.org/COPYRIGHT. | |
4 | // | |
5 | // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or | |
6 | // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license | |
7 | // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your | |
8 | // option. This file may not be copied, modified, or distributed | |
9 | // except according to those terms. | |
10 | ||
11 | use arena::TypedArena; | |
12 | use back::abi; | |
13 | use back::link; | |
62682a34 | 14 | use llvm::{ValueRef, get_params}; |
1a4d82fc | 15 | use metadata::csearch; |
c34b1796 | 16 | use middle::subst::{Subst, Substs}; |
1a4d82fc JJ |
17 | use middle::subst::VecPerParamSpace; |
18 | use middle::subst; | |
19 | use middle::traits; | |
62682a34 | 20 | use rustc::ast_map; |
1a4d82fc JJ |
21 | use trans::base::*; |
22 | use trans::build::*; | |
23 | use trans::callee::*; | |
24 | use trans::callee; | |
25 | use trans::cleanup; | |
c34b1796 | 26 | use trans::closure; |
1a4d82fc | 27 | use trans::common::*; |
85aaf69f | 28 | use trans::consts; |
1a4d82fc | 29 | use trans::datum::*; |
85aaf69f | 30 | use trans::debuginfo::DebugLoc; |
9346a6ac | 31 | use trans::declare; |
c34b1796 | 32 | use trans::expr::SaveIn; |
1a4d82fc JJ |
33 | use trans::expr; |
34 | use trans::glue; | |
35 | use trans::machine; | |
85aaf69f | 36 | use trans::monomorphize; |
1a4d82fc JJ |
37 | use trans::type_::Type; |
38 | use trans::type_of::*; | |
c1a9b12d | 39 | use middle::ty::{self, Ty, HasTypeFlags}; |
1a4d82fc | 40 | use middle::ty::MethodCall; |
1a4d82fc | 41 | |
62682a34 | 42 | use syntax::{ast, attr, visit}; |
1a4d82fc | 43 | use syntax::codemap::DUMMY_SP; |
c34b1796 | 44 | use syntax::ptr::P; |
1a4d82fc JJ |
45 | |
46 | // drop_glue pointer, size, align. | |
c34b1796 | 47 | const VTABLE_OFFSET: usize = 3; |
1a4d82fc JJ |
48 | |
49 | /// The main "translation" pass for methods. Generates code | |
50 | /// for non-monomorphized methods only. Other methods will | |
51 | /// be generated once they are invoked with specific type parameters, | |
52 | /// see `trans::base::lval_static_fn()` or `trans::base::monomorphic_fn()`. | |
53 | pub fn trans_impl(ccx: &CrateContext, | |
54 | name: ast::Ident, | |
c34b1796 | 55 | impl_items: &[P<ast::ImplItem>], |
1a4d82fc JJ |
56 | generics: &ast::Generics, |
57 | id: ast::NodeId) { | |
58 | let _icx = push_ctxt("meth::trans_impl"); | |
59 | let tcx = ccx.tcx(); | |
60 | ||
62682a34 | 61 | debug!("trans_impl(name={}, id={})", name, id); |
1a4d82fc | 62 | |
c34b1796 AL |
63 | let mut v = TransItemVisitor { ccx: ccx }; |
64 | ||
1a4d82fc JJ |
65 | // Both here and below with generic methods, be sure to recurse and look for |
66 | // items that we need to translate. | |
67 | if !generics.ty_params.is_empty() { | |
85aaf69f | 68 | for impl_item in impl_items { |
c34b1796 AL |
69 | match impl_item.node { |
70 | ast::MethodImplItem(..) => { | |
71 | visit::walk_impl_item(&mut v, impl_item); | |
1a4d82fc | 72 | } |
d9579d0f | 73 | _ => {} |
1a4d82fc JJ |
74 | } |
75 | } | |
76 | return; | |
77 | } | |
85aaf69f | 78 | for impl_item in impl_items { |
c34b1796 AL |
79 | match impl_item.node { |
80 | ast::MethodImplItem(ref sig, ref body) => { | |
9346a6ac | 81 | if sig.generics.ty_params.is_empty() { |
c34b1796 | 82 | let trans_everywhere = attr::requests_inline(&impl_item.attrs); |
1a4d82fc | 83 | for (ref ccx, is_origin) in ccx.maybe_iter(trans_everywhere) { |
c34b1796 | 84 | let llfn = get_item_val(ccx, impl_item.id); |
85aaf69f | 85 | let empty_substs = tcx.mk_substs(Substs::trans_empty()); |
c34b1796 AL |
86 | trans_fn(ccx, &sig.decl, body, llfn, |
87 | empty_substs, impl_item.id, &[]); | |
1a4d82fc JJ |
88 | update_linkage(ccx, |
89 | llfn, | |
c34b1796 | 90 | Some(impl_item.id), |
1a4d82fc JJ |
91 | if is_origin { OriginalTranslation } else { InlinedCopy }); |
92 | } | |
93 | } | |
c34b1796 | 94 | visit::walk_impl_item(&mut v, impl_item); |
1a4d82fc | 95 | } |
d9579d0f | 96 | _ => {} |
1a4d82fc JJ |
97 | } |
98 | } | |
99 | } | |
100 | ||
101 | pub fn trans_method_callee<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, | |
102 | method_call: MethodCall, | |
103 | self_expr: Option<&ast::Expr>, | |
104 | arg_cleanup_scope: cleanup::ScopeId) | |
105 | -> Callee<'blk, 'tcx> { | |
106 | let _icx = push_ctxt("meth::trans_method_callee"); | |
107 | ||
c1a9b12d SL |
108 | let method = bcx.tcx().tables.borrow().method_map[&method_call]; |
109 | ||
110 | match bcx.tcx().impl_or_trait_item(method.def_id).container() { | |
111 | ty::ImplContainer(_) => { | |
112 | debug!("trans_method_callee: static, {:?}", method.def_id); | |
113 | let datum = callee::trans_fn_ref(bcx.ccx(), | |
114 | method.def_id, | |
115 | MethodCallKey(method_call), | |
116 | bcx.fcx.param_substs); | |
1a4d82fc JJ |
117 | Callee { |
118 | bcx: bcx, | |
c1a9b12d SL |
119 | data: Fn(datum.val), |
120 | ty: datum.ty | |
1a4d82fc JJ |
121 | } |
122 | } | |
123 | ||
c1a9b12d SL |
124 | ty::TraitContainer(trait_def_id) => { |
125 | let trait_substs = method.substs.clone().method_to_trait(); | |
126 | let trait_substs = bcx.tcx().mk_substs(trait_substs); | |
127 | let trait_ref = ty::TraitRef::new(trait_def_id, trait_substs); | |
128 | ||
129 | let trait_ref = ty::Binder(bcx.monomorphize(&trait_ref)); | |
1a4d82fc | 130 | let span = bcx.tcx().map.span(method_call.expr_id); |
62682a34 | 131 | debug!("method_call={:?} trait_ref={:?} trait_ref id={:?} substs={:?}", |
1a4d82fc | 132 | method_call, |
62682a34 SL |
133 | trait_ref, |
134 | trait_ref.0.def_id, | |
135 | trait_ref.0.substs); | |
1a4d82fc JJ |
136 | let origin = fulfill_obligation(bcx.ccx(), |
137 | span, | |
138 | trait_ref.clone()); | |
62682a34 | 139 | debug!("origin = {:?}", origin); |
1a4d82fc JJ |
140 | trans_monomorphized_callee(bcx, |
141 | method_call, | |
c1a9b12d SL |
142 | self_expr, |
143 | trait_def_id, | |
144 | method.def_id, | |
145 | method.ty, | |
146 | origin, | |
147 | arg_cleanup_scope) | |
1a4d82fc JJ |
148 | } |
149 | } | |
150 | } | |
151 | ||
152 | pub fn trans_static_method_callee<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, | |
153 | method_id: ast::DefId, | |
154 | trait_id: ast::DefId, | |
155 | expr_id: ast::NodeId, | |
85aaf69f | 156 | param_substs: &'tcx subst::Substs<'tcx>) |
1a4d82fc JJ |
157 | -> Datum<'tcx, Rvalue> |
158 | { | |
159 | let _icx = push_ctxt("meth::trans_static_method_callee"); | |
160 | let tcx = ccx.tcx(); | |
161 | ||
162 | debug!("trans_static_method_callee(method_id={:?}, trait_id={}, \ | |
163 | expr_id={})", | |
164 | method_id, | |
c1a9b12d | 165 | tcx.item_path_str(trait_id), |
1a4d82fc JJ |
166 | expr_id); |
167 | ||
168 | let mname = if method_id.krate == ast::LOCAL_CRATE { | |
169 | match tcx.map.get(method_id.node) { | |
c34b1796 | 170 | ast_map::NodeTraitItem(trait_item) => trait_item.ident.name, |
1a4d82fc JJ |
171 | _ => panic!("callee is not a trait method") |
172 | } | |
173 | } else { | |
174 | csearch::get_item_path(tcx, method_id).last().unwrap().name() | |
175 | }; | |
176 | debug!("trans_static_method_callee: method_id={:?}, expr_id={}, \ | |
c1a9b12d | 177 | name={}", method_id, expr_id, mname); |
1a4d82fc JJ |
178 | |
179 | // Find the substitutions for the fn itself. This includes | |
180 | // type parameters that belong to the trait but also some that | |
181 | // belong to the method: | |
182 | let rcvr_substs = node_id_substs(ccx, ExprId(expr_id), param_substs); | |
183 | let subst::SeparateVecsPerParamSpace { | |
184 | types: rcvr_type, | |
185 | selfs: rcvr_self, | |
186 | fns: rcvr_method | |
187 | } = rcvr_substs.types.split(); | |
188 | ||
189 | // Lookup the precise impl being called. To do that, we need to | |
190 | // create a trait reference identifying the self type and other | |
191 | // input type parameters. To create that trait reference, we have | |
192 | // to pick apart the type parameters to identify just those that | |
193 | // pertain to the trait. This is easiest to explain by example: | |
194 | // | |
195 | // trait Convert { | |
196 | // fn from<U:Foo>(n: U) -> Option<Self>; | |
197 | // } | |
198 | // ... | |
199 | // let f = <Vec<int> as Convert>::from::<String>(...) | |
200 | // | |
201 | // Here, in this call, which I've written with explicit UFCS | |
202 | // notation, the set of type parameters will be: | |
203 | // | |
204 | // rcvr_type: [] <-- nothing declared on the trait itself | |
205 | // rcvr_self: [Vec<int>] <-- the self type | |
206 | // rcvr_method: [String] <-- method type parameter | |
207 | // | |
208 | // So we create a trait reference using the first two, | |
209 | // basically corresponding to `<Vec<int> as Convert>`. | |
210 | // The remaining type parameters (`rcvr_method`) will be used below. | |
211 | let trait_substs = | |
212 | Substs::erased(VecPerParamSpace::new(rcvr_type, | |
213 | rcvr_self, | |
214 | Vec::new())); | |
215 | let trait_substs = tcx.mk_substs(trait_substs); | |
62682a34 | 216 | debug!("trait_substs={:?}", trait_substs); |
c1a9b12d | 217 | let trait_ref = ty::Binder(ty::TraitRef::new(trait_id, trait_substs)); |
1a4d82fc JJ |
218 | let vtbl = fulfill_obligation(ccx, |
219 | DUMMY_SP, | |
220 | trait_ref); | |
221 | ||
222 | // Now that we know which impl is being used, we can dispatch to | |
223 | // the actual function: | |
224 | match vtbl { | |
225 | traits::VtableImpl(traits::VtableImplData { | |
226 | impl_def_id: impl_did, | |
227 | substs: impl_substs, | |
228 | nested: _ }) => | |
229 | { | |
c1a9b12d | 230 | assert!(!impl_substs.types.needs_infer()); |
1a4d82fc JJ |
231 | |
232 | // Create the substitutions that are in scope. This combines | |
233 | // the type parameters from the impl with those declared earlier. | |
234 | // To see what I mean, consider a possible impl: | |
235 | // | |
236 | // impl<T> Convert for Vec<T> { | |
237 | // fn from<U:Foo>(n: U) { ... } | |
238 | // } | |
239 | // | |
240 | // Recall that we matched `<Vec<int> as Convert>`. Trait | |
241 | // resolution will have given us a substitution | |
242 | // containing `impl_substs=[[T=int],[],[]]` (the type | |
243 | // parameters defined on the impl). We combine | |
244 | // that with the `rcvr_method` from before, which tells us | |
245 | // the type parameters from the *method*, to yield | |
246 | // `callee_substs=[[T=int],[],[U=String]]`. | |
247 | let subst::SeparateVecsPerParamSpace { | |
248 | types: impl_type, | |
249 | selfs: impl_self, | |
250 | fns: _ | |
251 | } = impl_substs.types.split(); | |
252 | let callee_substs = | |
253 | Substs::erased(VecPerParamSpace::new(impl_type, | |
254 | impl_self, | |
255 | rcvr_method)); | |
256 | ||
257 | let mth_id = method_with_name(ccx, impl_did, mname); | |
258 | trans_fn_ref_with_substs(ccx, mth_id, ExprId(expr_id), | |
259 | param_substs, | |
260 | callee_substs) | |
261 | } | |
85aaf69f | 262 | traits::VtableObject(ref data) => { |
c1a9b12d SL |
263 | let idx = traits::get_vtable_index_of_object_method(tcx, data, method_id); |
264 | trans_object_shim(ccx, | |
265 | data.upcast_trait_ref.clone(), | |
266 | method_id, | |
267 | idx) | |
85aaf69f | 268 | } |
1a4d82fc | 269 | _ => { |
62682a34 SL |
270 | tcx.sess.bug(&format!("static call to invalid vtable: {:?}", |
271 | vtbl)); | |
1a4d82fc JJ |
272 | } |
273 | } | |
274 | } | |
275 | ||
276 | fn method_with_name(ccx: &CrateContext, impl_id: ast::DefId, name: ast::Name) | |
277 | -> ast::DefId { | |
278 | match ccx.impl_method_cache().borrow().get(&(impl_id, name)).cloned() { | |
279 | Some(m) => return m, | |
280 | None => {} | |
281 | } | |
282 | ||
283 | let impl_items = ccx.tcx().impl_items.borrow(); | |
284 | let impl_items = | |
285 | impl_items.get(&impl_id) | |
286 | .expect("could not find impl while translating"); | |
287 | let meth_did = impl_items.iter() | |
288 | .find(|&did| { | |
c1a9b12d | 289 | ccx.tcx().impl_or_trait_item(did.def_id()).name() == name |
1a4d82fc JJ |
290 | }).expect("could not find method while \ |
291 | translating"); | |
292 | ||
293 | ccx.impl_method_cache().borrow_mut().insert((impl_id, name), | |
294 | meth_did.def_id()); | |
295 | meth_did.def_id() | |
296 | } | |
297 | ||
298 | fn trans_monomorphized_callee<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, | |
299 | method_call: MethodCall, | |
c1a9b12d | 300 | self_expr: Option<&ast::Expr>, |
1a4d82fc | 301 | trait_id: ast::DefId, |
c1a9b12d SL |
302 | method_id: ast::DefId, |
303 | method_ty: Ty<'tcx>, | |
304 | vtable: traits::Vtable<'tcx, ()>, | |
305 | arg_cleanup_scope: cleanup::ScopeId) | |
1a4d82fc JJ |
306 | -> Callee<'blk, 'tcx> { |
307 | let _icx = push_ctxt("meth::trans_monomorphized_callee"); | |
308 | match vtable { | |
309 | traits::VtableImpl(vtable_impl) => { | |
310 | let ccx = bcx.ccx(); | |
311 | let impl_did = vtable_impl.impl_def_id; | |
c1a9b12d | 312 | let mname = match ccx.tcx().impl_or_trait_item(method_id) { |
1a4d82fc | 313 | ty::MethodTraitItem(method) => method.name, |
d9579d0f AL |
314 | _ => { |
315 | bcx.tcx().sess.bug("can't monomorphize a non-method trait \ | |
316 | item") | |
1a4d82fc JJ |
317 | } |
318 | }; | |
319 | let mth_id = method_with_name(bcx.ccx(), impl_did, mname); | |
320 | ||
321 | // create a concatenated set of substitutions which includes | |
322 | // those from the impl and those from the method: | |
323 | let callee_substs = | |
324 | combine_impl_and_methods_tps( | |
325 | bcx, MethodCallKey(method_call), vtable_impl.substs); | |
326 | ||
327 | // translate the function | |
c1a9b12d SL |
328 | let datum = trans_fn_ref_with_substs(bcx.ccx(), |
329 | mth_id, | |
330 | MethodCallKey(method_call), | |
331 | bcx.fcx.param_substs, | |
332 | callee_substs); | |
1a4d82fc | 333 | |
c1a9b12d | 334 | Callee { bcx: bcx, data: Fn(datum.val), ty: datum.ty } |
1a4d82fc | 335 | } |
62682a34 | 336 | traits::VtableClosure(vtable_closure) => { |
1a4d82fc JJ |
337 | // The substitutions should have no type parameters remaining |
338 | // after passing through fulfill_obligation | |
c34b1796 AL |
339 | let trait_closure_kind = bcx.tcx().lang_items.fn_trait_kind(trait_id).unwrap(); |
340 | let llfn = closure::trans_closure_method(bcx.ccx(), | |
62682a34 SL |
341 | vtable_closure.closure_def_id, |
342 | vtable_closure.substs, | |
c34b1796 | 343 | trait_closure_kind); |
1a4d82fc JJ |
344 | Callee { |
345 | bcx: bcx, | |
346 | data: Fn(llfn), | |
c1a9b12d | 347 | ty: monomorphize_type(bcx, method_ty) |
1a4d82fc JJ |
348 | } |
349 | } | |
350 | traits::VtableFnPointer(fn_ty) => { | |
c34b1796 AL |
351 | let trait_closure_kind = bcx.tcx().lang_items.fn_trait_kind(trait_id).unwrap(); |
352 | let llfn = trans_fn_pointer_shim(bcx.ccx(), trait_closure_kind, fn_ty); | |
c1a9b12d SL |
353 | Callee { |
354 | bcx: bcx, | |
355 | data: Fn(llfn), | |
356 | ty: monomorphize_type(bcx, method_ty) | |
357 | } | |
1a4d82fc JJ |
358 | } |
359 | traits::VtableObject(ref data) => { | |
c1a9b12d SL |
360 | let idx = traits::get_vtable_index_of_object_method(bcx.tcx(), data, method_id); |
361 | if let Some(self_expr) = self_expr { | |
362 | if let ty::TyBareFn(_, ref fty) = monomorphize_type(bcx, method_ty).sty { | |
363 | let ty = bcx.tcx().mk_fn(None, opaque_method_ty(bcx.tcx(), fty)); | |
364 | return trans_trait_callee(bcx, ty, idx, self_expr, arg_cleanup_scope); | |
365 | } | |
366 | } | |
367 | let datum = trans_object_shim(bcx.ccx(), | |
368 | data.upcast_trait_ref.clone(), | |
369 | method_id, | |
370 | idx); | |
371 | Callee { bcx: bcx, data: Fn(datum.val), ty: datum.ty } | |
1a4d82fc JJ |
372 | } |
373 | traits::VtableBuiltin(..) | | |
c34b1796 | 374 | traits::VtableDefaultImpl(..) | |
1a4d82fc JJ |
375 | traits::VtableParam(..) => { |
376 | bcx.sess().bug( | |
62682a34 SL |
377 | &format!("resolved vtable bad vtable {:?} in trans", |
378 | vtable)); | |
1a4d82fc JJ |
379 | } |
380 | } | |
381 | } | |
382 | ||
383 | /// Creates a concatenated set of substitutions which includes those from the impl and those from | |
384 | /// the method. This are some subtle complications here. Statically, we have a list of type | |
385 | /// parameters like `[T0, T1, T2, M1, M2, M3]` where `Tn` are type parameters that appear on the | |
386 | /// receiver. For example, if the receiver is a method parameter `A` with a bound like | |
387 | /// `trait<B,C,D>` then `Tn` would be `[B,C,D]`. | |
388 | /// | |
389 | /// The weird part is that the type `A` might now be bound to any other type, such as `foo<X>`. | |
390 | /// In that case, the vector we want is: `[X, M1, M2, M3]`. Therefore, what we do now is to slice | |
391 | /// off the method type parameters and append them to the type parameters from the type that the | |
392 | /// receiver is mapped to. | |
393 | fn combine_impl_and_methods_tps<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, | |
394 | node: ExprOrMethodCall, | |
395 | rcvr_substs: subst::Substs<'tcx>) | |
396 | -> subst::Substs<'tcx> | |
397 | { | |
398 | let ccx = bcx.ccx(); | |
399 | ||
400 | let node_substs = node_id_substs(ccx, node, bcx.fcx.param_substs); | |
401 | ||
62682a34 SL |
402 | debug!("rcvr_substs={:?}", rcvr_substs); |
403 | debug!("node_substs={:?}", node_substs); | |
1a4d82fc JJ |
404 | |
405 | // Break apart the type parameters from the node and type | |
406 | // parameters from the receiver. | |
407 | let node_method = node_substs.types.split().fns; | |
408 | let subst::SeparateVecsPerParamSpace { | |
409 | types: rcvr_type, | |
410 | selfs: rcvr_self, | |
411 | fns: rcvr_method | |
412 | } = rcvr_substs.types.clone().split(); | |
413 | assert!(rcvr_method.is_empty()); | |
414 | subst::Substs { | |
415 | regions: subst::ErasedRegions, | |
416 | types: subst::VecPerParamSpace::new(rcvr_type, rcvr_self, node_method) | |
417 | } | |
418 | } | |
419 | ||
420 | /// Create a method callee where the method is coming from a trait object (e.g., Box<Trait> type). | |
421 | /// In this case, we must pull the fn pointer out of the vtable that is packaged up with the | |
422 | /// object. Objects are represented as a pair, so we first evaluate the self expression and then | |
423 | /// extract the self data and vtable out of the pair. | |
424 | fn trans_trait_callee<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, | |
c1a9b12d | 425 | opaque_fn_ty: Ty<'tcx>, |
c34b1796 | 426 | vtable_index: usize, |
1a4d82fc JJ |
427 | self_expr: &ast::Expr, |
428 | arg_cleanup_scope: cleanup::ScopeId) | |
429 | -> Callee<'blk, 'tcx> { | |
430 | let _icx = push_ctxt("meth::trans_trait_callee"); | |
431 | let mut bcx = bcx; | |
432 | ||
433 | // Translate self_datum and take ownership of the value by | |
434 | // converting to an rvalue. | |
435 | let self_datum = unpack_datum!( | |
436 | bcx, expr::trans(bcx, self_expr)); | |
437 | ||
c34b1796 | 438 | let llval = if bcx.fcx.type_needs_drop(self_datum.ty) { |
1a4d82fc JJ |
439 | let self_datum = unpack_datum!( |
440 | bcx, self_datum.to_rvalue_datum(bcx, "trait_callee")); | |
441 | ||
442 | // Convert to by-ref since `trans_trait_callee_from_llval` wants it | |
443 | // that way. | |
444 | let self_datum = unpack_datum!( | |
445 | bcx, self_datum.to_ref_datum(bcx)); | |
446 | ||
447 | // Arrange cleanup in case something should go wrong before the | |
448 | // actual call occurs. | |
449 | self_datum.add_clean(bcx.fcx, arg_cleanup_scope) | |
450 | } else { | |
451 | // We don't have to do anything about cleanups for &Trait and &mut Trait. | |
452 | assert!(self_datum.kind.is_by_ref()); | |
453 | self_datum.val | |
454 | }; | |
455 | ||
62682a34 SL |
456 | let llself = Load(bcx, GEPi(bcx, llval, &[0, abi::FAT_PTR_ADDR])); |
457 | let llvtable = Load(bcx, GEPi(bcx, llval, &[0, abi::FAT_PTR_EXTRA])); | |
c1a9b12d | 458 | trans_trait_callee_from_llval(bcx, opaque_fn_ty, vtable_index, llself, llvtable) |
1a4d82fc JJ |
459 | } |
460 | ||
461 | /// Same as `trans_trait_callee()` above, except that it is given a by-ref pointer to the object | |
462 | /// pair. | |
c1a9b12d SL |
463 | fn trans_trait_callee_from_llval<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, |
464 | opaque_fn_ty: Ty<'tcx>, | |
465 | vtable_index: usize, | |
466 | llself: ValueRef, | |
467 | llvtable: ValueRef) | |
468 | -> Callee<'blk, 'tcx> { | |
1a4d82fc JJ |
469 | let _icx = push_ctxt("meth::trans_trait_callee"); |
470 | let ccx = bcx.ccx(); | |
471 | ||
472 | // Load the data pointer from the object. | |
62682a34 | 473 | debug!("trans_trait_callee_from_llval(callee_ty={}, vtable_index={}, llself={}, llvtable={})", |
c1a9b12d | 474 | opaque_fn_ty, |
85aaf69f | 475 | vtable_index, |
62682a34 SL |
476 | bcx.val_to_string(llself), |
477 | bcx.val_to_string(llvtable)); | |
1a4d82fc | 478 | |
1a4d82fc | 479 | // Replace the self type (&Self or Box<Self>) with an opaque pointer. |
62682a34 | 480 | let mptr = Load(bcx, GEPi(bcx, llvtable, &[vtable_index + VTABLE_OFFSET])); |
c1a9b12d | 481 | let llcallee_ty = type_of_fn_from_ty(ccx, opaque_fn_ty); |
1a4d82fc | 482 | |
c1a9b12d | 483 | Callee { |
1a4d82fc JJ |
484 | bcx: bcx, |
485 | data: TraitItem(MethodData { | |
62682a34 SL |
486 | llfn: PointerCast(bcx, mptr, llcallee_ty.ptr_to()), |
487 | llself: PointerCast(bcx, llself, Type::i8p(ccx)), | |
c1a9b12d SL |
488 | }), |
489 | ty: opaque_fn_ty | |
490 | } | |
1a4d82fc JJ |
491 | } |
492 | ||
493 | /// Generate a shim function that allows an object type like `SomeTrait` to | |
494 | /// implement the type `SomeTrait`. Imagine a trait definition: | |
495 | /// | |
496 | /// trait SomeTrait { fn get(&self) -> int; ... } | |
497 | /// | |
498 | /// And a generic bit of code: | |
499 | /// | |
500 | /// fn foo<T:SomeTrait>(t: &T) { | |
501 | /// let x = SomeTrait::get; | |
502 | /// x(t) | |
503 | /// } | |
504 | /// | |
505 | /// What is the value of `x` when `foo` is invoked with `T=SomeTrait`? | |
506 | /// The answer is that it it is a shim function generate by this | |
507 | /// routine: | |
508 | /// | |
509 | /// fn shim(t: &SomeTrait) -> int { | |
510 | /// // ... call t.get() virtually ... | |
511 | /// } | |
512 | /// | |
513 | /// In fact, all virtual calls can be thought of as normal trait calls | |
514 | /// that go through this shim function. | |
c1a9b12d | 515 | fn trans_object_shim<'a, 'tcx>( |
1a4d82fc | 516 | ccx: &'a CrateContext<'a, 'tcx>, |
c34b1796 | 517 | upcast_trait_ref: ty::PolyTraitRef<'tcx>, |
c1a9b12d SL |
518 | method_id: ast::DefId, |
519 | vtable_index: usize) | |
520 | -> Datum<'tcx, Rvalue> | |
1a4d82fc JJ |
521 | { |
522 | let _icx = push_ctxt("trans_object_shim"); | |
523 | let tcx = ccx.tcx(); | |
524 | ||
c1a9b12d | 525 | debug!("trans_object_shim(upcast_trait_ref={:?}, method_id={:?})", |
62682a34 | 526 | upcast_trait_ref, |
c1a9b12d | 527 | method_id); |
1a4d82fc JJ |
528 | |
529 | // Upcast to the trait in question and extract out the substitutions. | |
c1a9b12d | 530 | let upcast_trait_ref = tcx.erase_late_bound_regions(&upcast_trait_ref); |
1a4d82fc | 531 | let object_substs = upcast_trait_ref.substs.clone().erase_regions(); |
62682a34 | 532 | debug!("trans_object_shim: object_substs={:?}", object_substs); |
1a4d82fc JJ |
533 | |
534 | // Lookup the type of this method as declared in the trait and apply substitutions. | |
c1a9b12d | 535 | let method_ty = match tcx.impl_or_trait_item(method_id) { |
1a4d82fc | 536 | ty::MethodTraitItem(method) => method, |
d9579d0f AL |
537 | _ => { |
538 | tcx.sess.bug("can't create a method shim for a non-method item") | |
1a4d82fc JJ |
539 | } |
540 | }; | |
85aaf69f | 541 | let fty = monomorphize::apply_param_substs(tcx, &object_substs, &method_ty.fty); |
1a4d82fc | 542 | let fty = tcx.mk_bare_fn(fty); |
c34b1796 | 543 | let method_ty = opaque_method_ty(tcx, fty); |
62682a34 | 544 | debug!("trans_object_shim: fty={:?} method_ty={:?}", fty, method_ty); |
1a4d82fc JJ |
545 | |
546 | // | |
c1a9b12d SL |
547 | let shim_fn_ty = tcx.mk_fn(None, fty); |
548 | let method_bare_fn_ty = tcx.mk_fn(None, method_ty); | |
9346a6ac | 549 | let function_name = link::mangle_internal_name_by_type_and_seq(ccx, shim_fn_ty, "object_shim"); |
c1a9b12d | 550 | let llfn = declare::define_internal_rust_fn(ccx, &function_name, shim_fn_ty); |
1a4d82fc | 551 | |
c1a9b12d | 552 | let sig = ccx.tcx().erase_late_bound_regions(&fty.sig); |
1a4d82fc | 553 | |
85aaf69f SL |
554 | let empty_substs = tcx.mk_substs(Substs::trans_empty()); |
555 | let (block_arena, fcx): (TypedArena<_>, FunctionContext); | |
556 | block_arena = TypedArena::new(); | |
557 | fcx = new_fn_ctxt(ccx, | |
558 | llfn, | |
559 | ast::DUMMY_NODE_ID, | |
560 | false, | |
561 | sig.output, | |
562 | empty_substs, | |
563 | None, | |
564 | &block_arena); | |
1a4d82fc JJ |
565 | let mut bcx = init_function(&fcx, false, sig.output); |
566 | ||
62682a34 | 567 | let llargs = get_params(fcx.llfn); |
1a4d82fc | 568 | |
62682a34 SL |
569 | let self_idx = fcx.arg_offset(); |
570 | let llself = llargs[self_idx]; | |
571 | let llvtable = llargs[self_idx + 1]; | |
572 | ||
573 | debug!("trans_object_shim: llself={}, llvtable={}", | |
574 | bcx.val_to_string(llself), bcx.val_to_string(llvtable)); | |
1a4d82fc JJ |
575 | |
576 | assert!(!fcx.needs_ret_allocas); | |
577 | ||
1a4d82fc JJ |
578 | let dest = |
579 | fcx.llretslotptr.get().map( | |
580 | |_| expr::SaveIn(fcx.get_ret_slot(bcx, sig.output, "ret_slot"))); | |
581 | ||
1a4d82fc | 582 | debug!("trans_object_shim: method_offset_in_vtable={}", |
c1a9b12d | 583 | vtable_index); |
1a4d82fc JJ |
584 | |
585 | bcx = trans_call_inner(bcx, | |
85aaf69f | 586 | DebugLoc::None, |
1a4d82fc JJ |
587 | |bcx, _| trans_trait_callee_from_llval(bcx, |
588 | method_bare_fn_ty, | |
c1a9b12d | 589 | vtable_index, |
62682a34 SL |
590 | llself, llvtable), |
591 | ArgVals(&llargs[(self_idx + 2)..]), | |
1a4d82fc JJ |
592 | dest).bcx; |
593 | ||
85aaf69f | 594 | finish_fn(&fcx, bcx, sig.output, DebugLoc::None); |
1a4d82fc | 595 | |
c1a9b12d | 596 | immediate_rvalue(llfn, shim_fn_ty) |
1a4d82fc JJ |
597 | } |
598 | ||
599 | /// Creates a returns a dynamic vtable for the given type and vtable origin. | |
600 | /// This is used only for objects. | |
601 | /// | |
602 | /// The `trait_ref` encodes the erased self type. Hence if we are | |
603 | /// making an object `Foo<Trait>` from a value of type `Foo<T>`, then | |
c34b1796 | 604 | /// `trait_ref` would map `T:Trait`. |
85aaf69f | 605 | pub fn get_vtable<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, |
85aaf69f SL |
606 | trait_ref: ty::PolyTraitRef<'tcx>, |
607 | param_substs: &'tcx subst::Substs<'tcx>) | |
608 | -> ValueRef | |
1a4d82fc | 609 | { |
85aaf69f | 610 | let tcx = ccx.tcx(); |
1a4d82fc JJ |
611 | let _icx = push_ctxt("meth::get_vtable"); |
612 | ||
62682a34 | 613 | debug!("get_vtable(trait_ref={:?})", trait_ref); |
85aaf69f | 614 | |
1a4d82fc | 615 | // Check the cache. |
c34b1796 | 616 | match ccx.vtables().borrow().get(&trait_ref) { |
1a4d82fc JJ |
617 | Some(&val) => { return val } |
618 | None => { } | |
619 | } | |
620 | ||
621 | // Not in the cache. Build it. | |
622 | let methods = traits::supertraits(tcx, trait_ref.clone()).flat_map(|trait_ref| { | |
85aaf69f | 623 | let vtable = fulfill_obligation(ccx, DUMMY_SP, trait_ref.clone()); |
1a4d82fc | 624 | match vtable { |
c34b1796 AL |
625 | // Should default trait error here? |
626 | traits::VtableDefaultImpl(_) | | |
1a4d82fc JJ |
627 | traits::VtableBuiltin(_) => { |
628 | Vec::new().into_iter() | |
629 | } | |
630 | traits::VtableImpl( | |
631 | traits::VtableImplData { | |
632 | impl_def_id: id, | |
633 | substs, | |
634 | nested: _ }) => { | |
85aaf69f | 635 | emit_vtable_methods(ccx, id, substs, param_substs).into_iter() |
1a4d82fc | 636 | } |
62682a34 SL |
637 | traits::VtableClosure( |
638 | traits::VtableClosureData { | |
639 | closure_def_id, | |
640 | substs, | |
641 | nested: _ }) => { | |
c34b1796 AL |
642 | let trait_closure_kind = tcx.lang_items.fn_trait_kind(trait_ref.def_id()).unwrap(); |
643 | let llfn = closure::trans_closure_method(ccx, | |
644 | closure_def_id, | |
645 | substs, | |
c34b1796 | 646 | trait_closure_kind); |
85aaf69f | 647 | vec![llfn].into_iter() |
1a4d82fc JJ |
648 | } |
649 | traits::VtableFnPointer(bare_fn_ty) => { | |
c34b1796 AL |
650 | let trait_closure_kind = tcx.lang_items.fn_trait_kind(trait_ref.def_id()).unwrap(); |
651 | vec![trans_fn_pointer_shim(ccx, trait_closure_kind, bare_fn_ty)].into_iter() | |
1a4d82fc JJ |
652 | } |
653 | traits::VtableObject(ref data) => { | |
654 | // this would imply that the Self type being erased is | |
655 | // an object type; this cannot happen because we | |
656 | // cannot cast an unsized type into a trait object | |
85aaf69f | 657 | tcx.sess.bug( |
62682a34 SL |
658 | &format!("cannot get vtable for an object type: {:?}", |
659 | data)); | |
1a4d82fc | 660 | } |
85aaf69f SL |
661 | traits::VtableParam(..) => { |
662 | tcx.sess.bug( | |
62682a34 SL |
663 | &format!("resolved vtable for {:?} to bad vtable {:?} in trans", |
664 | trait_ref, | |
665 | vtable)); | |
1a4d82fc JJ |
666 | } |
667 | } | |
668 | }); | |
669 | ||
670 | let size_ty = sizing_type_of(ccx, trait_ref.self_ty()); | |
671 | let size = machine::llsize_of_alloc(ccx, size_ty); | |
1a4d82fc | 672 | let align = align_of(ccx, trait_ref.self_ty()); |
1a4d82fc | 673 | |
85aaf69f SL |
674 | let components: Vec<_> = vec![ |
675 | // Generate a destructor for the vtable. | |
c34b1796 | 676 | glue::get_drop_glue(ccx, trait_ref.self_ty()), |
85aaf69f SL |
677 | C_uint(ccx, size), |
678 | C_uint(ccx, align) | |
679 | ].into_iter().chain(methods).collect(); | |
680 | ||
9346a6ac | 681 | let vtable = consts::addr_of(ccx, C_struct(ccx, &components, false), "vtable"); |
1a4d82fc | 682 | |
c34b1796 | 683 | ccx.vtables().borrow_mut().insert(trait_ref, vtable); |
1a4d82fc JJ |
684 | vtable |
685 | } | |
686 | ||
85aaf69f SL |
687 | fn emit_vtable_methods<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, |
688 | impl_id: ast::DefId, | |
689 | substs: subst::Substs<'tcx>, | |
690 | param_substs: &'tcx subst::Substs<'tcx>) | |
c34b1796 AL |
691 | -> Vec<ValueRef> |
692 | { | |
1a4d82fc JJ |
693 | let tcx = ccx.tcx(); |
694 | ||
62682a34 SL |
695 | debug!("emit_vtable_methods(impl_id={:?}, substs={:?}, param_substs={:?})", |
696 | impl_id, | |
697 | substs, | |
698 | param_substs); | |
c34b1796 | 699 | |
c1a9b12d | 700 | let trt_id = match tcx.impl_trait_ref(impl_id) { |
1a4d82fc JJ |
701 | Some(t_id) => t_id.def_id, |
702 | None => ccx.sess().bug("make_impl_vtable: don't know how to \ | |
703 | make a vtable for a type impl!") | |
704 | }; | |
705 | ||
c1a9b12d | 706 | tcx.populate_implementations_for_trait_if_necessary(trt_id); |
1a4d82fc | 707 | |
c34b1796 | 708 | let nullptr = C_null(Type::nil(ccx).ptr_to()); |
c1a9b12d | 709 | let trait_item_def_ids = tcx.trait_item_def_ids(trt_id); |
c34b1796 AL |
710 | trait_item_def_ids |
711 | .iter() | |
712 | ||
d9579d0f | 713 | // Filter out non-method items. |
c34b1796 AL |
714 | .filter_map(|item_def_id| { |
715 | match *item_def_id { | |
716 | ty::MethodTraitItemId(def_id) => Some(def_id), | |
d9579d0f | 717 | _ => None, |
1a4d82fc | 718 | } |
c34b1796 | 719 | }) |
1a4d82fc | 720 | |
c34b1796 AL |
721 | // Now produce pointers for each remaining method. If the |
722 | // method could never be called from this object, just supply | |
723 | // null. | |
724 | .map(|trait_method_def_id| { | |
62682a34 SL |
725 | debug!("emit_vtable_methods: trait_method_def_id={:?}", |
726 | trait_method_def_id); | |
1a4d82fc | 727 | |
c1a9b12d | 728 | let trait_method_type = match tcx.impl_or_trait_item(trait_method_def_id) { |
c34b1796 | 729 | ty::MethodTraitItem(m) => m, |
d9579d0f | 730 | _ => ccx.sess().bug("should be a method, not other assoc item"), |
c34b1796 AL |
731 | }; |
732 | let name = trait_method_type.name; | |
733 | ||
734 | // Some methods cannot be called on an object; skip those. | |
735 | if !traits::is_vtable_safe_method(tcx, trt_id, &trait_method_type) { | |
736 | debug!("emit_vtable_methods: not vtable safe"); | |
737 | return nullptr; | |
738 | } | |
1a4d82fc | 739 | |
62682a34 SL |
740 | debug!("emit_vtable_methods: trait_method_type={:?}", |
741 | trait_method_type); | |
1a4d82fc | 742 | |
c34b1796 AL |
743 | // The substitutions we have are on the impl, so we grab |
744 | // the method type from the impl to substitute into. | |
745 | let impl_method_def_id = method_with_name(ccx, impl_id, name); | |
c1a9b12d | 746 | let impl_method_type = match tcx.impl_or_trait_item(impl_method_def_id) { |
c34b1796 | 747 | ty::MethodTraitItem(m) => m, |
d9579d0f | 748 | _ => ccx.sess().bug("should be a method, not other assoc item"), |
c34b1796 | 749 | }; |
1a4d82fc | 750 | |
62682a34 SL |
751 | debug!("emit_vtable_methods: impl_method_type={:?}", |
752 | impl_method_type); | |
c34b1796 AL |
753 | |
754 | // If this is a default method, it's possible that it | |
755 | // relies on where clauses that do not hold for this | |
756 | // particular set of type parameters. Note that this | |
757 | // method could then never be called, so we do not want to | |
758 | // try and trans it, in that case. Issue #23435. | |
c1a9b12d | 759 | if tcx.provided_source(impl_method_def_id).is_some() { |
c34b1796 AL |
760 | let predicates = impl_method_type.predicates.predicates.subst(tcx, &substs); |
761 | if !normalize_and_test_predicates(ccx, predicates.into_vec()) { | |
762 | debug!("emit_vtable_methods: predicates do not hold"); | |
763 | return nullptr; | |
764 | } | |
765 | } | |
1a4d82fc | 766 | |
c34b1796 AL |
767 | trans_fn_ref_with_substs(ccx, |
768 | impl_method_def_id, | |
769 | ExprId(0), | |
770 | param_substs, | |
771 | substs.clone()).val | |
772 | }) | |
773 | .collect() | |
774 | } | |
1a4d82fc | 775 | |
c34b1796 | 776 | /// Replace the self type (&Self or Box<Self>) with an opaque pointer. |
c1a9b12d SL |
777 | fn opaque_method_ty<'tcx>(tcx: &ty::ctxt<'tcx>, method_ty: &ty::BareFnTy<'tcx>) |
778 | -> &'tcx ty::BareFnTy<'tcx> { | |
c34b1796 | 779 | let mut inputs = method_ty.sig.0.inputs.clone(); |
c1a9b12d | 780 | inputs[0] = tcx.mk_mut_ptr(tcx.mk_mach_int(ast::TyI8)); |
c34b1796 AL |
781 | |
782 | tcx.mk_bare_fn(ty::BareFnTy { | |
783 | unsafety: method_ty.unsafety, | |
784 | abi: method_ty.abi, | |
785 | sig: ty::Binder(ty::FnSig { | |
786 | inputs: inputs, | |
787 | output: method_ty.sig.0.output, | |
788 | variadic: method_ty.sig.0.variadic, | |
789 | }), | |
790 | }) | |
1a4d82fc | 791 | } |