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
11 changed files with 122 additions and 43 deletions
|
@ -118,7 +118,9 @@ type ty_param = {ident: ident, id: node_id, bounds: @~[ty_param_bound]};
|
||||||
#[auto_deserialize]
|
#[auto_deserialize]
|
||||||
enum def {
|
enum def {
|
||||||
def_fn(def_id, purity),
|
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_self(node_id),
|
||||||
def_mod(def_id),
|
def_mod(def_id),
|
||||||
def_foreign_mod(def_id),
|
def_foreign_mod(def_id),
|
||||||
|
@ -150,9 +152,10 @@ impl def : cmp::Eq {
|
||||||
_ => false
|
_ => false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
def_static_method(e0a, e1a) => {
|
def_static_method(e0a, e1a, e2a) => {
|
||||||
match (*other) {
|
match (*other) {
|
||||||
def_static_method(e0b, e1b) => e0a == e0b && e1a == e1b,
|
def_static_method(e0b, e1b, e2b) =>
|
||||||
|
e0a == e0b && e1a == e1b && e2a == e2b,
|
||||||
_ => false
|
_ => 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 {
|
pure fn def_id_of_def(d: def) -> def_id {
|
||||||
match d {
|
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_foreign_mod(id) | def_const(id) |
|
||||||
def_variant(_, id) | def_ty(id) | def_ty_param(id, _) |
|
def_variant(_, id) | def_ty(id) | def_ty_param(id, _) |
|
||||||
def_use(id) | def_class(id, _) => {
|
def_use(id) | def_class(id, _) => {
|
||||||
|
|
|
@ -178,6 +178,12 @@ fn item_parent_item(d: ebml::Doc) -> Option<ast::def_id> {
|
||||||
None
|
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 {
|
fn item_def_id(d: ebml::Doc, cdata: cmd) -> ast::def_id {
|
||||||
let tagdoc = ebml::get_doc(d, tag_def_id);
|
let tagdoc = ebml::get_doc(d, tag_def_id);
|
||||||
return translate_def_id(cdata, ebml::with_doc_data(tagdoc,
|
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)
|
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);
|
let fam = item_family(item);
|
||||||
match fam {
|
match fam {
|
||||||
Const => dl_def(ast::def_const(did)),
|
Const => dl_def(ast::def_const(did)),
|
||||||
Class => dl_def(ast::def_class(did, true)),
|
Class => dl_def(ast::def_class(did, true)),
|
||||||
Struct => dl_def(ast::def_class(did, false)),
|
Struct => dl_def(ast::def_class(did, false)),
|
||||||
UnsafeFn => dl_def(ast::def_fn(did, ast::unsafe_fn)),
|
UnsafeFn => dl_def(ast::def_fn(did, ast::unsafe_fn)),
|
||||||
Fn => dl_def(ast::def_fn(did, ast::impure_fn)),
|
Fn => dl_def(ast::def_fn(did, ast::impure_fn)),
|
||||||
PureFn => dl_def(ast::def_fn(did, ast::pure_fn)),
|
PureFn => dl_def(ast::def_fn(did, ast::pure_fn)),
|
||||||
ForeignFn => dl_def(ast::def_fn(did, ast::extern_fn)),
|
ForeignFn => dl_def(ast::def_fn(did, ast::extern_fn)),
|
||||||
UnsafeStaticMethod => dl_def(ast::def_static_method(did,
|
UnsafeStaticMethod => {
|
||||||
ast::unsafe_fn)),
|
let trait_did = item_reqd_and_translated_parent_item(cnum, item);
|
||||||
StaticMethod => dl_def(ast::def_static_method(did, ast::impure_fn)),
|
dl_def(ast::def_static_method(did, trait_did, ast::unsafe_fn))
|
||||||
PureStaticMethod => dl_def(ast::def_static_method(did, ast::pure_fn)),
|
}
|
||||||
Type | ForeignType => dl_def(ast::def_ty(did)),
|
StaticMethod => {
|
||||||
Mod => dl_def(ast::def_mod(did)),
|
let trait_did = item_reqd_and_translated_parent_item(cnum, item);
|
||||||
ForeignMod => dl_def(ast::def_foreign_mod(did)),
|
dl_def(ast::def_static_method(did, trait_did, ast::impure_fn))
|
||||||
Variant => {
|
}
|
||||||
match item_parent_item(item) {
|
PureStaticMethod => {
|
||||||
Some(t) => {
|
let trait_did = item_reqd_and_translated_parent_item(cnum, item);
|
||||||
let tid = {crate: cnum, node: t.node};
|
dl_def(ast::def_static_method(did, trait_did, ast::pure_fn))
|
||||||
dl_def(ast::def_variant(tid, did))
|
}
|
||||||
}
|
Type | ForeignType => dl_def(ast::def_ty(did)),
|
||||||
None => fail ~"item_to_def_like: enum item has no parent"
|
Mod => dl_def(ast::def_mod(did)),
|
||||||
}
|
ForeignMod => dl_def(ast::def_foreign_mod(did)),
|
||||||
}
|
Variant => {
|
||||||
Trait | Enum => dl_def(ast::def_ty(did)),
|
let enum_did = item_reqd_and_translated_parent_item(cnum, item);
|
||||||
Impl => dl_impl(did),
|
dl_def(ast::def_variant(enum_did, did))
|
||||||
PublicField | PrivateField | InheritedField => dl_field,
|
}
|
||||||
|
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);
|
ebml_w.start_tag(tag_items_data_item);
|
||||||
encode_def_id(ebml_w, local_def(ty_m.id));
|
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_name(ecx, ebml_w, ty_m.ident);
|
||||||
encode_family(ebml_w,
|
encode_family(ebml_w,
|
||||||
purity_static_method_family(ty_m.purity));
|
purity_static_method_family(ty_m.purity));
|
||||||
|
|
|
@ -345,8 +345,8 @@ impl ast::def: tr {
|
||||||
fn tr(xcx: extended_decode_ctxt) -> ast::def {
|
fn tr(xcx: extended_decode_ctxt) -> ast::def {
|
||||||
match self {
|
match self {
|
||||||
ast::def_fn(did, p) => { ast::def_fn(did.tr(xcx), p) }
|
ast::def_fn(did, p) => { ast::def_fn(did.tr(xcx), p) }
|
||||||
ast::def_static_method(did, p) => {
|
ast::def_static_method(did, did2, p) => {
|
||||||
ast::def_static_method(did.tr(xcx), 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_self(nid) => { ast::def_self(xcx.tr_id(nid)) }
|
||||||
ast::def_mod(did) => { ast::def_mod(did.tr(xcx)) }
|
ast::def_mod(did) => { ast::def_mod(did.tr(xcx)) }
|
||||||
|
|
|
@ -1126,6 +1126,7 @@ impl Resolver {
|
||||||
self.add_child(ident, new_parent, ~[ValueNS],
|
self.add_child(ident, new_parent, ~[ValueNS],
|
||||||
ty_m.span);
|
ty_m.span);
|
||||||
let def = def_static_method(local_def(ty_m.id),
|
let def = def_static_method(local_def(ty_m.id),
|
||||||
|
local_def(item.id),
|
||||||
ty_m.purity);
|
ty_m.purity);
|
||||||
(*method_name_bindings).define_value
|
(*method_name_bindings).define_value
|
||||||
(Public, def, ty_m.span);
|
(Public, def, ty_m.span);
|
||||||
|
|
|
@ -78,8 +78,9 @@ fn trans(bcx: block, expr: @ast::expr) -> Callee {
|
||||||
ast::def_fn(did, _) => {
|
ast::def_fn(did, _) => {
|
||||||
fn_callee(bcx, trans_fn_ref(bcx, did, ref_expr.id))
|
fn_callee(bcx, trans_fn_ref(bcx, did, ref_expr.id))
|
||||||
}
|
}
|
||||||
ast::def_static_method(did, _) => {
|
ast::def_static_method(impl_did, trait_did, _) => {
|
||||||
fn_callee(bcx, meth::trans_static_method_callee(bcx, did,
|
fn_callee(bcx, meth::trans_static_method_callee(bcx, impl_did,
|
||||||
|
trait_did,
|
||||||
ref_expr.id))
|
ref_expr.id))
|
||||||
}
|
}
|
||||||
ast::def_variant(tid, vid) => {
|
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);
|
let fn_data = callee::trans_fn_ref(bcx, did, ref_expr.id);
|
||||||
return fn_data_to_datum(bcx, did, fn_data, lldest);
|
return fn_data_to_datum(bcx, did, fn_data, lldest);
|
||||||
}
|
}
|
||||||
ast::def_static_method(did, _) => {
|
ast::def_static_method(impl_did, trait_did, _) => {
|
||||||
let fn_data = meth::trans_static_method_callee(bcx, did,
|
let fn_data = meth::trans_static_method_callee(bcx, impl_did,
|
||||||
|
trait_did,
|
||||||
ref_expr.id);
|
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) => {
|
ast::def_variant(tid, vid) => {
|
||||||
if ty::enum_variant_with_id(ccx.tcx, tid, vid).args.len() > 0u {
|
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,
|
fn trans_static_method_callee(bcx: block,
|
||||||
method_id: ast::def_id,
|
method_id: ast::def_id,
|
||||||
|
trait_id: ast::def_id,
|
||||||
callee_id: ast::node_id) -> FnData
|
callee_id: ast::node_id) -> FnData
|
||||||
{
|
{
|
||||||
let _icx = bcx.insn_ctxt("impl::trans_static_method_callee");
|
let _icx = bcx.insn_ctxt("impl::trans_static_method_callee");
|
||||||
let ccx = bcx.ccx();
|
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 {
|
let mname = if method_id.crate == ast::local_crate {
|
||||||
match bcx.tcx().items.get(method_id.node) {
|
match bcx.tcx().items.get(method_id.node) {
|
||||||
ast_map::node_trait_method(trait_method, _, _) => {
|
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(
|
let vtbls = resolve_vtables_in_fn_ctxt(
|
||||||
bcx.fcx, ccx.maps.vtable_map.get(callee_id));
|
bcx.fcx, ccx.maps.vtable_map.get(callee_id));
|
||||||
|
|
||||||
// FIXME(#3446) -- I am pretty sure index 0 is not the right one,
|
match vtbls[bound_index] {
|
||||||
// if the static method is implemented on a generic type. (NDM)
|
|
||||||
match vtbls[0] {
|
|
||||||
typeck::vtable_static(impl_did, rcvr_substs, rcvr_origins) => {
|
typeck::vtable_static(impl_did, rcvr_substs, rcvr_origins) => {
|
||||||
|
|
||||||
let mth_id = method_with_name(bcx.ccx(), impl_did, mname);
|
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_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
|
// Unsafe functions can only be touched in an unsafe context
|
||||||
fcx.require_unsafe(sp, ~"access to unsafe function");
|
fcx.require_unsafe(sp, ~"access to unsafe function");
|
||||||
return ty::lookup_item_type(fcx.ccx.tcx, id);
|
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_const(id) | ast::def_variant(_, id) |
|
||||||
ast::def_class(id, _) => {
|
ast::def_class(id, _) => {
|
||||||
return ty::lookup_item_type(fcx.ccx.tcx, 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…
Add table
Add a link
Reference in a new issue