Use the Nth impl when translating a static method call, instead

of the 0th.  0th is only correct when there are no bound tps
on the trait.

Fixes #3741.
This commit is contained in:
Niko Matsakis 2012-10-12 17:00:08 -07:00
parent 57b4d10ff6
commit cb55e246ba
11 changed files with 122 additions and 43 deletions

View File

@ -118,7 +118,9 @@ type ty_param = {ident: ident, id: node_id, bounds: @~[ty_param_bound]};
#[auto_deserialize]
enum def {
def_fn(def_id, purity),
def_static_method(def_id, purity),
def_static_method(/* method */ def_id,
/* trait */ def_id,
purity),
def_self(node_id),
def_mod(def_id),
def_foreign_mod(def_id),
@ -150,9 +152,10 @@ impl def : cmp::Eq {
_ => false
}
}
def_static_method(e0a, e1a) => {
def_static_method(e0a, e1a, e2a) => {
match (*other) {
def_static_method(e0b, e1b) => e0a == e0b && e1a == e1b,
def_static_method(e0b, e1b, e2b) =>
e0a == e0b && e1a == e1b && e2a == e2b,
_ => false
}
}

View File

@ -54,7 +54,7 @@ fn variant_def_ids(d: def) -> {enm: def_id, var: def_id} {
pure fn def_id_of_def(d: def) -> def_id {
match d {
def_fn(id, _) | def_static_method(id, _) | def_mod(id) |
def_fn(id, _) | def_static_method(id, _, _) | def_mod(id) |
def_foreign_mod(id) | def_const(id) |
def_variant(_, id) | def_ty(id) | def_ty_param(id, _) |
def_use(id) | def_class(id, _) => {

View File

@ -178,6 +178,12 @@ fn item_parent_item(d: ebml::Doc) -> Option<ast::def_id> {
None
}
fn item_reqd_and_translated_parent_item(cnum: ast::crate_num,
d: ebml::Doc) -> ast::def_id {
let trait_did = item_parent_item(d).expect(~"item without parent");
{crate: cnum, node: trait_did.node}
}
fn item_def_id(d: ebml::Doc, cdata: cmd) -> ast::def_id {
let tagdoc = ebml::get_doc(d, tag_def_id);
return translate_def_id(cdata, ebml::with_doc_data(tagdoc,
@ -297,35 +303,39 @@ fn item_name(intr: @ident_interner, item: ebml::Doc) -> ast::ident {
}
fn item_to_def_like(item: ebml::Doc, did: ast::def_id, cnum: ast::crate_num)
-> def_like {
-> def_like
{
let fam = item_family(item);
match fam {
Const => dl_def(ast::def_const(did)),
Class => dl_def(ast::def_class(did, true)),
Struct => dl_def(ast::def_class(did, false)),
UnsafeFn => dl_def(ast::def_fn(did, ast::unsafe_fn)),
Fn => dl_def(ast::def_fn(did, ast::impure_fn)),
PureFn => dl_def(ast::def_fn(did, ast::pure_fn)),
ForeignFn => dl_def(ast::def_fn(did, ast::extern_fn)),
UnsafeStaticMethod => dl_def(ast::def_static_method(did,
ast::unsafe_fn)),
StaticMethod => dl_def(ast::def_static_method(did, ast::impure_fn)),
PureStaticMethod => dl_def(ast::def_static_method(did, ast::pure_fn)),
Type | ForeignType => dl_def(ast::def_ty(did)),
Mod => dl_def(ast::def_mod(did)),
ForeignMod => dl_def(ast::def_foreign_mod(did)),
Variant => {
match item_parent_item(item) {
Some(t) => {
let tid = {crate: cnum, node: t.node};
dl_def(ast::def_variant(tid, did))
}
None => fail ~"item_to_def_like: enum item has no parent"
}
}
Trait | Enum => dl_def(ast::def_ty(did)),
Impl => dl_impl(did),
PublicField | PrivateField | InheritedField => dl_field,
Const => dl_def(ast::def_const(did)),
Class => dl_def(ast::def_class(did, true)),
Struct => dl_def(ast::def_class(did, false)),
UnsafeFn => dl_def(ast::def_fn(did, ast::unsafe_fn)),
Fn => dl_def(ast::def_fn(did, ast::impure_fn)),
PureFn => dl_def(ast::def_fn(did, ast::pure_fn)),
ForeignFn => dl_def(ast::def_fn(did, ast::extern_fn)),
UnsafeStaticMethod => {
let trait_did = item_reqd_and_translated_parent_item(cnum, item);
dl_def(ast::def_static_method(did, trait_did, ast::unsafe_fn))
}
StaticMethod => {
let trait_did = item_reqd_and_translated_parent_item(cnum, item);
dl_def(ast::def_static_method(did, trait_did, ast::impure_fn))
}
PureStaticMethod => {
let trait_did = item_reqd_and_translated_parent_item(cnum, item);
dl_def(ast::def_static_method(did, trait_did, ast::pure_fn))
}
Type | ForeignType => dl_def(ast::def_ty(did)),
Mod => dl_def(ast::def_mod(did)),
ForeignMod => dl_def(ast::def_foreign_mod(did)),
Variant => {
let enum_did = item_reqd_and_translated_parent_item(cnum, item);
dl_def(ast::def_variant(enum_did, did))
}
Trait | Enum => dl_def(ast::def_ty(did)),
Impl => dl_impl(did),
PublicField | PrivateField | InheritedField => dl_field,
}
}

View File

@ -794,6 +794,7 @@ fn encode_info_for_item(ecx: @encode_ctxt, ebml_w: ebml::Serializer,
ebml_w.start_tag(tag_items_data_item);
encode_def_id(ebml_w, local_def(ty_m.id));
encode_parent_item(ebml_w, local_def(item.id));
encode_name(ecx, ebml_w, ty_m.ident);
encode_family(ebml_w,
purity_static_method_family(ty_m.purity));

View File

@ -345,8 +345,8 @@ impl ast::def: tr {
fn tr(xcx: extended_decode_ctxt) -> ast::def {
match self {
ast::def_fn(did, p) => { ast::def_fn(did.tr(xcx), p) }
ast::def_static_method(did, p) => {
ast::def_static_method(did.tr(xcx), p)
ast::def_static_method(did, did2, p) => {
ast::def_static_method(did.tr(xcx), did2.tr(xcx), p)
}
ast::def_self(nid) => { ast::def_self(xcx.tr_id(nid)) }
ast::def_mod(did) => { ast::def_mod(did.tr(xcx)) }

View File

@ -1126,6 +1126,7 @@ impl Resolver {
self.add_child(ident, new_parent, ~[ValueNS],
ty_m.span);
let def = def_static_method(local_def(ty_m.id),
local_def(item.id),
ty_m.purity);
(*method_name_bindings).define_value
(Public, def, ty_m.span);

View File

@ -78,8 +78,9 @@ fn trans(bcx: block, expr: @ast::expr) -> Callee {
ast::def_fn(did, _) => {
fn_callee(bcx, trans_fn_ref(bcx, did, ref_expr.id))
}
ast::def_static_method(did, _) => {
fn_callee(bcx, meth::trans_static_method_callee(bcx, did,
ast::def_static_method(impl_did, trait_did, _) => {
fn_callee(bcx, meth::trans_static_method_callee(bcx, impl_did,
trait_did,
ref_expr.id))
}
ast::def_variant(tid, vid) => {

View File

@ -641,10 +641,11 @@ fn trans_def_dps_unadjusted(bcx: block, ref_expr: @ast::expr,
let fn_data = callee::trans_fn_ref(bcx, did, ref_expr.id);
return fn_data_to_datum(bcx, did, fn_data, lldest);
}
ast::def_static_method(did, _) => {
let fn_data = meth::trans_static_method_callee(bcx, did,
ast::def_static_method(impl_did, trait_did, _) => {
let fn_data = meth::trans_static_method_callee(bcx, impl_did,
trait_did,
ref_expr.id);
return fn_data_to_datum(bcx, did, fn_data, lldest);
return fn_data_to_datum(bcx, impl_did, fn_data, lldest);
}
ast::def_variant(tid, vid) => {
if ty::enum_variant_with_id(ccx.tcx, tid, vid).args.len() > 0u {

View File

@ -162,11 +162,50 @@ fn trans_method_callee(bcx: block, callee_id: ast::node_id,
fn trans_static_method_callee(bcx: block,
method_id: ast::def_id,
trait_id: ast::def_id,
callee_id: ast::node_id) -> FnData
{
let _icx = bcx.insn_ctxt("impl::trans_static_method_callee");
let ccx = bcx.ccx();
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 {
// static fn foo<M1...Mn>(...) {...}
// }
//
// 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 = {
let trait_polyty = ty::lookup_item_type(bcx.tcx(), trait_id);
let mut index = 0;
for trait_polyty.bounds.each |param_bounds| {
for param_bounds.each |param_bound| {
match *param_bound {
ty::bound_trait(_) => { index += 1; }
ty::bound_copy | ty::bound_owned |
ty::bound_send | ty::bound_const => {}
}
}
}
index
};
let mname = if method_id.crate == ast::local_crate {
match bcx.tcx().items.get(method_id.node) {
ast_map::node_trait_method(trait_method, _, _) => {
@ -187,9 +226,7 @@ fn trans_static_method_callee(bcx: block,
let vtbls = resolve_vtables_in_fn_ctxt(
bcx.fcx, ccx.maps.vtable_map.get(callee_id));
// FIXME(#3446) -- I am pretty sure index 0 is not the right one,
// if the static method is implemented on a generic type. (NDM)
match vtbls[0] {
match vtbls[bound_index] {
typeck::vtable_static(impl_did, rcvr_substs, rcvr_origins) => {
let mth_id = method_with_name(bcx.ccx(), impl_did, mname);

View File

@ -2403,13 +2403,13 @@ fn ty_param_bounds_and_ty_for_def(fcx: @fn_ctxt, sp: span, defn: ast::def) ->
}
ast::def_fn(id, ast::unsafe_fn) |
ast::def_static_method(id, ast::unsafe_fn) => {
ast::def_static_method(id, _, ast::unsafe_fn) => {
// Unsafe functions can only be touched in an unsafe context
fcx.require_unsafe(sp, ~"access to unsafe function");
return ty::lookup_item_type(fcx.ccx.tcx, id);
}
ast::def_fn(id, _) | ast::def_static_method(id, _) |
ast::def_fn(id, _) | ast::def_static_method(id, _, _) |
ast::def_const(id) | ast::def_variant(_, id) |
ast::def_class(id, _) => {
return ty::lookup_item_type(fcx.ccx.tcx, id);

View File

@ -0,0 +1,25 @@
trait Deserializer {
fn read_int() -> int;
}
trait Deserializable<D: Deserializer> {
static fn deserialize(d: &D) -> self;
}
impl<D: Deserializer> int: Deserializable<D> {
static fn deserialize(d: &D) -> int {
return d.read_int();
}
}
struct FromThinAir { dummy: () }
impl FromThinAir: Deserializer {
fn read_int() -> int { 22 }
}
fn main() {
let d = FromThinAir { dummy: () };
let i: int = deserialize(&d);
assert i == 22;
}