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
|
|
|
use core::prelude::*;
|
|
|
|
|
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::*;
|
|
|
|
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;
|
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
|
|
|
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-05-24 21:35:29 -05:00
|
|
|
use core::str;
|
|
|
|
use core::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-04-26 21:10:28 -05:00
|
|
|
llfn,
|
2012-10-08 14:39:30 -05:00
|
|
|
ast_util::local_def(id));
|
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-01-30 13:46:19 -06:00
|
|
|
llfn: ValueRef,
|
|
|
|
impl_id: ast::def_id) {
|
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-02-18 14:36:30 -06:00
|
|
|
Some(@param_substs {tys: ref tys, _}) => {
|
2012-10-08 14:39:30 -05:00
|
|
|
ty::subst_tps(ccx.tcx, *tys, None, self_ty)
|
|
|
|
}
|
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 {
|
2012-08-22 15:18:29 -05:00
|
|
|
ast::sty_value => {
|
|
|
|
impl_owned_self(self_ty)
|
|
|
|
}
|
|
|
|
_ => {
|
|
|
|
impl_self(self_ty)
|
|
|
|
}
|
|
|
|
}
|
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
|
|
|
Some(impl_id),
|
|
|
|
[]);
|
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,
|
|
|
|
mentry: typeck::method_map_entry) -> Result {
|
2013-06-16 23:23:24 -05:00
|
|
|
let _icx = push_ctxt("impl::trans_self_arg");
|
2012-06-29 18:26:56 -05:00
|
|
|
let mut temp_cleanups = ~[];
|
2012-10-08 14:39:30 -05:00
|
|
|
|
2013-04-24 03:29:46 -05:00
|
|
|
// Compute the type of self.
|
2013-04-26 21:13:38 -05:00
|
|
|
let self_ty = monomorphize_type(bcx, mentry.self_ty);
|
2012-10-08 14:39:30 -05:00
|
|
|
|
2013-04-24 03:29:46 -05:00
|
|
|
let result = trans_arg_expr(bcx,
|
2013-04-26 21:13:38 -05:00
|
|
|
self_ty,
|
2013-04-24 03:29:46 -05:00
|
|
|
mentry.self_mode,
|
|
|
|
base,
|
|
|
|
&mut temp_cleanups,
|
|
|
|
None,
|
|
|
|
DontAutorefArg);
|
2012-09-11 23:25:01 -05:00
|
|
|
|
|
|
|
// FIXME(#3446)---this is wrong, actually. The temp_cleanups
|
|
|
|
// should be revoked only after all arguments have been passed.
|
2013-06-21 07:29:53 -05:00
|
|
|
for temp_cleanups.iter().advance |c| {
|
2012-09-19 18:55:01 -05:00
|
|
|
revoke_clean(bcx, *c)
|
2012-09-11 23:25:01 -05:00
|
|
|
}
|
2012-02-24 19:45:16 -06:00
|
|
|
|
2012-08-01 19:30:05 -05:00
|
|
|
return result;
|
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-05-29 14:49:23 -05:00
|
|
|
typeck::method_self(trait_id, method_index) => {
|
2012-10-08 14:39:30 -05:00
|
|
|
// Get the ID of the impl we're inside.
|
|
|
|
let impl_def_id = bcx.fcx.impl_id.get();
|
|
|
|
|
2012-10-22 15:33:12 -05:00
|
|
|
debug!("impl_def_id is %?", impl_def_id);
|
2012-10-08 14:39:30 -05:00
|
|
|
|
|
|
|
// Get the ID of the method we're calling.
|
|
|
|
let method_name =
|
2013-03-27 09:26:57 -05:00
|
|
|
ty::trait_method(tcx, trait_id, method_index).ident;
|
|
|
|
let method_id =
|
2013-06-07 12:29:21 -05:00
|
|
|
method_with_name_or_default(bcx.ccx(),
|
|
|
|
impl_def_id,
|
|
|
|
method_name);
|
2012-10-08 14:39:30 -05:00
|
|
|
origin = typeck::method_static(method_id);
|
|
|
|
}
|
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
|
|
|
}
|
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-05-10 17:15:06 -05:00
|
|
|
let Result {bcx, val} = trans_self_arg(bcx, this, mentry);
|
2012-08-28 17:54:45 -05:00
|
|
|
Callee {
|
|
|
|
bcx: bcx,
|
|
|
|
data: Method(MethodData {
|
|
|
|
llfn: callee_fn.llfn,
|
|
|
|
llself: val,
|
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-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-01-16 20:45:05 -06:00
|
|
|
typeck::method_self(*) | typeck::method_super(*) => {
|
2013-05-05 17:18:51 -05:00
|
|
|
fail!("method_self or method_super should have been handled \
|
2013-01-31 19:51:01 -06:00
|
|
|
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
|
|
|
|
// bound to. Due to the fact that we use a flattened list of
|
|
|
|
// impls, one per bound, this means we have to total up the bounds
|
|
|
|
// found on the type parametesr T1...Tn to find the index of the
|
|
|
|
// one we are interested in.
|
|
|
|
let bound_index = {
|
2013-03-27 05:16:28 -05:00
|
|
|
let trait_def = ty::lookup_trait_def(bcx.tcx(), trait_id);
|
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
|
|
|
ty::count_traits_and_supertraits(
|
|
|
|
bcx.tcx(), *trait_def.generics.type_param_defs)
|
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-03-20 00:17:42 -05:00
|
|
|
match vtbls[bound_index] {
|
|
|
|
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);
|
2012-09-10 14:25:45 -05:00
|
|
|
let callee_substs = combine_impl_and_methods_tps(
|
2013-03-20 00:17:42 -05:00
|
|
|
bcx, mth_id, impl_did, callee_id, *rcvr_substs);
|
2012-09-10 14:25:45 -05:00
|
|
|
let callee_origins = combine_impl_and_methods_origins(
|
|
|
|
bcx, mth_id, impl_did, callee_id, 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-13 02:19:50 -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:
|
|
|
|
let Result {bcx, val: llself_val} =
|
|
|
|
trans_self_arg(bcx, base, mentry);
|
|
|
|
|
|
|
|
// create a concatenated set of substitutions which includes
|
|
|
|
// those from the impl and those from the method:
|
2012-09-10 14:25:45 -05:00
|
|
|
let callee_substs = combine_impl_and_methods_tps(
|
2013-03-20 00:17:42 -05:00
|
|
|
bcx, mth_id, impl_did, callee_id, *rcvr_substs);
|
2012-09-10 14:25:45 -05:00
|
|
|
let callee_origins = combine_impl_and_methods_origins(
|
|
|
|
bcx, mth_id, impl_did, callee_id, 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,
|
|
|
|
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
|
|
|
}
|
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-03-20 00:17:42 -05:00
|
|
|
rcvr_substs: &[ty::t])
|
2013-04-24 03:29:46 -05:00
|
|
|
-> ~[ty::t] {
|
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(),
|
2012-09-10 14:25:45 -05:00
|
|
|
vec::tailn(node_substs,
|
|
|
|
node_substs.len() - n_m_tps));
|
|
|
|
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
|
|
|
|
|
|
|
return ty_substs;
|
|
|
|
}
|
|
|
|
|
2013-01-30 13:46:19 -06:00
|
|
|
pub fn combine_impl_and_methods_origins(bcx: block,
|
|
|
|
mth_did: ast::def_id,
|
|
|
|
impl_did: ast::def_id,
|
|
|
|
callee_id: ast::node_id,
|
|
|
|
rcvr_origins: typeck::vtable_res)
|
|
|
|
-> typeck::vtable_res {
|
2012-09-10 14:25:45 -05:00
|
|
|
/*!
|
|
|
|
*
|
|
|
|
* Similar to `combine_impl_and_methods_tps`, but for vtables.
|
|
|
|
* This is much messier because of the flattened layout we are
|
|
|
|
* currently using (for some reason that I fail to understand).
|
|
|
|
* The proper fix is described in #3446.
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
|
|
// Find the bounds for the method, which are the tail of the
|
|
|
|
// bounds found in the item type, as the item type combines the
|
|
|
|
// rcvr + method bounds.
|
2013-06-04 23:43:41 -05:00
|
|
|
let ccx = bcx.ccx();
|
|
|
|
let tcx = bcx.tcx();
|
2012-09-10 14:25:45 -05:00
|
|
|
let n_m_tps = method_ty_param_count(ccx, mth_did, impl_did);
|
2013-03-27 05:16:28 -05:00
|
|
|
let ty::ty_param_bounds_and_ty {
|
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
|
|
|
generics: r_m_generics,
|
2013-03-27 05:16:28 -05:00
|
|
|
_
|
|
|
|
} = ty::lookup_item_type(tcx, mth_did);
|
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
|
|
|
let n_r_m_tps = r_m_generics.type_param_defs.len(); // rcvr + method tps
|
|
|
|
let m_type_param_defs =
|
|
|
|
vec::slice(*r_m_generics.type_param_defs, n_r_m_tps - n_m_tps, n_r_m_tps);
|
2012-09-10 14:25:45 -05:00
|
|
|
|
|
|
|
// Flatten out to find the number of vtables the method expects.
|
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
|
|
|
let m_vtables = ty::count_traits_and_supertraits(tcx, m_type_param_defs);
|
2012-09-10 14:25:45 -05:00
|
|
|
|
|
|
|
// Find the vtables we computed at type check time and monomorphize them
|
|
|
|
let r_m_origins = match node_vtables(bcx, callee_id) {
|
|
|
|
Some(vt) => vt,
|
|
|
|
None => @~[]
|
|
|
|
};
|
|
|
|
|
|
|
|
// Extract those that belong to method:
|
|
|
|
let m_origins = vec::tailn(*r_m_origins, r_m_origins.len() - m_vtables);
|
|
|
|
|
|
|
|
// Combine rcvr + method to find the final result:
|
2013-01-07 16:16:52 -06:00
|
|
|
@vec::append(/*bad*/copy *rcvr_origins, m_origins)
|
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 |
|
2012-12-13 15:09:38 -06:00
|
|
|
ast::sty_box(_) | ast::sty_uniq(_) => llpair
|
|
|
|
};
|
|
|
|
|
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
|
|
|
let mut bcx = bcx;
|
|
|
|
|
|
|
|
// 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-05-01 03:59:36 -05:00
|
|
|
let llbox = Load(bcx, GEPi(bcx, llpair, [0u, abi::trt_field_box]));
|
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.
|
2012-11-29 12:59:49 -06:00
|
|
|
let self_mode;
|
2012-11-28 19:33:30 -06:00
|
|
|
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(*) => {
|
2012-11-29 12:59:49 -06:00
|
|
|
// As before, we need to pass a pointer to a pointer to the
|
|
|
|
// payload.
|
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
|
|
|
let llscratch = alloca(bcx, val_ty(llself));
|
|
|
|
Store(bcx, llself, llscratch);
|
|
|
|
llself = llscratch;
|
2012-11-29 12:59:49 -06:00
|
|
|
|
2013-04-24 03:29:46 -05:00
|
|
|
self_mode = ty::ByRef;
|
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));
|
2012-11-29 12:59:49 -06:00
|
|
|
bcx = glue::take_ty(bcx, llbox, callee_ty);
|
|
|
|
|
|
|
|
// 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
|
|
|
}
|
|
|
|
|
|
|
|
let llscratch = alloca(bcx, val_ty(llself));
|
|
|
|
Store(bcx, llself, llscratch);
|
|
|
|
llself = llscratch;
|
|
|
|
|
2013-04-24 03:29:46 -05:00
|
|
|
self_mode = ty::ByRef;
|
2012-11-29 12:59:49 -06:00
|
|
|
}
|
|
|
|
ast::sty_uniq(_) => {
|
|
|
|
// 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
|
|
|
}
|
|
|
|
|
|
|
|
let llscratch = alloca(bcx, val_ty(llself));
|
|
|
|
Store(bcx, llself, llscratch);
|
|
|
|
llself = llscratch;
|
|
|
|
|
2013-04-24 03:29:46 -05:00
|
|
|
self_mode = ty::ByRef;
|
2012-11-28 19:33:30 -06: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,
|
|
|
|
llself: llself,
|
|
|
|
self_ty: ty::mk_opaque_box(bcx.tcx()),
|
2012-11-29 12:59:49 -06:00
|
|
|
self_mode: self_mode,
|
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) => {
|
2012-08-28 17:54:45 -05:00
|
|
|
monomorphize::make_mono_id(
|
2012-10-08 14:39:30 -05:00
|
|
|
ccx,
|
|
|
|
impl_id,
|
2013-05-17 19:27:44 -05:00
|
|
|
*substs,
|
|
|
|
if sub_vtables.is_empty() {
|
2012-10-08 14:39:30 -05:00
|
|
|
None
|
|
|
|
} else {
|
|
|
|
Some(sub_vtables)
|
|
|
|
},
|
|
|
|
None,
|
|
|
|
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-13 02:19:50 -05:00
|
|
|
pub fn make_vtable(ccx: @mut CrateContext,
|
2013-05-15 19:38:52 -05:00
|
|
|
tydesc: @mut tydesc_info,
|
|
|
|
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-05-02 03:16:07 -05:00
|
|
|
let vtable = ccx.sess.str_of((ccx.names)("vtable"));
|
2013-06-12 12:02:55 -05:00
|
|
|
let vt_gvar = do str::as_c_str(vtable) |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-01-30 13:46:19 -06:00
|
|
|
substs: ~[ty::t],
|
|
|
|
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-02-05 21:41:45 -06:00
|
|
|
let orig = /*bad*/copy ccx.maps.vtable_map.get(&id)[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
|
|
|
}
|