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:
parent
07cdb85331
commit
006f3eacae
10 changed files with 81 additions and 75 deletions
|
|
@ -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()
|
||||
},
|
||||
|
|
|
|||
|
|
@ -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
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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> {
|
||||
|
|
|
|||
|
|
@ -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)]
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue