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:
commit
d681bccb6a
@ -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));
|
||||
|
@ -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")
|
||||
}
|
||||
|
@ -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| {
|
||||
|
@ -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
|
||||
|
@ -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,
|
||||
|
@ -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: ¶m_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: ¶m_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 {
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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)
|
||||
|
@ -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,
|
||||
|
@ -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 })
|
||||
})
|
||||
}
|
||||
|
@ -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| {
|
||||
|
@ -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) {
|
||||
|
@ -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)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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 {
|
||||
|
24
src/test/compile-fail/impl-bounds-checking.rs
Normal file
24
src/test/compile-fail/impl-bounds-checking.rs
Normal 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() { }
|
45
src/test/run-pass/bug-7183-generics.rs
Normal file
45
src/test/run-pass/bug-7183-generics.rs
Normal 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");
|
||||
}
|
41
src/test/run-pass/trait-with-bounds-default.rs
Normal file
41
src/test/run-pass/trait-with-bounds-default.rs
Normal 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"));
|
||||
}
|
Loading…
Reference in New Issue
Block a user