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:
parent
57b4d10ff6
commit
cb55e246ba
@ -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
|
||||
}
|
||||
}
|
||||
|
@ -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, _) => {
|
||||
|
@ -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,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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));
|
||||
|
@ -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)) }
|
||||
|
@ -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);
|
||||
|
@ -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) => {
|
||||
|
@ -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 {
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user