Skip to content

Commit cb55e24

Browse files
committed
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.
1 parent 57b4d10 commit cb55e24

File tree

11 files changed

+122
-43
lines changed

11 files changed

+122
-43
lines changed

src/libsyntax/ast.rs

+6-3
Original file line numberDiff line numberDiff line change
@@ -118,7 +118,9 @@ type ty_param = {ident: ident, id: node_id, bounds: @~[ty_param_bound]};
118118
#[auto_deserialize]
119119
enum def {
120120
def_fn(def_id, purity),
121-
def_static_method(def_id, purity),
121+
def_static_method(/* method */ def_id,
122+
/* trait */ def_id,
123+
purity),
122124
def_self(node_id),
123125
def_mod(def_id),
124126
def_foreign_mod(def_id),
@@ -150,9 +152,10 @@ impl def : cmp::Eq {
150152
_ => false
151153
}
152154
}
153-
def_static_method(e0a, e1a) => {
155+
def_static_method(e0a, e1a, e2a) => {
154156
match (*other) {
155-
def_static_method(e0b, e1b) => e0a == e0b && e1a == e1b,
157+
def_static_method(e0b, e1b, e2b) =>
158+
e0a == e0b && e1a == e1b && e2a == e2b,
156159
_ => false
157160
}
158161
}

src/libsyntax/ast_util.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,7 @@ fn variant_def_ids(d: def) -> {enm: def_id, var: def_id} {
5454

5555
pure fn def_id_of_def(d: def) -> def_id {
5656
match d {
57-
def_fn(id, _) | def_static_method(id, _) | def_mod(id) |
57+
def_fn(id, _) | def_static_method(id, _, _) | def_mod(id) |
5858
def_foreign_mod(id) | def_const(id) |
5959
def_variant(_, id) | def_ty(id) | def_ty_param(id, _) |
6060
def_use(id) | def_class(id, _) => {

src/rustc/metadata/decoder.rs

+37-27
Original file line numberDiff line numberDiff line change
@@ -178,6 +178,12 @@ fn item_parent_item(d: ebml::Doc) -> Option<ast::def_id> {
178178
None
179179
}
180180

181+
fn item_reqd_and_translated_parent_item(cnum: ast::crate_num,
182+
d: ebml::Doc) -> ast::def_id {
183+
let trait_did = item_parent_item(d).expect(~"item without parent");
184+
{crate: cnum, node: trait_did.node}
185+
}
186+
181187
fn item_def_id(d: ebml::Doc, cdata: cmd) -> ast::def_id {
182188
let tagdoc = ebml::get_doc(d, tag_def_id);
183189
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 {
297303
}
298304

299305
fn item_to_def_like(item: ebml::Doc, did: ast::def_id, cnum: ast::crate_num)
300-
-> def_like {
306+
-> def_like
307+
{
301308
let fam = item_family(item);
302309
match fam {
303-
Const => dl_def(ast::def_const(did)),
304-
Class => dl_def(ast::def_class(did, true)),
305-
Struct => dl_def(ast::def_class(did, false)),
306-
UnsafeFn => dl_def(ast::def_fn(did, ast::unsafe_fn)),
307-
Fn => dl_def(ast::def_fn(did, ast::impure_fn)),
308-
PureFn => dl_def(ast::def_fn(did, ast::pure_fn)),
309-
ForeignFn => dl_def(ast::def_fn(did, ast::extern_fn)),
310-
UnsafeStaticMethod => dl_def(ast::def_static_method(did,
311-
ast::unsafe_fn)),
312-
StaticMethod => dl_def(ast::def_static_method(did, ast::impure_fn)),
313-
PureStaticMethod => dl_def(ast::def_static_method(did, ast::pure_fn)),
314-
Type | ForeignType => dl_def(ast::def_ty(did)),
315-
Mod => dl_def(ast::def_mod(did)),
316-
ForeignMod => dl_def(ast::def_foreign_mod(did)),
317-
Variant => {
318-
match item_parent_item(item) {
319-
Some(t) => {
320-
let tid = {crate: cnum, node: t.node};
321-
dl_def(ast::def_variant(tid, did))
322-
}
323-
None => fail ~"item_to_def_like: enum item has no parent"
324-
}
325-
}
326-
Trait | Enum => dl_def(ast::def_ty(did)),
327-
Impl => dl_impl(did),
328-
PublicField | PrivateField | InheritedField => dl_field,
310+
Const => dl_def(ast::def_const(did)),
311+
Class => dl_def(ast::def_class(did, true)),
312+
Struct => dl_def(ast::def_class(did, false)),
313+
UnsafeFn => dl_def(ast::def_fn(did, ast::unsafe_fn)),
314+
Fn => dl_def(ast::def_fn(did, ast::impure_fn)),
315+
PureFn => dl_def(ast::def_fn(did, ast::pure_fn)),
316+
ForeignFn => dl_def(ast::def_fn(did, ast::extern_fn)),
317+
UnsafeStaticMethod => {
318+
let trait_did = item_reqd_and_translated_parent_item(cnum, item);
319+
dl_def(ast::def_static_method(did, trait_did, ast::unsafe_fn))
320+
}
321+
StaticMethod => {
322+
let trait_did = item_reqd_and_translated_parent_item(cnum, item);
323+
dl_def(ast::def_static_method(did, trait_did, ast::impure_fn))
324+
}
325+
PureStaticMethod => {
326+
let trait_did = item_reqd_and_translated_parent_item(cnum, item);
327+
dl_def(ast::def_static_method(did, trait_did, ast::pure_fn))
328+
}
329+
Type | ForeignType => dl_def(ast::def_ty(did)),
330+
Mod => dl_def(ast::def_mod(did)),
331+
ForeignMod => dl_def(ast::def_foreign_mod(did)),
332+
Variant => {
333+
let enum_did = item_reqd_and_translated_parent_item(cnum, item);
334+
dl_def(ast::def_variant(enum_did, did))
335+
}
336+
Trait | Enum => dl_def(ast::def_ty(did)),
337+
Impl => dl_impl(did),
338+
PublicField | PrivateField | InheritedField => dl_field,
329339
}
330340
}
331341

src/rustc/metadata/encoder.rs

+1
Original file line numberDiff line numberDiff line change
@@ -794,6 +794,7 @@ fn encode_info_for_item(ecx: @encode_ctxt, ebml_w: ebml::Serializer,
794794

795795
ebml_w.start_tag(tag_items_data_item);
796796
encode_def_id(ebml_w, local_def(ty_m.id));
797+
encode_parent_item(ebml_w, local_def(item.id));
797798
encode_name(ecx, ebml_w, ty_m.ident);
798799
encode_family(ebml_w,
799800
purity_static_method_family(ty_m.purity));

src/rustc/middle/astencode.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -345,8 +345,8 @@ impl ast::def: tr {
345345
fn tr(xcx: extended_decode_ctxt) -> ast::def {
346346
match self {
347347
ast::def_fn(did, p) => { ast::def_fn(did.tr(xcx), p) }
348-
ast::def_static_method(did, p) => {
349-
ast::def_static_method(did.tr(xcx), p)
348+
ast::def_static_method(did, did2, p) => {
349+
ast::def_static_method(did.tr(xcx), did2.tr(xcx), p)
350350
}
351351
ast::def_self(nid) => { ast::def_self(xcx.tr_id(nid)) }
352352
ast::def_mod(did) => { ast::def_mod(did.tr(xcx)) }

src/rustc/middle/resolve.rs

+1
Original file line numberDiff line numberDiff line change
@@ -1126,6 +1126,7 @@ impl Resolver {
11261126
self.add_child(ident, new_parent, ~[ValueNS],
11271127
ty_m.span);
11281128
let def = def_static_method(local_def(ty_m.id),
1129+
local_def(item.id),
11291130
ty_m.purity);
11301131
(*method_name_bindings).define_value
11311132
(Public, def, ty_m.span);

src/rustc/middle/trans/callee.rs

+3-2
Original file line numberDiff line numberDiff line change
@@ -78,8 +78,9 @@ fn trans(bcx: block, expr: @ast::expr) -> Callee {
7878
ast::def_fn(did, _) => {
7979
fn_callee(bcx, trans_fn_ref(bcx, did, ref_expr.id))
8080
}
81-
ast::def_static_method(did, _) => {
82-
fn_callee(bcx, meth::trans_static_method_callee(bcx, did,
81+
ast::def_static_method(impl_did, trait_did, _) => {
82+
fn_callee(bcx, meth::trans_static_method_callee(bcx, impl_did,
83+
trait_did,
8384
ref_expr.id))
8485
}
8586
ast::def_variant(tid, vid) => {

src/rustc/middle/trans/expr.rs

+4-3
Original file line numberDiff line numberDiff line change
@@ -641,10 +641,11 @@ fn trans_def_dps_unadjusted(bcx: block, ref_expr: @ast::expr,
641641
let fn_data = callee::trans_fn_ref(bcx, did, ref_expr.id);
642642
return fn_data_to_datum(bcx, did, fn_data, lldest);
643643
}
644-
ast::def_static_method(did, _) => {
645-
let fn_data = meth::trans_static_method_callee(bcx, did,
644+
ast::def_static_method(impl_did, trait_did, _) => {
645+
let fn_data = meth::trans_static_method_callee(bcx, impl_did,
646+
trait_did,
646647
ref_expr.id);
647-
return fn_data_to_datum(bcx, did, fn_data, lldest);
648+
return fn_data_to_datum(bcx, impl_did, fn_data, lldest);
648649
}
649650
ast::def_variant(tid, vid) => {
650651
if ty::enum_variant_with_id(ccx.tcx, tid, vid).args.len() > 0u {

src/rustc/middle/trans/meth.rs

+40-3
Original file line numberDiff line numberDiff line change
@@ -162,11 +162,50 @@ fn trans_method_callee(bcx: block, callee_id: ast::node_id,
162162

163163
fn trans_static_method_callee(bcx: block,
164164
method_id: ast::def_id,
165+
trait_id: ast::def_id,
165166
callee_id: ast::node_id) -> FnData
166167
{
167168
let _icx = bcx.insn_ctxt("impl::trans_static_method_callee");
168169
let ccx = bcx.ccx();
169170

171+
debug!("trans_static_method_callee(method_id=%?, trait_id=%s, \
172+
callee_id=%?)",
173+
method_id,
174+
ty::item_path_str(bcx.tcx(), trait_id),
175+
callee_id);
176+
let _indenter = indenter();
177+
178+
// When we translate a static fn defined in a trait like:
179+
//
180+
// trait<T1...Tn> Trait {
181+
// static fn foo<M1...Mn>(...) {...}
182+
// }
183+
//
184+
// this winds up being translated as something like:
185+
//
186+
// fn foo<T1...Tn,self: Trait<T1...Tn>,M1...Mn>(...) {...}
187+
//
188+
// So when we see a call to this function foo, we have to figure
189+
// out which impl the `Trait<T1...Tn>` bound on the type `self` was
190+
// bound to. Due to the fact that we use a flattened list of
191+
// impls, one per bound, this means we have to total up the bounds
192+
// found on the type parametesr T1...Tn to find the index of the
193+
// one we are interested in.
194+
let bound_index = {
195+
let trait_polyty = ty::lookup_item_type(bcx.tcx(), trait_id);
196+
let mut index = 0;
197+
for trait_polyty.bounds.each |param_bounds| {
198+
for param_bounds.each |param_bound| {
199+
match *param_bound {
200+
ty::bound_trait(_) => { index += 1; }
201+
ty::bound_copy | ty::bound_owned |
202+
ty::bound_send | ty::bound_const => {}
203+
}
204+
}
205+
}
206+
index
207+
};
208+
170209
let mname = if method_id.crate == ast::local_crate {
171210
match bcx.tcx().items.get(method_id.node) {
172211
ast_map::node_trait_method(trait_method, _, _) => {
@@ -187,9 +226,7 @@ fn trans_static_method_callee(bcx: block,
187226
let vtbls = resolve_vtables_in_fn_ctxt(
188227
bcx.fcx, ccx.maps.vtable_map.get(callee_id));
189228

190-
// FIXME(#3446) -- I am pretty sure index 0 is not the right one,
191-
// if the static method is implemented on a generic type. (NDM)
192-
match vtbls[0] {
229+
match vtbls[bound_index] {
193230
typeck::vtable_static(impl_did, rcvr_substs, rcvr_origins) => {
194231

195232
let mth_id = method_with_name(bcx.ccx(), impl_did, mname);

src/rustc/middle/typeck/check.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -2403,13 +2403,13 @@ fn ty_param_bounds_and_ty_for_def(fcx: @fn_ctxt, sp: span, defn: ast::def) ->
24032403
}
24042404
24052405
ast::def_fn(id, ast::unsafe_fn) |
2406-
ast::def_static_method(id, ast::unsafe_fn) => {
2406+
ast::def_static_method(id, _, ast::unsafe_fn) => {
24072407
// Unsafe functions can only be touched in an unsafe context
24082408
fcx.require_unsafe(sp, ~"access to unsafe function");
24092409
return ty::lookup_item_type(fcx.ccx.tcx, id);
24102410
}
24112411
2412-
ast::def_fn(id, _) | ast::def_static_method(id, _) |
2412+
ast::def_fn(id, _) | ast::def_static_method(id, _, _) |
24132413
ast::def_const(id) | ast::def_variant(_, id) |
24142414
ast::def_class(id, _) => {
24152415
return ty::lookup_item_type(fcx.ccx.tcx, id);
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
trait Deserializer {
2+
fn read_int() -> int;
3+
}
4+
5+
trait Deserializable<D: Deserializer> {
6+
static fn deserialize(d: &D) -> self;
7+
}
8+
9+
impl<D: Deserializer> int: Deserializable<D> {
10+
static fn deserialize(d: &D) -> int {
11+
return d.read_int();
12+
}
13+
}
14+
15+
struct FromThinAir { dummy: () }
16+
17+
impl FromThinAir: Deserializer {
18+
fn read_int() -> int { 22 }
19+
}
20+
21+
fn main() {
22+
let d = FromThinAir { dummy: () };
23+
let i: int = deserialize(&d);
24+
assert i == 22;
25+
}

0 commit comments

Comments
 (0)