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.
|
|
|
|
|
2013-05-17 17:28:44 -05:00
|
|
|
|
2013-03-26 15:38:07 -05:00
|
|
|
use back::abi;
|
2012-09-04 13:54:36 -05:00
|
|
|
use lib::llvm::llvm;
|
2013-03-26 15:38:07 -05:00
|
|
|
use lib::llvm::ValueRef;
|
2012-12-23 16:41:37 -06:00
|
|
|
use lib;
|
2012-12-13 15:05:22 -06:00
|
|
|
use metadata::csearch;
|
|
|
|
use middle::trans::base::*;
|
|
|
|
use middle::trans::build::*;
|
|
|
|
use middle::trans::callee::*;
|
2012-12-23 16:41:37 -06:00
|
|
|
use middle::trans::callee;
|
2012-12-13 15:05:22 -06:00
|
|
|
use middle::trans::common::*;
|
2013-06-27 18:40:27 -05:00
|
|
|
use middle::trans::datum::*;
|
2012-12-13 15:05:22 -06:00
|
|
|
use middle::trans::expr::{SaveIn, Ignore};
|
2012-12-23 16:41:37 -06:00
|
|
|
use middle::trans::expr;
|
|
|
|
use middle::trans::glue;
|
|
|
|
use middle::trans::monomorphize;
|
2012-12-13 15:05:22 -06:00
|
|
|
use middle::trans::type_of::*;
|
2013-02-25 13:11:21 -06:00
|
|
|
use middle::ty;
|
2012-12-23 16:41:37 -06:00
|
|
|
use middle::typeck;
|
2013-02-25 13:11:21 -06:00
|
|
|
use util::common::indenter;
|
2013-06-29 00:07:24 -05:00
|
|
|
use util::ppaux::Repr;
|
2012-12-13 15:05:22 -06:00
|
|
|
|
2013-06-16 05:52:44 -05:00
|
|
|
use middle::trans::type_::Type;
|
|
|
|
|
2013-06-28 17:32:26 -05:00
|
|
|
use std::vec;
|
2013-03-26 15:38:07 -05:00
|
|
|
use syntax::ast_map::{path, path_mod, path_name};
|
2013-02-25 13:11:21 -06:00
|
|
|
use syntax::ast_util;
|
2012-12-13 15:05:22 -06:00
|
|
|
use syntax::{ast, ast_map};
|
2012-08-28 17:54:45 -05:00
|
|
|
|
2012-08-21 21:51:43 -05: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()`.
|
|
|
|
*/
|
2013-06-13 02:19:50 -05:00
|
|
|
pub fn trans_impl(ccx: @mut CrateContext,
|
2013-05-15 19:38:52 -05:00
|
|
|
path: path,
|
|
|
|
name: ast::ident,
|
|
|
|
methods: &[@ast::method],
|
|
|
|
generics: &ast::Generics,
|
|
|
|
id: ast::node_id) {
|
2013-06-16 23:23:24 -05:00
|
|
|
let _icx = push_ctxt("impl::trans_impl");
|
2013-03-15 14:24:24 -05:00
|
|
|
let tcx = ccx.tcx;
|
|
|
|
|
2013-06-19 20:03:02 -05:00
|
|
|
debug!("trans_impl(path=%s, name=%s, id=%?)",
|
|
|
|
path.repr(tcx), name.repr(tcx), id);
|
2013-03-15 14:24:24 -05:00
|
|
|
|
2013-02-14 23:50:03 -06:00
|
|
|
if !generics.ty_params.is_empty() { return; }
|
2012-06-28 15:52:13 -05:00
|
|
|
let sub_path = vec::append_one(path, path_name(name));
|
2013-06-21 07:29:53 -05:00
|
|
|
for methods.iter().advance |method| {
|
2013-02-14 23:50:03 -06:00
|
|
|
if method.generics.ty_params.len() == 0u {
|
2012-08-21 21:51:43 -05:00
|
|
|
let llfn = get_item_val(ccx, method.id);
|
2013-01-07 16:16:52 -06:00
|
|
|
let path = vec::append_one(/*bad*/copy sub_path,
|
|
|
|
path_name(method.ident));
|
2012-10-08 14:39:30 -05:00
|
|
|
|
2013-04-26 21:10:28 -05:00
|
|
|
trans_method(ccx,
|
|
|
|
path,
|
|
|
|
*method,
|
2013-06-19 20:03:02 -05:00
|
|
|
None,
|
2013-06-28 13:11:47 -05:00
|
|
|
llfn);
|
2012-03-08 06:30:22 -06:00
|
|
|
}
|
2012-01-02 05:21:44 -06:00
|
|
|
}
|
|
|
|
}
|
2012-01-02 06:26:51 -06:00
|
|
|
|
2012-08-21 21:51:43 -05:00
|
|
|
/**
|
|
|
|
Translates a (possibly monomorphized) method body.
|
|
|
|
|
|
|
|
# Parameters
|
|
|
|
|
|
|
|
- `path`: the path to the method
|
|
|
|
- `method`: the AST node for the method
|
|
|
|
- `param_substs`: if this is a generic method, the current values for
|
|
|
|
type parameters and so forth, else none
|
|
|
|
- `llfn`: the LLVM ValueRef for the method
|
2012-10-08 14:39:30 -05:00
|
|
|
- `impl_id`: the node ID of the impl this method is inside
|
2012-08-21 21:51:43 -05:00
|
|
|
*/
|
2013-06-13 02:19:50 -05:00
|
|
|
pub fn trans_method(ccx: @mut CrateContext,
|
2013-04-17 11:15:37 -05:00
|
|
|
path: path,
|
2013-01-30 13:46:19 -06:00
|
|
|
method: &ast::method,
|
2013-02-18 14:36:30 -06:00
|
|
|
param_substs: Option<@param_substs>,
|
2013-06-28 13:11:47 -05:00
|
|
|
llfn: ValueRef) {
|
2012-08-22 15:18:29 -05:00
|
|
|
// figure out how self is being passed
|
2013-04-30 10:49:48 -05:00
|
|
|
let self_arg = match method.explicit_self.node {
|
2012-08-21 21:51:43 -05:00
|
|
|
ast::sty_static => {
|
|
|
|
no_self
|
|
|
|
}
|
2012-08-22 15:18:29 -05:00
|
|
|
_ => {
|
|
|
|
// determine the (monomorphized) type that `self` maps to for
|
|
|
|
// this method
|
2013-06-19 20:03:02 -05:00
|
|
|
let self_ty = ty::node_id_to_type(ccx.tcx, method.self_id);
|
2012-08-22 15:18:29 -05:00
|
|
|
let self_ty = match param_substs {
|
2012-10-08 14:39:30 -05:00
|
|
|
None => self_ty,
|
2013-06-24 12:34:18 -05:00
|
|
|
Some(@param_substs {tys: ref tys, self_ty: ref self_sub, _}) => {
|
|
|
|
ty::subst_tps(ccx.tcx, *tys, *self_sub, self_ty)
|
2012-10-08 14:39:30 -05:00
|
|
|
}
|
2012-08-22 15:18:29 -05:00
|
|
|
};
|
2013-06-19 20:03:02 -05:00
|
|
|
debug!("calling trans_fn with self_ty %s",
|
Cleanup substitutions and treatment of generics around traits in a number of ways.
- In a TraitRef, use the self type consistently to refer to the Self type:
- trait ref in `impl Trait<A,B,C> for S` has a self type of `S`.
- trait ref in `A:Trait` has the self type `A`
- trait ref associated with a trait decl has self type `Self`
- trait ref associated with a supertype has self type `Self`
- trait ref in an object type `@Trait` has no self type
- Rewrite `each_bound_traits_and_supertraits` to perform
substitutions as it goes, and thus yield a series of trait refs
that are always in the same 'namespace' as the type parameter
bound given as input. Before, we left this to the caller, but
this doesn't work because the caller lacks adequare information
to perform the type substitutions correctly.
- For provided methods, substitute the generics involved in the provided
method correctly.
- Introduce TypeParameterDef, which tracks the bounds declared on a type
parameter and brings them together with the def_id and (in the future)
other information (maybe even the parameter's name!).
- Introduce Subst trait, which helps to cleanup a lot of the
repetitive code involved with doing type substitution.
- Introduce Repr trait, which makes debug printouts far more convenient.
Fixes #4183. Needed for #5656.
2013-04-09 00:54:49 -05:00
|
|
|
self_ty.repr(ccx.tcx));
|
2013-04-30 10:49:48 -05:00
|
|
|
match method.explicit_self.node {
|
2013-06-27 18:40:27 -05:00
|
|
|
ast::sty_value => impl_self(self_ty, ty::ByRef),
|
|
|
|
_ => impl_self(self_ty, ty::ByCopy),
|
2012-08-22 15:18:29 -05:00
|
|
|
}
|
2012-08-21 21:51:43 -05:00
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
// generate the actual code
|
|
|
|
trans_fn(ccx,
|
|
|
|
path,
|
2013-01-31 19:12:29 -06:00
|
|
|
&method.decl,
|
|
|
|
&method.body,
|
2012-08-21 21:51:43 -05:00
|
|
|
llfn,
|
|
|
|
self_arg,
|
|
|
|
param_substs,
|
2012-10-08 14:39:30 -05:00
|
|
|
method.id,
|
2013-03-29 18:55:04 -05:00
|
|
|
[]);
|
2012-08-21 21:51:43 -05:00
|
|
|
}
|
|
|
|
|
2013-01-30 13:46:19 -06:00
|
|
|
pub fn trans_self_arg(bcx: block,
|
|
|
|
base: @ast::expr,
|
2013-06-29 10:45:59 -05:00
|
|
|
temp_cleanups: &mut ~[ValueRef],
|
2013-01-30 13:46:19 -06:00
|
|
|
mentry: typeck::method_map_entry) -> Result {
|
2013-06-16 23:23:24 -05:00
|
|
|
let _icx = push_ctxt("impl::trans_self_arg");
|
2012-02-24 19:45:16 -06:00
|
|
|
|
2013-06-29 09:43:39 -05:00
|
|
|
// self is passed as an opaque box in the environment slot
|
|
|
|
let self_ty = ty::mk_opaque_box(bcx.tcx());
|
2013-06-29 10:45:59 -05:00
|
|
|
trans_arg_expr(bcx,
|
|
|
|
self_ty,
|
|
|
|
mentry.self_mode,
|
|
|
|
base,
|
|
|
|
temp_cleanups,
|
|
|
|
None,
|
|
|
|
DontAutorefArg)
|
2012-01-02 09:50:51 -06:00
|
|
|
}
|
|
|
|
|
2013-01-30 13:46:19 -06:00
|
|
|
pub fn trans_method_callee(bcx: block,
|
|
|
|
callee_id: ast::node_id,
|
2013-05-10 17:15:06 -05:00
|
|
|
this: @ast::expr,
|
2013-01-30 13:46:19 -06:00
|
|
|
mentry: typeck::method_map_entry)
|
2013-05-10 17:15:06 -05:00
|
|
|
-> Callee {
|
2013-06-16 23:23:24 -05:00
|
|
|
let _icx = push_ctxt("impl::trans_method_callee");
|
2013-03-27 09:26:57 -05:00
|
|
|
let tcx = bcx.tcx();
|
2012-10-08 14:39:30 -05:00
|
|
|
|
2013-05-10 17:15:06 -05:00
|
|
|
debug!("trans_method_callee(callee_id=%?, this=%s, mentry=%s)",
|
|
|
|
callee_id,
|
|
|
|
bcx.expr_to_str(this),
|
Cleanup substitutions and treatment of generics around traits in a number of ways.
- In a TraitRef, use the self type consistently to refer to the Self type:
- trait ref in `impl Trait<A,B,C> for S` has a self type of `S`.
- trait ref in `A:Trait` has the self type `A`
- trait ref associated with a trait decl has self type `Self`
- trait ref associated with a supertype has self type `Self`
- trait ref in an object type `@Trait` has no self type
- Rewrite `each_bound_traits_and_supertraits` to perform
substitutions as it goes, and thus yield a series of trait refs
that are always in the same 'namespace' as the type parameter
bound given as input. Before, we left this to the caller, but
this doesn't work because the caller lacks adequare information
to perform the type substitutions correctly.
- For provided methods, substitute the generics involved in the provided
method correctly.
- Introduce TypeParameterDef, which tracks the bounds declared on a type
parameter and brings them together with the def_id and (in the future)
other information (maybe even the parameter's name!).
- Introduce Subst trait, which helps to cleanup a lot of the
repetitive code involved with doing type substitution.
- Introduce Repr trait, which makes debug printouts far more convenient.
Fixes #4183. Needed for #5656.
2013-04-09 00:54:49 -05:00
|
|
|
mentry.repr(bcx.tcx()));
|
2013-03-21 07:33:52 -05:00
|
|
|
|
2012-10-08 14:39:30 -05:00
|
|
|
// Replace method_self with method_static here.
|
|
|
|
let mut origin = mentry.origin;
|
|
|
|
match origin {
|
2013-01-16 20:45:05 -06:00
|
|
|
typeck::method_super(trait_id, method_index) => {
|
|
|
|
// <self_ty> is the self type for this method call
|
2013-05-10 17:15:06 -05:00
|
|
|
let self_ty = node_id_type(bcx, this.id);
|
2013-01-16 20:45:05 -06:00
|
|
|
// <impl_id> is the ID of the implementation of
|
|
|
|
// trait <trait_id> for type <self_ty>
|
|
|
|
let impl_id = ty::get_impl_id(tcx, trait_id, self_ty);
|
|
|
|
// Get the supertrait's methods
|
2013-03-27 09:26:57 -05:00
|
|
|
let supertrait_method_def_ids = ty::trait_method_def_ids(tcx, trait_id);
|
2013-01-16 20:45:05 -06:00
|
|
|
// Make sure to fail with a readable error message if
|
|
|
|
// there's some internal error here
|
2013-03-27 09:26:57 -05:00
|
|
|
if !(method_index < supertrait_method_def_ids.len()) {
|
2013-05-19 00:07:44 -05:00
|
|
|
tcx.sess.bug("trans_method_callee: supertrait method \
|
|
|
|
index is out of bounds");
|
2013-01-16 20:45:05 -06:00
|
|
|
}
|
|
|
|
// Get the method name using the method index in the origin
|
2013-03-27 09:26:57 -05:00
|
|
|
let method_name =
|
|
|
|
ty::method(tcx, supertrait_method_def_ids[method_index]).ident;
|
2013-01-16 20:45:05 -06:00
|
|
|
// Now that we know the impl ID, we can look up the method
|
|
|
|
// ID from its name
|
2013-06-07 12:29:21 -05:00
|
|
|
origin = typeck::method_static(
|
|
|
|
method_with_name_or_default(bcx.ccx(),
|
|
|
|
impl_id,
|
|
|
|
method_name));
|
2013-01-16 20:45:05 -06:00
|
|
|
}
|
2013-06-20 11:29:24 -05:00
|
|
|
typeck::method_self(*) |
|
2012-10-08 14:39:30 -05:00
|
|
|
typeck::method_static(*) | typeck::method_param(*) |
|
|
|
|
typeck::method_trait(*) => {}
|
|
|
|
}
|
|
|
|
|
2013-03-21 07:33:52 -05:00
|
|
|
debug!("origin=%?", origin);
|
|
|
|
|
2012-10-08 14:39:30 -05:00
|
|
|
match origin {
|
2012-08-28 17:54:45 -05:00
|
|
|
typeck::method_static(did) => {
|
|
|
|
let callee_fn = callee::trans_fn_ref(bcx, did, callee_id);
|
2013-06-29 10:45:59 -05:00
|
|
|
let mut temp_cleanups = ~[];
|
|
|
|
let Result {bcx, val} = trans_self_arg(bcx, this, &mut temp_cleanups, mentry);
|
2012-08-28 17:54:45 -05:00
|
|
|
Callee {
|
|
|
|
bcx: bcx,
|
|
|
|
data: Method(MethodData {
|
|
|
|
llfn: callee_fn.llfn,
|
|
|
|
llself: val,
|
2013-06-29 10:45:59 -05:00
|
|
|
temp_cleanup: temp_cleanups.head_opt().map(|&v| *v),
|
2013-05-10 17:15:06 -05:00
|
|
|
self_ty: node_id_type(bcx, this.id),
|
2013-04-24 03:29:46 -05:00
|
|
|
self_mode: mentry.self_mode,
|
2012-08-28 17:54:45 -05:00
|
|
|
})
|
|
|
|
}
|
|
|
|
}
|
2013-01-16 21:24:10 -06:00
|
|
|
typeck::method_param(typeck::method_param {
|
|
|
|
trait_id: trait_id,
|
|
|
|
method_num: off,
|
|
|
|
param_num: p,
|
|
|
|
bound_num: b
|
|
|
|
}) => {
|
2012-08-28 17:54:45 -05:00
|
|
|
match bcx.fcx.param_substs {
|
2013-02-18 14:36:30 -06:00
|
|
|
Some(substs) => {
|
2013-01-30 13:46:19 -06:00
|
|
|
let vtbl = find_vtable(bcx.tcx(), substs, p, b);
|
2013-05-10 17:15:06 -05:00
|
|
|
trans_monomorphized_callee(bcx, callee_id, this, mentry,
|
2012-08-28 17:54:45 -05:00
|
|
|
trait_id, off, vtbl)
|
|
|
|
}
|
|
|
|
// how to get rid of this?
|
2013-05-05 17:18:51 -05:00
|
|
|
None => fail!("trans_method_callee: missing param_substs")
|
2012-08-28 17:54:45 -05:00
|
|
|
}
|
|
|
|
}
|
2013-06-20 11:29:24 -05:00
|
|
|
|
|
|
|
typeck::method_self(trait_id, method_index) => {
|
|
|
|
match bcx.fcx.param_substs {
|
|
|
|
Some(@param_substs
|
|
|
|
{self_vtable: Some(ref vtbl), _}) => {
|
|
|
|
trans_monomorphized_callee(bcx, callee_id, this, mentry,
|
|
|
|
trait_id, method_index,
|
|
|
|
copy *vtbl)
|
|
|
|
}
|
|
|
|
_ => {
|
|
|
|
fail!("trans_method_callee: missing self_vtable")
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-03-08 23:16:09 -06:00
|
|
|
typeck::method_trait(_, off, store) => {
|
2012-11-28 19:33:30 -06:00
|
|
|
trans_trait_callee(bcx,
|
|
|
|
callee_id,
|
|
|
|
off,
|
2013-05-10 17:15:06 -05:00
|
|
|
this,
|
2013-03-08 23:16:09 -06:00
|
|
|
store,
|
2012-11-28 19:33:30 -06:00
|
|
|
mentry.explicit_self)
|
2012-02-09 04:17:11 -06:00
|
|
|
}
|
2013-06-29 10:45:59 -05:00
|
|
|
typeck::method_super(*) => {
|
|
|
|
fail!("method_super should have been handled above")
|
2012-10-05 20:51:36 -05:00
|
|
|
}
|
2012-01-26 05:26:14 -06:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-01-30 13:46:19 -06:00
|
|
|
pub fn trans_static_method_callee(bcx: block,
|
|
|
|
method_id: ast::def_id,
|
|
|
|
trait_id: ast::def_id,
|
|
|
|
callee_id: ast::node_id)
|
|
|
|
-> FnData {
|
2013-06-16 23:23:24 -05:00
|
|
|
let _icx = push_ctxt("impl::trans_static_method_callee");
|
2012-08-02 18:01:38 -05:00
|
|
|
let ccx = bcx.ccx();
|
|
|
|
|
2012-10-12 19:00:08 -05:00
|
|
|
debug!("trans_static_method_callee(method_id=%?, trait_id=%s, \
|
|
|
|
callee_id=%?)",
|
|
|
|
method_id,
|
|
|
|
ty::item_path_str(bcx.tcx(), trait_id),
|
|
|
|
callee_id);
|
|
|
|
let _indenter = indenter();
|
|
|
|
|
|
|
|
// When we translate a static fn defined in a trait like:
|
|
|
|
//
|
|
|
|
// trait<T1...Tn> Trait {
|
2013-03-21 21:07:54 -05:00
|
|
|
// fn foo<M1...Mn>(...) {...}
|
2012-10-12 19:00:08 -05:00
|
|
|
// }
|
|
|
|
//
|
|
|
|
// this winds up being translated as something like:
|
|
|
|
//
|
|
|
|
// fn foo<T1...Tn,self: Trait<T1...Tn>,M1...Mn>(...) {...}
|
|
|
|
//
|
|
|
|
// So when we see a call to this function foo, we have to figure
|
|
|
|
// out which impl the `Trait<T1...Tn>` bound on the type `self` was
|
2013-06-26 19:20:53 -05:00
|
|
|
// bound to.
|
|
|
|
let bound_index = ty::lookup_trait_def(bcx.tcx(), trait_id).
|
|
|
|
generics.type_param_defs.len();
|
2012-10-12 19:00:08 -05:00
|
|
|
|
2012-08-02 18:01:38 -05:00
|
|
|
let mname = if method_id.crate == ast::local_crate {
|
2013-05-05 11:17:59 -05:00
|
|
|
match bcx.tcx().items.get_copy(&method_id.node) {
|
2012-08-28 17:54:45 -05:00
|
|
|
ast_map::node_trait_method(trait_method, _, _) => {
|
2013-02-18 00:20:36 -06:00
|
|
|
ast_util::trait_method_to_ty_method(trait_method).ident
|
2012-08-28 17:54:45 -05:00
|
|
|
}
|
2013-05-05 17:18:51 -05:00
|
|
|
_ => fail!("callee is not a trait method")
|
2012-08-02 18:01:38 -05:00
|
|
|
}
|
|
|
|
} else {
|
|
|
|
let path = csearch::get_item_path(bcx.tcx(), method_id);
|
|
|
|
match path[path.len()-1] {
|
2012-08-28 17:54:45 -05:00
|
|
|
path_name(s) => { s }
|
2013-05-05 17:18:51 -05:00
|
|
|
path_mod(_) => { fail!("path doesn't have a name?") }
|
2012-08-02 18:01:38 -05:00
|
|
|
}
|
|
|
|
};
|
|
|
|
debug!("trans_static_method_callee: method_id=%?, callee_id=%?, \
|
2013-06-12 12:02:55 -05:00
|
|
|
name=%s", method_id, callee_id, ccx.sess.str_of(mname));
|
2012-08-02 18:01:38 -05:00
|
|
|
|
|
|
|
let vtbls = resolve_vtables_in_fn_ctxt(
|
2013-05-05 11:17:59 -05:00
|
|
|
bcx.fcx, ccx.maps.vtable_map.get_copy(&callee_id));
|
2012-08-02 18:01:38 -05:00
|
|
|
|
2013-06-26 19:20:53 -05:00
|
|
|
match vtbls[bound_index][0] {
|
2013-03-20 00:17:42 -05:00
|
|
|
typeck::vtable_static(impl_did, ref rcvr_substs, rcvr_origins) => {
|
2013-06-17 18:43:22 -05:00
|
|
|
assert!(rcvr_substs.iter().all(|t| !ty::type_needs_infer(*t)));
|
2012-08-28 17:54:45 -05:00
|
|
|
|
2013-06-07 12:29:21 -05:00
|
|
|
let mth_id = method_with_name_or_default(bcx.ccx(),
|
|
|
|
impl_did,
|
|
|
|
mname);
|
2013-06-26 19:20:53 -05:00
|
|
|
let (callee_substs, callee_origins) =
|
|
|
|
combine_impl_and_methods_tps(
|
|
|
|
bcx, mth_id, impl_did, callee_id,
|
|
|
|
*rcvr_substs, rcvr_origins);
|
2012-08-28 17:54:45 -05:00
|
|
|
|
|
|
|
let FnData {llfn: lval} =
|
2012-09-10 17:12:37 -05:00
|
|
|
trans_fn_ref_with_vtables(bcx,
|
|
|
|
mth_id,
|
|
|
|
callee_id,
|
|
|
|
callee_substs,
|
|
|
|
Some(callee_origins));
|
2012-08-28 17:54:45 -05:00
|
|
|
|
|
|
|
let callee_ty = node_id_type(bcx, callee_id);
|
2013-06-15 22:45:48 -05:00
|
|
|
let llty = type_of_fn_from_ty(ccx, callee_ty).ptr_to();
|
2012-08-28 17:54:45 -05:00
|
|
|
FnData {llfn: PointerCast(bcx, lval, llty)}
|
|
|
|
}
|
|
|
|
_ => {
|
2013-05-05 17:18:51 -05:00
|
|
|
fail!("vtable_param left in monomorphized \
|
2013-01-31 19:51:01 -06:00
|
|
|
function's vtable substs");
|
2012-08-28 17:54:45 -05:00
|
|
|
}
|
2012-08-02 18:01:38 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-03-20 00:17:42 -05:00
|
|
|
pub fn method_from_methods(ms: &[@ast::method], name: ast::ident)
|
2012-12-02 20:29:22 -06:00
|
|
|
-> Option<ast::def_id> {
|
2013-06-17 18:43:22 -05:00
|
|
|
ms.iter().find_(|m| m.ident == name).map(|m| ast_util::local_def(m.id))
|
2012-04-13 14:22:35 -05:00
|
|
|
}
|
|
|
|
|
2013-06-27 08:04:22 -05:00
|
|
|
pub fn method_with_name_or_default(ccx: &mut CrateContext,
|
2013-03-28 21:04:13 -05:00
|
|
|
impl_id: ast::def_id,
|
2013-01-30 13:46:19 -06:00
|
|
|
name: ast::ident) -> ast::def_id {
|
2013-06-14 00:38:17 -05:00
|
|
|
let imp = ccx.impl_method_cache.find_copy(&(impl_id, name));
|
|
|
|
match imp {
|
2013-06-12 16:22:17 -05:00
|
|
|
Some(m) => return m,
|
|
|
|
None => {}
|
|
|
|
}
|
2013-06-14 00:38:17 -05:00
|
|
|
|
2013-06-12 16:22:17 -05:00
|
|
|
// None of this feels like it should be the best way to do this.
|
|
|
|
let mut did = if impl_id.crate == ast::local_crate {
|
|
|
|
match ccx.tcx.items.get_copy(&impl_id.node) {
|
|
|
|
ast_map::node_item(@ast::item {
|
|
|
|
node: ast::item_impl(_, _, _, ref ms), _
|
|
|
|
}, _) => { method_from_methods(*ms, name) },
|
|
|
|
_ => fail!("method_with_name")
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
csearch::get_impl_method(ccx.sess.cstore, impl_id, name)
|
|
|
|
};
|
2013-06-14 00:38:17 -05:00
|
|
|
|
2013-06-12 16:22:17 -05:00
|
|
|
if did.is_none() {
|
|
|
|
// Look for a default method
|
|
|
|
let pmm = ccx.tcx.provided_methods;
|
|
|
|
match pmm.find(&impl_id) {
|
|
|
|
Some(pmis) => {
|
2013-06-21 07:29:53 -05:00
|
|
|
for pmis.iter().advance |pmi| {
|
2013-06-12 16:22:17 -05:00
|
|
|
if pmi.method_info.ident == name {
|
|
|
|
debug!("pmi.method_info.did = %?",
|
|
|
|
pmi.method_info.did);
|
|
|
|
did = Some(pmi.method_info.did);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
None => {}
|
2012-03-08 05:15:02 -06:00
|
|
|
}
|
|
|
|
}
|
2013-06-12 16:22:17 -05:00
|
|
|
|
|
|
|
let imp = did.expect("could not find method while translating");
|
|
|
|
ccx.impl_method_cache.insert((impl_id, name), imp);
|
|
|
|
imp
|
2012-03-08 05:15:02 -06:00
|
|
|
}
|
|
|
|
|
2013-06-13 02:19:50 -05:00
|
|
|
pub fn method_ty_param_count(ccx: &CrateContext, m_id: ast::def_id,
|
2013-01-30 13:46:19 -06:00
|
|
|
i_id: ast::def_id) -> uint {
|
2012-12-10 15:47:54 -06:00
|
|
|
debug!("method_ty_param_count: m_id: %?, i_id: %?", m_id, i_id);
|
2013-06-12 16:22:17 -05:00
|
|
|
ty::method(ccx.tcx, m_id).generics.type_param_defs.len()
|
2012-03-09 01:44:53 -06:00
|
|
|
}
|
|
|
|
|
2013-01-30 13:46:19 -06:00
|
|
|
pub fn trans_monomorphized_callee(bcx: block,
|
|
|
|
callee_id: ast::node_id,
|
|
|
|
base: @ast::expr,
|
|
|
|
mentry: typeck::method_map_entry,
|
|
|
|
trait_id: ast::def_id,
|
|
|
|
n_method: uint,
|
2013-04-17 11:15:37 -05:00
|
|
|
vtbl: typeck::vtable_origin)
|
2013-04-24 03:29:46 -05:00
|
|
|
-> Callee {
|
2013-06-16 23:23:24 -05:00
|
|
|
let _icx = push_ctxt("impl::trans_monomorphized_callee");
|
2012-09-10 14:25:45 -05:00
|
|
|
return match vtbl {
|
2013-03-20 00:17:42 -05:00
|
|
|
typeck::vtable_static(impl_did, ref rcvr_substs, rcvr_origins) => {
|
2012-08-28 17:54:45 -05:00
|
|
|
let ccx = bcx.ccx();
|
2013-03-27 09:26:57 -05:00
|
|
|
let mname = ty::trait_method(ccx.tcx, trait_id, n_method).ident;
|
2012-12-02 20:29:22 -06:00
|
|
|
let mth_id = method_with_name_or_default(
|
|
|
|
bcx.ccx(), impl_did, mname);
|
2012-08-28 17:54:45 -05:00
|
|
|
|
|
|
|
// obtain the `self` value:
|
2013-06-29 10:45:59 -05:00
|
|
|
let mut temp_cleanups = ~[];
|
2012-08-28 17:54:45 -05:00
|
|
|
let Result {bcx, val: llself_val} =
|
2013-06-29 10:45:59 -05:00
|
|
|
trans_self_arg(bcx, base, &mut temp_cleanups, mentry);
|
2012-08-28 17:54:45 -05:00
|
|
|
|
|
|
|
// create a concatenated set of substitutions which includes
|
|
|
|
// those from the impl and those from the method:
|
2013-06-26 19:20:53 -05:00
|
|
|
let (callee_substs, callee_origins) =
|
|
|
|
combine_impl_and_methods_tps(
|
|
|
|
bcx, mth_id, impl_did, callee_id,
|
|
|
|
*rcvr_substs, rcvr_origins);
|
2012-08-28 17:54:45 -05:00
|
|
|
|
|
|
|
// translate the function
|
2013-04-24 03:29:46 -05:00
|
|
|
let callee = trans_fn_ref_with_vtables(bcx,
|
|
|
|
mth_id,
|
|
|
|
callee_id,
|
|
|
|
callee_substs,
|
|
|
|
Some(callee_origins));
|
2012-08-28 17:54:45 -05:00
|
|
|
|
|
|
|
// create a llvalue that represents the fn ptr
|
|
|
|
let fn_ty = node_id_type(bcx, callee_id);
|
2013-06-16 05:52:44 -05:00
|
|
|
let llfn_ty = type_of_fn_from_ty(ccx, fn_ty).ptr_to();
|
2012-08-28 17:54:45 -05:00
|
|
|
let llfn_val = PointerCast(bcx, callee.llfn, llfn_ty);
|
|
|
|
|
|
|
|
// combine the self environment with the rest
|
|
|
|
Callee {
|
|
|
|
bcx: bcx,
|
|
|
|
data: Method(MethodData {
|
|
|
|
llfn: llfn_val,
|
|
|
|
llself: llself_val,
|
2013-06-29 10:45:59 -05:00
|
|
|
temp_cleanup: temp_cleanups.head_opt().map(|&v| *v),
|
2012-08-28 17:54:45 -05:00
|
|
|
self_ty: node_id_type(bcx, base.id),
|
2013-04-24 03:29:46 -05:00
|
|
|
self_mode: mentry.self_mode,
|
2012-08-28 17:54:45 -05:00
|
|
|
})
|
|
|
|
}
|
2012-02-09 04:17:11 -06:00
|
|
|
}
|
2012-08-26 11:58:45 -05:00
|
|
|
typeck::vtable_param(*) => {
|
2013-05-05 17:18:51 -05:00
|
|
|
fail!("vtable_param left in monomorphized function's vtable substs");
|
2012-02-09 04:17:11 -06:00
|
|
|
}
|
2013-06-20 11:29:24 -05:00
|
|
|
typeck::vtable_self(*) => {
|
|
|
|
fail!("vtable_self left in monomorphized function's vtable substs");
|
|
|
|
}
|
2012-09-10 14:25:45 -05:00
|
|
|
};
|
|
|
|
|
|
|
|
}
|
|
|
|
|
2013-01-30 13:46:19 -06:00
|
|
|
pub fn combine_impl_and_methods_tps(bcx: block,
|
|
|
|
mth_did: ast::def_id,
|
|
|
|
impl_did: ast::def_id,
|
|
|
|
callee_id: ast::node_id,
|
2013-06-26 19:20:53 -05:00
|
|
|
rcvr_substs: &[ty::t],
|
|
|
|
rcvr_origins: typeck::vtable_res)
|
|
|
|
-> (~[ty::t], typeck::vtable_res) {
|
2012-09-10 14:25:45 -05: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. */
|
|
|
|
|
|
|
|
let ccx = bcx.ccx();
|
|
|
|
let n_m_tps = method_ty_param_count(ccx, mth_did, impl_did);
|
|
|
|
let node_substs = node_id_type_params(bcx, callee_id);
|
2013-01-07 16:16:52 -06:00
|
|
|
debug!("rcvr_substs=%?", rcvr_substs.map(|t| bcx.ty_to_str(*t)));
|
2012-09-10 14:25:45 -05:00
|
|
|
let ty_substs
|
2013-06-17 18:43:22 -05:00
|
|
|
= vec::append(rcvr_substs.to_owned(),
|
2013-06-27 07:36:27 -05:00
|
|
|
node_substs.tailn(node_substs.len() - n_m_tps));
|
2012-09-10 14:25:45 -05:00
|
|
|
debug!("n_m_tps=%?", n_m_tps);
|
2012-09-21 20:43:30 -05:00
|
|
|
debug!("node_substs=%?", node_substs.map(|t| bcx.ty_to_str(*t)));
|
|
|
|
debug!("ty_substs=%?", ty_substs.map(|t| bcx.ty_to_str(*t)));
|
2012-09-10 14:25:45 -05:00
|
|
|
|
|
|
|
|
2013-06-26 19:20:53 -05:00
|
|
|
// Now, do the same work for the vtables. The vtables might not
|
|
|
|
// exist, in which case we need to make them.
|
2012-09-10 14:25:45 -05:00
|
|
|
let r_m_origins = match node_vtables(bcx, callee_id) {
|
|
|
|
Some(vt) => vt,
|
2013-06-26 19:20:53 -05:00
|
|
|
None => @vec::from_elem(node_substs.len(), @~[])
|
2012-09-10 14:25:45 -05:00
|
|
|
};
|
2013-06-26 19:20:53 -05:00
|
|
|
let vtables
|
|
|
|
= @vec::append(rcvr_origins.to_owned(),
|
|
|
|
r_m_origins.tailn(r_m_origins.len() - n_m_tps));
|
2012-09-10 14:25:45 -05:00
|
|
|
|
2013-06-26 19:20:53 -05:00
|
|
|
return (ty_substs, vtables);
|
2012-02-09 04:17:11 -06:00
|
|
|
}
|
|
|
|
|
2012-09-10 14:25:45 -05:00
|
|
|
|
2013-01-30 13:46:19 -06:00
|
|
|
pub fn trans_trait_callee(bcx: block,
|
|
|
|
callee_id: ast::node_id,
|
|
|
|
n_method: uint,
|
|
|
|
self_expr: @ast::expr,
|
2013-03-08 23:16:09 -06:00
|
|
|
store: ty::TraitStore,
|
2013-04-30 10:49:48 -05:00
|
|
|
explicit_self: ast::explicit_self_)
|
2013-01-30 13:46:19 -06:00
|
|
|
-> Callee {
|
2012-08-28 17:54:45 -05:00
|
|
|
//!
|
|
|
|
//
|
|
|
|
// Create a method callee where the method is coming from a trait
|
|
|
|
// instance (e.g., @Trait type). In this case, we must pull the
|
|
|
|
// fn pointer out of the vtable that is packaged up with the
|
2012-10-05 18:55:42 -05:00
|
|
|
// @/~/&Trait instance. @/~/&Traits are represented as a pair, so we
|
|
|
|
// first evaluate the self expression (expected a by-ref result) and then
|
2012-08-28 17:54:45 -05:00
|
|
|
// extract the self data and vtable out of the pair.
|
|
|
|
|
2013-06-16 23:23:24 -05:00
|
|
|
let _icx = push_ctxt("impl::trans_trait_callee");
|
2012-08-28 17:54:45 -05:00
|
|
|
let mut bcx = bcx;
|
2012-12-13 15:09:38 -06:00
|
|
|
let self_datum = unpack_datum!(bcx,
|
|
|
|
expr::trans_to_datum(bcx, self_expr));
|
2012-08-28 17:54:45 -05:00
|
|
|
let llpair = self_datum.to_ref_llval(bcx);
|
2012-12-13 15:09:38 -06:00
|
|
|
|
|
|
|
let llpair = match explicit_self {
|
2013-03-09 18:43:53 -06:00
|
|
|
ast::sty_region(*) => Load(bcx, llpair),
|
2013-03-26 05:05:40 -05:00
|
|
|
ast::sty_static | ast::sty_value |
|
2013-06-23 23:12:17 -05:00
|
|
|
ast::sty_box(_) | ast::sty_uniq => llpair
|
2012-12-13 15:09:38 -06:00
|
|
|
};
|
|
|
|
|
2012-08-28 17:54:45 -05:00
|
|
|
let callee_ty = node_id_type(bcx, callee_id);
|
2012-11-28 19:33:30 -06:00
|
|
|
trans_trait_callee_from_llval(bcx,
|
|
|
|
callee_ty,
|
|
|
|
n_method,
|
|
|
|
llpair,
|
2013-03-08 23:16:09 -06:00
|
|
|
store,
|
2012-11-28 19:33:30 -06:00
|
|
|
explicit_self)
|
2012-08-28 17:54:45 -05:00
|
|
|
}
|
|
|
|
|
2013-01-30 13:46:19 -06:00
|
|
|
pub fn trans_trait_callee_from_llval(bcx: block,
|
|
|
|
callee_ty: ty::t,
|
|
|
|
n_method: uint,
|
|
|
|
llpair: ValueRef,
|
2013-03-08 23:16:09 -06:00
|
|
|
store: ty::TraitStore,
|
2013-04-30 10:49:48 -05:00
|
|
|
explicit_self: ast::explicit_self_)
|
2013-01-30 13:46:19 -06:00
|
|
|
-> Callee {
|
2012-08-28 17:54:45 -05:00
|
|
|
//!
|
|
|
|
//
|
|
|
|
// Same as `trans_trait_callee()` above, except that it is given
|
|
|
|
// a by-ref pointer to the @Trait pair.
|
|
|
|
|
2013-06-16 23:23:24 -05:00
|
|
|
let _icx = push_ctxt("impl::trans_trait_callee");
|
2012-05-14 17:48:58 -05:00
|
|
|
let ccx = bcx.ccx();
|
2012-08-28 17:54:45 -05:00
|
|
|
|
|
|
|
// Load the vtable from the @Trait pair
|
2012-11-28 19:33:30 -06:00
|
|
|
debug!("(translating trait callee) loading vtable from pair %s",
|
2013-06-14 22:16:03 -05:00
|
|
|
bcx.val_to_str(llpair));
|
2012-08-28 17:54:45 -05:00
|
|
|
let llvtable = Load(bcx,
|
|
|
|
PointerCast(bcx,
|
2013-05-01 03:59:36 -05:00
|
|
|
GEPi(bcx, llpair,
|
|
|
|
[0u, abi::trt_field_vtable]),
|
2013-06-15 22:45:48 -05:00
|
|
|
Type::vtable().ptr_to().ptr_to()));
|
2012-08-28 17:54:45 -05:00
|
|
|
|
2012-10-05 18:55:42 -05:00
|
|
|
// Load the box from the @Trait pair and GEP over the box header if
|
|
|
|
// necessary:
|
2012-11-28 19:33:30 -06:00
|
|
|
let mut llself;
|
|
|
|
debug!("(translating trait callee) loading second index from pair");
|
2013-06-27 18:40:27 -05:00
|
|
|
let llboxptr = GEPi(bcx, llpair, [0u, abi::trt_field_box]);
|
|
|
|
let llbox = Load(bcx, llboxptr);
|
2012-08-28 17:54:45 -05:00
|
|
|
|
2012-11-28 19:33:30 -06:00
|
|
|
// Munge `llself` appropriately for the type of `self` in the method.
|
|
|
|
match explicit_self {
|
|
|
|
ast::sty_static => {
|
2013-05-19 00:07:44 -05:00
|
|
|
bcx.tcx().sess.bug("shouldn't see static method here");
|
2012-11-28 19:33:30 -06:00
|
|
|
}
|
|
|
|
ast::sty_value => {
|
2013-05-19 00:07:44 -05:00
|
|
|
bcx.tcx().sess.bug("methods with by-value self should not be \
|
|
|
|
called on objects");
|
2012-11-28 19:33:30 -06:00
|
|
|
}
|
2013-03-09 18:43:53 -06:00
|
|
|
ast::sty_region(*) => {
|
2013-03-08 23:16:09 -06:00
|
|
|
match store {
|
|
|
|
ty::BoxTraitStore |
|
|
|
|
ty::UniqTraitStore => {
|
2012-11-29 12:59:49 -06:00
|
|
|
llself = GEPi(bcx, llbox, [0u, abi::box_field_body]);
|
|
|
|
}
|
2013-03-08 23:16:09 -06:00
|
|
|
ty::RegionTraitStore(_) => {
|
2012-11-29 12:59:49 -06:00
|
|
|
llself = llbox;
|
|
|
|
}
|
|
|
|
}
|
2012-11-28 19:33:30 -06:00
|
|
|
}
|
|
|
|
ast::sty_box(_) => {
|
|
|
|
// Bump the reference count on the box.
|
|
|
|
debug!("(translating trait callee) callee type is `%s`",
|
|
|
|
bcx.ty_to_str(callee_ty));
|
2013-06-27 18:40:27 -05:00
|
|
|
glue::incr_refcnt_of_boxed(bcx, llbox);
|
2012-11-29 12:59:49 -06:00
|
|
|
|
|
|
|
// Pass a pointer to the box.
|
2013-03-08 23:16:09 -06:00
|
|
|
match store {
|
2013-03-27 05:16:28 -05:00
|
|
|
ty::BoxTraitStore => llself = llbox,
|
2013-05-19 00:07:44 -05:00
|
|
|
_ => bcx.tcx().sess.bug("@self receiver with non-@Trait")
|
2012-11-29 12:59:49 -06:00
|
|
|
}
|
|
|
|
}
|
2013-06-23 23:12:17 -05:00
|
|
|
ast::sty_uniq => {
|
2012-11-29 12:59:49 -06:00
|
|
|
// Pass the unique pointer.
|
2013-03-08 23:16:09 -06:00
|
|
|
match store {
|
|
|
|
ty::UniqTraitStore => llself = llbox,
|
2013-05-19 00:07:44 -05:00
|
|
|
_ => bcx.tcx().sess.bug("~self receiver with non-~Trait")
|
2012-11-29 12:59:49 -06:00
|
|
|
}
|
|
|
|
|
2013-06-27 18:40:27 -05:00
|
|
|
zero_mem(bcx, llboxptr, ty::mk_opaque_box(bcx.tcx()));
|
2012-11-28 19:33:30 -06:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-06-27 18:40:27 -05:00
|
|
|
llself = PointerCast(bcx, llself, Type::opaque_box(ccx).ptr_to());
|
|
|
|
let scratch = scratch_datum(bcx, ty::mk_opaque_box(bcx.tcx()), false);
|
|
|
|
Store(bcx, llself, scratch.val);
|
|
|
|
scratch.add_clean(bcx);
|
2013-06-29 09:43:39 -05:00
|
|
|
|
2012-08-28 17:54:45 -05:00
|
|
|
// Load the function from the vtable and cast it to the expected type.
|
2012-11-28 19:33:30 -06:00
|
|
|
debug!("(translating trait callee) loading method");
|
2013-02-25 13:11:21 -06:00
|
|
|
let llcallee_ty = type_of_fn_from_ty(ccx, callee_ty);
|
2013-05-15 19:38:52 -05:00
|
|
|
|
|
|
|
// Plus one in order to skip past the type descriptor.
|
|
|
|
let mptr = Load(bcx, GEPi(bcx, llvtable, [0u, n_method + 1]));
|
|
|
|
|
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,
|
|
|
|
data: Method(MethodData {
|
|
|
|
llfn: mptr,
|
2013-06-27 18:40:27 -05:00
|
|
|
llself: scratch.to_value_llval(bcx),
|
|
|
|
temp_cleanup: Some(scratch.val),
|
|
|
|
self_ty: scratch.ty,
|
|
|
|
self_mode: ty::ByCopy,
|
2012-08-28 17:54:45 -05:00
|
|
|
/* XXX: Some(llbox) */
|
|
|
|
})
|
|
|
|
};
|
2012-01-07 15:44:14 -06:00
|
|
|
}
|
|
|
|
|
2013-06-13 02:19:50 -05:00
|
|
|
pub fn vtable_id(ccx: @mut CrateContext,
|
2013-05-17 19:27:44 -05:00
|
|
|
origin: &typeck::vtable_origin)
|
2013-01-30 13:46:19 -06:00
|
|
|
-> mono_id {
|
2012-08-23 19:39:07 -05:00
|
|
|
match origin {
|
2013-05-17 19:27:44 -05:00
|
|
|
&typeck::vtable_static(impl_id, ref substs, sub_vtables) => {
|
2013-07-01 20:38:41 -05:00
|
|
|
let psubsts = param_substs {
|
|
|
|
tys: copy *substs,
|
|
|
|
vtables: Some(sub_vtables),
|
|
|
|
self_ty: None,
|
|
|
|
self_vtable: None
|
|
|
|
};
|
|
|
|
|
2012-08-28 17:54:45 -05:00
|
|
|
monomorphize::make_mono_id(
|
2012-10-08 14:39:30 -05:00
|
|
|
ccx,
|
|
|
|
impl_id,
|
|
|
|
None,
|
2013-07-01 20:38:41 -05:00
|
|
|
&psubsts,
|
2012-10-08 14:39:30 -05:00
|
|
|
None)
|
2012-08-28 17:54:45 -05:00
|
|
|
}
|
2013-03-05 16:49:50 -06:00
|
|
|
|
2012-08-28 17:54:45 -05:00
|
|
|
// can't this be checked at the callee?
|
2013-05-05 17:18:51 -05:00
|
|
|
_ => fail!("vtable_id")
|
2012-03-08 09:10:25 -06:00
|
|
|
}
|
2012-01-12 09:57:30 -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.
|
2013-06-07 12:29:21 -05:00
|
|
|
pub fn get_vtable(bcx: block,
|
2013-05-15 19:38:52 -05:00
|
|
|
self_ty: ty::t,
|
2013-04-17 11:15:37 -05:00
|
|
|
origin: typeck::vtable_origin)
|
2013-05-15 19:38:52 -05:00
|
|
|
-> ValueRef {
|
2013-06-07 12:29:21 -05:00
|
|
|
let hash_id = vtable_id(bcx.ccx(), &origin);
|
|
|
|
match bcx.ccx().vtables.find(&hash_id) {
|
2013-05-15 19:38:52 -05:00
|
|
|
Some(&val) => val,
|
|
|
|
None => {
|
|
|
|
match origin {
|
|
|
|
typeck::vtable_static(id, substs, sub_vtables) => {
|
2013-06-07 12:29:21 -05:00
|
|
|
make_impl_vtable(bcx, id, self_ty, substs, sub_vtables)
|
2013-05-15 19:38:52 -05:00
|
|
|
}
|
|
|
|
_ => fail!("get_vtable: expected a static origin"),
|
|
|
|
}
|
2012-01-02 09:50:51 -06:00
|
|
|
}
|
|
|
|
}
|
2012-01-12 09:57:30 -06:00
|
|
|
}
|
2012-01-02 06:26:51 -06:00
|
|
|
|
2013-05-15 19:38:52 -05:00
|
|
|
/// Helper function to declare and initialize the vtable.
|
2013-06-27 08:04:22 -05:00
|
|
|
pub fn make_vtable(ccx: &mut CrateContext,
|
|
|
|
tydesc: &tydesc_info,
|
2013-05-15 19:38:52 -05:00
|
|
|
ptrs: &[ValueRef])
|
|
|
|
-> ValueRef {
|
2013-01-10 23:23:07 -06:00
|
|
|
unsafe {
|
2013-06-16 23:23:24 -05:00
|
|
|
let _icx = push_ctxt("impl::make_vtable");
|
2013-05-15 19:38:52 -05:00
|
|
|
|
|
|
|
let mut components = ~[ tydesc.tydesc ];
|
2013-06-21 07:29:53 -05:00
|
|
|
for ptrs.iter().advance |&ptr| {
|
2013-05-15 19:38:52 -05:00
|
|
|
components.push(ptr)
|
|
|
|
}
|
|
|
|
|
|
|
|
let tbl = C_struct(components);
|
2013-06-29 00:07:24 -05:00
|
|
|
let vtable = ccx.sess.str_of(gensym_name("vtable"));
|
|
|
|
let vt_gvar = do vtable.as_c_str |buf| {
|
2013-06-16 05:52:44 -05:00
|
|
|
llvm::LLVMAddGlobal(ccx.llmod, val_ty(tbl).to_ref(), buf)
|
2013-02-10 18:33:16 -06:00
|
|
|
};
|
2013-01-10 23:23:07 -06:00
|
|
|
llvm::LLVMSetInitializer(vt_gvar, tbl);
|
|
|
|
llvm::LLVMSetGlobalConstant(vt_gvar, lib::llvm::True);
|
|
|
|
lib::llvm::SetLinkage(vt_gvar, lib::llvm::InternalLinkage);
|
|
|
|
vt_gvar
|
|
|
|
}
|
2012-01-12 09:57:30 -06:00
|
|
|
}
|
2012-01-02 06:26:51 -06:00
|
|
|
|
2013-05-15 19:38:52 -05:00
|
|
|
/// Generates a dynamic vtable for objects.
|
2013-06-07 12:29:21 -05:00
|
|
|
pub fn make_impl_vtable(bcx: block,
|
2013-01-30 13:46:19 -06:00
|
|
|
impl_id: ast::def_id,
|
2013-05-15 19:38:52 -05:00
|
|
|
self_ty: ty::t,
|
2013-06-27 08:04:22 -05:00
|
|
|
substs: &[ty::t],
|
2013-01-30 13:46:19 -06:00
|
|
|
vtables: typeck::vtable_res)
|
2013-05-15 19:38:52 -05:00
|
|
|
-> ValueRef {
|
2013-06-07 12:29:21 -05:00
|
|
|
let ccx = bcx.ccx();
|
2013-06-16 23:23:24 -05:00
|
|
|
let _icx = push_ctxt("impl::make_impl_vtable");
|
2012-03-08 09:10:25 -06:00
|
|
|
let tcx = ccx.tcx;
|
2012-07-18 18:49:55 -05:00
|
|
|
|
2013-05-16 17:54:51 -05:00
|
|
|
let trt_id = match ty::impl_trait_ref(tcx, impl_id) {
|
|
|
|
Some(t_id) => t_id.def_id,
|
|
|
|
None => ccx.sess.bug("make_impl_vtable: don't know how to \
|
|
|
|
make a vtable for a type impl!")
|
|
|
|
};
|
2013-03-27 05:16:28 -05:00
|
|
|
|
2013-05-15 19:38:52 -05:00
|
|
|
let trait_method_def_ids = ty::trait_method_def_ids(tcx, trt_id);
|
|
|
|
let methods = do trait_method_def_ids.map |method_def_id| {
|
2013-03-27 09:26:57 -05:00
|
|
|
let im = ty::method(tcx, *method_def_id);
|
2013-05-15 19:38:52 -05:00
|
|
|
let fty = ty::subst_tps(tcx,
|
|
|
|
substs,
|
|
|
|
None,
|
2013-01-31 19:12:29 -06:00
|
|
|
ty::mk_bare_fn(tcx, copy im.fty));
|
Cleanup substitutions and treatment of generics around traits in a number of ways.
- In a TraitRef, use the self type consistently to refer to the Self type:
- trait ref in `impl Trait<A,B,C> for S` has a self type of `S`.
- trait ref in `A:Trait` has the self type `A`
- trait ref associated with a trait decl has self type `Self`
- trait ref associated with a supertype has self type `Self`
- trait ref in an object type `@Trait` has no self type
- Rewrite `each_bound_traits_and_supertraits` to perform
substitutions as it goes, and thus yield a series of trait refs
that are always in the same 'namespace' as the type parameter
bound given as input. Before, we left this to the caller, but
this doesn't work because the caller lacks adequare information
to perform the type substitutions correctly.
- For provided methods, substitute the generics involved in the provided
method correctly.
- Introduce TypeParameterDef, which tracks the bounds declared on a type
parameter and brings them together with the def_id and (in the future)
other information (maybe even the parameter's name!).
- Introduce Subst trait, which helps to cleanup a lot of the
repetitive code involved with doing type substitution.
- Introduce Repr trait, which makes debug printouts far more convenient.
Fixes #4183. Needed for #5656.
2013-04-09 00:54:49 -05:00
|
|
|
if im.generics.has_type_params() || ty::type_has_self(fty) {
|
2012-11-28 19:33:30 -06:00
|
|
|
debug!("(making impl vtable) method has self or type params: %s",
|
2013-06-12 12:02:55 -05:00
|
|
|
tcx.sess.str_of(im.ident));
|
2013-06-15 22:45:48 -05:00
|
|
|
C_null(Type::nil().ptr_to())
|
2012-03-08 09:10:25 -06:00
|
|
|
} else {
|
2012-11-28 19:33:30 -06:00
|
|
|
debug!("(making impl vtable) adding method to vtable: %s",
|
2013-06-12 12:02:55 -05:00
|
|
|
tcx.sess.str_of(im.ident));
|
2013-06-07 12:29:21 -05:00
|
|
|
let m_id = method_with_name_or_default(ccx, impl_id, im.ident);
|
|
|
|
|
|
|
|
trans_fn_ref_with_vtables(bcx, m_id, 0,
|
|
|
|
substs, Some(vtables)).llfn
|
2012-01-12 09:57:30 -06:00
|
|
|
}
|
2013-05-15 19:38:52 -05:00
|
|
|
};
|
|
|
|
|
|
|
|
// Generate a type descriptor for the vtable.
|
|
|
|
let tydesc = get_tydesc(ccx, self_ty);
|
|
|
|
glue::lazily_emit_all_tydesc_glue(ccx, tydesc);
|
|
|
|
|
|
|
|
make_vtable(ccx, tydesc, methods)
|
2012-01-12 09:57:30 -06:00
|
|
|
}
|
|
|
|
|
2013-01-30 13:46:19 -06:00
|
|
|
pub fn trans_trait_cast(bcx: block,
|
|
|
|
val: @ast::expr,
|
|
|
|
id: ast::node_id,
|
|
|
|
dest: expr::Dest,
|
2013-05-23 11:39:10 -05:00
|
|
|
_store: ty::TraitStore)
|
2013-01-30 13:46:19 -06:00
|
|
|
-> block {
|
2012-10-03 17:18:50 -05:00
|
|
|
let mut bcx = bcx;
|
2013-06-16 23:23:24 -05:00
|
|
|
let _icx = push_ctxt("impl::trans_cast");
|
2012-08-28 17:54:45 -05:00
|
|
|
|
|
|
|
let lldest = match dest {
|
|
|
|
Ignore => {
|
|
|
|
return expr::trans_into(bcx, val, Ignore);
|
|
|
|
}
|
|
|
|
SaveIn(dest) => dest
|
|
|
|
};
|
|
|
|
|
2012-02-21 07:20:18 -06:00
|
|
|
let ccx = bcx.ccx();
|
2012-02-10 04:32:03 -06:00
|
|
|
let v_ty = expr_ty(bcx, val);
|
2012-08-28 17:54:45 -05:00
|
|
|
|
2013-05-15 19:38:52 -05:00
|
|
|
let mut llboxdest = GEPi(bcx, lldest, [0u, abi::trt_field_box]);
|
|
|
|
// Just store the pointer into the pair. (Region/borrowed
|
|
|
|
// and boxed trait objects are represented as pairs, and
|
|
|
|
// have no type descriptor field.)
|
|
|
|
llboxdest = PointerCast(bcx,
|
|
|
|
llboxdest,
|
2013-06-15 22:45:48 -05:00
|
|
|
type_of(bcx.ccx(), v_ty).ptr_to());
|
2013-05-15 19:38:52 -05:00
|
|
|
bcx = expr::trans_into(bcx, val, SaveIn(llboxdest));
|
2012-08-28 17:54:45 -05:00
|
|
|
|
2012-10-31 17:09:26 -05:00
|
|
|
// Store the vtable into the pair or triple.
|
2013-06-26 19:20:53 -05:00
|
|
|
let orig = /*bad*/copy ccx.maps.vtable_map.get(&id)[0][0];
|
2012-03-08 09:10:25 -06:00
|
|
|
let orig = resolve_vtable_in_fn_ctxt(bcx.fcx, orig);
|
2013-06-07 12:29:21 -05:00
|
|
|
let vtable = get_vtable(bcx, v_ty, orig);
|
2012-08-28 17:54:45 -05:00
|
|
|
Store(bcx, vtable, PointerCast(bcx,
|
2013-05-01 03:59:36 -05:00
|
|
|
GEPi(bcx, lldest, [0u, abi::trt_field_vtable]),
|
2013-06-15 22:45:48 -05:00
|
|
|
val_ty(vtable).ptr_to()));
|
2012-08-28 17:54:45 -05:00
|
|
|
|
2012-02-10 04:32:03 -06:00
|
|
|
bcx
|
2012-01-07 15:44:14 -06:00
|
|
|
}
|