auto merge of #7471 : msullivan/rust/default-methods, r=graydon

This fixes a bunch of default method bugs and restructures how vtable resolutions are represented.

(It also adds a depth counter to llvm::type_to_str as a hacky work around for our circular llvm types. This is related in the sense that I needed to do it to make debug tracing not cause rustc to crash after running out of stack space.)
This commit is contained in:
bors 2013-06-28 20:16:56 -07:00
commit d681bccb6a
18 changed files with 425 additions and 177 deletions

View File

@ -2149,18 +2149,24 @@ impl TypeNames {
self.named_types.find_equiv(&s).map_consume(|x| Type::from_ref(*x))
}
pub fn type_to_str(&self, ty: Type) -> ~str {
// We have a depth count, because we seem to make infinite types.
pub fn type_to_str_depth(&self, ty: Type, depth: int) -> ~str {
match self.find_name(&ty) {
option::Some(name) => return name.to_owned(),
None => ()
}
if depth == 0 {
return ~"###";
}
unsafe {
let kind = ty.kind();
match kind {
Void => ~"Void",
Half => ~"Half",
Float => ~"Float",
Double => ~"Double",
X86_FP80 => ~"X86_FP80",
FP128 => ~"FP128",
@ -2175,24 +2181,25 @@ impl TypeNames {
Function => {
let out_ty = ty.return_type();
let args = ty.func_params();
let args = args.map(|&ty| self.type_to_str(ty)).connect(", ");
let out_ty = self.type_to_str(out_ty);
let args =
args.map(|&ty| self.type_to_str_depth(ty, depth-1)).connect(", ");
let out_ty = self.type_to_str_depth(out_ty, depth-1);
fmt!("fn(%s) -> %s", args, out_ty)
}
Struct => {
let tys = ty.field_types();
let tys = tys.map(|&ty| self.type_to_str(ty)).connect(", ");
let tys = tys.map(|&ty| self.type_to_str_depth(ty, depth-1)).connect(", ");
fmt!("{%s}", tys)
}
Array => {
let el_ty = ty.element_type();
let el_ty = self.type_to_str(el_ty);
let el_ty = self.type_to_str_depth(el_ty, depth-1);
let len = ty.array_length();
fmt!("[%s x %u]", el_ty, len)
}
Pointer => {
let el_ty = ty.element_type();
let el_ty = self.type_to_str(el_ty);
let el_ty = self.type_to_str_depth(el_ty, depth-1);
fmt!("*%s", el_ty)
}
_ => fail!("Unknown Type Kind (%u)", kind as uint)
@ -2200,6 +2207,10 @@ impl TypeNames {
}
}
pub fn type_to_str(&self, ty: Type) -> ~str {
self.type_to_str_depth(ty, 30)
}
pub fn val_to_str(&self, val: ValueRef) -> ~str {
unsafe {
let ty = Type::from_ref(llvm::LLVMTypeOf(val));

View File

@ -599,8 +599,10 @@ fn encode_vtable_res(ecx: &e::EncodeContext,
// ty::t doesn't work, and there is no way (atm) to have
// hand-written encoding routines combine with auto-generated
// ones. perhaps we should fix this.
do ebml_w.emit_from_vec(*dr) |ebml_w, vtable_origin| {
encode_vtable_origin(ecx, ebml_w, vtable_origin)
do ebml_w.emit_from_vec(*dr) |ebml_w, param_tables| {
do ebml_w.emit_from_vec(**param_tables) |ebml_w, vtable_origin| {
encode_vtable_origin(ecx, ebml_w, vtable_origin)
}
}
}
@ -632,6 +634,13 @@ fn encode_vtable_origin(ecx: &e::EncodeContext,
}
}
}
typeck::vtable_self(def_id) => {
do ebml_w.emit_enum_variant("vtable_self", 2u, 1u) |ebml_w| {
do ebml_w.emit_enum_variant_arg(0u) |ebml_w| {
ebml_w.emit_def_id(def_id)
}
}
}
}
}
}
@ -646,13 +655,17 @@ trait vtable_decoder_helpers {
impl vtable_decoder_helpers for reader::Decoder {
fn read_vtable_res(&mut self, xcx: @ExtendedDecodeContext)
-> typeck::vtable_res {
@self.read_to_vec(|this| this.read_vtable_origin(xcx))
@self.read_to_vec(|this|
@this.read_to_vec(|this|
this.read_vtable_origin(xcx)))
}
fn read_vtable_origin(&mut self, xcx: @ExtendedDecodeContext)
-> typeck::vtable_origin {
do self.read_enum("vtable_origin") |this| {
do this.read_enum_variant(["vtable_static", "vtable_param"])
do this.read_enum_variant(["vtable_static",
"vtable_param",
"vtable_self"])
|this, i| {
match i {
0 => {
@ -678,6 +691,13 @@ impl vtable_decoder_helpers for reader::Decoder {
}
)
}
2 => {
typeck::vtable_self(
do this.read_enum_variant_arg(0u) |this| {
this.read_def_id(xcx)
}
)
}
// hard to avoid - user input
_ => fail!("bad enum variant")
}

View File

@ -461,6 +461,7 @@ pub fn get_res_dtor(ccx: @mut CrateContext,
&tsubsts,
None,
None,
None,
None);
val
@ -1544,17 +1545,15 @@ pub fn new_fn_ctxt_w_id(ccx: @mut CrateContext,
llfndecl: ValueRef,
id: ast::node_id,
output_type: ty::t,
impl_id: Option<ast::def_id>,
param_substs: Option<@param_substs>,
sp: Option<span>)
-> fn_ctxt {
for param_substs.iter().advance |p| { p.validate(); }
debug!("new_fn_ctxt_w_id(path=%s, id=%?, impl_id=%?, \
debug!("new_fn_ctxt_w_id(path=%s, id=%?, \
param_substs=%s)",
path_str(ccx.sess, path),
id,
impl_id,
param_substs.repr(ccx.tcx));
let llbbs = mk_standard_basic_blocks(llfndecl);
@ -1583,7 +1582,6 @@ pub fn new_fn_ctxt_w_id(ccx: @mut CrateContext,
lllocals: @mut HashMap::new(),
llupvars: @mut HashMap::new(),
id: id,
impl_id: impl_id,
param_substs: param_substs,
span: sp,
path: path,
@ -1604,7 +1602,7 @@ pub fn new_fn_ctxt(ccx: @mut CrateContext,
output_type: ty::t,
sp: Option<span>)
-> fn_ctxt {
new_fn_ctxt_w_id(ccx, path, llfndecl, -1, output_type, None, None, sp)
new_fn_ctxt_w_id(ccx, path, llfndecl, -1, output_type, None, sp)
}
// NB: must keep 4 fns in sync:
@ -1773,7 +1771,6 @@ pub fn trans_closure(ccx: @mut CrateContext,
self_arg: self_arg,
param_substs: Option<@param_substs>,
id: ast::node_id,
impl_id: Option<ast::def_id>,
attributes: &[ast::attribute],
output_type: ty::t,
maybe_load_env: &fn(fn_ctxt),
@ -1791,7 +1788,6 @@ pub fn trans_closure(ccx: @mut CrateContext,
llfndecl,
id,
output_type,
impl_id,
param_substs,
Some(body.span));
let raw_llargs = create_llargs_for_fn_args(fcx, self_arg, decl.inputs);
@ -1850,7 +1846,6 @@ pub fn trans_fn(ccx: @mut CrateContext,
self_arg: self_arg,
param_substs: Option<@param_substs>,
id: ast::node_id,
impl_id: Option<ast::def_id>,
attrs: &[ast::attribute]) {
let do_time = ccx.sess.trans_stats();
let start = if do_time { time::get_time() }
@ -1870,7 +1865,6 @@ pub fn trans_fn(ccx: @mut CrateContext,
self_arg,
param_substs,
id,
impl_id,
attrs,
output_type,
|fcx| {
@ -1920,7 +1914,6 @@ pub fn trans_enum_variant(ccx: @mut CrateContext,
llfndecl,
variant.node.id,
enum_ty,
None,
param_substs,
None);
@ -2000,7 +1993,6 @@ pub fn trans_tuple_struct(ccx: @mut CrateContext,
llfndecl,
ctor_id,
tup_ty,
None,
param_substs,
None);
@ -2080,7 +2072,6 @@ pub fn trans_item(ccx: @mut CrateContext, item: &ast::item) {
no_self,
None,
item.id,
None,
item.attrs);
} else {
for body.node.stmts.iter().advance |stmt| {

View File

@ -17,6 +17,7 @@
// closure.
use core::prelude::*;
use core::vec;
use back::abi;
use driver::session;
@ -194,6 +195,58 @@ pub fn trans_fn_ref_with_vtables_to_callee(
type_params, vtables))}
}
fn get_impl_resolutions(bcx: block,
impl_id: ast::def_id)
-> typeck::vtable_res {
if impl_id.crate == ast::local_crate {
*bcx.ccx().maps.vtable_map.get(&impl_id.node)
} else {
// XXX: This is a temporary hack to work around not properly
// exporting information about resolutions for impls.
// This doesn't actually work if the trait has param bounds,
// but it does allow us to survive the case when it does not.
let trait_ref = ty::impl_trait_ref(bcx.tcx(), impl_id).get();
@vec::from_elem(trait_ref.substs.tps.len(), @~[])
}
}
fn resolve_default_method_vtables(bcx: block,
impl_id: ast::def_id,
method: &ty::Method,
substs: &ty::substs,
impl_vtables: Option<typeck::vtable_res>)
-> typeck::vtable_res {
// Get the vtables that the impl implements the trait at
let trait_vtables = get_impl_resolutions(bcx, impl_id);
// Build up a param_substs that we are going to resolve the
// trait_vtables under.
let param_substs = Some(@param_substs {
tys: copy substs.tps,
self_ty: substs.self_ty,
vtables: impl_vtables,
self_vtable: None
});
let trait_vtables_fixed = resolve_vtables_under_param_substs(
bcx.tcx(), param_substs, trait_vtables);
// Now we pull any vtables for parameters on the actual method.
let num_method_vtables = method.generics.type_param_defs.len();
let method_vtables = match impl_vtables {
Some(vtables) => {
let num_impl_type_parameters =
vtables.len() - num_method_vtables;
vtables.tailn(num_impl_type_parameters).to_owned()
},
None => vec::from_elem(num_method_vtables, @~[])
};
@(*trait_vtables_fixed + method_vtables)
}
pub fn trans_fn_ref_with_vtables(
bcx: block, //
def_id: ast::def_id, // def id of fn
@ -233,15 +286,21 @@ pub fn trans_fn_ref_with_vtables(
// Polytype of the function item (may have type params)
let fn_tpt = ty::lookup_item_type(tcx, def_id);
let substs = ty::substs { self_r: None, self_ty: None,
// For simplicity, we want to use the Subst trait when composing
// substitutions for default methods. The subst trait does
// substitutions with regions, though, so we put a dummy self
// region parameter in to keep it from failing. This is a hack.
let substs = ty::substs { self_r: Some(ty::re_empty),
self_ty: None,
tps: /*bad*/ type_params.to_owned() };
// We need to do a bunch of special handling for default methods.
// We need to modify the def_id and our substs in order to monomorphize
// the function.
let (def_id, opt_impl_did, substs) = match tcx.provided_method_sources.find(&def_id) {
None => (def_id, None, substs),
let (def_id, opt_impl_did, substs, self_vtable, vtables) =
match tcx.provided_method_sources.find(&def_id) {
None => (def_id, None, substs, None, vtables),
Some(source) => {
// There are two relevant substitutions when compiling
// default methods. First, there is the substitution for
@ -261,20 +320,42 @@ pub fn trans_fn_ref_with_vtables(
default methods");
let method = ty::method(tcx, source.method_id);
// Get all of the type params for the receiver
let param_defs = method.generics.type_param_defs;
let receiver_substs =
type_params.initn(param_defs.len()).to_owned();
let receiver_vtables = match vtables {
None => @~[],
Some(call_vtables) => {
@call_vtables.initn(param_defs.len()).to_owned()
}
};
let self_vtable =
typeck::vtable_static(source.impl_id, receiver_substs,
receiver_vtables);
// Compute the first substitution
let first_subst = make_substs_for_receiver_types(
tcx, source.impl_id, trait_ref, method);
// And compose them
let new_substs = first_subst.subst(tcx, &substs);
let vtables =
resolve_default_method_vtables(bcx, source.impl_id,
method, &new_substs, vtables);
debug!("trans_fn_with_vtables - default method: \
substs = %s, trait_subst = %s, \
first_subst = %s, new_subst = %s",
first_subst = %s, new_subst = %s, \
self_vtable = %s, vtables = %s",
substs.repr(tcx), trait_ref.substs.repr(tcx),
first_subst.repr(tcx), new_substs.repr(tcx));
first_subst.repr(tcx), new_substs.repr(tcx),
self_vtable.repr(tcx), vtables.repr(tcx));
(source.method_id, Some(source.impl_id), new_substs)
(source.method_id, Some(source.impl_id),
new_substs, Some(self_vtable), Some(vtables))
}
};
@ -321,7 +402,8 @@ pub fn trans_fn_ref_with_vtables(
let (val, must_cast) =
monomorphize::monomorphic_fn(ccx, def_id, &substs,
vtables, opt_impl_did, Some(ref_id));
vtables, self_vtable,
opt_impl_did, Some(ref_id));
let mut val = val;
if must_cast && ref_id != 0 {
// Monotype of the REFERENCE to the function (type params

View File

@ -444,7 +444,6 @@ pub fn trans_expr_fn(bcx: block,
no_self,
/*bad*/ copy bcx.fcx.param_substs,
user_id,
None,
[],
real_return_type,
|fcx| load_environment(fcx, cdata_ty, cap_vars,

View File

@ -130,9 +130,9 @@ pub struct ValSelfData {
// will only be set in the case of default methods.
pub struct param_substs {
tys: ~[ty::t],
self_ty: Option<ty::t>,
vtables: Option<typeck::vtable_res>,
type_param_defs: @~[ty::TypeParameterDef],
self_ty: Option<ty::t>
self_vtable: Option<typeck::vtable_origin>
}
impl param_substs {
@ -143,10 +143,9 @@ impl param_substs {
}
fn param_substs_to_str(this: &param_substs, tcx: ty::ctxt) -> ~str {
fmt!("param_substs {tys:%s, vtables:%s, type_param_defs:%s}",
fmt!("param_substs {tys:%s, vtables:%s}",
this.tys.repr(tcx),
this.vtables.repr(tcx),
this.type_param_defs.repr(tcx))
this.vtables.repr(tcx))
}
impl Repr for param_substs {
@ -223,9 +222,6 @@ pub struct fn_ctxt_ {
// a user-defined function.
id: ast::node_id,
// The def_id of the impl we're inside, or None if we aren't inside one.
impl_id: Option<ast::def_id>,
// If this function is being monomorphized, this contains the type
// substitutions used.
param_substs: Option<@param_substs>,
@ -981,7 +977,11 @@ pub fn monomorphize_type(bcx: block, t: ty::t) -> ty::t {
Some(substs) => {
ty::subst_tps(bcx.tcx(), substs.tys, substs.self_ty, t)
}
_ => { assert!(!ty::type_has_params(t)); t }
_ => {
assert!(!ty::type_has_params(t));
assert!(!ty::type_has_self(t));
t
}
}
}
@ -1030,17 +1030,37 @@ pub fn node_vtables(bcx: block, id: ast::node_id)
pub fn resolve_vtables_in_fn_ctxt(fcx: fn_ctxt, vts: typeck::vtable_res)
-> typeck::vtable_res {
@vec::map(*vts, |d| resolve_vtable_in_fn_ctxt(fcx, copy *d))
resolve_vtables_under_param_substs(fcx.ccx.tcx,
fcx.param_substs,
vts)
}
pub fn resolve_vtables_under_param_substs(tcx: ty::ctxt,
param_substs: Option<@param_substs>,
vts: typeck::vtable_res)
-> typeck::vtable_res {
@vec::map(*vts, |ds|
@vec::map(**ds, |d|
resolve_vtable_under_param_substs(tcx, param_substs, copy *d)))
}
// Apply the typaram substitutions in the fn_ctxt to a vtable. This should
// eliminate any vtable_params.
pub fn resolve_vtable_in_fn_ctxt(fcx: fn_ctxt, vt: typeck::vtable_origin)
-> typeck::vtable_origin {
let tcx = fcx.ccx.tcx;
resolve_vtable_under_param_substs(fcx.ccx.tcx,
fcx.param_substs,
vt)
}
pub fn resolve_vtable_under_param_substs(tcx: ty::ctxt,
param_substs: Option<@param_substs>,
vt: typeck::vtable_origin)
-> typeck::vtable_origin {
match vt {
typeck::vtable_static(trait_id, tys, sub) => {
let tys = match fcx.param_substs {
let tys = match param_substs {
Some(substs) => {
do vec::map(tys) |t| {
ty::subst_tps(tcx, substs.tys, substs.self_ty, *t)
@ -1048,11 +1068,12 @@ pub fn resolve_vtable_in_fn_ctxt(fcx: fn_ctxt, vt: typeck::vtable_origin)
}
_ => tys
};
typeck::vtable_static(trait_id, tys,
resolve_vtables_in_fn_ctxt(fcx, sub))
typeck::vtable_static(
trait_id, tys,
resolve_vtables_under_param_substs(tcx, param_substs, sub))
}
typeck::vtable_param(n_param, n_bound) => {
match fcx.param_substs {
match param_substs {
Some(substs) => {
find_vtable(tcx, substs, n_param, n_bound)
}
@ -1063,6 +1084,19 @@ pub fn resolve_vtable_in_fn_ctxt(fcx: fn_ctxt, vt: typeck::vtable_origin)
}
}
}
typeck::vtable_self(_trait_id) => {
match param_substs {
Some(@param_substs
{self_vtable: Some(ref self_vtable), _}) => {
copy *self_vtable
}
_ => {
tcx.sess.bug(fmt!(
"resolve_vtable_in_fn_ctxt: asked to lookup but \
no self_vtable in the fn_ctxt!"))
}
}
}
}
}
@ -1072,13 +1106,7 @@ pub fn find_vtable(tcx: ty::ctxt, ps: &param_substs,
debug!("find_vtable(n_param=%u, n_bound=%u, ps=%s)",
n_param, n_bound, ps.repr(tcx));
// Vtables are stored in a flat array, finding the right one is
// somewhat awkward
let first_n_type_param_defs = ps.type_param_defs.slice(0, n_param);
let vtables_to_skip =
ty::count_traits_and_supertraits(tcx, first_n_type_param_defs);
let vtable_off = vtables_to_skip + n_bound;
/*bad*/ copy ps.vtables.get()[vtable_off]
/*bad*/ copy ps.vtables.get()[n_param][n_bound]
}
pub fn dummy_substs(tps: ~[ty::t]) -> ty::substs {

View File

@ -555,7 +555,6 @@ pub fn trans_intrinsic(ccx: @mut CrateContext,
decl,
item.id,
output_type,
None,
Some(substs),
Some(item.span));
@ -1183,7 +1182,6 @@ pub fn trans_foreign_fn(ccx: @mut CrateContext,
no_self,
None,
id,
None,
[]);
return llfndecl;
}

View File

@ -127,7 +127,6 @@ pub fn maybe_instantiate_inline(ccx: @mut CrateContext, fn_id: ast::def_id,
self_kind,
None,
mth.id,
Some(impl_did),
[]);
}
local_def(mth.id)

View File

@ -68,8 +68,7 @@ pub fn trans_impl(ccx: @mut CrateContext,
path,
*method,
None,
llfn,
ast_util::local_def(id));
llfn);
}
}
}
@ -90,8 +89,7 @@ pub fn trans_method(ccx: @mut CrateContext,
path: path,
method: &ast::method,
param_substs: Option<@param_substs>,
llfn: ValueRef,
impl_id: ast::def_id) {
llfn: ValueRef) {
// figure out how self is being passed
let self_arg = match method.explicit_self.node {
ast::sty_static => {
@ -127,7 +125,6 @@ pub fn trans_method(ccx: @mut CrateContext,
self_arg,
param_substs,
method.id,
Some(impl_id),
[]);
}
@ -139,7 +136,6 @@ pub fn trans_self_arg(bcx: block,
// Compute the type of self.
let self_ty = monomorphize_type(bcx, mentry.self_ty);
let result = trans_arg_expr(bcx,
self_ty,
mentry.self_mode,
@ -174,21 +170,6 @@ pub fn trans_method_callee(bcx: block,
// Replace method_self with method_static here.
let mut origin = mentry.origin;
match origin {
typeck::method_self(trait_id, method_index) => {
// Get the ID of the impl we're inside.
let impl_def_id = bcx.fcx.impl_id.get();
debug!("impl_def_id is %?", impl_def_id);
// Get the ID of the method we're calling.
let method_name =
ty::trait_method(tcx, trait_id, method_index).ident;
let method_id =
method_with_name_or_default(bcx.ccx(),
impl_def_id,
method_name);
origin = typeck::method_static(method_id);
}
typeck::method_super(trait_id, method_index) => {
// <self_ty> is the self type for this method call
let self_ty = node_id_type(bcx, this.id);
@ -213,6 +194,7 @@ pub fn trans_method_callee(bcx: block,
impl_id,
method_name));
}
typeck::method_self(*) |
typeck::method_static(*) | typeck::method_param(*) |
typeck::method_trait(*) => {}
}
@ -250,6 +232,21 @@ pub fn trans_method_callee(bcx: block,
None => fail!("trans_method_callee: missing param_substs")
}
}
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")
}
}
}
typeck::method_trait(_, off, store) => {
trans_trait_callee(bcx,
callee_id,
@ -258,9 +255,9 @@ pub fn trans_method_callee(bcx: block,
store,
mentry.explicit_self)
}
typeck::method_self(*) | typeck::method_super(*) => {
fail!("method_self or method_super should have been handled \
above")
typeck::method_super(*) => {
fail!("method_super should have been handled \
above")
}
}
}
@ -292,15 +289,9 @@ pub fn trans_static_method_callee(bcx: block,
//
// 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 = {
let trait_def = ty::lookup_trait_def(bcx.tcx(), trait_id);
ty::count_traits_and_supertraits(
bcx.tcx(), *trait_def.generics.type_param_defs)
};
// bound to.
let bound_index = ty::lookup_trait_def(bcx.tcx(), trait_id).
generics.type_param_defs.len();
let mname = if method_id.crate == ast::local_crate {
match bcx.tcx().items.get_copy(&method_id.node) {
@ -322,17 +313,17 @@ pub fn trans_static_method_callee(bcx: block,
let vtbls = resolve_vtables_in_fn_ctxt(
bcx.fcx, ccx.maps.vtable_map.get_copy(&callee_id));
match vtbls[bound_index] {
match vtbls[bound_index][0] {
typeck::vtable_static(impl_did, ref rcvr_substs, rcvr_origins) => {
assert!(rcvr_substs.iter().all(|t| !ty::type_needs_infer(*t)));
let mth_id = method_with_name_or_default(bcx.ccx(),
impl_did,
mname);
let callee_substs = combine_impl_and_methods_tps(
bcx, mth_id, impl_did, callee_id, *rcvr_substs);
let callee_origins = combine_impl_and_methods_origins(
bcx, mth_id, impl_did, callee_id, rcvr_origins);
let (callee_substs, callee_origins) =
combine_impl_and_methods_tps(
bcx, mth_id, impl_did, callee_id,
*rcvr_substs, rcvr_origins);
let FnData {llfn: lval} =
trans_fn_ref_with_vtables(bcx,
@ -428,10 +419,10 @@ pub fn trans_monomorphized_callee(bcx: block,
// create a concatenated set of substitutions which includes
// those from the impl and those from the method:
let callee_substs = combine_impl_and_methods_tps(
bcx, mth_id, impl_did, callee_id, *rcvr_substs);
let callee_origins = combine_impl_and_methods_origins(
bcx, mth_id, impl_did, callee_id, rcvr_origins);
let (callee_substs, callee_origins) =
combine_impl_and_methods_tps(
bcx, mth_id, impl_did, callee_id,
*rcvr_substs, rcvr_origins);
// translate the function
let callee = trans_fn_ref_with_vtables(bcx,
@ -460,6 +451,9 @@ pub fn trans_monomorphized_callee(bcx: block,
typeck::vtable_param(*) => {
fail!("vtable_param left in monomorphized function's vtable substs");
}
typeck::vtable_self(*) => {
fail!("vtable_self left in monomorphized function's vtable substs");
}
};
}
@ -468,8 +462,9 @@ pub fn combine_impl_and_methods_tps(bcx: block,
mth_did: ast::def_id,
impl_did: ast::def_id,
callee_id: ast::node_id,
rcvr_substs: &[ty::t])
-> ~[ty::t] {
rcvr_substs: &[ty::t],
rcvr_origins: typeck::vtable_res)
-> (~[ty::t], typeck::vtable_res) {
/*!
*
* Creates a concatenated set of substitutions which includes
@ -498,52 +493,18 @@ pub fn combine_impl_and_methods_tps(bcx: block,
debug!("node_substs=%?", node_substs.map(|t| bcx.ty_to_str(*t)));
debug!("ty_substs=%?", ty_substs.map(|t| bcx.ty_to_str(*t)));
return ty_substs;
}
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 {
/*!
*
* 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.
let ccx = bcx.ccx();
let tcx = bcx.tcx();
let n_m_tps = method_ty_param_count(ccx, mth_did, impl_did);
let ty::ty_param_bounds_and_ty {
generics: r_m_generics,
_
} = ty::lookup_item_type(tcx, mth_did);
let n_r_m_tps = r_m_generics.type_param_defs.len(); // rcvr + method tps
let m_type_param_defs =
r_m_generics.type_param_defs.slice(n_r_m_tps - n_m_tps, n_r_m_tps);
// Flatten out to find the number of vtables the method expects.
let m_vtables = ty::count_traits_and_supertraits(tcx, m_type_param_defs);
// Find the vtables we computed at type check time and monomorphize them
// Now, do the same work for the vtables. The vtables might not
// exist, in which case we need to make them.
let r_m_origins = match node_vtables(bcx, callee_id) {
Some(vt) => vt,
None => @~[]
None => @vec::from_elem(node_substs.len(), @~[])
};
let vtables
= @vec::append(rcvr_origins.to_owned(),
r_m_origins.tailn(r_m_origins.len() - n_m_tps));
// Extract those that belong to method:
let m_origins = r_m_origins.tailn(r_m_origins.len() - m_vtables);
// Combine rcvr + method to find the final result:
@vec::append(/*bad*/copy *rcvr_origins, m_origins)
return (ty_substs, vtables);
}
@ -842,7 +803,7 @@ pub fn trans_trait_cast(bcx: block,
bcx = expr::trans_into(bcx, val, SaveIn(llboxdest));
// Store the vtable into the pair or triple.
let orig = /*bad*/copy ccx.maps.vtable_map.get(&id)[0];
let orig = /*bad*/copy ccx.maps.vtable_map.get(&id)[0][0];
let orig = resolve_vtable_in_fn_ctxt(bcx.fcx, orig);
let vtable = get_vtable(bcx, v_ty, orig);
Store(bcx, vtable, PointerCast(bcx,

View File

@ -43,6 +43,7 @@ pub fn monomorphic_fn(ccx: @mut CrateContext,
fn_id: ast::def_id,
real_substs: &ty::substs,
vtables: Option<typeck::vtable_res>,
self_vtable: Option<typeck::vtable_origin>,
impl_did_opt: Option<ast::def_id>,
ref_id: Option<ast::node_id>)
-> (ValueRef, bool)
@ -165,6 +166,7 @@ pub fn monomorphic_fn(ccx: @mut CrateContext,
let mut pt = /* bad */copy (*pt);
pt.push(elt);
let s = mangle_exported_name(ccx, /*bad*/copy pt, mono_ty);
debug!("monomorphize_fn mangled to %s", s);
let mk_lldecl = || {
let lldecl = decl_internal_cdecl_fn(ccx.llmod, /*bad*/copy s, llfty);
@ -175,8 +177,8 @@ pub fn monomorphic_fn(ccx: @mut CrateContext,
let psubsts = Some(@param_substs {
tys: substs,
vtables: vtables,
type_param_defs: tpt.generics.type_param_defs,
self_ty: real_substs.self_ty
self_ty: real_substs.self_ty,
self_vtable: self_vtable
});
let lldecl = match map_node {
@ -194,7 +196,6 @@ pub fn monomorphic_fn(ccx: @mut CrateContext,
no_self,
psubsts,
fn_id.node,
None,
[]);
d
}
@ -222,27 +223,17 @@ pub fn monomorphic_fn(ccx: @mut CrateContext,
}
d
}
ast_map::node_method(mth, supplied_impl_did, _) => {
ast_map::node_method(mth, _, _) => {
// XXX: What should the self type be here?
let d = mk_lldecl();
set_inline_hint_if_appr(/*bad*/copy mth.attrs, d);
// Override the impl def ID if necessary.
let impl_did;
match impl_did_opt {
None => impl_did = supplied_impl_did,
Some(override_impl_did) => impl_did = override_impl_did
}
meth::trans_method(ccx, pt, mth, psubsts, d, impl_did);
meth::trans_method(ccx, pt, mth, psubsts, d);
d
}
ast_map::node_trait_method(@ast::provided(mth), _, pt) => {
let d = mk_lldecl();
set_inline_hint_if_appr(/*bad*/copy mth.attrs, d);
debug!("monomorphic_fn impl_did_opt is %?", impl_did_opt);
meth::trans_method(ccx, /*bad*/copy *pt, mth, psubsts, d,
impl_did_opt.get());
meth::trans_method(ccx, /*bad*/copy *pt, mth, psubsts, d);
d
}
ast_map::node_struct_ctor(struct_def, _, _) => {
@ -337,14 +328,10 @@ pub fn make_mono_id(ccx: @mut CrateContext,
param_uses: Option<@~[type_use::type_uses]>) -> mono_id {
let precise_param_ids = match vtables {
Some(vts) => {
let item_ty = ty::lookup_item_type(ccx.tcx, item);
let mut i = 0;
vec::map_zip(*item_ty.generics.type_param_defs, substs, |type_param_def, subst| {
let mut v = ~[];
for type_param_def.bounds.trait_bounds.iter().advance |_bound| {
v.push(meth::vtable_id(ccx, &vts[i]));
i += 1;
}
debug!("make_mono_id vtables=%s substs=%s",
vts.repr(ccx.tcx), substs.repr(ccx.tcx));
vec::map_zip(*vts, substs, |vtable, subst| {
let v = vtable.map(|vt| meth::vtable_id(ccx, vt));
(*subst, if !v.is_empty() { Some(@v) } else { None })
})
}

View File

@ -609,6 +609,7 @@ pub fn check_item(ccx: @mut CrateCtxt, it: @ast::item) {
for ms.iter().advance |m| {
check_method(ccx, *m);
}
vtable::resolve_impl(ccx, it);
}
ast::item_trait(_, _, ref trait_methods) => {
for (*trait_methods).iter().advance |trait_method| {

View File

@ -17,8 +17,8 @@ use middle::typeck::check::{structurally_resolved_type};
use middle::typeck::infer::fixup_err_to_str;
use middle::typeck::infer::{resolve_and_force_all_but_regions, resolve_type};
use middle::typeck::infer;
use middle::typeck::{CrateCtxt, vtable_origin, vtable_param, vtable_res};
use middle::typeck::vtable_static;
use middle::typeck::{CrateCtxt, vtable_origin, vtable_res};
use middle::typeck::{vtable_static, vtable_param, vtable_self};
use middle::subst::Subst;
use util::common::indenter;
use util::ppaux::tys_to_str;
@ -90,6 +90,7 @@ fn lookup_vtables(vcx: &VtableContext,
let mut i = 0u;
for substs.tps.iter().advance |ty| {
// ty is the value supplied for the type parameter A...
let mut param_result = ~[];
for ty::each_bound_trait_and_supertraits(
tcx, type_param_defs[i].bounds) |trait_ref|
@ -106,7 +107,7 @@ fn lookup_vtables(vcx: &VtableContext,
debug!("after subst: %s", trait_ref.repr(tcx));
match lookup_vtable(vcx, location_info, *ty, &trait_ref, is_early) {
Some(vtable) => result.push(vtable),
Some(vtable) => param_result.push(vtable),
None => {
vcx.tcx().sess.span_fatal(
location_info.span,
@ -117,6 +118,7 @@ fn lookup_vtables(vcx: &VtableContext,
}
}
}
result.push(@param_result);
i += 1u;
}
debug!("lookup_vtables result(\
@ -237,6 +239,17 @@ fn lookup_vtable(vcx: &VtableContext,
}
}
ty::ty_self(trait_id) => {
debug!("trying to find %? vtable for type %?",
trait_ref.def_id, trait_id);
if trait_id == trait_ref.def_id {
let vtable = vtable_self(trait_id);
debug!("found self vtable: %?", vtable);
return Some(vtable);
}
}
_ => {
let mut found = ~[];
@ -467,6 +480,12 @@ pub fn location_info_for_expr(expr: @ast::expr) -> LocationInfo {
id: expr.id
}
}
pub fn location_info_for_item(item: @ast::item) -> LocationInfo {
LocationInfo {
span: item.span,
id: item.id
}
}
pub fn early_resolve_expr(ex: @ast::expr,
fcx: @mut FnCtxt,
@ -583,7 +602,8 @@ pub fn early_resolve_expr(ex: @ast::expr,
// vtable (that is: "ex has vtable
// <vtable>")
if !is_early {
insert_vtables(fcx, ex.id, @~[vtable]);
insert_vtables(fcx, ex.id,
@~[@~[vtable]]);
}
}
None => {
@ -650,6 +670,27 @@ fn resolve_expr(ex: @ast::expr,
visit::visit_expr(ex, (fcx, v));
}
pub fn resolve_impl(ccx: @mut CrateCtxt, impl_item: @ast::item) {
let def_id = ast_util::local_def(impl_item.id);
match ty::impl_trait_ref(ccx.tcx, def_id) {
None => {},
Some(trait_ref) => {
let infcx = infer::new_infer_ctxt(ccx.tcx);
let vcx = VtableContext { ccx: ccx, infcx: infcx };
let trait_def = ty::lookup_trait_def(ccx.tcx, trait_ref.def_id);
let vtbls = lookup_vtables(&vcx,
&location_info_for_item(impl_item),
*trait_def.generics.type_param_defs,
&trait_ref.substs,
false);
// FIXME(#7450): Doesn't work cross crate
ccx.vtable_map.insert(impl_item.id, vtbls);
}
}
}
// Detect points where a trait-bounded type parameter is
// instantiated, resolve the impls for the parameters.
pub fn resolve_in_block(fcx: @mut FnCtxt, bl: &ast::blk) {

View File

@ -20,7 +20,8 @@ use middle::typeck::check::{FnCtxt, SelfInfo};
use middle::typeck::infer::{force_all, resolve_all, resolve_region};
use middle::typeck::infer::resolve_type;
use middle::typeck::infer;
use middle::typeck::{vtable_origin, vtable_static, vtable_param};
use middle::typeck::{vtable_res, vtable_origin};
use middle::typeck::{vtable_static, vtable_param, vtable_self};
use middle::typeck::method_map_entry;
use middle::typeck::write_substs_to_tcx;
use middle::typeck::write_ty_to_tcx;
@ -84,7 +85,7 @@ fn resolve_vtable_map_entry(fcx: @mut FnCtxt, sp: span, id: ast::node_id) {
match fcx.inh.vtable_map.find(&id) {
None => {}
Some(origins) => {
let r_origins = @origins.map(|o| resolve_origin(fcx, sp, o));
let r_origins = resolve_origins(fcx, sp, *origins);
let vtable_map = fcx.ccx.vtable_map;
vtable_map.insert(id, r_origins);
debug!("writeback::resolve_vtable_map_entry(id=%d, vtables=%?)",
@ -92,18 +93,26 @@ fn resolve_vtable_map_entry(fcx: @mut FnCtxt, sp: span, id: ast::node_id) {
}
}
fn resolve_origins(fcx: @mut FnCtxt, sp: span,
vtbls: vtable_res) -> vtable_res {
@vtbls.map(|os| @os.map(|o| resolve_origin(fcx, sp, o)))
}
fn resolve_origin(fcx: @mut FnCtxt,
sp: span,
origin: &vtable_origin) -> vtable_origin {
match origin {
&vtable_static(def_id, ref tys, origins) => {
let r_tys = resolve_type_vars_in_types(fcx, sp, *tys);
let r_origins = @origins.map(|o| resolve_origin(fcx, sp, o));
let r_origins = resolve_origins(fcx, sp, origins);
vtable_static(def_id, r_tys, r_origins)
}
&vtable_param(n, b) => {
vtable_param(n, b)
}
&vtable_self(def_id) => {
vtable_self(def_id)
}
}
}
}

View File

@ -135,8 +135,9 @@ pub struct method_map_entry {
// of the method to be invoked
pub type method_map = @mut HashMap<ast::node_id, method_map_entry>;
pub type vtable_param_res = @~[vtable_origin];
// Resolutions for bounds of all parameters, left to right, for a given path.
pub type vtable_res = @~[vtable_origin];
pub type vtable_res = @~[vtable_param_res];
pub enum vtable_origin {
/*
@ -154,7 +155,12 @@ pub enum vtable_origin {
The first uint is the param number (identifying T in the example),
and the second is the bound number (identifying baz)
*/
vtable_param(uint, uint)
vtable_param(uint, uint),
/*
Dynamic vtable, comes from self.
*/
vtable_self(ast::def_id)
}
impl Repr for vtable_origin {
@ -171,6 +177,9 @@ impl Repr for vtable_origin {
vtable_param(x, y) => {
fmt!("vtable_param(%?, %?)", x, y)
}
vtable_self(def_id) => {
fmt!("vtable_self(%?)", def_id)
}
}
}
}

View File

@ -2346,6 +2346,7 @@ impl<T> FromIter<T> for ~[T]{
}
}
#[cfg(stage0)]
impl<A, T: Iterator<A>> FromIterator<A, T> for ~[A] {
pub fn from_iterator(iterator: &mut T) -> ~[A] {
let mut xs = ~[];
@ -2356,7 +2357,8 @@ impl<A, T: Iterator<A>> FromIterator<A, T> for ~[A] {
}
}
/* FIXME: #7341 - ICE
#[cfg(not(stage0))]
impl<A, T: Iterator<A>> FromIterator<A, T> for ~[A] {
pub fn from_iterator(iterator: &mut T) -> ~[A] {
let (lower, _) = iterator.size_hint();
@ -2367,7 +2369,7 @@ impl<A, T: Iterator<A>> FromIterator<A, T> for ~[A] {
xs
}
}
*/
#[cfg(test)]
mod tests {

View File

@ -0,0 +1,24 @@
// Copyright 2013 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.
pub trait Clone2 {
fn clone(&self) -> Self;
}
trait Getter<T: Clone2> {
fn get(&self) -> T;
}
impl Getter<int> for int { //~ ERROR failed to find an implementation of trait Clone2 for int
fn get(&self) -> int { *self }
}
fn main() { }

View File

@ -0,0 +1,45 @@
// Copyright 2013 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.
#[allow(default_methods)]
trait Speak {
fn say(&self, s:&str) -> ~str;
fn hi(&self) -> ~str { hello(self) }
}
fn hello<S:Speak>(s:&S) -> ~str{
s.say("hello")
}
impl Speak for int {
fn say(&self, s:&str) -> ~str {
fmt!("%s: %d", s, *self)
}
}
impl<T: Speak> Speak for Option<T> {
fn say(&self, s:&str) -> ~str {
match *self {
None => fmt!("%s - none", s),
Some(ref x) => { ~"something!" + x.say(s) }
}
}
}
fn main() {
assert_eq!(3.hi(), ~"hello: 3");
assert_eq!(Some(Some(3)).hi(), ~"something!something!hello: 3");
assert_eq!(None::<int>.hi(), ~"hello - none");
// These fail because of a bug in monomorphization's ID generation.
//assert_eq!(Some(None::<int>).hi(), ~"something!hello - none");
//assert_eq!(Some(3).hi(), ~"something!hello: 3");
}

View File

@ -0,0 +1,41 @@
// Copyright 2013 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.
pub trait Clone2 {
/// Returns a copy of the value. The contents of owned pointers
/// are copied to maintain uniqueness, while the contents of
/// managed pointers are not copied.
fn clone(&self) -> Self;
}
#[allow(default_methods)]
trait Getter<T: Clone> {
fn do_get(&self) -> T;
fn do_get2(&self) -> (T, T) {
let x = self.do_get();
(x.clone(), x.clone())
}
}
impl Getter<int> for int {
fn do_get(&self) -> int { *self }
}
impl<T: Clone> Getter<T> for Option<T> {
fn do_get(&self) -> T { self.get_ref().clone() }
}
fn main() {
assert_eq!(3.do_get2(), (3, 3));
assert_eq!(Some(~"hi").do_get2(), (~"hi", ~"hi"));
}