Fix a latent bug in trait dispatch where we sometimes counted associated types

when constructing the vtable-index. Not good.
This commit is contained in:
Niko Matsakis 2015-01-11 15:18:06 -05:00
parent 07cdb85331
commit 006f3eacae
10 changed files with 81 additions and 75 deletions

View file

@ -904,8 +904,8 @@ impl<'a, 'tcx> rbml_writer_helpers<'tcx> for Encoder<'a> {
try!(this.emit_struct_field("method_num", 0, |this| {
this.emit_uint(o.method_num)
}));
try!(this.emit_struct_field("real_index", 0, |this| {
this.emit_uint(o.real_index)
try!(this.emit_struct_field("vtable_index", 0, |this| {
this.emit_uint(o.vtable_index)
}));
Ok(())
})
@ -1492,8 +1492,8 @@ impl<'a, 'tcx> rbml_decoder_decoder_helpers<'tcx> for reader::Decoder<'a> {
this.read_uint()
}).unwrap()
},
real_index: {
this.read_struct_field("real_index", 3, |this| {
vtable_index: {
this.read_struct_field("vtable_index", 3, |this| {
this.read_uint()
}).unwrap()
},

View file

@ -214,7 +214,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
self.closure_typer.param_env()
}
pub fn closure_typer(&self) -> &'cx (ty::UnboxedClosureTyper<'tcx>+'cx) {
pub fn closure_typer(&self) -> &'cx (ty::ClosureTyper<'tcx>+'cx) {
self.closure_typer
}

View file

@ -329,58 +329,67 @@ pub fn upcast<'tcx>(tcx: &ty::ctxt<'tcx>,
pub fn get_vtable_index_of_object_method<'tcx>(tcx: &ty::ctxt<'tcx>,
object_trait_ref: ty::PolyTraitRef<'tcx>,
trait_def_id: ast::DefId,
method_index_in_trait: uint) -> uint {
method_offset_in_trait: uint) -> uint {
// We need to figure the "real index" of the method in a
// listing of all the methods of an object. We do this by
// iterating down the supertraits of the object's trait until
// we find the trait the method came from, counting up the
// methods from them.
let mut method_count = 0;
ty::each_bound_trait_and_supertraits(tcx, &[object_trait_ref], |bound_ref| {
for bound_ref in transitive_bounds(tcx, &[object_trait_ref]) {
if bound_ref.def_id() == trait_def_id {
false
} else {
let trait_items = ty::trait_items(tcx, bound_ref.def_id());
for trait_item in trait_items.iter() {
match *trait_item {
ty::MethodTraitItem(_) => method_count += 1,
ty::TypeTraitItem(_) => {}
}
}
true
break;
}
let trait_items = ty::trait_items(tcx, bound_ref.def_id());
for trait_item in trait_items.iter() {
match *trait_item {
ty::MethodTraitItem(_) => method_count += 1,
ty::TypeTraitItem(_) => {}
}
}
}
// count number of methods preceding the one we are selecting and
// add them to the total offset; skip over associated types.
let trait_items = ty::trait_items(tcx, trait_def_id);
for trait_item in trait_items.iter().take(method_offset_in_trait) {
match *trait_item {
ty::MethodTraitItem(_) => method_count += 1,
ty::TypeTraitItem(_) => {}
}
}
// the item at the offset we were given really ought to be a method
assert!(match trait_items[method_offset_in_trait] {
ty::MethodTraitItem(_) => true,
ty::TypeTraitItem(_) => false
});
method_count + method_index_in_trait
method_count
}
pub fn unboxed_closure_trait_ref_and_return_type<'tcx>(
closure_typer: &ty::UnboxedClosureTyper<'tcx>,
pub enum TupleArgumentsFlag { Yes, No }
pub fn closure_trait_ref_and_return_type<'tcx>(
tcx: &ty::ctxt<'tcx>,
fn_trait_def_id: ast::DefId,
self_ty: Ty<'tcx>,
closure_def_id: ast::DefId,
substs: &Substs<'tcx>)
sig: &ty::PolyFnSig<'tcx>,
tuple_arguments: TupleArgumentsFlag)
-> ty::Binder<(Rc<ty::TraitRef<'tcx>>, Ty<'tcx>)>
{
let tcx = closure_typer.param_env().tcx;
let closure_type = closure_typer.unboxed_closure_type(closure_def_id, substs);
debug!("unboxed_closure_trait_ref: closure_def_id={} closure_type={}",
closure_def_id.repr(tcx),
closure_type.repr(tcx));
let closure_sig = &closure_type.sig;
let arguments_tuple = closure_sig.0.inputs[0];
let trait_substs =
Substs::new_trait(
vec![arguments_tuple],
vec![],
self_ty);
let arguments_tuple = match tuple_arguments {
TupleArgumentsFlag::No => sig.0.inputs[0],
TupleArgumentsFlag::Yes => ty::mk_tup(tcx, sig.0.inputs.to_vec()),
};
let trait_substs = Substs::new_trait(vec![arguments_tuple], vec![], self_ty);
let trait_ref = Rc::new(ty::TraitRef {
def_id: fn_trait_def_id,
substs: tcx.mk_substs(trait_substs),
});
ty::Binder((trait_ref, closure_sig.0.output.unwrap()))
ty::Binder((trait_ref, sig.0.output.unwrap()))
}
impl<'tcx,O:Repr<'tcx>> Repr<'tcx> for super::Obligation<'tcx, O> {

View file

@ -452,7 +452,10 @@ pub struct MethodParam<'tcx> {
// never contains bound regions; those regions should have been
// instantiated with fresh variables at this point.
pub trait_ref: Rc<ty::TraitRef<'tcx>>,
// index of uint in the list of methods for the trait
// index of uint in the list of trait items. Note that this is NOT
// the index into the vtable, because the list of trait items
// includes associated types.
pub method_num: uint,
/// The impl for the trait from which the method comes. This
@ -471,14 +474,14 @@ pub struct MethodObject<'tcx> {
// the actual base trait id of the object
pub object_trait_id: ast::DefId,
// index of the method to be invoked amongst the trait's methods
// index of the method to be invoked amongst the trait's items
pub method_num: uint,
// index into the actual runtime vtable.
// the vtable is formed by concatenating together the method lists of
// the base object trait and all supertraits; this is the index into
// the base object trait and all supertraits; this is the index into
// that vtable
pub real_index: uint,
pub vtable_index: uint,
}
#[derive(Clone)]

View file

@ -319,7 +319,7 @@ impl<'tcx> TypeFoldable<'tcx> for ty::MethodOrigin<'tcx> {
trait_ref: object.trait_ref.fold_with(folder),
object_trait_id: object.object_trait_id,
method_num: object.method_num,
real_index: object.real_index
vtable_index: object.vtable_index,
})
}
}

View file

@ -1061,7 +1061,7 @@ impl<'tcx> Repr<'tcx> for ty::MethodObject<'tcx> {
format!("MethodObject({},{},{})",
self.trait_ref.repr(tcx),
self.method_num,
self.real_index)
self.vtable_index)
}
}