From 2c1d7a7caa279ae3dc284940eebf08cbac75df1e Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Sat, 20 Dec 2014 09:15:52 -0500 Subject: [PATCH] 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`). --- src/librustc/middle/traits/mod.rs | 2 + src/librustc/middle/traits/util.rs | 52 +++++++++++++++++++++ src/librustc_typeck/check/method/confirm.rs | 17 ++++--- src/librustc_typeck/check/method/probe.rs | 34 ++------------ 4 files changed, 66 insertions(+), 39 deletions(-) diff --git a/src/librustc/middle/traits/mod.rs b/src/librustc/middle/traits/mod.rs index b10dfa5b718..2f19a4ebb6a 100644 --- a/src/librustc/middle/traits/mod.rs +++ b/src/librustc/middle/traits/mod.rs @@ -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; diff --git a/src/librustc/middle/traits/util.rs b/src/librustc/middle/traits/util.rs index 109810fc7ee..541fa4dbbf7 100644 --- a/src/librustc/middle/traits/util.rs +++ b/src/librustc/middle/traits/util.rs @@ -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> +{ + 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={})", diff --git a/src/librustc_typeck/check/method/confirm.rs b/src/librustc_typeck/check/method/confirm.rs index a751b65a0f8..ee859bbe8f5 100644 --- a/src/librustc_typeck/check/method/confirm.rs +++ b/src/librustc_typeck/check/method/confirm.rs @@ -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(&self, value: &ty::Binder) -> T diff --git a/src/librustc_typeck/check/method/probe.rs b/src/librustc_typeck/check/method/probe.rs index f00e3e2d452..257d11cc84a 100644 --- a/src/librustc_typeck/check/method/probe.rs +++ b/src/librustc_typeck/check/method/probe.rs @@ -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 {