Move the `upcast` routine into traits and use it for method selection; also

move get_method_index into traits and give it a better name (`get_vtable_index_of_object_method`).
This commit is contained in:
Niko Matsakis 2014-12-20 09:15:52 -05:00
parent 50ed6c1906
commit 2c1d7a7caa
4 changed files with 66 additions and 39 deletions

View File

@ -34,10 +34,12 @@ pub use self::select::SelectionCache;
pub use self::select::{MethodMatchResult, MethodMatched, MethodAmbiguous, MethodDidNotMatch};
pub use self::select::{MethodMatchedData}; // intentionally don't export variants
pub use self::util::elaborate_predicates;
pub use self::util::get_vtable_index_of_object_method;
pub use self::util::trait_ref_for_builtin_bound;
pub use self::util::supertraits;
pub use self::util::Supertraits;
pub use self::util::transitive_bounds;
pub use self::util::upcast;
mod coherence;
mod error_reporting;

View File

@ -291,6 +291,58 @@ pub fn predicate_for_builtin_bound<'tcx>(
})
}
/// Cast a trait reference into a reference to one of its super
/// traits; returns `None` if `target_trait_def_id` is not a
/// supertrait.
pub fn upcast<'tcx>(tcx: &ty::ctxt<'tcx>,
source_trait_ref: ty::PolyTraitRef<'tcx>,
target_trait_def_id: ast::DefId)
-> Option<ty::PolyTraitRef<'tcx>>
{
if source_trait_ref.def_id() == target_trait_def_id {
return Some(source_trait_ref); // shorcut the most common case
}
for super_trait_ref in supertraits(tcx, source_trait_ref) {
if super_trait_ref.def_id() == target_trait_def_id {
return Some(super_trait_ref);
}
}
None
}
/// Given an object of type `object_trait_ref`, returns the index of
/// the method `n_method` found in the trait `trait_def_id` (which
/// should be a supertrait of `object_trait_ref`) within the vtable
/// for `object_trait_ref`.
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 {
// 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| {
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
}
});
method_count + method_index_in_trait
}
impl<'tcx,O:Repr<'tcx>> Repr<'tcx> for super::Obligation<'tcx, O> {
fn repr(&self, tcx: &ty::ctxt<'tcx>) -> String {
format!("Obligation(predicate={},depth={})",

View File

@ -633,17 +633,16 @@ impl<'a,'tcx> ConfirmContext<'a,'tcx> {
target_trait_def_id: ast::DefId)
-> ty::PolyTraitRef<'tcx>
{
for super_trait_ref in traits::supertraits(self.tcx(), source_trait_ref.clone()) {
if super_trait_ref.def_id() == target_trait_def_id {
return super_trait_ref;
match traits::upcast(self.tcx(), source_trait_ref.clone(), target_trait_def_id) {
Some(super_trait_ref) => super_trait_ref,
None => {
self.tcx().sess.span_bug(
self.span,
format!("cannot upcast `{}` to `{}`",
source_trait_ref.repr(self.tcx()),
target_trait_def_id.repr(self.tcx()))[]);
}
}
self.tcx().sess.span_bug(
self.span,
format!("cannot upcast `{}` to `{}`",
source_trait_ref.repr(self.tcx()),
target_trait_def_id.repr(self.tcx()))[]);
}
fn replace_late_bound_regions_with_fresh_var<T>(&self, value: &ty::Binder<T>) -> T

View File

@ -308,7 +308,10 @@ impl<'a,'tcx> ProbeContext<'a,'tcx> {
let trait_ref = data.principal_trait_ref_with_self_ty(self.tcx(), self_ty);
self.elaborate_bounds(&[trait_ref.clone()], false, |this, new_trait_ref, m, method_num| {
let vtable_index =
get_method_index(tcx, &new_trait_ref, trait_ref.clone(), method_num);
traits::get_vtable_index_of_object_method(tcx,
trait_ref.clone(),
new_trait_ref.def_id(),
method_num);
let xform_self_ty = this.xform_self_ty(&m, new_trait_ref.substs());
@ -996,35 +999,6 @@ fn trait_method<'tcx>(tcx: &ty::ctxt<'tcx>,
.and_then(|(idx, item)| item.as_opt_method().map(|m| (idx, m)))
}
// Determine the index of a method in the list of all methods belonging
// to a trait and its supertraits.
fn get_method_index<'tcx>(tcx: &ty::ctxt<'tcx>,
trait_ref: &ty::PolyTraitRef<'tcx>,
subtrait: ty::PolyTraitRef<'tcx>,
n_method: 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 = n_method;
ty::each_bound_trait_and_supertraits(tcx, &[subtrait], |bound_ref| {
if bound_ref.def_id() == trait_ref.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
}
});
method_count
}
impl<'tcx> Candidate<'tcx> {
fn to_unadjusted_pick(&self) -> Pick<'tcx> {
Pick {