Skip to content

Commit 006f3ea

Browse files
committed
Fix a latent bug in trait dispatch where we sometimes counted associated types
when constructing the vtable-index. Not good.
1 parent 07cdb85 commit 006f3ea

File tree

10 files changed

+80
-74
lines changed

10 files changed

+80
-74
lines changed

src/librustc/middle/astencode.rs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -904,8 +904,8 @@ impl<'a, 'tcx> rbml_writer_helpers<'tcx> for Encoder<'a> {
904904
try!(this.emit_struct_field("method_num", 0, |this| {
905905
this.emit_uint(o.method_num)
906906
}));
907-
try!(this.emit_struct_field("real_index", 0, |this| {
908-
this.emit_uint(o.real_index)
907+
try!(this.emit_struct_field("vtable_index", 0, |this| {
908+
this.emit_uint(o.vtable_index)
909909
}));
910910
Ok(())
911911
})
@@ -1492,8 +1492,8 @@ impl<'a, 'tcx> rbml_decoder_decoder_helpers<'tcx> for reader::Decoder<'a> {
14921492
this.read_uint()
14931493
}).unwrap()
14941494
},
1495-
real_index: {
1496-
this.read_struct_field("real_index", 3, |this| {
1495+
vtable_index: {
1496+
this.read_struct_field("vtable_index", 3, |this| {
14971497
this.read_uint()
14981498
}).unwrap()
14991499
},

src/librustc/middle/traits/select.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -214,7 +214,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
214214
self.closure_typer.param_env()
215215
}
216216

217-
pub fn closure_typer(&self) -> &'cx (ty::UnboxedClosureTyper<'tcx>+'cx) {
217+
pub fn closure_typer(&self) -> &'cx (ty::ClosureTyper<'tcx>+'cx) {
218218
self.closure_typer
219219
}
220220

src/librustc/middle/traits/util.rs

Lines changed: 41 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -329,58 +329,67 @@ pub fn upcast<'tcx>(tcx: &ty::ctxt<'tcx>,
329329
pub fn get_vtable_index_of_object_method<'tcx>(tcx: &ty::ctxt<'tcx>,
330330
object_trait_ref: ty::PolyTraitRef<'tcx>,
331331
trait_def_id: ast::DefId,
332-
method_index_in_trait: uint) -> uint {
332+
method_offset_in_trait: uint) -> uint {
333333
// We need to figure the "real index" of the method in a
334334
// listing of all the methods of an object. We do this by
335335
// iterating down the supertraits of the object's trait until
336336
// we find the trait the method came from, counting up the
337337
// methods from them.
338338
let mut method_count = 0;
339-
ty::each_bound_trait_and_supertraits(tcx, &[object_trait_ref], |bound_ref| {
339+
340+
for bound_ref in transitive_bounds(tcx, &[object_trait_ref]) {
340341
if bound_ref.def_id() == trait_def_id {
341-
false
342-
} else {
343-
let trait_items = ty::trait_items(tcx, bound_ref.def_id());
344-
for trait_item in trait_items.iter() {
345-
match *trait_item {
346-
ty::MethodTraitItem(_) => method_count += 1,
347-
ty::TypeTraitItem(_) => {}
348-
}
342+
break;
343+
}
344+
345+
let trait_items = ty::trait_items(tcx, bound_ref.def_id());
346+
for trait_item in trait_items.iter() {
347+
match *trait_item {
348+
ty::MethodTraitItem(_) => method_count += 1,
349+
ty::TypeTraitItem(_) => {}
349350
}
350-
true
351351
}
352+
}
353+
354+
// count number of methods preceding the one we are selecting and
355+
// add them to the total offset; skip over associated types.
356+
let trait_items = ty::trait_items(tcx, trait_def_id);
357+
for trait_item in trait_items.iter().take(method_offset_in_trait) {
358+
match *trait_item {
359+
ty::MethodTraitItem(_) => method_count += 1,
360+
ty::TypeTraitItem(_) => {}
361+
}
362+
}
363+
364+
// the item at the offset we were given really ought to be a method
365+
assert!(match trait_items[method_offset_in_trait] {
366+
ty::MethodTraitItem(_) => true,
367+
ty::TypeTraitItem(_) => false
352368
});
353-
method_count + method_index_in_trait
369+
370+
method_count
354371
}
355372

356-
pub fn unboxed_closure_trait_ref_and_return_type<'tcx>(
357-
closure_typer: &ty::UnboxedClosureTyper<'tcx>,
373+
pub enum TupleArgumentsFlag { Yes, No }
374+
375+
pub fn closure_trait_ref_and_return_type<'tcx>(
376+
tcx: &ty::ctxt<'tcx>,
358377
fn_trait_def_id: ast::DefId,
359378
self_ty: Ty<'tcx>,
360-
closure_def_id: ast::DefId,
361-
substs: &Substs<'tcx>)
379+
sig: &ty::PolyFnSig<'tcx>,
380+
tuple_arguments: TupleArgumentsFlag)
362381
-> ty::Binder<(Rc<ty::TraitRef<'tcx>>, Ty<'tcx>)>
363382
{
364-
let tcx = closure_typer.param_env().tcx;
365-
let closure_type = closure_typer.unboxed_closure_type(closure_def_id, substs);
366-
367-
debug!("unboxed_closure_trait_ref: closure_def_id={} closure_type={}",
368-
closure_def_id.repr(tcx),
369-
closure_type.repr(tcx));
370-
371-
let closure_sig = &closure_type.sig;
372-
let arguments_tuple = closure_sig.0.inputs[0];
373-
let trait_substs =
374-
Substs::new_trait(
375-
vec![arguments_tuple],
376-
vec![],
377-
self_ty);
383+
let arguments_tuple = match tuple_arguments {
384+
TupleArgumentsFlag::No => sig.0.inputs[0],
385+
TupleArgumentsFlag::Yes => ty::mk_tup(tcx, sig.0.inputs.to_vec()),
386+
};
387+
let trait_substs = Substs::new_trait(vec![arguments_tuple], vec![], self_ty);
378388
let trait_ref = Rc::new(ty::TraitRef {
379389
def_id: fn_trait_def_id,
380390
substs: tcx.mk_substs(trait_substs),
381391
});
382-
383-
ty::Binder((trait_ref, closure_sig.0.output.unwrap()))
392+
ty::Binder((trait_ref, sig.0.output.unwrap()))
384393
}
385394

386395
impl<'tcx,O:Repr<'tcx>> Repr<'tcx> for super::Obligation<'tcx, O> {

src/librustc/middle/ty.rs

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -452,7 +452,10 @@ pub struct MethodParam<'tcx> {
452452
// never contains bound regions; those regions should have been
453453
// instantiated with fresh variables at this point.
454454
pub trait_ref: Rc<ty::TraitRef<'tcx>>,
455-
// index of uint in the list of methods for the trait
455+
456+
// index of uint in the list of trait items. Note that this is NOT
457+
// the index into the vtable, because the list of trait items
458+
// includes associated types.
456459
pub method_num: uint,
457460

458461
/// The impl for the trait from which the method comes. This
@@ -471,14 +474,14 @@ pub struct MethodObject<'tcx> {
471474
// the actual base trait id of the object
472475
pub object_trait_id: ast::DefId,
473476

474-
// index of the method to be invoked amongst the trait's methods
477+
// index of the method to be invoked amongst the trait's items
475478
pub method_num: uint,
476479

477480
// index into the actual runtime vtable.
478481
// the vtable is formed by concatenating together the method lists of
479-
// the base object trait and all supertraits; this is the index into
482+
// the base object trait and all supertraits; this is the index into
480483
// that vtable
481-
pub real_index: uint,
484+
pub vtable_index: uint,
482485
}
483486

484487
#[derive(Clone)]

src/librustc/middle/ty_fold.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -319,7 +319,7 @@ impl<'tcx> TypeFoldable<'tcx> for ty::MethodOrigin<'tcx> {
319319
trait_ref: object.trait_ref.fold_with(folder),
320320
object_trait_id: object.object_trait_id,
321321
method_num: object.method_num,
322-
real_index: object.real_index
322+
vtable_index: object.vtable_index,
323323
})
324324
}
325325
}

src/librustc/util/ppaux.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1061,7 +1061,7 @@ impl<'tcx> Repr<'tcx> for ty::MethodObject<'tcx> {
10611061
format!("MethodObject({},{},{})",
10621062
self.trait_ref.repr(tcx),
10631063
self.method_num,
1064-
self.real_index)
1064+
self.vtable_index)
10651065
}
10661066
}
10671067

src/librustc_trans/trans/meth.rs

Lines changed: 14 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ use back::abi;
1313
use back::link;
1414
use llvm::{self, ValueRef, get_param};
1515
use metadata::csearch;
16-
use middle::subst::{Subst, Substs};
16+
use middle::subst::Substs;
1717
use middle::subst::VecPerParamSpace;
1818
use middle::subst;
1919
use middle::traits;
@@ -29,6 +29,7 @@ use trans::expr::{SaveIn, Ignore};
2929
use trans::expr;
3030
use trans::glue;
3131
use trans::machine;
32+
use trans::monomorphize;
3233
use trans::type_::Type;
3334
use trans::type_of::*;
3435
use middle::ty::{self, Ty};
@@ -162,7 +163,7 @@ pub fn trans_method_callee<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
162163
};
163164
trans_trait_callee(bcx,
164165
monomorphize_type(bcx, method_ty),
165-
mt.real_index,
166+
mt.vtable_index,
166167
self_expr,
167168
arg_cleanup_scope)
168169
}
@@ -439,7 +440,7 @@ fn combine_impl_and_methods_tps<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
439440
/// extract the self data and vtable out of the pair.
440441
fn trans_trait_callee<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
441442
method_ty: Ty<'tcx>,
442-
n_method: uint,
443+
vtable_index: uint,
443444
self_expr: &ast::Expr,
444445
arg_cleanup_scope: cleanup::ScopeId)
445446
-> Callee<'blk, 'tcx> {
@@ -469,28 +470,28 @@ fn trans_trait_callee<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
469470
self_datum.val
470471
};
471472

472-
trans_trait_callee_from_llval(bcx, method_ty, n_method, llval)
473+
trans_trait_callee_from_llval(bcx, method_ty, vtable_index, llval)
473474
}
474475

475476
/// Same as `trans_trait_callee()` above, except that it is given a by-ref pointer to the object
476477
/// pair.
477478
pub fn trans_trait_callee_from_llval<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
478479
callee_ty: Ty<'tcx>,
479-
n_method: uint,
480+
vtable_index: uint,
480481
llpair: ValueRef)
481482
-> Callee<'blk, 'tcx> {
482483
let _icx = push_ctxt("meth::trans_trait_callee");
483484
let ccx = bcx.ccx();
484485

485486
// Load the data pointer from the object.
486-
debug!("(translating trait callee) loading second index from pair");
487+
debug!("trans_trait_callee_from_llval(callee_ty={}, vtable_index={}, llpair={})",
488+
callee_ty.repr(ccx.tcx()),
489+
vtable_index,
490+
bcx.val_to_string(llpair));
487491
let llboxptr = GEPi(bcx, llpair, &[0u, abi::FAT_PTR_ADDR]);
488492
let llbox = Load(bcx, llboxptr);
489493
let llself = PointerCast(bcx, llbox, Type::i8p(ccx));
490494

491-
// Load the function from the vtable and cast it to the expected type.
492-
debug!("(translating trait callee) loading method");
493-
494495
// Replace the self type (&Self or Box<Self>) with an opaque pointer.
495496
let llcallee_ty = match callee_ty.sty {
496497
ty::ty_bare_fn(_, ref f) if f.abi == Rust || f.abi == RustCall => {
@@ -500,10 +501,7 @@ pub fn trans_trait_callee_from_llval<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
500501
output: f.sig.0.output,
501502
variadic: f.sig.0.variadic,
502503
});
503-
type_of_rust_fn(ccx,
504-
Some(Type::i8p(ccx)),
505-
&fake_sig,
506-
f.abi)
504+
type_of_rust_fn(ccx, Some(Type::i8p(ccx)), &fake_sig, f.abi)
507505
}
508506
_ => {
509507
ccx.sess().bug("meth::trans_trait_callee given non-bare-rust-fn");
@@ -514,7 +512,7 @@ pub fn trans_trait_callee_from_llval<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
514512
GEPi(bcx, llpair,
515513
&[0u, abi::FAT_PTR_EXTRA]),
516514
Type::vtable(ccx).ptr_to().ptr_to()));
517-
let mptr = Load(bcx, GEPi(bcx, llvtable, &[0u, n_method + VTABLE_OFFSET]));
515+
let mptr = Load(bcx, GEPi(bcx, llvtable, &[0u, vtable_index + VTABLE_OFFSET]));
518516
let mptr = PointerCast(bcx, mptr, llcallee_ty.ptr_to());
519517

520518
return Callee {
@@ -558,7 +556,7 @@ pub fn trans_object_shim<'a, 'tcx>(
558556
let _icx = push_ctxt("trans_object_shim");
559557
let tcx = ccx.tcx();
560558

561-
debug!("trans_object_shim(object_ty={}, trait_id={}, n_method={})",
559+
debug!("trans_object_shim(object_ty={}, trait_id={}, method_offset_in_trait={})",
562560
object_ty.repr(tcx),
563561
trait_id.repr(tcx),
564562
method_offset_in_trait);
@@ -587,7 +585,7 @@ pub fn trans_object_shim<'a, 'tcx>(
587585
tcx.sess.bug("can't create a method shim for an associated type")
588586
}
589587
};
590-
let fty = method_ty.fty.subst(tcx, &object_substs);
588+
let fty = monomorphize::apply_param_substs(tcx, &object_substs, &method_ty.fty);
591589
let fty = tcx.mk_bare_fn(fty);
592590
debug!("trans_object_shim: fty={}", fty.repr(tcx));
593591

src/librustc_trans/trans/type_of.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -103,6 +103,10 @@ pub fn type_of_rust_fn<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
103103
abi: abi::Abi)
104104
-> Type
105105
{
106+
debug!("type_of_rust_fn(sig={},abi={:?})",
107+
sig.repr(cx.tcx()),
108+
abi);
109+
106110
let sig = ty::erase_late_bound_regions(cx.tcx(), sig);
107111
assert!(!sig.variadic); // rust fns are never variadic
108112

src/librustc_typeck/check/method/confirm.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -206,7 +206,7 @@ impl<'a,'tcx> ConfirmContext<'a,'tcx> {
206206
(impl_polytype.substs, MethodStatic(pick.method_ty.def_id))
207207
}
208208

209-
probe::ObjectPick(trait_def_id, method_num, real_index) => {
209+
probe::ObjectPick(trait_def_id, method_num, vtable_index) => {
210210
self.extract_trait_ref(self_ty, |this, object_ty, data| {
211211
// The object data has no entry for the Self
212212
// Type. For the purposes of this method call, we
@@ -233,7 +233,7 @@ impl<'a,'tcx> ConfirmContext<'a,'tcx> {
233233
trait_ref: upcast_trait_ref,
234234
object_trait_id: trait_def_id,
235235
method_num: method_num,
236-
real_index: real_index,
236+
vtable_index: vtable_index,
237237
});
238238
(substs, origin)
239239
})

src/librustc_typeck/check/method/probe.rs

Lines changed: 5 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,7 @@ struct Candidate<'tcx> {
5959

6060
enum CandidateKind<'tcx> {
6161
InherentImplCandidate(/* Impl */ ast::DefId, subst::Substs<'tcx>),
62-
ObjectCandidate(/* Trait */ ast::DefId, /* method_num */ uint, /* real_index */ uint),
62+
ObjectCandidate(/* Trait */ ast::DefId, /* method_num */ uint, /* vtable index */ uint),
6363
ExtensionImplCandidate(/* Impl */ ast::DefId, Rc<ty::TraitRef<'tcx>>,
6464
subst::Substs<'tcx>, MethodIndex),
6565
ClosureCandidate(/* Trait */ ast::DefId, MethodIndex),
@@ -318,7 +318,7 @@ impl<'a,'tcx> ProbeContext<'a,'tcx> {
318318
// itself. Hence, a `&self` method will wind up with an
319319
// argument type like `&Trait`.
320320
let trait_ref = data.principal_trait_ref_with_self_ty(self.tcx(), self_ty);
321-
self.elaborate_bounds(&[trait_ref.clone()], false, |this, new_trait_ref, m, method_num| {
321+
self.elaborate_bounds(&[trait_ref.clone()], |this, new_trait_ref, m, method_num| {
322322
let new_trait_ref = this.erase_late_bound_regions(&new_trait_ref);
323323

324324
let vtable_index =
@@ -365,7 +365,7 @@ impl<'a,'tcx> ProbeContext<'a,'tcx> {
365365
})
366366
.collect();
367367

368-
self.elaborate_bounds(bounds.as_slice(), true, |this, poly_trait_ref, m, method_num| {
368+
self.elaborate_bounds(bounds.as_slice(), |this, poly_trait_ref, m, method_num| {
369369
let trait_ref =
370370
this.erase_late_bound_regions(&poly_trait_ref);
371371

@@ -405,7 +405,6 @@ impl<'a,'tcx> ProbeContext<'a,'tcx> {
405405
fn elaborate_bounds<F>(
406406
&mut self,
407407
bounds: &[ty::PolyTraitRef<'tcx>],
408-
num_includes_types: bool,
409408
mut mk_cand: F,
410409
) where
411410
F: for<'b> FnMut(
@@ -427,8 +426,7 @@ impl<'a,'tcx> ProbeContext<'a,'tcx> {
427426

428427
let (pos, method) = match trait_method(tcx,
429428
bound_trait_ref.def_id(),
430-
self.method_name,
431-
num_includes_types) {
429+
self.method_name) {
432430
Some(v) => v,
433431
None => { continue; }
434432
};
@@ -1139,19 +1137,13 @@ fn impl_method<'tcx>(tcx: &ty::ctxt<'tcx>,
11391137
/// index (or `None`, if no such method).
11401138
fn trait_method<'tcx>(tcx: &ty::ctxt<'tcx>,
11411139
trait_def_id: ast::DefId,
1142-
method_name: ast::Name,
1143-
num_includes_types: bool)
1140+
method_name: ast::Name)
11441141
-> Option<(uint, Rc<ty::Method<'tcx>>)>
11451142
{
11461143
let trait_items = ty::trait_items(tcx, trait_def_id);
11471144
debug!("trait_method; items: {:?}", trait_items);
11481145
trait_items
11491146
.iter()
1150-
.filter(|item|
1151-
num_includes_types || match *item {
1152-
&ty::MethodTraitItem(_) => true,
1153-
&ty::TypeTraitItem(_) => false
1154-
})
11551147
.enumerate()
11561148
.find(|&(_, ref item)| item.name() == method_name)
11571149
.and_then(|(idx, item)| item.as_opt_method().map(|m| (idx, m)))

0 commit comments

Comments
 (0)