2012-12-03 18:48:01 -06:00
|
|
|
// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
|
|
|
|
// file at the top-level directory of this distribution and at
|
|
|
|
// http://rust-lang.org/COPYRIGHT.
|
|
|
|
//
|
|
|
|
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
|
|
|
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
|
|
|
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
|
|
|
// option. This file may not be copied, modified, or distributed
|
|
|
|
// except according to those terms.
|
|
|
|
|
2014-12-23 04:26:34 -06:00
|
|
|
use arena::TypedArena;
|
2013-03-26 15:38:07 -05:00
|
|
|
use back::abi;
|
2014-12-23 04:26:34 -06:00
|
|
|
use back::link;
|
2015-01-29 06:03:34 -06:00
|
|
|
use llvm::{ValueRef, get_param};
|
2012-12-13 15:05:22 -06:00
|
|
|
use metadata::csearch;
|
2015-03-18 14:26:38 -05:00
|
|
|
use middle::subst::{Subst, Substs};
|
2014-05-29 00:26:56 -05:00
|
|
|
use middle::subst::VecPerParamSpace;
|
2014-05-13 10:35:42 -05:00
|
|
|
use middle::subst;
|
2014-09-12 10:42:58 -05:00
|
|
|
use middle::traits;
|
2015-02-15 14:09:26 -06:00
|
|
|
use middle::ty::ClosureTyper;
|
2014-11-15 19:30:33 -06:00
|
|
|
use trans::base::*;
|
|
|
|
use trans::build::*;
|
|
|
|
use trans::callee::*;
|
|
|
|
use trans::callee;
|
|
|
|
use trans::cleanup;
|
2015-02-15 14:09:26 -06:00
|
|
|
use trans::closure;
|
2014-11-15 19:30:33 -06:00
|
|
|
use trans::common::*;
|
2015-01-29 06:03:34 -06:00
|
|
|
use trans::consts;
|
2014-11-15 19:30:33 -06:00
|
|
|
use trans::datum::*;
|
2014-12-11 06:53:30 -06:00
|
|
|
use trans::debuginfo::DebugLoc;
|
2015-03-03 17:08:06 -06:00
|
|
|
use trans::declare;
|
Add trivial cast lints.
This permits all coercions to be performed in casts, but adds lints to warn in those cases.
Part of this patch moves cast checking to a later stage of type checking. We acquire obligations to check casts as part of type checking where we previously checked them. Once we have type checked a function or module, then we check any cast obligations which have been acquired. That means we have more type information available to check casts (this was crucial to making coercions work properly in place of some casts), but it means that casts cannot feed input into type inference.
[breaking change]
* Adds two new lints for trivial casts and trivial numeric casts, these are warn by default, but can cause errors if you build with warnings as errors. Previously, trivial numeric casts and casts to trait objects were allowed.
* The unused casts lint has gone.
* Interactions between casting and type inference have changed in subtle ways. Two ways this might manifest are:
- You may need to 'direct' casts more with extra type information, for example, in some cases where `foo as _ as T` succeeded, you may now need to specify the type for `_`
- Casts do not influence inference of integer types. E.g., the following used to type check:
```
let x = 42;
let y = &x as *const u32;
```
Because the cast would inform inference that `x` must have type `u32`. This no longer applies and the compiler will fallback to `i32` for `x` and thus there will be a type error in the cast. The solution is to add more type information:
```
let x: u32 = 42;
let y = &x as *const u32;
```
2015-03-19 23:15:27 -05:00
|
|
|
use trans::expr::SaveIn;
|
2014-11-15 19:30:33 -06:00
|
|
|
use trans::expr;
|
|
|
|
use trans::glue;
|
|
|
|
use trans::machine;
|
2015-01-11 14:18:06 -06:00
|
|
|
use trans::monomorphize;
|
2014-11-15 19:30:33 -06:00
|
|
|
use trans::type_::Type;
|
|
|
|
use trans::type_of::*;
|
2015-01-03 21:42:21 -06:00
|
|
|
use middle::ty::{self, Ty};
|
2014-11-25 13:21:20 -06:00
|
|
|
use middle::ty::MethodCall;
|
2013-06-29 00:07:24 -05:00
|
|
|
use util::ppaux::Repr;
|
2012-12-13 15:05:22 -06:00
|
|
|
|
2014-05-29 00:26:56 -05:00
|
|
|
use syntax::abi::{Rust, RustCall};
|
2013-09-07 01:56:17 -05:00
|
|
|
use syntax::parse::token;
|
2014-08-01 14:27:12 -05:00
|
|
|
use syntax::{ast, ast_map, attr, visit};
|
2014-09-12 10:42:58 -05:00
|
|
|
use syntax::codemap::DUMMY_SP;
|
2015-03-04 20:48:54 -06:00
|
|
|
use syntax::ptr::P;
|
2012-08-28 17:54:45 -05:00
|
|
|
|
2014-08-06 04:59:40 -05:00
|
|
|
// drop_glue pointer, size, align.
|
2015-03-25 19:06:52 -05:00
|
|
|
const VTABLE_OFFSET: usize = 3;
|
2014-08-06 04:59:40 -05:00
|
|
|
|
2014-11-24 19:06:06 -06:00
|
|
|
/// The main "translation" pass for methods. Generates code
|
|
|
|
/// for non-monomorphized methods only. Other methods will
|
|
|
|
/// be generated once they are invoked with specific type parameters,
|
|
|
|
/// see `trans::base::lval_static_fn()` or `trans::base::monomorphic_fn()`.
|
2014-03-06 10:47:24 -06:00
|
|
|
pub fn trans_impl(ccx: &CrateContext,
|
2013-09-01 19:50:59 -05:00
|
|
|
name: ast::Ident,
|
2015-03-04 20:48:54 -06:00
|
|
|
impl_items: &[P<ast::ImplItem>],
|
2013-05-15 19:38:52 -05:00
|
|
|
generics: &ast::Generics,
|
2013-07-27 03:25:59 -05:00
|
|
|
id: ast::NodeId) {
|
2014-01-27 06:18:36 -06:00
|
|
|
let _icx = push_ctxt("meth::trans_impl");
|
2014-03-15 15:29:34 -05:00
|
|
|
let tcx = ccx.tcx();
|
2013-03-15 14:24:24 -05:00
|
|
|
|
2014-10-15 01:25:34 -05:00
|
|
|
debug!("trans_impl(name={}, id={})", name.repr(tcx), id);
|
2013-03-15 14:24:24 -05:00
|
|
|
|
2015-03-10 05:28:44 -05:00
|
|
|
let mut v = TransItemVisitor { ccx: ccx };
|
|
|
|
|
2013-08-29 01:28:06 -05:00
|
|
|
// Both here and below with generic methods, be sure to recurse and look for
|
|
|
|
// items that we need to translate.
|
|
|
|
if !generics.ty_params.is_empty() {
|
2015-01-31 11:20:46 -06:00
|
|
|
for impl_item in impl_items {
|
2015-03-10 05:28:44 -05:00
|
|
|
match impl_item.node {
|
2015-03-11 16:38:58 -05:00
|
|
|
ast::MethodImplItem(..) => {
|
2015-03-10 05:28:44 -05:00
|
|
|
visit::walk_impl_item(&mut v, impl_item);
|
2014-08-04 15:56:56 -05:00
|
|
|
}
|
2015-03-14 13:05:00 -05:00
|
|
|
_ => {}
|
2014-08-04 15:56:56 -05:00
|
|
|
}
|
2013-08-29 01:28:06 -05:00
|
|
|
}
|
|
|
|
return;
|
|
|
|
}
|
2015-01-31 11:20:46 -06:00
|
|
|
for impl_item in impl_items {
|
2015-03-10 05:28:44 -05:00
|
|
|
match impl_item.node {
|
2015-03-11 16:38:58 -05:00
|
|
|
ast::MethodImplItem(ref sig, ref body) => {
|
2015-03-24 18:53:34 -05:00
|
|
|
if sig.generics.ty_params.is_empty() {
|
2015-03-10 05:28:44 -05:00
|
|
|
let trans_everywhere = attr::requests_inline(&impl_item.attrs);
|
2014-08-01 14:27:12 -05:00
|
|
|
for (ref ccx, is_origin) in ccx.maybe_iter(trans_everywhere) {
|
2015-03-10 05:28:44 -05:00
|
|
|
let llfn = get_item_val(ccx, impl_item.id);
|
2015-01-29 06:03:34 -06:00
|
|
|
let empty_substs = tcx.mk_substs(Substs::trans_empty());
|
2015-03-11 16:38:58 -05:00
|
|
|
trans_fn(ccx, &sig.decl, body, llfn,
|
|
|
|
empty_substs, impl_item.id, &[]);
|
2014-08-01 14:27:12 -05:00
|
|
|
update_linkage(ccx,
|
|
|
|
llfn,
|
2015-03-10 05:28:44 -05:00
|
|
|
Some(impl_item.id),
|
2014-08-01 14:27:12 -05:00
|
|
|
if is_origin { OriginalTranslation } else { InlinedCopy });
|
|
|
|
}
|
2014-08-04 15:56:56 -05:00
|
|
|
}
|
2015-03-10 05:28:44 -05:00
|
|
|
visit::walk_impl_item(&mut v, impl_item);
|
2014-08-04 15:56:56 -05:00
|
|
|
}
|
2015-03-14 13:05:00 -05:00
|
|
|
_ => {}
|
2012-03-08 06:30:22 -06:00
|
|
|
}
|
2012-01-02 05:21:44 -06:00
|
|
|
}
|
|
|
|
}
|
2012-01-02 06:26:51 -06:00
|
|
|
|
2014-09-06 11:13:04 -05:00
|
|
|
pub fn trans_method_callee<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
|
|
|
|
method_call: MethodCall,
|
|
|
|
self_expr: Option<&ast::Expr>,
|
|
|
|
arg_cleanup_scope: cleanup::ScopeId)
|
|
|
|
-> Callee<'blk, 'tcx> {
|
2014-01-27 06:18:36 -06:00
|
|
|
let _icx = push_ctxt("meth::trans_method_callee");
|
2012-10-08 14:39:30 -05:00
|
|
|
|
2014-09-12 10:42:58 -05:00
|
|
|
let (origin, method_ty) =
|
|
|
|
bcx.tcx().method_map
|
|
|
|
.borrow()
|
2014-11-06 11:25:16 -06:00
|
|
|
.get(&method_call)
|
2014-09-12 10:42:58 -05:00
|
|
|
.map(|method| (method.origin.clone(), method.ty))
|
|
|
|
.unwrap();
|
2013-03-21 07:33:52 -05:00
|
|
|
|
2014-02-19 14:11:45 -06:00
|
|
|
match origin {
|
2014-11-25 13:21:20 -06:00
|
|
|
ty::MethodStatic(did) |
|
2015-01-24 14:00:03 -06:00
|
|
|
ty::MethodStaticClosure(did) => {
|
2012-08-28 17:54:45 -05:00
|
|
|
Callee {
|
|
|
|
bcx: bcx,
|
2015-01-04 10:47:58 -06:00
|
|
|
data: Fn(callee::trans_fn_ref(bcx.ccx(),
|
2014-05-29 00:26:56 -05:00
|
|
|
did,
|
2015-01-04 10:47:58 -06:00
|
|
|
MethodCallKey(method_call),
|
|
|
|
bcx.fcx.param_substs).val),
|
2012-08-28 17:54:45 -05:00
|
|
|
}
|
|
|
|
}
|
2014-09-12 10:42:58 -05:00
|
|
|
|
2014-11-25 13:21:20 -06:00
|
|
|
ty::MethodTypeParam(ty::MethodParam {
|
2014-10-05 19:36:53 -05:00
|
|
|
ref trait_ref,
|
2014-12-31 10:03:14 -06:00
|
|
|
method_num,
|
|
|
|
impl_def_id: _
|
2013-01-16 21:24:10 -06:00
|
|
|
}) => {
|
2014-12-17 13:16:28 -06:00
|
|
|
let trait_ref = ty::Binder(bcx.monomorphize(trait_ref));
|
2014-09-12 10:42:58 -05:00
|
|
|
let span = bcx.tcx().map.span(method_call.expr_id);
|
2014-12-20 02:09:35 -06:00
|
|
|
debug!("method_call={:?} trait_ref={}",
|
2014-11-15 15:50:34 -06:00
|
|
|
method_call,
|
|
|
|
trait_ref.repr(bcx.tcx()));
|
2014-09-12 10:42:58 -05:00
|
|
|
let origin = fulfill_obligation(bcx.ccx(),
|
|
|
|
span,
|
2014-12-14 06:17:23 -06:00
|
|
|
trait_ref.clone());
|
2014-09-12 10:42:58 -05:00
|
|
|
debug!("origin = {}", origin.repr(bcx.tcx()));
|
2014-12-17 13:16:28 -06:00
|
|
|
trans_monomorphized_callee(bcx,
|
|
|
|
method_call,
|
|
|
|
trait_ref.def_id(),
|
|
|
|
method_num,
|
|
|
|
origin)
|
2012-08-28 17:54:45 -05:00
|
|
|
}
|
2013-06-20 11:29:24 -05:00
|
|
|
|
2014-11-25 13:21:20 -06:00
|
|
|
ty::MethodTraitObject(ref mt) => {
|
2014-03-06 11:24:11 -06:00
|
|
|
let self_expr = match self_expr {
|
|
|
|
Some(self_expr) => self_expr,
|
|
|
|
None => {
|
2014-03-05 08:36:01 -06:00
|
|
|
bcx.sess().span_bug(bcx.tcx().map.span(method_call.expr_id),
|
|
|
|
"self expr wasn't provided for trait object \
|
|
|
|
callee (trying to call overloaded op?)")
|
2014-03-06 11:24:11 -06:00
|
|
|
}
|
|
|
|
};
|
2012-11-28 19:33:30 -06:00
|
|
|
trans_trait_callee(bcx,
|
2014-02-26 08:06:45 -06:00
|
|
|
monomorphize_type(bcx, method_ty),
|
2015-01-11 14:18:06 -06:00
|
|
|
mt.vtable_index,
|
2014-03-06 11:24:11 -06:00
|
|
|
self_expr,
|
2014-01-15 13:39:08 -06:00
|
|
|
arg_cleanup_scope)
|
2012-02-09 04:17:11 -06:00
|
|
|
}
|
2012-01-26 05:26:14 -06:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-01-04 10:47:58 -06:00
|
|
|
pub fn trans_static_method_callee<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
|
|
|
|
method_id: ast::DefId,
|
|
|
|
trait_id: ast::DefId,
|
|
|
|
expr_id: ast::NodeId,
|
2015-01-29 06:03:34 -06:00
|
|
|
param_substs: &'tcx subst::Substs<'tcx>)
|
2015-01-04 10:47:58 -06:00
|
|
|
-> Datum<'tcx, Rvalue>
|
2014-09-12 10:42:58 -05:00
|
|
|
{
|
2014-01-27 06:18:36 -06:00
|
|
|
let _icx = push_ctxt("meth::trans_static_method_callee");
|
2015-01-04 10:47:58 -06:00
|
|
|
let tcx = ccx.tcx();
|
2012-08-02 18:01:38 -05:00
|
|
|
|
2014-12-20 02:09:35 -06:00
|
|
|
debug!("trans_static_method_callee(method_id={:?}, trait_id={}, \
|
2014-10-15 01:25:34 -05:00
|
|
|
expr_id={})",
|
2012-10-12 19:00:08 -05:00
|
|
|
method_id,
|
2015-01-04 10:47:58 -06:00
|
|
|
ty::item_path_str(tcx, trait_id),
|
2014-02-26 08:06:45 -06:00
|
|
|
expr_id);
|
2013-08-23 16:34:00 -05:00
|
|
|
|
2014-02-05 15:15:24 -06:00
|
|
|
let mname = if method_id.krate == ast::LOCAL_CRATE {
|
2015-01-04 10:47:58 -06:00
|
|
|
match tcx.map.get(method_id.node) {
|
2015-03-10 05:28:44 -05:00
|
|
|
ast_map::NodeTraitItem(trait_item) => trait_item.ident.name,
|
2014-10-09 14:17:22 -05:00
|
|
|
_ => panic!("callee is not a trait method")
|
2012-08-02 18:01:38 -05:00
|
|
|
}
|
|
|
|
} else {
|
2015-01-04 10:47:58 -06:00
|
|
|
csearch::get_item_path(tcx, method_id).last().unwrap().name()
|
2012-08-02 18:01:38 -05:00
|
|
|
};
|
2014-12-20 02:09:35 -06:00
|
|
|
debug!("trans_static_method_callee: method_id={:?}, expr_id={}, \
|
2014-02-26 08:06:45 -06:00
|
|
|
name={}", method_id, expr_id, token::get_name(mname));
|
2012-08-02 18:01:38 -05:00
|
|
|
|
2014-09-12 10:42:58 -05:00
|
|
|
// Find the substitutions for the fn itself. This includes
|
|
|
|
// type parameters that belong to the trait but also some that
|
|
|
|
// belong to the method:
|
2015-01-04 10:47:58 -06:00
|
|
|
let rcvr_substs = node_id_substs(ccx, ExprId(expr_id), param_substs);
|
2014-11-03 16:36:30 -06:00
|
|
|
let subst::SeparateVecsPerParamSpace {
|
|
|
|
types: rcvr_type,
|
|
|
|
selfs: rcvr_self,
|
|
|
|
fns: rcvr_method
|
|
|
|
} = rcvr_substs.types.split();
|
2014-09-12 10:42:58 -05:00
|
|
|
|
|
|
|
// Lookup the precise impl being called. To do that, we need to
|
|
|
|
// create a trait reference identifying the self type and other
|
|
|
|
// input type parameters. To create that trait reference, we have
|
|
|
|
// to pick apart the type parameters to identify just those that
|
|
|
|
// pertain to the trait. This is easiest to explain by example:
|
|
|
|
//
|
|
|
|
// trait Convert {
|
|
|
|
// fn from<U:Foo>(n: U) -> Option<Self>;
|
|
|
|
// }
|
|
|
|
// ...
|
|
|
|
// let f = <Vec<int> as Convert>::from::<String>(...)
|
|
|
|
//
|
|
|
|
// Here, in this call, which I've written with explicit UFCS
|
|
|
|
// notation, the set of type parameters will be:
|
|
|
|
//
|
2015-01-07 10:58:31 -06:00
|
|
|
// rcvr_type: [] <-- nothing declared on the trait itself
|
2014-09-12 10:42:58 -05:00
|
|
|
// rcvr_self: [Vec<int>] <-- the self type
|
|
|
|
// rcvr_method: [String] <-- method type parameter
|
|
|
|
//
|
|
|
|
// So we create a trait reference using the first two,
|
|
|
|
// basically corresponding to `<Vec<int> as Convert>`.
|
|
|
|
// The remaining type parameters (`rcvr_method`) will be used below.
|
|
|
|
let trait_substs =
|
|
|
|
Substs::erased(VecPerParamSpace::new(rcvr_type,
|
|
|
|
rcvr_self,
|
|
|
|
Vec::new()));
|
2015-01-04 10:47:58 -06:00
|
|
|
let trait_substs = tcx.mk_substs(trait_substs);
|
|
|
|
debug!("trait_substs={}", trait_substs.repr(tcx));
|
2015-04-21 10:59:58 -05:00
|
|
|
let trait_ref = ty::Binder(ty::TraitRef { def_id: trait_id,
|
|
|
|
substs: trait_substs });
|
2015-01-04 10:47:58 -06:00
|
|
|
let vtbl = fulfill_obligation(ccx,
|
2014-09-12 10:42:58 -05:00
|
|
|
DUMMY_SP,
|
|
|
|
trait_ref);
|
|
|
|
|
|
|
|
// Now that we know which impl is being used, we can dispatch to
|
|
|
|
// the actual function:
|
|
|
|
match vtbl {
|
2014-09-11 00:07:49 -05:00
|
|
|
traits::VtableImpl(traits::VtableImplData {
|
2014-09-12 10:42:58 -05:00
|
|
|
impl_def_id: impl_did,
|
|
|
|
substs: impl_substs,
|
|
|
|
nested: _ }) =>
|
|
|
|
{
|
|
|
|
assert!(impl_substs.types.all(|t| !ty::type_needs_infer(*t)));
|
|
|
|
|
|
|
|
// Create the substitutions that are in scope. This combines
|
|
|
|
// the type parameters from the impl with those declared earlier.
|
|
|
|
// To see what I mean, consider a possible impl:
|
|
|
|
//
|
|
|
|
// impl<T> Convert for Vec<T> {
|
|
|
|
// fn from<U:Foo>(n: U) { ... }
|
|
|
|
// }
|
|
|
|
//
|
|
|
|
// Recall that we matched `<Vec<int> as Convert>`. Trait
|
|
|
|
// resolution will have given us a substitution
|
2015-01-07 10:58:31 -06:00
|
|
|
// containing `impl_substs=[[T=int],[],[]]` (the type
|
2014-09-12 10:42:58 -05:00
|
|
|
// parameters defined on the impl). We combine
|
|
|
|
// that with the `rcvr_method` from before, which tells us
|
|
|
|
// the type parameters from the *method*, to yield
|
2015-01-07 10:58:31 -06:00
|
|
|
// `callee_substs=[[T=int],[],[U=String]]`.
|
2014-11-03 16:36:30 -06:00
|
|
|
let subst::SeparateVecsPerParamSpace {
|
|
|
|
types: impl_type,
|
|
|
|
selfs: impl_self,
|
|
|
|
fns: _
|
|
|
|
} = impl_substs.types.split();
|
2014-09-12 10:42:58 -05:00
|
|
|
let callee_substs =
|
|
|
|
Substs::erased(VecPerParamSpace::new(impl_type,
|
|
|
|
impl_self,
|
|
|
|
rcvr_method));
|
2012-08-28 17:54:45 -05:00
|
|
|
|
2014-02-13 23:07:09 -06:00
|
|
|
let mth_id = method_with_name(ccx, impl_did, mname);
|
2015-01-04 10:47:58 -06:00
|
|
|
trans_fn_ref_with_substs(ccx, mth_id, ExprId(expr_id),
|
|
|
|
param_substs,
|
|
|
|
callee_substs)
|
2012-08-28 17:54:45 -05:00
|
|
|
}
|
2015-01-13 08:17:07 -06:00
|
|
|
traits::VtableObject(ref data) => {
|
|
|
|
let trait_item_def_ids =
|
|
|
|
ty::trait_item_def_ids(ccx.tcx(), trait_id);
|
|
|
|
let method_offset_in_trait =
|
|
|
|
trait_item_def_ids.iter()
|
|
|
|
.position(|item| item.def_id() == method_id)
|
|
|
|
.unwrap();
|
|
|
|
let (llfn, ty) =
|
2015-03-05 04:46:12 -06:00
|
|
|
trans_object_shim(ccx,
|
|
|
|
data.object_ty,
|
|
|
|
data.upcast_trait_ref.clone(),
|
2015-03-03 07:01:13 -06:00
|
|
|
method_offset_in_trait);
|
2015-01-13 08:17:07 -06:00
|
|
|
immediate_rvalue(llfn, ty)
|
|
|
|
}
|
2012-08-28 17:54:45 -05:00
|
|
|
_ => {
|
2015-01-07 10:58:31 -06:00
|
|
|
tcx.sess.bug(&format!("static call to invalid vtable: {}",
|
2015-02-20 13:08:14 -06:00
|
|
|
vtbl.repr(tcx)));
|
2012-08-28 17:54:45 -05:00
|
|
|
}
|
2012-08-02 18:01:38 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-08-04 15:56:56 -05:00
|
|
|
fn method_with_name(ccx: &CrateContext, impl_id: ast::DefId, name: ast::Name)
|
|
|
|
-> ast::DefId {
|
2014-11-07 13:35:18 -06:00
|
|
|
match ccx.impl_method_cache().borrow().get(&(impl_id, name)).cloned() {
|
2014-03-20 21:49:20 -05:00
|
|
|
Some(m) => return m,
|
|
|
|
None => {}
|
2013-06-12 16:22:17 -05:00
|
|
|
}
|
2013-06-14 00:38:17 -05:00
|
|
|
|
2014-09-05 11:18:53 -05:00
|
|
|
let impl_items = ccx.tcx().impl_items.borrow();
|
2014-08-04 15:56:56 -05:00
|
|
|
let impl_items =
|
2014-11-06 11:25:16 -06:00
|
|
|
impl_items.get(&impl_id)
|
2014-08-04 15:56:56 -05:00
|
|
|
.expect("could not find impl while translating");
|
|
|
|
let meth_did = impl_items.iter()
|
|
|
|
.find(|&did| {
|
2014-09-30 19:11:34 -05:00
|
|
|
ty::impl_or_trait_item(ccx.tcx(), did.def_id()).name() == name
|
2014-08-04 15:56:56 -05:00
|
|
|
}).expect("could not find method while \
|
|
|
|
translating");
|
|
|
|
|
2014-09-05 11:18:53 -05:00
|
|
|
ccx.impl_method_cache().borrow_mut().insert((impl_id, name),
|
2014-08-04 15:56:56 -05:00
|
|
|
meth_did.def_id());
|
|
|
|
meth_did.def_id()
|
2012-03-09 01:44:53 -06:00
|
|
|
}
|
|
|
|
|
2014-09-06 11:13:04 -05:00
|
|
|
fn trans_monomorphized_callee<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
|
|
|
|
method_call: MethodCall,
|
|
|
|
trait_id: ast::DefId,
|
2015-03-25 19:06:52 -05:00
|
|
|
n_method: usize,
|
2014-09-29 14:11:30 -05:00
|
|
|
vtable: traits::Vtable<'tcx, ()>)
|
2014-09-06 11:13:04 -05:00
|
|
|
-> Callee<'blk, 'tcx> {
|
2014-01-27 06:18:36 -06:00
|
|
|
let _icx = push_ctxt("meth::trans_monomorphized_callee");
|
2014-09-12 10:42:58 -05:00
|
|
|
match vtable {
|
|
|
|
traits::VtableImpl(vtable_impl) => {
|
|
|
|
let ccx = bcx.ccx();
|
|
|
|
let impl_did = vtable_impl.impl_def_id;
|
|
|
|
let mname = match ty::trait_item(ccx.tcx(), trait_id, n_method) {
|
2014-09-30 19:11:34 -05:00
|
|
|
ty::MethodTraitItem(method) => method.name,
|
2015-03-14 13:05:00 -05:00
|
|
|
_ => {
|
|
|
|
bcx.tcx().sess.bug("can't monomorphize a non-method trait \
|
|
|
|
item")
|
2014-08-05 21:44:21 -05:00
|
|
|
}
|
2014-09-12 10:42:58 -05:00
|
|
|
};
|
2014-09-30 19:11:34 -05:00
|
|
|
let mth_id = method_with_name(bcx.ccx(), impl_did, mname);
|
2014-09-12 10:42:58 -05:00
|
|
|
|
|
|
|
// create a concatenated set of substitutions which includes
|
|
|
|
// those from the impl and those from the method:
|
|
|
|
let callee_substs =
|
|
|
|
combine_impl_and_methods_tps(
|
2014-12-14 22:03:00 -06:00
|
|
|
bcx, MethodCallKey(method_call), vtable_impl.substs);
|
2014-09-12 10:42:58 -05:00
|
|
|
|
|
|
|
// translate the function
|
2015-01-04 10:47:58 -06:00
|
|
|
let llfn = trans_fn_ref_with_substs(bcx.ccx(),
|
2014-09-12 10:42:58 -05:00
|
|
|
mth_id,
|
2014-12-14 22:03:00 -06:00
|
|
|
MethodCallKey(method_call),
|
2015-01-04 10:47:58 -06:00
|
|
|
bcx.fcx.param_substs,
|
|
|
|
callee_substs).val;
|
2014-09-12 10:42:58 -05:00
|
|
|
|
|
|
|
Callee { bcx: bcx, data: Fn(llfn) }
|
|
|
|
}
|
2015-01-24 14:00:03 -06:00
|
|
|
traits::VtableClosure(closure_def_id, substs) => {
|
2014-11-06 01:50:10 -06:00
|
|
|
// The substitutions should have no type parameters remaining
|
|
|
|
// after passing through fulfill_obligation
|
2015-02-15 14:09:26 -06:00
|
|
|
let trait_closure_kind = bcx.tcx().lang_items.fn_trait_kind(trait_id).unwrap();
|
|
|
|
let llfn = closure::trans_closure_method(bcx.ccx(),
|
|
|
|
closure_def_id,
|
|
|
|
substs,
|
|
|
|
MethodCallKey(method_call),
|
|
|
|
bcx.fcx.param_substs,
|
|
|
|
trait_closure_kind);
|
2014-09-12 10:42:58 -05:00
|
|
|
Callee {
|
|
|
|
bcx: bcx,
|
|
|
|
data: Fn(llfn),
|
|
|
|
}
|
|
|
|
}
|
2014-12-01 08:23:40 -06:00
|
|
|
traits::VtableFnPointer(fn_ty) => {
|
2015-02-15 14:09:26 -06:00
|
|
|
let trait_closure_kind = bcx.tcx().lang_items.fn_trait_kind(trait_id).unwrap();
|
|
|
|
let llfn = trans_fn_pointer_shim(bcx.ccx(), trait_closure_kind, fn_ty);
|
2014-12-01 08:23:40 -06:00
|
|
|
Callee { bcx: bcx, data: Fn(llfn) }
|
|
|
|
}
|
2014-12-23 04:26:34 -06:00
|
|
|
traits::VtableObject(ref data) => {
|
2015-03-05 04:46:12 -06:00
|
|
|
let (llfn, _) = trans_object_shim(bcx.ccx(),
|
|
|
|
data.object_ty,
|
|
|
|
data.upcast_trait_ref.clone(),
|
|
|
|
n_method);
|
2014-12-23 04:26:34 -06:00
|
|
|
Callee { bcx: bcx, data: Fn(llfn) }
|
|
|
|
}
|
2014-12-01 08:23:40 -06:00
|
|
|
traits::VtableBuiltin(..) |
|
2015-02-07 07:24:34 -06:00
|
|
|
traits::VtableDefaultImpl(..) |
|
2014-12-01 08:23:40 -06:00
|
|
|
traits::VtableParam(..) => {
|
|
|
|
bcx.sess().bug(
|
2015-01-07 10:58:31 -06:00
|
|
|
&format!("resolved vtable bad vtable {} in trans",
|
2015-02-20 13:08:14 -06:00
|
|
|
vtable.repr(bcx.tcx())));
|
2014-09-12 10:42:58 -05:00
|
|
|
}
|
2014-02-26 08:06:45 -06:00
|
|
|
}
|
2012-09-10 14:25:45 -05:00
|
|
|
}
|
|
|
|
|
2014-11-25 20:17:11 -06:00
|
|
|
/// Creates a concatenated set of substitutions which includes those from the impl and those from
|
|
|
|
/// the method. This are some subtle complications here. Statically, we have a list of type
|
|
|
|
/// parameters like `[T0, T1, T2, M1, M2, M3]` where `Tn` are type parameters that appear on the
|
|
|
|
/// receiver. For example, if the receiver is a method parameter `A` with a bound like
|
|
|
|
/// `trait<B,C,D>` then `Tn` would be `[B,C,D]`.
|
|
|
|
///
|
|
|
|
/// The weird part is that the type `A` might now be bound to any other type, such as `foo<X>`.
|
|
|
|
/// In that case, the vector we want is: `[X, M1, M2, M3]`. Therefore, what we do now is to slice
|
|
|
|
/// off the method type parameters and append them to the type parameters from the type that the
|
|
|
|
/// receiver is mapped to.
|
2014-09-29 14:11:30 -05:00
|
|
|
fn combine_impl_and_methods_tps<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
|
|
|
|
node: ExprOrMethodCall,
|
|
|
|
rcvr_substs: subst::Substs<'tcx>)
|
|
|
|
-> subst::Substs<'tcx>
|
2014-05-07 06:20:15 -05:00
|
|
|
{
|
2012-09-10 14:25:45 -05:00
|
|
|
let ccx = bcx.ccx();
|
|
|
|
|
2015-01-04 10:47:58 -06:00
|
|
|
let node_substs = node_id_substs(ccx, node, bcx.fcx.param_substs);
|
2014-05-31 17:53:13 -05:00
|
|
|
|
2014-09-12 10:42:58 -05:00
|
|
|
debug!("rcvr_substs={}", rcvr_substs.repr(ccx.tcx()));
|
|
|
|
debug!("node_substs={}", node_substs.repr(ccx.tcx()));
|
2012-09-10 14:25:45 -05:00
|
|
|
|
2014-05-31 17:53:13 -05:00
|
|
|
// Break apart the type parameters from the node and type
|
|
|
|
// parameters from the receiver.
|
2014-11-03 16:36:30 -06:00
|
|
|
let node_method = node_substs.types.split().fns;
|
|
|
|
let subst::SeparateVecsPerParamSpace {
|
|
|
|
types: rcvr_type,
|
|
|
|
selfs: rcvr_self,
|
|
|
|
fns: rcvr_method
|
|
|
|
} = rcvr_substs.types.clone().split();
|
2014-05-31 17:53:13 -05:00
|
|
|
assert!(rcvr_method.is_empty());
|
2014-09-12 10:42:58 -05:00
|
|
|
subst::Substs {
|
2014-05-13 10:35:42 -05:00
|
|
|
regions: subst::ErasedRegions,
|
2014-12-29 15:32:12 -06:00
|
|
|
types: subst::VecPerParamSpace::new(rcvr_type, rcvr_self, node_method)
|
2014-09-12 10:42:58 -05:00
|
|
|
}
|
2012-02-09 04:17:11 -06:00
|
|
|
}
|
|
|
|
|
2014-11-25 20:17:11 -06:00
|
|
|
/// Create a method callee where the method is coming from a trait object (e.g., Box<Trait> type).
|
|
|
|
/// In this case, we must pull the fn pointer out of the vtable that is packaged up with the
|
|
|
|
/// object. Objects are represented as a pair, so we first evaluate the self expression and then
|
|
|
|
/// extract the self data and vtable out of the pair.
|
2014-09-06 11:13:04 -05:00
|
|
|
fn trans_trait_callee<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
|
2014-09-29 14:11:30 -05:00
|
|
|
method_ty: Ty<'tcx>,
|
2015-03-25 19:06:52 -05:00
|
|
|
vtable_index: usize,
|
2014-09-06 11:13:04 -05:00
|
|
|
self_expr: &ast::Expr,
|
|
|
|
arg_cleanup_scope: cleanup::ScopeId)
|
|
|
|
-> Callee<'blk, 'tcx> {
|
2014-01-27 06:18:36 -06:00
|
|
|
let _icx = push_ctxt("meth::trans_trait_callee");
|
2012-08-28 17:54:45 -05:00
|
|
|
let mut bcx = bcx;
|
2013-08-11 12:42:26 -05:00
|
|
|
|
2014-01-15 19:31:20 -06:00
|
|
|
// Translate self_datum and take ownership of the value by
|
|
|
|
// converting to an rvalue.
|
|
|
|
let self_datum = unpack_datum!(
|
|
|
|
bcx, expr::trans(bcx, self_expr));
|
|
|
|
|
2015-02-25 16:09:58 -06:00
|
|
|
let llval = if bcx.fcx.type_needs_drop(self_datum.ty) {
|
2014-02-13 13:52:53 -06:00
|
|
|
let self_datum = unpack_datum!(
|
|
|
|
bcx, self_datum.to_rvalue_datum(bcx, "trait_callee"));
|
|
|
|
|
|
|
|
// Convert to by-ref since `trans_trait_callee_from_llval` wants it
|
|
|
|
// that way.
|
|
|
|
let self_datum = unpack_datum!(
|
|
|
|
bcx, self_datum.to_ref_datum(bcx));
|
2014-01-15 19:31:20 -06:00
|
|
|
|
2014-02-13 13:52:53 -06:00
|
|
|
// Arrange cleanup in case something should go wrong before the
|
|
|
|
// actual call occurs.
|
|
|
|
self_datum.add_clean(bcx.fcx, arg_cleanup_scope)
|
|
|
|
} else {
|
|
|
|
// We don't have to do anything about cleanups for &Trait and &mut Trait.
|
|
|
|
assert!(self_datum.kind.is_by_ref());
|
|
|
|
self_datum.val
|
|
|
|
};
|
2013-08-11 12:42:26 -05:00
|
|
|
|
2015-01-11 14:18:06 -06:00
|
|
|
trans_trait_callee_from_llval(bcx, method_ty, vtable_index, llval)
|
2012-08-28 17:54:45 -05:00
|
|
|
}
|
|
|
|
|
2014-11-25 20:17:11 -06:00
|
|
|
/// Same as `trans_trait_callee()` above, except that it is given a by-ref pointer to the object
|
|
|
|
/// pair.
|
2014-09-06 11:13:04 -05:00
|
|
|
pub fn trans_trait_callee_from_llval<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
|
2014-09-29 14:11:30 -05:00
|
|
|
callee_ty: Ty<'tcx>,
|
2015-03-25 19:06:52 -05:00
|
|
|
vtable_index: usize,
|
2014-09-06 11:13:04 -05:00
|
|
|
llpair: ValueRef)
|
|
|
|
-> Callee<'blk, 'tcx> {
|
2014-01-27 06:18:36 -06:00
|
|
|
let _icx = push_ctxt("meth::trans_trait_callee");
|
2012-05-14 17:48:58 -05:00
|
|
|
let ccx = bcx.ccx();
|
2012-08-28 17:54:45 -05:00
|
|
|
|
2013-08-11 12:42:26 -05:00
|
|
|
// Load the data pointer from the object.
|
2015-01-11 14:18:06 -06:00
|
|
|
debug!("trans_trait_callee_from_llval(callee_ty={}, vtable_index={}, llpair={})",
|
|
|
|
callee_ty.repr(ccx.tcx()),
|
|
|
|
vtable_index,
|
|
|
|
bcx.val_to_string(llpair));
|
2015-01-25 04:58:43 -06:00
|
|
|
let llboxptr = GEPi(bcx, llpair, &[0, abi::FAT_PTR_ADDR]);
|
2013-06-27 18:40:27 -05:00
|
|
|
let llbox = Load(bcx, llboxptr);
|
2014-03-15 15:29:34 -05:00
|
|
|
let llself = PointerCast(bcx, llbox, Type::i8p(ccx));
|
2013-06-29 09:43:39 -05:00
|
|
|
|
2014-05-05 20:56:44 -05:00
|
|
|
// Replace the self type (&Self or Box<Self>) with an opaque pointer.
|
2014-10-31 03:51:16 -05:00
|
|
|
let llcallee_ty = match callee_ty.sty {
|
2014-11-26 05:01:28 -06:00
|
|
|
ty::ty_bare_fn(_, ref f) if f.abi == Rust || f.abi == RustCall => {
|
2015-01-06 04:03:42 -06:00
|
|
|
let fake_sig =
|
|
|
|
ty::Binder(ty::FnSig {
|
2015-01-17 18:15:52 -06:00
|
|
|
inputs: f.sig.0.inputs[1..].to_vec(),
|
2015-01-06 04:03:42 -06:00
|
|
|
output: f.sig.0.output,
|
|
|
|
variadic: f.sig.0.variadic,
|
|
|
|
});
|
2015-01-11 14:18:06 -06:00
|
|
|
type_of_rust_fn(ccx, Some(Type::i8p(ccx)), &fake_sig, f.abi)
|
2014-01-27 06:18:36 -06:00
|
|
|
}
|
|
|
|
_ => {
|
2014-03-05 08:36:01 -06:00
|
|
|
ccx.sess().bug("meth::trans_trait_callee given non-bare-rust-fn");
|
2014-01-27 06:18:36 -06:00
|
|
|
}
|
|
|
|
};
|
2013-08-11 12:42:26 -05:00
|
|
|
let llvtable = Load(bcx,
|
|
|
|
PointerCast(bcx,
|
|
|
|
GEPi(bcx, llpair,
|
2015-01-25 04:58:43 -06:00
|
|
|
&[0, abi::FAT_PTR_EXTRA]),
|
2014-03-15 15:29:34 -05:00
|
|
|
Type::vtable(ccx).ptr_to().ptr_to()));
|
2015-01-25 04:58:43 -06:00
|
|
|
let mptr = Load(bcx, GEPi(bcx, llvtable, &[0, vtable_index + VTABLE_OFFSET]));
|
2013-06-15 22:45:48 -05:00
|
|
|
let mptr = PointerCast(bcx, mptr, llcallee_ty.ptr_to());
|
2012-08-28 17:54:45 -05:00
|
|
|
|
|
|
|
return Callee {
|
|
|
|
bcx: bcx,
|
2014-08-04 15:56:56 -05:00
|
|
|
data: TraitItem(MethodData {
|
2012-08-28 17:54:45 -05:00
|
|
|
llfn: mptr,
|
2013-08-11 12:42:26 -05:00
|
|
|
llself: llself,
|
2012-08-28 17:54:45 -05:00
|
|
|
})
|
|
|
|
};
|
2012-01-07 15:44:14 -06:00
|
|
|
}
|
|
|
|
|
2014-12-23 04:26:34 -06:00
|
|
|
/// Generate a shim function that allows an object type like `SomeTrait` to
|
|
|
|
/// implement the type `SomeTrait`. Imagine a trait definition:
|
|
|
|
///
|
|
|
|
/// trait SomeTrait { fn get(&self) -> int; ... }
|
|
|
|
///
|
|
|
|
/// And a generic bit of code:
|
|
|
|
///
|
|
|
|
/// fn foo<T:SomeTrait>(t: &T) {
|
|
|
|
/// let x = SomeTrait::get;
|
|
|
|
/// x(t)
|
|
|
|
/// }
|
|
|
|
///
|
|
|
|
/// What is the value of `x` when `foo` is invoked with `T=SomeTrait`?
|
|
|
|
/// The answer is that it it is a shim function generate by this
|
|
|
|
/// routine:
|
|
|
|
///
|
|
|
|
/// fn shim(t: &SomeTrait) -> int {
|
|
|
|
/// // ... call t.get() virtually ...
|
|
|
|
/// }
|
|
|
|
///
|
|
|
|
/// In fact, all virtual calls can be thought of as normal trait calls
|
|
|
|
/// that go through this shim function.
|
|
|
|
pub fn trans_object_shim<'a, 'tcx>(
|
|
|
|
ccx: &'a CrateContext<'a, 'tcx>,
|
|
|
|
object_ty: Ty<'tcx>,
|
2015-03-03 07:01:13 -06:00
|
|
|
upcast_trait_ref: ty::PolyTraitRef<'tcx>,
|
2015-03-25 19:06:52 -05:00
|
|
|
method_offset_in_trait: usize)
|
2015-01-13 08:17:07 -06:00
|
|
|
-> (ValueRef, Ty<'tcx>)
|
2014-12-23 04:26:34 -06:00
|
|
|
{
|
|
|
|
let _icx = push_ctxt("trans_object_shim");
|
|
|
|
let tcx = ccx.tcx();
|
2015-03-03 07:01:13 -06:00
|
|
|
let trait_id = upcast_trait_ref.def_id();
|
2014-12-23 04:26:34 -06:00
|
|
|
|
2015-03-03 07:01:13 -06:00
|
|
|
debug!("trans_object_shim(object_ty={}, upcast_trait_ref={}, method_offset_in_trait={})",
|
2014-12-23 04:26:34 -06:00
|
|
|
object_ty.repr(tcx),
|
2015-03-03 07:01:13 -06:00
|
|
|
upcast_trait_ref.repr(tcx),
|
2014-12-23 04:26:34 -06:00
|
|
|
method_offset_in_trait);
|
|
|
|
|
|
|
|
let object_trait_ref =
|
|
|
|
match object_ty.sty {
|
|
|
|
ty::ty_trait(ref data) => {
|
|
|
|
data.principal_trait_ref_with_self_ty(tcx, object_ty)
|
|
|
|
}
|
|
|
|
_ => {
|
2015-02-01 20:53:25 -06:00
|
|
|
tcx.sess.bug(&format!("trans_object_shim() called on non-object: {}",
|
|
|
|
object_ty.repr(tcx)));
|
2014-12-23 04:26:34 -06:00
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
// Upcast to the trait in question and extract out the substitutions.
|
2015-01-06 04:03:42 -06:00
|
|
|
let upcast_trait_ref = ty::erase_late_bound_regions(tcx, &upcast_trait_ref);
|
|
|
|
let object_substs = upcast_trait_ref.substs.clone().erase_regions();
|
2014-12-23 04:26:34 -06:00
|
|
|
debug!("trans_object_shim: object_substs={}", object_substs.repr(tcx));
|
|
|
|
|
2015-01-06 19:53:18 -06:00
|
|
|
// Lookup the type of this method as declared in the trait and apply substitutions.
|
2014-12-23 04:26:34 -06:00
|
|
|
let method_ty = match ty::trait_item(tcx, trait_id, method_offset_in_trait) {
|
|
|
|
ty::MethodTraitItem(method) => method,
|
2015-03-14 13:05:00 -05:00
|
|
|
_ => {
|
|
|
|
tcx.sess.bug("can't create a method shim for a non-method item")
|
2014-12-23 04:26:34 -06:00
|
|
|
}
|
|
|
|
};
|
2015-01-11 14:18:06 -06:00
|
|
|
let fty = monomorphize::apply_param_substs(tcx, &object_substs, &method_ty.fty);
|
2014-12-23 04:26:34 -06:00
|
|
|
let fty = tcx.mk_bare_fn(fty);
|
2015-03-01 11:19:07 -06:00
|
|
|
let method_ty = opaque_method_ty(tcx, fty);
|
|
|
|
debug!("trans_object_shim: fty={} method_ty={}", fty.repr(tcx), method_ty.repr(tcx));
|
2014-12-23 04:26:34 -06:00
|
|
|
|
|
|
|
//
|
2015-03-01 11:19:07 -06:00
|
|
|
let shim_fn_ty = ty::mk_bare_fn(tcx, None, fty);
|
|
|
|
let method_bare_fn_ty = ty::mk_bare_fn(tcx, None, method_ty);
|
2015-03-03 17:08:06 -06:00
|
|
|
let function_name = link::mangle_internal_name_by_type_and_seq(ccx, shim_fn_ty, "object_shim");
|
|
|
|
let llfn = declare::define_internal_rust_fn(ccx, &function_name, shim_fn_ty).unwrap_or_else(||{
|
|
|
|
ccx.sess().bug(&format!("symbol `{}` already defined", function_name));
|
|
|
|
});
|
2014-12-23 04:26:34 -06:00
|
|
|
|
2015-01-06 04:03:42 -06:00
|
|
|
let sig = ty::erase_late_bound_regions(ccx.tcx(), &fty.sig);
|
|
|
|
|
2015-01-29 06:03:34 -06:00
|
|
|
let empty_substs = tcx.mk_substs(Substs::trans_empty());
|
2015-01-26 06:38:33 -06:00
|
|
|
let (block_arena, fcx): (TypedArena<_>, FunctionContext);
|
|
|
|
block_arena = TypedArena::new();
|
|
|
|
fcx = new_fn_ctxt(ccx,
|
|
|
|
llfn,
|
|
|
|
ast::DUMMY_NODE_ID,
|
|
|
|
false,
|
|
|
|
sig.output,
|
2015-01-29 06:03:34 -06:00
|
|
|
empty_substs,
|
2015-01-26 06:38:33 -06:00
|
|
|
None,
|
|
|
|
&block_arena);
|
2015-01-06 04:03:42 -06:00
|
|
|
let mut bcx = init_function(&fcx, false, sig.output);
|
2014-12-23 04:26:34 -06:00
|
|
|
|
|
|
|
// the first argument (`self`) will be a trait object
|
|
|
|
let llobject = get_param(fcx.llfn, fcx.arg_pos(0) as u32);
|
|
|
|
|
|
|
|
debug!("trans_object_shim: llobject={}",
|
|
|
|
bcx.val_to_string(llobject));
|
|
|
|
|
|
|
|
// the remaining arguments will be, well, whatever they are
|
2015-01-05 12:53:39 -06:00
|
|
|
let input_tys =
|
|
|
|
match fty.abi {
|
|
|
|
RustCall => {
|
|
|
|
// unpack the tuple to extract the input type arguments:
|
2015-01-06 04:03:42 -06:00
|
|
|
match sig.inputs[1].sty {
|
2015-02-01 20:53:25 -06:00
|
|
|
ty::ty_tup(ref tys) => &**tys,
|
2015-01-05 12:53:39 -06:00
|
|
|
_ => {
|
|
|
|
bcx.sess().bug(
|
2015-02-01 20:53:25 -06:00
|
|
|
&format!("rust-call expects a tuple not {}",
|
|
|
|
sig.inputs[1].repr(tcx)));
|
2015-01-05 12:53:39 -06:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
_ => {
|
|
|
|
// skip the self parameter:
|
2015-01-17 18:15:52 -06:00
|
|
|
&sig.inputs[1..]
|
2015-01-05 12:53:39 -06:00
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2014-12-23 04:26:34 -06:00
|
|
|
let llargs: Vec<_> =
|
2015-01-05 12:53:39 -06:00
|
|
|
input_tys.iter()
|
2014-12-23 04:26:34 -06:00
|
|
|
.enumerate()
|
|
|
|
.map(|(i, _)| {
|
|
|
|
let llarg = get_param(fcx.llfn, fcx.arg_pos(i+1) as u32);
|
|
|
|
debug!("trans_object_shim: input #{} == {}",
|
|
|
|
i, bcx.val_to_string(llarg));
|
|
|
|
llarg
|
|
|
|
})
|
|
|
|
.collect();
|
2015-01-05 12:53:39 -06:00
|
|
|
|
2014-12-23 04:26:34 -06:00
|
|
|
assert!(!fcx.needs_ret_allocas);
|
|
|
|
|
|
|
|
let dest =
|
|
|
|
fcx.llretslotptr.get().map(
|
2015-01-06 04:03:42 -06:00
|
|
|
|_| expr::SaveIn(fcx.get_ret_slot(bcx, sig.output, "ret_slot")));
|
2014-12-23 04:26:34 -06:00
|
|
|
|
|
|
|
let method_offset_in_vtable =
|
|
|
|
traits::get_vtable_index_of_object_method(bcx.tcx(),
|
|
|
|
object_trait_ref.clone(),
|
|
|
|
trait_id,
|
|
|
|
method_offset_in_trait);
|
|
|
|
debug!("trans_object_shim: method_offset_in_vtable={}",
|
|
|
|
method_offset_in_vtable);
|
|
|
|
|
|
|
|
bcx = trans_call_inner(bcx,
|
2015-02-04 10:16:59 -06:00
|
|
|
DebugLoc::None,
|
2014-12-23 04:26:34 -06:00
|
|
|
method_bare_fn_ty,
|
|
|
|
|bcx, _| trans_trait_callee_from_llval(bcx,
|
|
|
|
method_bare_fn_ty,
|
|
|
|
method_offset_in_vtable,
|
|
|
|
llobject),
|
2015-02-01 20:53:25 -06:00
|
|
|
ArgVals(&llargs),
|
2014-12-23 04:26:34 -06:00
|
|
|
dest).bcx;
|
|
|
|
|
2014-12-11 06:53:30 -06:00
|
|
|
finish_fn(&fcx, bcx, sig.output, DebugLoc::None);
|
2014-12-23 04:26:34 -06:00
|
|
|
|
2015-01-13 08:17:07 -06:00
|
|
|
(llfn, method_bare_fn_ty)
|
2014-12-23 04:26:34 -06:00
|
|
|
}
|
|
|
|
|
2013-05-15 19:38:52 -05:00
|
|
|
/// Creates a returns a dynamic vtable for the given type and vtable origin.
|
|
|
|
/// This is used only for objects.
|
2014-09-12 10:42:58 -05:00
|
|
|
///
|
|
|
|
/// The `trait_ref` encodes the erased self type. Hence if we are
|
|
|
|
/// making an object `Foo<Trait>` from a value of type `Foo<T>`, then
|
2015-03-13 19:36:41 -05:00
|
|
|
/// `trait_ref` would map `T:Trait`.
|
2015-01-29 06:03:34 -06:00
|
|
|
pub fn get_vtable<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
|
|
|
|
trait_ref: ty::PolyTraitRef<'tcx>,
|
|
|
|
param_substs: &'tcx subst::Substs<'tcx>)
|
|
|
|
-> ValueRef
|
2014-05-31 17:53:13 -05:00
|
|
|
{
|
2015-01-29 06:03:34 -06:00
|
|
|
let tcx = ccx.tcx();
|
2014-01-27 06:18:36 -06:00
|
|
|
let _icx = push_ctxt("meth::get_vtable");
|
2013-08-13 15:22:58 -05:00
|
|
|
|
2015-03-13 19:36:41 -05:00
|
|
|
debug!("get_vtable(trait_ref={})", trait_ref.repr(tcx));
|
2015-01-29 06:03:34 -06:00
|
|
|
|
2013-08-13 15:22:58 -05:00
|
|
|
// Check the cache.
|
2015-03-13 19:36:41 -05:00
|
|
|
match ccx.vtables().borrow().get(&trait_ref) {
|
2014-03-20 21:49:20 -05:00
|
|
|
Some(&val) => { return val }
|
|
|
|
None => { }
|
2013-08-13 15:22:58 -05:00
|
|
|
}
|
|
|
|
|
2014-09-12 10:42:58 -05:00
|
|
|
// Not in the cache. Build it.
|
|
|
|
let methods = traits::supertraits(tcx, trait_ref.clone()).flat_map(|trait_ref| {
|
2015-01-29 06:03:34 -06:00
|
|
|
let vtable = fulfill_obligation(ccx, DUMMY_SP, trait_ref.clone());
|
2014-09-12 10:42:58 -05:00
|
|
|
match vtable {
|
2015-01-24 07:17:24 -06:00
|
|
|
// Should default trait error here?
|
2015-02-07 07:24:34 -06:00
|
|
|
traits::VtableDefaultImpl(_) |
|
2014-10-09 16:19:50 -05:00
|
|
|
traits::VtableBuiltin(_) => {
|
2014-09-18 10:08:04 -05:00
|
|
|
Vec::new().into_iter()
|
|
|
|
}
|
2014-09-12 10:42:58 -05:00
|
|
|
traits::VtableImpl(
|
2014-09-11 00:07:49 -05:00
|
|
|
traits::VtableImplData {
|
2014-09-12 10:42:58 -05:00
|
|
|
impl_def_id: id,
|
2014-10-05 19:36:53 -05:00
|
|
|
substs,
|
2014-09-12 10:42:58 -05:00
|
|
|
nested: _ }) => {
|
2015-01-29 06:03:34 -06:00
|
|
|
emit_vtable_methods(ccx, id, substs, param_substs).into_iter()
|
2013-05-15 19:38:52 -05:00
|
|
|
}
|
2015-01-24 14:00:03 -06:00
|
|
|
traits::VtableClosure(closure_def_id, substs) => {
|
2015-02-15 14:09:26 -06:00
|
|
|
let trait_closure_kind = tcx.lang_items.fn_trait_kind(trait_ref.def_id()).unwrap();
|
|
|
|
let llfn = closure::trans_closure_method(ccx,
|
|
|
|
closure_def_id,
|
|
|
|
substs,
|
|
|
|
ExprId(0),
|
|
|
|
param_substs,
|
|
|
|
trait_closure_kind);
|
2015-01-29 06:03:34 -06:00
|
|
|
vec![llfn].into_iter()
|
2014-05-29 00:26:56 -05:00
|
|
|
}
|
2014-12-01 08:23:40 -06:00
|
|
|
traits::VtableFnPointer(bare_fn_ty) => {
|
2015-02-15 14:09:26 -06:00
|
|
|
let trait_closure_kind = tcx.lang_items.fn_trait_kind(trait_ref.def_id()).unwrap();
|
|
|
|
vec![trans_fn_pointer_shim(ccx, trait_closure_kind, bare_fn_ty)].into_iter()
|
2014-12-01 08:23:40 -06:00
|
|
|
}
|
2014-12-23 04:26:34 -06:00
|
|
|
traits::VtableObject(ref data) => {
|
|
|
|
// this would imply that the Self type being erased is
|
|
|
|
// an object type; this cannot happen because we
|
|
|
|
// cannot cast an unsized type into a trait object
|
2015-01-29 06:03:34 -06:00
|
|
|
tcx.sess.bug(
|
2015-02-01 20:53:25 -06:00
|
|
|
&format!("cannot get vtable for an object type: {}",
|
2015-01-29 06:03:34 -06:00
|
|
|
data.repr(tcx)));
|
2014-12-23 04:26:34 -06:00
|
|
|
}
|
2015-01-08 20:41:42 -06:00
|
|
|
traits::VtableParam(..) => {
|
2015-01-29 06:03:34 -06:00
|
|
|
tcx.sess.bug(
|
2015-01-07 10:58:31 -06:00
|
|
|
&format!("resolved vtable for {} to bad vtable {} in trans",
|
2015-01-29 06:03:34 -06:00
|
|
|
trait_ref.repr(tcx),
|
2015-02-20 13:08:14 -06:00
|
|
|
vtable.repr(tcx)));
|
2014-09-12 10:42:58 -05:00
|
|
|
}
|
2012-01-02 09:50:51 -06:00
|
|
|
}
|
2014-04-10 06:04:45 -05:00
|
|
|
});
|
2013-08-13 15:22:58 -05:00
|
|
|
|
2014-09-12 10:42:58 -05:00
|
|
|
let size_ty = sizing_type_of(ccx, trait_ref.self_ty());
|
2014-08-06 04:59:40 -05:00
|
|
|
let size = machine::llsize_of_alloc(ccx, size_ty);
|
2014-09-12 10:42:58 -05:00
|
|
|
let align = align_of(ccx, trait_ref.self_ty());
|
2014-08-06 04:59:40 -05:00
|
|
|
|
2015-01-29 06:03:34 -06:00
|
|
|
let components: Vec<_> = vec![
|
|
|
|
// Generate a destructor for the vtable.
|
2015-03-13 19:36:41 -05:00
|
|
|
glue::get_drop_glue(ccx, trait_ref.self_ty()),
|
2015-01-29 06:03:34 -06:00
|
|
|
C_uint(ccx, size),
|
|
|
|
C_uint(ccx, align)
|
|
|
|
].into_iter().chain(methods).collect();
|
|
|
|
|
2015-03-03 17:08:06 -06:00
|
|
|
let vtable = consts::addr_of(ccx, C_struct(ccx, &components, false), "vtable");
|
2013-12-18 19:00:56 -06:00
|
|
|
|
2015-03-13 19:36:41 -05:00
|
|
|
ccx.vtables().borrow_mut().insert(trait_ref, vtable);
|
2014-04-10 06:04:45 -05:00
|
|
|
vtable
|
2012-01-12 09:57:30 -06:00
|
|
|
}
|
2012-01-02 06:26:51 -06:00
|
|
|
|
2015-01-29 06:03:34 -06:00
|
|
|
fn emit_vtable_methods<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
|
|
|
|
impl_id: ast::DefId,
|
|
|
|
substs: subst::Substs<'tcx>,
|
|
|
|
param_substs: &'tcx subst::Substs<'tcx>)
|
2015-03-17 04:18:01 -05:00
|
|
|
-> Vec<ValueRef>
|
|
|
|
{
|
2014-03-15 15:29:34 -05:00
|
|
|
let tcx = ccx.tcx();
|
2012-07-18 18:49:55 -05:00
|
|
|
|
2015-03-17 04:18:01 -05:00
|
|
|
debug!("emit_vtable_methods(impl_id={}, substs={}, param_substs={})",
|
|
|
|
impl_id.repr(tcx),
|
|
|
|
substs.repr(tcx),
|
|
|
|
param_substs.repr(tcx));
|
|
|
|
|
2013-05-16 17:54:51 -05:00
|
|
|
let trt_id = match ty::impl_trait_ref(tcx, impl_id) {
|
2014-12-14 06:17:23 -06:00
|
|
|
Some(t_id) => t_id.def_id,
|
2014-03-05 08:36:01 -06:00
|
|
|
None => ccx.sess().bug("make_impl_vtable: don't know how to \
|
|
|
|
make a vtable for a type impl!")
|
2013-05-16 17:54:51 -05:00
|
|
|
};
|
2013-03-27 05:16:28 -05:00
|
|
|
|
2015-01-29 06:03:34 -06:00
|
|
|
ty::populate_implementations_for_trait_if_necessary(tcx, trt_id);
|
2013-08-23 16:34:00 -05:00
|
|
|
|
2015-03-18 14:26:38 -05:00
|
|
|
let nullptr = C_null(Type::nil(ccx).ptr_to());
|
2014-08-04 15:56:56 -05:00
|
|
|
let trait_item_def_ids = ty::trait_item_def_ids(tcx, trt_id);
|
2015-03-17 04:18:01 -05:00
|
|
|
trait_item_def_ids
|
|
|
|
.iter()
|
|
|
|
|
2015-03-14 13:05:00 -05:00
|
|
|
// Filter out non-method items.
|
2015-03-17 04:18:01 -05:00
|
|
|
.filter_map(|item_def_id| {
|
|
|
|
match *item_def_id {
|
|
|
|
ty::MethodTraitItemId(def_id) => Some(def_id),
|
2015-03-14 13:05:00 -05:00
|
|
|
_ => None,
|
2014-06-28 14:55:17 -05:00
|
|
|
}
|
2015-03-17 04:18:01 -05:00
|
|
|
})
|
|
|
|
|
|
|
|
// Now produce pointers for each remaining method. If the
|
|
|
|
// method could never be called from this object, just supply
|
|
|
|
// null.
|
|
|
|
.map(|trait_method_def_id| {
|
|
|
|
debug!("emit_vtable_methods: trait_method_def_id={}",
|
|
|
|
trait_method_def_id.repr(tcx));
|
|
|
|
|
|
|
|
let trait_method_type = match ty::impl_or_trait_item(tcx, trait_method_def_id) {
|
|
|
|
ty::MethodTraitItem(m) => m,
|
2015-03-14 13:05:00 -05:00
|
|
|
_ => ccx.sess().bug("should be a method, not other assoc item"),
|
2015-03-17 04:18:01 -05:00
|
|
|
};
|
|
|
|
let name = trait_method_type.name;
|
|
|
|
|
2015-03-18 14:26:38 -05:00
|
|
|
// Some methods cannot be called on an object; skip those.
|
|
|
|
if !traits::is_vtable_safe_method(tcx, trt_id, &trait_method_type) {
|
|
|
|
debug!("emit_vtable_methods: not vtable safe");
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
|
2015-03-17 04:18:01 -05:00
|
|
|
debug!("emit_vtable_methods: trait_method_type={}",
|
|
|
|
trait_method_type.repr(tcx));
|
|
|
|
|
|
|
|
// The substitutions we have are on the impl, so we grab
|
|
|
|
// the method type from the impl to substitute into.
|
|
|
|
let impl_method_def_id = method_with_name(ccx, impl_id, name);
|
|
|
|
let impl_method_type = match ty::impl_or_trait_item(tcx, impl_method_def_id) {
|
|
|
|
ty::MethodTraitItem(m) => m,
|
2015-03-14 13:05:00 -05:00
|
|
|
_ => ccx.sess().bug("should be a method, not other assoc item"),
|
2015-03-17 04:18:01 -05:00
|
|
|
};
|
|
|
|
|
2015-03-18 14:26:38 -05:00
|
|
|
debug!("emit_vtable_methods: impl_method_type={}",
|
2015-03-17 04:18:01 -05:00
|
|
|
impl_method_type.repr(tcx));
|
|
|
|
|
2015-03-17 06:36:42 -05:00
|
|
|
// If this is a default method, it's possible that it
|
|
|
|
// relies on where clauses that do not hold for this
|
|
|
|
// particular set of type parameters. Note that this
|
|
|
|
// method could then never be called, so we do not want to
|
|
|
|
// try and trans it, in that case. Issue #23435.
|
|
|
|
if ty::provided_source(tcx, impl_method_def_id).is_some() {
|
2015-03-18 14:26:38 -05:00
|
|
|
let predicates = impl_method_type.predicates.predicates.subst(tcx, &substs);
|
|
|
|
if !normalize_and_test_predicates(ccx, predicates.into_vec()) {
|
2015-03-17 06:36:42 -05:00
|
|
|
debug!("emit_vtable_methods: predicates do not hold");
|
|
|
|
return nullptr;
|
|
|
|
}
|
2015-03-17 05:24:11 -05:00
|
|
|
}
|
|
|
|
|
2015-03-17 04:18:01 -05:00
|
|
|
trans_fn_ref_with_substs(ccx,
|
|
|
|
impl_method_def_id,
|
|
|
|
ExprId(0),
|
|
|
|
param_substs,
|
|
|
|
substs.clone()).val
|
|
|
|
})
|
|
|
|
.collect()
|
2012-01-12 09:57:30 -06:00
|
|
|
}
|
|
|
|
|
2015-03-01 11:19:07 -06:00
|
|
|
/// Replace the self type (&Self or Box<Self>) with an opaque pointer.
|
|
|
|
pub fn opaque_method_ty<'tcx>(tcx: &ty::ctxt<'tcx>, method_ty: &ty::BareFnTy<'tcx>)
|
|
|
|
-> &'tcx ty::BareFnTy<'tcx> {
|
|
|
|
let mut inputs = method_ty.sig.0.inputs.clone();
|
|
|
|
inputs[0] = ty::mk_mut_ptr(tcx, ty::mk_mach_int(tcx, ast::TyI8));
|
|
|
|
|
|
|
|
tcx.mk_bare_fn(ty::BareFnTy {
|
|
|
|
unsafety: method_ty.unsafety,
|
|
|
|
abi: method_ty.abi,
|
|
|
|
sig: ty::Binder(ty::FnSig {
|
|
|
|
inputs: inputs,
|
|
|
|
output: method_ty.sig.0.output,
|
|
|
|
variadic: method_ty.sig.0.variadic,
|
|
|
|
}),
|
|
|
|
})
|
|
|
|
}
|