about summary refs log tree commit diff
diff options
context:
space:
mode:
authorBranimir <branimir@volomp.com>2013-09-25 23:55:38 +0200
committerBranimir <branimir@volomp.com>2013-09-26 11:14:18 +0200
commit56d415aa60b41e171890cb76a323cb95d617b077 (patch)
tree37e9897a8b88371b809fe1a3d226c0e83656c8c0
parentaf25f58ac3da45899ed65b3af965150c8a90dcda (diff)
downloadrust-56d415aa60b41e171890cb76a323cb95d617b077.tar.gz
rust-56d415aa60b41e171890cb76a323cb95d617b077.zip
fix for issue #9394
    This solves problem of incorrect indexing into vtable
    when method from super trait was called through pointer
    to derived trait.
    Problem was that offset of super trait vtables
    was not calculated at all.
    Now it works, correct offset is calculated by
    traversing all super traits up to super trait
    where method belongs. That is how it is
    intended to work.
-rw-r--r--src/librustc/middle/typeck/check/method.rs11
-rw-r--r--src/test/run-pass/issue-9394-inherited-trait-calls.rs61
2 files changed, 66 insertions, 6 deletions
diff --git a/src/librustc/middle/typeck/check/method.rs b/src/librustc/middle/typeck/check/method.rs
index 48d630b4aa9..60712769de5 100644
--- a/src/librustc/middle/typeck/check/method.rs
+++ b/src/librustc/middle/typeck/check/method.rs
@@ -372,7 +372,7 @@ impl<'self> LookupContext<'self> {
     // to a trait and its supertraits.
     fn get_method_index(&self,
                         trait_ref: @TraitRef,
-                        subtrait_id: ast::DefId,
+                        subtrait: @TraitRef,
                         n_method: uint) -> uint {
         let tcx = self.tcx();
 
@@ -382,15 +382,14 @@ impl<'self> LookupContext<'self> {
         // we find the trait the method came from, counting up the
         // methods from them.
         let mut method_count = 0;
-        do ty::each_bound_trait_and_supertraits(tcx, &[trait_ref])
+        do ty::each_bound_trait_and_supertraits(tcx, &[subtrait])
             |bound_ref| {
-            if bound_ref.def_id == subtrait_id { false }
+            if bound_ref.def_id == trait_ref.def_id { false }
                 else {
                 method_count += ty::trait_methods(tcx, bound_ref.def_id).len();
                 true
             }
         };
-
         return method_count + n_method;
     }
 
@@ -418,9 +417,9 @@ impl<'self> LookupContext<'self> {
         let trait_ref = @TraitRef { def_id: did, substs: rcvr_substs.clone() };
 
         do self.push_inherent_candidates_from_bounds_inner(&[trait_ref])
-            |trait_ref, m, method_num, _bound_num| {
+            |new_trait_ref, m, method_num, _bound_num| {
             let vtable_index =
-                self.get_method_index(trait_ref, trait_ref.def_id, method_num);
+                self.get_method_index(new_trait_ref, trait_ref, method_num);
             // We need to fix up the transformed self type.
             let transformed_self_ty =
                 self.construct_transformed_self_ty_for_object(
diff --git a/src/test/run-pass/issue-9394-inherited-trait-calls.rs b/src/test/run-pass/issue-9394-inherited-trait-calls.rs
new file mode 100644
index 00000000000..e60f8d4c888
--- /dev/null
+++ b/src/test/run-pass/issue-9394-inherited-trait-calls.rs
@@ -0,0 +1,61 @@
+// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+trait Base: Base2 + Base3{
+    fn foo(&self) -> ~str;
+}
+
+trait Base2: Base3{
+    fn baz(&self) -> ~str;
+}
+
+trait Base3{
+    fn root(&self) -> ~str;
+}
+
+trait Super: Base{
+    fn bar(&self) -> ~str;
+}
+
+struct X;
+
+impl Base for X {
+    fn foo(&self) -> ~str{
+        ~"base foo"
+    }
+
+}
+
+impl Base2 for X {
+    fn baz(&self) -> ~str{
+        ~"base2 baz"
+    }
+}
+
+impl Base3 for X {
+    fn root(&self) -> ~str{
+        ~"base3 root"
+    }
+}
+
+impl Super for X {
+    fn bar(&self) -> ~str{
+        ~"super bar"
+    }
+}
+
+pub fn main() {
+    let n = X;
+    let s = &n as &Super;
+    assert_eq!(s.bar(),~"super bar");
+    assert_eq!(s.foo(),~"base foo");
+    assert_eq!(s.baz(),~"base2 baz");
+    assert_eq!(s.root(),~"base3 root");
+}