about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--src/librustc/middle/traits/mod.rs2
-rw-r--r--src/librustc/middle/traits/util.rs52
-rw-r--r--src/librustc_typeck/check/method/confirm.rs17
-rw-r--r--src/librustc_typeck/check/method/probe.rs34
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<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={})",
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<T>(&self, value: &ty::Binder<T>) -> 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 {