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