about summary refs log tree commit diff
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2013-07-25 03:07:44 -0700
committerbors <bors@rust-lang.org>2013-07-25 03:07:44 -0700
commit906264b50fa6b69eed567388063233bd279242b1 (patch)
treecfe2808a6e0bbb5aec20ade1ee0af8174f8fc34d
parentb30a16c9aefbc568f67c8121f170b6d478102c5f (diff)
parentf37c7cd30651e6514c6ac03a081940e28a53292c (diff)
downloadrust-906264b50fa6b69eed567388063233bd279242b1.tar.gz
rust-906264b50fa6b69eed567388063233bd279242b1.zip
auto merge of #8015 : msullivan/rust/default-methods, r=nikomatsakis
Lots of changes to vtable resolution, handling of super/self method calls in default methods. Fix a lot of trait inheritance bugs.

r? @nikomatsakis 
-rw-r--r--src/libextra/num/bigint.rs5
-rw-r--r--src/libextra/num/rational.rs19
-rw-r--r--src/librustc/metadata/common.rs1
-rw-r--r--src/librustc/metadata/csearch.rs9
-rw-r--r--src/librustc/metadata/decoder.rs18
-rw-r--r--src/librustc/metadata/encoder.rs13
-rw-r--r--src/librustc/middle/astencode.rs113
-rw-r--r--src/librustc/middle/privacy.rs7
-rw-r--r--src/librustc/middle/trans/callee.rs60
-rw-r--r--src/librustc/middle/trans/common.rs52
-rw-r--r--src/librustc/middle/trans/meth.rs64
-rw-r--r--src/librustc/middle/trans/monomorphize.rs9
-rw-r--r--src/librustc/middle/trans/type_use.rs5
-rw-r--r--src/librustc/middle/ty.rs48
-rw-r--r--src/librustc/middle/typeck/check/method.rs201
-rw-r--r--src/librustc/middle/typeck/check/vtable.rs586
-rw-r--r--src/librustc/middle/typeck/check/writeback.rs5
-rw-r--r--src/librustc/middle/typeck/infer/mod.rs5
-rw-r--r--src/librustc/middle/typeck/mod.rs51
-rw-r--r--src/librustc/util/ppaux.rs7
-rw-r--r--src/libstd/cmp.rs6
-rw-r--r--src/libstd/iterator.rs19
-rw-r--r--src/test/auxiliary/issue_3979_traits.rs7
-rw-r--r--src/test/run-pass/default-method-supertrait-vtable.rs36
-rw-r--r--src/test/run-pass/issue-3979-2.rs2
-rw-r--r--src/test/run-pass/issue-3979-generics.rs12
-rw-r--r--src/test/run-pass/issue-3979-xcrate.rs2
-rw-r--r--src/test/run-pass/issue-3979.rs2
-rw-r--r--src/test/run-pass/supertrait-default-generics.rs42
29 files changed, 776 insertions, 630 deletions
diff --git a/src/libextra/num/bigint.rs b/src/libextra/num/bigint.rs
index d940b6d6667..46a74457274 100644
--- a/src/libextra/num/bigint.rs
+++ b/src/libextra/num/bigint.rs
@@ -732,6 +732,11 @@ impl Ord for Sign {
     }
 }
 
+impl TotalEq for Sign {
+    fn equals(&self, other: &Sign) -> bool {
+        *self == *other
+    }
+}
 impl TotalOrd for Sign {
 
     fn cmp(&self, other: &Sign) -> Ordering {
diff --git a/src/libextra/num/rational.rs b/src/libextra/num/rational.rs
index 6733599d1ea..ff14009e556 100644
--- a/src/libextra/num/rational.rs
+++ b/src/libextra/num/rational.rs
@@ -110,6 +110,25 @@ cmp_impl!(impl TotalEq, equals)
 cmp_impl!(impl Ord, lt, gt, le, ge)
 cmp_impl!(impl TotalOrd, cmp -> cmp::Ordering)
 
+impl<T: Clone + Integer + Ord> Orderable for Ratio<T> {
+    #[inline]
+    fn min(&self, other: &Ratio<T>) -> Ratio<T> {
+        if *self < *other { self.clone() } else { other.clone() }
+    }
+
+    #[inline]
+    fn max(&self, other: &Ratio<T>) -> Ratio<T> {
+        if *self > *other { self.clone() } else { other.clone() }
+    }
+
+    #[inline]
+    fn clamp(&self, mn: &Ratio<T>, mx: &Ratio<T>) -> Ratio<T> {
+        if *self > *mx { mx.clone()} else
+        if *self < *mn { mn.clone() } else { self.clone() }
+    }
+}
+
+
 /* Arithmetic */
 // a/b * c/d = (a*c)/(b*d)
 impl<T: Clone + Integer + Ord>
diff --git a/src/librustc/metadata/common.rs b/src/librustc/metadata/common.rs
index 645188ce5a4..1c5d202d4d9 100644
--- a/src/librustc/metadata/common.rs
+++ b/src/librustc/metadata/common.rs
@@ -180,6 +180,7 @@ pub static tag_misc_info: uint = 0x7f;
 pub static tag_misc_info_crate_items: uint = 0x80;
 
 pub static tag_item_method_provided_source: uint = 0x81;
+pub static tag_item_impl_vtables: uint = 0x82;
 
 pub struct LinkMeta {
     name: @str,
diff --git a/src/librustc/metadata/csearch.rs b/src/librustc/metadata/csearch.rs
index 97344ee91ad..6f7feae4479 100644
--- a/src/librustc/metadata/csearch.rs
+++ b/src/librustc/metadata/csearch.rs
@@ -16,6 +16,7 @@ use metadata::cstore;
 use metadata::decoder;
 use metadata;
 use middle::ty;
+use middle::typeck;
 
 use std::vec;
 use reader = extra::ebml::reader;
@@ -216,6 +217,14 @@ pub fn get_impl_trait(tcx: ty::ctxt,
     decoder::get_impl_trait(cdata, def.node, tcx)
 }
 
+// Given a def_id for an impl, return information about its vtables
+pub fn get_impl_vtables(tcx: ty::ctxt,
+                        def: ast::def_id) -> typeck::impl_res {
+    let cstore = tcx.cstore;
+    let cdata = cstore::get_crate_data(cstore, def.crate);
+    decoder::get_impl_vtables(cdata, def.node, tcx)
+}
+
 pub fn get_impl_method(cstore: @mut cstore::CStore,
                        def: ast::def_id,
                        mname: ast::ident)
diff --git a/src/librustc/metadata/decoder.rs b/src/librustc/metadata/decoder.rs
index 480661b263a..01c5019154f 100644
--- a/src/librustc/metadata/decoder.rs
+++ b/src/librustc/metadata/decoder.rs
@@ -21,6 +21,9 @@ use metadata::tydecode::{parse_ty_data, parse_def_id,
                          parse_type_param_def_data,
                          parse_bare_fn_ty_data, parse_trait_ref_data};
 use middle::ty;
+use middle::typeck;
+use middle::astencode::vtable_decoder_helpers;
+
 
 use std::hash::HashUtil;
 use std::uint;
@@ -410,6 +413,21 @@ pub fn get_impl_trait(cdata: cmd,
     }
 }
 
+pub fn get_impl_vtables(cdata: cmd,
+                        id: ast::node_id,
+                        tcx: ty::ctxt) -> typeck::impl_res
+{
+    let item_doc = lookup_item(id, cdata.data);
+    let vtables_doc = reader::get_doc(item_doc, tag_item_impl_vtables);
+    let mut decoder = reader::Decoder(vtables_doc);
+
+    typeck::impl_res {
+        trait_vtables: decoder.read_vtable_res(tcx, cdata),
+        self_vtables: decoder.read_vtable_param_res(tcx, cdata)
+    }
+}
+
+
 pub fn get_impl_method(intr: @ident_interner, cdata: cmd, id: ast::node_id,
                        name: ast::ident) -> Option<ast::def_id> {
     let items = reader::get_doc(reader::Doc(cdata.data), tag_items);
diff --git a/src/librustc/metadata/encoder.rs b/src/librustc/metadata/encoder.rs
index 8d1f086b3a7..c216e8d2386 100644
--- a/src/librustc/metadata/encoder.rs
+++ b/src/librustc/metadata/encoder.rs
@@ -17,6 +17,8 @@ use metadata::decoder;
 use metadata::tyencode;
 use middle::ty::{node_id_to_type, lookup_item_type};
 use middle::ty;
+use middle::typeck;
+use middle::astencode;
 use middle;
 
 use std::hash::HashUtil;
@@ -161,6 +163,15 @@ fn encode_trait_ref(ebml_w: &mut writer::Encoder,
     ebml_w.end_tag();
 }
 
+fn encode_impl_vtables(ebml_w: &mut writer::Encoder,
+                       ecx: &EncodeContext,
+                       vtables: &typeck::impl_res) {
+    ebml_w.start_tag(tag_item_impl_vtables);
+    astencode::encode_vtable_res(ecx, ebml_w, vtables.trait_vtables);
+    astencode::encode_vtable_param_res(ecx, ebml_w, vtables.self_vtables);
+    ebml_w.end_tag();
+}
+
 // Item info table encoding
 fn encode_family(ebml_w: &mut writer::Encoder, c: char) {
     ebml_w.start_tag(tag_items_data_item_family);
@@ -1008,6 +1019,8 @@ fn encode_info_for_item(ecx: &EncodeContext,
             let trait_ref = ty::node_id_to_trait_ref(
                 tcx, ast_trait_ref.ref_id);
             encode_trait_ref(ebml_w, ecx, trait_ref, tag_item_trait_ref);
+            let impl_vtables = ty::lookup_impl_vtables(tcx, def_id);
+            encode_impl_vtables(ebml_w, ecx, &impl_vtables);
         }
         encode_path(ecx, ebml_w, path, ast_map::path_name(item.ident));
         ebml_w.end_tag();
diff --git a/src/librustc/middle/astencode.rs b/src/librustc/middle/astencode.rs
index f3e0779475c..bf39be407c5 100644
--- a/src/librustc/middle/astencode.rs
+++ b/src/librustc/middle/astencode.rs
@@ -250,6 +250,8 @@ impl<S:serialize::Encoder> def_id_encoder_helpers for S {
 
 trait def_id_decoder_helpers {
     fn read_def_id(&mut self, xcx: @ExtendedDecodeContext) -> ast::def_id;
+    fn read_def_id_noxcx(&mut self,
+                         cdata: @cstore::crate_metadata) -> ast::def_id;
 }
 
 impl<D:serialize::Decoder> def_id_decoder_helpers for D {
@@ -257,6 +259,12 @@ impl<D:serialize::Decoder> def_id_decoder_helpers for D {
         let did: ast::def_id = Decodable::decode(self);
         did.tr(xcx)
     }
+
+    fn read_def_id_noxcx(&mut self,
+                         cdata: @cstore::crate_metadata) -> ast::def_id {
+        let did: ast::def_id = Decodable::decode(self);
+        decoder::translate_def_id(cdata, did)
+    }
 }
 
 // ______________________________________________________________________
@@ -582,12 +590,6 @@ impl tr for method_origin {
           typeck::method_trait(did, m, vstore) => {
               typeck::method_trait(did.tr(xcx), m, vstore)
           }
-          typeck::method_self(did, m) => {
-              typeck::method_self(did.tr(xcx), m)
-          }
-          typeck::method_super(trait_did, m) => {
-              typeck::method_super(trait_did.tr(xcx), m)
-          }
         }
     }
 }
@@ -595,7 +597,7 @@ impl tr for method_origin {
 // ______________________________________________________________________
 // Encoding and decoding vtable_res
 
-fn encode_vtable_res(ecx: &e::EncodeContext,
+pub fn encode_vtable_res(ecx: &e::EncodeContext,
                      ebml_w: &mut writer::Encoder,
                      dr: typeck::vtable_res) {
     // can't autogenerate this code because automatic code of
@@ -603,13 +605,20 @@ fn encode_vtable_res(ecx: &e::EncodeContext,
     // hand-written encoding routines combine with auto-generated
     // ones.  perhaps we should fix this.
     do ebml_w.emit_from_vec(*dr) |ebml_w, param_tables| {
-        do ebml_w.emit_from_vec(**param_tables) |ebml_w, vtable_origin| {
-            encode_vtable_origin(ecx, ebml_w, vtable_origin)
-        }
+        encode_vtable_param_res(ecx, ebml_w, *param_tables);
     }
 }
 
-fn encode_vtable_origin(ecx: &e::EncodeContext,
+pub fn encode_vtable_param_res(ecx: &e::EncodeContext,
+                     ebml_w: &mut writer::Encoder,
+                     param_tables: typeck::vtable_param_res) {
+    do ebml_w.emit_from_vec(*param_tables) |ebml_w, vtable_origin| {
+        encode_vtable_origin(ecx, ebml_w, vtable_origin)
+    }
+}
+
+
+pub fn encode_vtable_origin(ecx: &e::EncodeContext,
                         ebml_w: &mut writer::Encoder,
                         vtable_origin: &typeck::vtable_origin) {
     do ebml_w.emit_enum("vtable_origin") |ebml_w| {
@@ -630,40 +639,46 @@ fn encode_vtable_origin(ecx: &e::EncodeContext,
           typeck::vtable_param(pn, bn) => {
             do ebml_w.emit_enum_variant("vtable_param", 1u, 2u) |ebml_w| {
                 do ebml_w.emit_enum_variant_arg(0u) |ebml_w| {
-                    ebml_w.emit_uint(pn);
+                    pn.encode(ebml_w);
                 }
                 do ebml_w.emit_enum_variant_arg(1u) |ebml_w| {
                     ebml_w.emit_uint(bn);
                 }
             }
           }
-          typeck::vtable_self(def_id) => {
-            do ebml_w.emit_enum_variant("vtable_self", 2u, 1u) |ebml_w| {
-                do ebml_w.emit_enum_variant_arg(0u) |ebml_w| {
-                    ebml_w.emit_def_id(def_id)
-                }
-            }
-          }
         }
     }
 }
 
-trait vtable_decoder_helpers {
-    fn read_vtable_res(&mut self, xcx: @ExtendedDecodeContext)
+pub trait vtable_decoder_helpers {
+    fn read_vtable_res(&mut self,
+                       tcx: ty::ctxt, cdata: @cstore::crate_metadata)
                       -> typeck::vtable_res;
-    fn read_vtable_origin(&mut self, xcx: @ExtendedDecodeContext)
+    fn read_vtable_param_res(&mut self,
+                       tcx: ty::ctxt, cdata: @cstore::crate_metadata)
+                      -> typeck::vtable_param_res;
+    fn read_vtable_origin(&mut self,
+                          tcx: ty::ctxt, cdata: @cstore::crate_metadata)
                           -> typeck::vtable_origin;
 }
 
 impl vtable_decoder_helpers for reader::Decoder {
-    fn read_vtable_res(&mut self, xcx: @ExtendedDecodeContext)
+    fn read_vtable_res(&mut self,
+                       tcx: ty::ctxt, cdata: @cstore::crate_metadata)
                       -> typeck::vtable_res {
         @self.read_to_vec(|this|
-           @this.read_to_vec(|this|
-               this.read_vtable_origin(xcx)))
+                          this.read_vtable_param_res(tcx, cdata))
     }
 
-    fn read_vtable_origin(&mut self, xcx: @ExtendedDecodeContext)
+    fn read_vtable_param_res(&mut self,
+                             tcx: ty::ctxt, cdata: @cstore::crate_metadata)
+                      -> typeck::vtable_param_res {
+        @self.read_to_vec(|this|
+                          this.read_vtable_origin(tcx, cdata))
+    }
+
+    fn read_vtable_origin(&mut self,
+                          tcx: ty::ctxt, cdata: @cstore::crate_metadata)
         -> typeck::vtable_origin {
         do self.read_enum("vtable_origin") |this| {
             do this.read_enum_variant(["vtable_static",
@@ -674,33 +689,26 @@ impl vtable_decoder_helpers for reader::Decoder {
                   0 => {
                     typeck::vtable_static(
                         do this.read_enum_variant_arg(0u) |this| {
-                            this.read_def_id(xcx)
+                            this.read_def_id_noxcx(cdata)
                         },
                         do this.read_enum_variant_arg(1u) |this| {
-                            this.read_tys(xcx)
+                            this.read_tys_noxcx(tcx, cdata)
                         },
                         do this.read_enum_variant_arg(2u) |this| {
-                            this.read_vtable_res(xcx)
+                            this.read_vtable_res(tcx, cdata)
                         }
                     )
                   }
                   1 => {
                     typeck::vtable_param(
                         do this.read_enum_variant_arg(0u) |this| {
-                            this.read_uint()
+                            Decodable::decode(this)
                         },
                         do this.read_enum_variant_arg(1u) |this| {
                             this.read_uint()
                         }
                     )
                   }
-                  2 => {
-                    typeck::vtable_self(
-                        do this.read_enum_variant_arg(0u) |this| {
-                            this.read_def_id(xcx)
-                        }
-                    )
-                  }
                   // hard to avoid - user input
                   _ => fail!("bad enum variant")
                 }
@@ -995,9 +1003,35 @@ trait ebml_decoder_decoder_helpers {
                       source: DefIdSource,
                       did: ast::def_id)
                       -> ast::def_id;
+
+    // Versions of the type reading functions that don't need the full
+    // ExtendedDecodeContext.
+    fn read_ty_noxcx(&mut self,
+                     tcx: ty::ctxt, cdata: @cstore::crate_metadata) -> ty::t;
+    fn read_tys_noxcx(&mut self,
+                      tcx: ty::ctxt,
+                      cdata: @cstore::crate_metadata) -> ~[ty::t];
 }
 
 impl ebml_decoder_decoder_helpers for reader::Decoder {
+    fn read_ty_noxcx(&mut self,
+                     tcx: ty::ctxt, cdata: @cstore::crate_metadata) -> ty::t {
+        do self.read_opaque |_, doc| {
+            tydecode::parse_ty_data(
+                *doc.data,
+                cdata.cnum,
+                doc.start,
+                tcx,
+                |_, id| decoder::translate_def_id(cdata, id))
+        }
+    }
+
+    fn read_tys_noxcx(&mut self,
+                      tcx: ty::ctxt,
+                      cdata: @cstore::crate_metadata) -> ~[ty::t] {
+        self.read_to_vec(|this| this.read_ty_noxcx(tcx, cdata) )
+    }
+
     fn read_ty(&mut self, xcx: @ExtendedDecodeContext) -> ty::t {
         // Note: regions types embed local node ids.  In principle, we
         // should translate these node ids into the new decode
@@ -1160,8 +1194,9 @@ fn decode_side_tables(xcx: @ExtendedDecodeContext,
                             val_dsr.read_method_map_entry(xcx));
                     }
                     c::tag_table_vtable_map => {
-                        dcx.maps.vtable_map.insert(id,
-                                                   val_dsr.read_vtable_res(xcx));
+                        dcx.maps.vtable_map.insert(
+                            id,
+                            val_dsr.read_vtable_res(xcx.dcx.tcx, xcx.dcx.cdata));
                     }
                     c::tag_table_adjustments => {
                         let adj: @ty::AutoAdjustment = @Decodable::decode(val_dsr);
diff --git a/src/librustc/middle/privacy.rs b/src/librustc/middle/privacy.rs
index 1ea32b3f404..e768a6d687c 100644
--- a/src/librustc/middle/privacy.rs
+++ b/src/librustc/middle/privacy.rs
@@ -15,8 +15,7 @@
 use metadata::csearch;
 use middle::ty::{ty_struct, ty_enum};
 use middle::ty;
-use middle::typeck::{method_map, method_origin, method_param, method_self};
-use middle::typeck::{method_super};
+use middle::typeck::{method_map, method_origin, method_param};
 use middle::typeck::{method_static, method_trait};
 
 use std::util::ignore;
@@ -291,9 +290,7 @@ pub fn check_crate<'mm>(tcx: ty::ctxt,
                  method_num: method_num,
                  _
             }) |
-            method_trait(trait_id, method_num, _) |
-            method_self(trait_id, method_num) |
-            method_super(trait_id, method_num) => {
+            method_trait(trait_id, method_num, _) => {
                 if trait_id.crate == local_crate {
                     match tcx.items.find(&trait_id.node) {
                         Some(&node_item(item, _)) => {
diff --git a/src/librustc/middle/trans/callee.rs b/src/librustc/middle/trans/callee.rs
index d64615e5dc7..057e2ae531c 100644
--- a/src/librustc/middle/trans/callee.rs
+++ b/src/librustc/middle/trans/callee.rs
@@ -193,30 +193,15 @@ pub fn trans_fn_ref_with_vtables_to_callee(
                                                type_params, vtables))}
 }
 
-fn get_impl_resolutions(bcx: @mut Block,
-                        impl_id: ast::def_id)
-                         -> typeck::vtable_res {
-    if impl_id.crate == ast::local_crate {
-        bcx.ccx().maps.vtable_map.get_copy(&impl_id.node)
-    } else {
-        // XXX: This is a temporary hack to work around not properly
-        // exporting information about resolutions for impls.
-        // This doesn't actually work if the trait has param bounds,
-        // but it does allow us to survive the case when it does not.
-        let trait_ref = ty::impl_trait_ref(bcx.tcx(), impl_id).get();
-        @vec::from_elem(trait_ref.substs.tps.len(), @~[])
-    }
-}
-
 fn resolve_default_method_vtables(bcx: @mut Block,
                                   impl_id: ast::def_id,
                                   method: &ty::Method,
                                   substs: &ty::substs,
                                   impl_vtables: Option<typeck::vtable_res>)
-                                 -> typeck::vtable_res {
+                          -> (typeck::vtable_res, typeck::vtable_param_res) {
 
     // Get the vtables that the impl implements the trait at
-    let trait_vtables = get_impl_resolutions(bcx, impl_id);
+    let impl_res = ty::lookup_impl_vtables(bcx.tcx(), impl_id);
 
     // Build up a param_substs that we are going to resolve the
     // trait_vtables under.
@@ -224,11 +209,11 @@ fn resolve_default_method_vtables(bcx: @mut Block,
         tys: substs.tps.clone(),
         self_ty: substs.self_ty,
         vtables: impl_vtables,
-        self_vtable: None
+        self_vtables: None
     });
 
     let trait_vtables_fixed = resolve_vtables_under_param_substs(
-        bcx.tcx(), param_substs, trait_vtables);
+        bcx.tcx(), param_substs, impl_res.trait_vtables);
 
     // Now we pull any vtables for parameters on the actual method.
     let num_method_vtables = method.generics.type_param_defs.len();
@@ -241,7 +226,12 @@ fn resolve_default_method_vtables(bcx: @mut Block,
         None => vec::from_elem(num_method_vtables, @~[])
     };
 
-    @(*trait_vtables_fixed + method_vtables)
+    let param_vtables = @(*trait_vtables_fixed + method_vtables);
+
+    let self_vtables = resolve_param_vtables_under_param_substs(
+        bcx.tcx(), param_substs, impl_res.self_vtables);
+
+    (param_vtables, self_vtables)
 }
 
 
@@ -296,7 +286,7 @@ pub fn trans_fn_ref_with_vtables(
     // We need to do a bunch of special handling for default methods.
     // We need to modify the def_id and our substs in order to monomorphize
     // the function.
-    let (is_default, def_id, substs, self_vtable, vtables) =
+    let (is_default, def_id, substs, self_vtables, vtables) =
         match ty::provided_source(tcx, def_id) {
         None => (false, def_id, substs, None, vtables),
         Some(source_id) => {
@@ -319,20 +309,6 @@ pub fn trans_fn_ref_with_vtables(
                 .expect("could not find trait_ref for impl with \
                          default methods");
 
-            // Get all of the type params for the receiver
-            let param_defs = method.generics.type_param_defs;
-            let receiver_substs =
-                type_params.initn(param_defs.len()).to_owned();
-            let receiver_vtables = match vtables {
-                None => @~[],
-                Some(call_vtables) => {
-                    @call_vtables.initn(param_defs.len()).to_owned()
-                }
-            };
-
-            let self_vtable =
-                typeck::vtable_static(impl_id, receiver_substs,
-                                      receiver_vtables);
             // Compute the first substitution
             let first_subst = make_substs_for_receiver_types(
                 tcx, impl_id, trait_ref, method);
@@ -341,20 +317,22 @@ pub fn trans_fn_ref_with_vtables(
             let new_substs = first_subst.subst(tcx, &substs);
 
 
-            let vtables =
+            let (param_vtables, self_vtables) =
                 resolve_default_method_vtables(bcx, impl_id,
-                                               method, &new_substs, vtables);
+                                               method, &substs, vtables);
 
             debug!("trans_fn_with_vtables - default method: \
                     substs = %s, trait_subst = %s, \
                     first_subst = %s, new_subst = %s, \
-                    self_vtable = %s, vtables = %s",
+                    vtables = %s, \
+                    self_vtable = %s, param_vtables = %s",
                    substs.repr(tcx), trait_ref.substs.repr(tcx),
                    first_subst.repr(tcx), new_substs.repr(tcx),
-                   self_vtable.repr(tcx), vtables.repr(tcx));
+                   vtables.repr(tcx),
+                   self_vtables.repr(tcx), param_vtables.repr(tcx));
 
             (true, source_id,
-             new_substs, Some(self_vtable), Some(vtables))
+             new_substs, Some(self_vtables), Some(param_vtables))
         }
     };
 
@@ -400,7 +378,7 @@ pub fn trans_fn_ref_with_vtables(
 
         let (val, must_cast) =
             monomorphize::monomorphic_fn(ccx, def_id, &substs,
-                                         vtables, self_vtable,
+                                         vtables, self_vtables,
                                          Some(ref_id));
         let mut val = val;
         if must_cast && ref_id != 0 {
diff --git a/src/librustc/middle/trans/common.rs b/src/librustc/middle/trans/common.rs
index 713939a5d83..702ef71a573 100644
--- a/src/librustc/middle/trans/common.rs
+++ b/src/librustc/middle/trans/common.rs
@@ -133,7 +133,7 @@ pub struct param_substs {
     tys: ~[ty::t],
     self_ty: Option<ty::t>,
     vtables: Option<typeck::vtable_res>,
-    self_vtable: Option<typeck::vtable_origin>
+    self_vtables: Option<typeck::vtable_param_res>
 }
 
 impl param_substs {
@@ -1020,14 +1020,25 @@ pub fn resolve_vtables_under_param_substs(tcx: ty::ctxt,
                                           vts: typeck::vtable_res)
     -> typeck::vtable_res {
     @vts.iter().transform(|ds|
-      @ds.iter().transform(
-          |d| resolve_vtable_under_param_substs(tcx,
-                                                param_substs,
-                                                d))
-                          .collect::<~[typeck::vtable_origin]>())
-        .collect::<~[typeck::vtable_param_res]>()
+      resolve_param_vtables_under_param_substs(tcx,
+                                               param_substs,
+                                               *ds))
+        .collect()
 }
 
+pub fn resolve_param_vtables_under_param_substs(
+    tcx: ty::ctxt,
+    param_substs: Option<@param_substs>,
+    ds: typeck::vtable_param_res)
+    -> typeck::vtable_param_res {
+    @ds.iter().transform(
+        |d| resolve_vtable_under_param_substs(tcx,
+                                              param_substs,
+                                              d))
+        .collect()
+}
+
+
 
 // Apply the typaram substitutions in the FunctionContext to a vtable. This should
 // eliminate any vtable_params.
@@ -1068,31 +1079,26 @@ pub fn resolve_vtable_under_param_substs(tcx: ty::ctxt,
                 }
             }
         }
-        typeck::vtable_self(_trait_id) => {
-            match param_substs {
-                Some(@param_substs
-                     {self_vtable: Some(ref self_vtable), _}) => {
-                    (*self_vtable).clone()
-                }
-                _ => {
-                    tcx.sess.bug(fmt!(
-                        "resolve_vtable_in_fn_ctxt: asked to lookup but \
-                         no self_vtable in the fn_ctxt!"))
-                }
-            }
-        }
     }
 }
 
 pub fn find_vtable(tcx: ty::ctxt,
                    ps: &param_substs,
-                   n_param: uint,
+                   n_param: typeck::param_index,
                    n_bound: uint)
                    -> typeck::vtable_origin {
-    debug!("find_vtable(n_param=%u, n_bound=%u, ps=%s)",
+    debug!("find_vtable(n_param=%?, n_bound=%u, ps=%s)",
            n_param, n_bound, ps.repr(tcx));
 
-    ps.vtables.get()[n_param][n_bound].clone()
+    let param_bounds = match n_param {
+        typeck::param_self => ps.self_vtables.expect("self vtables missing"),
+        typeck::param_numbered(n) => {
+            let tables = ps.vtables
+                .expect("vtables missing where they are needed");
+            tables[n]
+        }
+    };
+    param_bounds[n_bound].clone()
 }
 
 pub fn dummy_substs(tps: ~[ty::t]) -> ty::substs {
diff --git a/src/librustc/middle/trans/meth.rs b/src/librustc/middle/trans/meth.rs
index a65999ff2aa..9228f20513b 100644
--- a/src/librustc/middle/trans/meth.rs
+++ b/src/librustc/middle/trans/meth.rs
@@ -147,46 +147,13 @@ pub fn trans_method_callee(bcx: @mut Block,
                            mentry: typeck::method_map_entry)
                            -> Callee {
     let _icx = push_ctxt("impl::trans_method_callee");
-    let tcx = bcx.tcx();
 
     debug!("trans_method_callee(callee_id=%?, this=%s, mentry=%s)",
            callee_id,
            bcx.expr_to_str(this),
            mentry.repr(bcx.tcx()));
 
-    // Replace method_self with method_static here.
-    let mut origin = mentry.origin;
-    match origin {
-        typeck::method_super(trait_id, method_index) => {
-            // <self_ty> is the self type for this method call
-            let self_ty = node_id_type(bcx, this.id);
-            // <impl_id> is the ID of the implementation of
-            // trait <trait_id> for type <self_ty>
-            let impl_id = ty::bogus_get_impl_id_from_ty(tcx, trait_id, self_ty);
-            // Get the supertrait's methods
-            let supertrait_method_def_ids = ty::trait_method_def_ids(tcx, trait_id);
-            // Make sure to fail with a readable error message if
-            // there's some internal error here
-            if !(method_index < supertrait_method_def_ids.len()) {
-                tcx.sess.bug("trans_method_callee: supertrait method \
-                              index is out of bounds");
-            }
-            // Get the method name using the method index in the origin
-            let method_name =
-                ty::method(tcx, supertrait_method_def_ids[method_index]).ident;
-            // Now that we know the impl ID, we can look up the method
-            // ID from its name
-            origin = typeck::method_static(
-                method_with_name(bcx.ccx(), impl_id, method_name));
-        }
-        typeck::method_self(*) |
-        typeck::method_static(*) | typeck::method_param(*) |
-        typeck::method_trait(*) => {}
-    }
-
-    debug!("origin=%?", origin);
-
-    match origin {
+    match mentry.origin {
         typeck::method_static(did) => {
             let callee_fn = callee::trans_fn_ref(bcx, did, callee_id);
             let mut temp_cleanups = ~[];
@@ -210,7 +177,8 @@ pub fn trans_method_callee(bcx: @mut Block,
         }) => {
             match bcx.fcx.param_substs {
                 Some(substs) => {
-                    let vtbl = find_vtable(bcx.tcx(), substs, p, b);
+                    let vtbl = find_vtable(bcx.tcx(), substs,
+                                           p, b);
                     trans_monomorphized_callee(bcx, callee_id, this, mentry,
                                                trait_id, off, vtbl)
                 }
@@ -219,24 +187,6 @@ pub fn trans_method_callee(bcx: @mut Block,
             }
         }
 
-        typeck::method_self(trait_id, method_index) => {
-            match bcx.fcx.param_substs {
-                Some(@param_substs
-                     {self_vtable: Some(ref vtbl), _}) => {
-                    trans_monomorphized_callee(bcx,
-                                               callee_id,
-                                               this,
-                                               mentry,
-                                               trait_id,
-                                               method_index,
-                                               (*vtbl).clone())
-                }
-                _ => {
-                    fail!("trans_method_callee: missing self_vtable")
-                }
-            }
-        }
-
         typeck::method_trait(_, off, store) => {
             trans_trait_callee(bcx,
                                callee_id,
@@ -245,9 +195,6 @@ pub fn trans_method_callee(bcx: @mut Block,
                                store,
                                mentry.explicit_self)
         }
-        typeck::method_super(*) => {
-            fail!("method_super should have been handled above")
-        }
     }
 }
 
@@ -402,9 +349,6 @@ pub fn trans_monomorphized_callee(bcx: @mut Block,
       typeck::vtable_param(*) => {
           fail!("vtable_param left in monomorphized function's vtable substs");
       }
-      typeck::vtable_self(*) => {
-          fail!("vtable_self left in monomorphized function's vtable substs");
-      }
     };
 
 }
@@ -611,7 +555,7 @@ pub fn vtable_id(ccx: @mut CrateContext,
                 tys: (*substs).clone(),
                 vtables: Some(sub_vtables),
                 self_ty: None,
-                self_vtable: None
+                self_vtables: None
             };
 
             monomorphize::make_mono_id(
diff --git a/src/librustc/middle/trans/monomorphize.rs b/src/librustc/middle/trans/monomorphize.rs
index 789532abc61..9852e6b09b7 100644
--- a/src/librustc/middle/trans/monomorphize.rs
+++ b/src/librustc/middle/trans/monomorphize.rs
@@ -41,7 +41,7 @@ pub fn monomorphic_fn(ccx: @mut CrateContext,
                       fn_id: ast::def_id,
                       real_substs: &ty::substs,
                       vtables: Option<typeck::vtable_res>,
-                      self_vtable: Option<typeck::vtable_origin>,
+                      self_vtables: Option<typeck::vtable_param_res>,
                       ref_id: Option<ast::node_id>)
     -> (ValueRef, bool)
 {
@@ -54,7 +54,7 @@ pub fn monomorphic_fn(ccx: @mut CrateContext,
            fn_id.repr(ccx.tcx),
            real_substs.repr(ccx.tcx),
            vtables.repr(ccx.tcx),
-           self_vtable.repr(ccx.tcx),
+           self_vtables.repr(ccx.tcx),
            ref_id);
 
     assert!(real_substs.tps.iter().all(|t| !ty::type_needs_infer(*t)));
@@ -72,7 +72,7 @@ pub fn monomorphic_fn(ccx: @mut CrateContext,
         tys: real_substs.tps.map(|x| do_normalize(x)),
         vtables: vtables,
         self_ty: real_substs.self_ty.map(|x| do_normalize(x)),
-        self_vtable: self_vtable
+        self_vtables: self_vtables
     };
 
     for real_substs.tps.iter().advance |s| { assert!(!ty::type_has_params(*s)); }
@@ -371,8 +371,7 @@ pub fn make_mono_id(ccx: @mut CrateContext,
       Some(vts) => {
         debug!("make_mono_id vtables=%s substs=%s",
                vts.repr(ccx.tcx), substs.tys.repr(ccx.tcx));
-        let self_vtables = substs.self_vtable.map(|vtbl| @~[(*vtbl).clone()]);
-        let vts_iter = self_vtables.iter().chain_(vts.iter());
+        let vts_iter = substs.self_vtables.iter().chain_(vts.iter());
         vts_iter.zip(substs_iter).transform(|(vtable, subst)| {
             let v = vtable.map(|vt| meth::vtable_id(ccx, vt));
             (*subst, if !v.is_empty() { Some(@v) } else { None })
diff --git a/src/librustc/middle/trans/type_use.rs b/src/librustc/middle/trans/type_use.rs
index 4d5d597d382..aa19af01893 100644
--- a/src/librustc/middle/trans/type_use.rs
+++ b/src/librustc/middle/trans/type_use.rs
@@ -274,13 +274,12 @@ pub fn mark_for_method_call(cx: &Context, e_id: node_id, callee_id: node_id) {
                   opt_static_did = Some(did);
               }
               typeck::method_param(typeck::method_param {
-                  param_num: param,
+                  param_num: typeck::param_numbered(param),
                   _
               }) => {
                 cx.uses[param] |= use_tydesc;
               }
-              typeck::method_trait(*) | typeck::method_self(*)
-                  | typeck::method_super(*) => (),
+              _ => (),
             }
         }
     }
diff --git a/src/librustc/middle/ty.rs b/src/librustc/middle/ty.rs
index 20c39cc84ef..e2a926875e8 100644
--- a/src/librustc/middle/ty.rs
+++ b/src/librustc/middle/ty.rs
@@ -317,6 +317,9 @@ struct ctxt_ {
     // some point. Local variable definitions not in this set can be warned
     // about.
     used_mut_nodes: @mut HashSet<ast::node_id>,
+
+    // vtable resolution information for impl declarations
+    impl_vtables: typeck::impl_vtable_map
 }
 
 pub enum tbox_flag {
@@ -911,6 +914,7 @@ pub fn mk_ctxt(s: session::Session,
         impls:  @mut HashMap::new(),
         used_unsafe: @mut HashSet::new(),
         used_mut_nodes: @mut HashSet::new(),
+        impl_vtables: @mut HashMap::new(),
      }
 }
 
@@ -3061,9 +3065,7 @@ pub fn method_call_type_param_defs(tcx: ctxt,
           typeck::method_param(typeck::method_param {
               trait_id: trt_id,
               method_num: n_mth, _}) |
-          typeck::method_trait(trt_id, n_mth, _) |
-          typeck::method_self(trt_id, n_mth) |
-          typeck::method_super(trt_id, n_mth) => {
+          typeck::method_trait(trt_id, n_mth, _) => {
             // ...trait methods bounds, in contrast, include only the
             // method bounds, so we must preprend the tps from the
             // trait itself.  This ought to be harmonized.
@@ -3956,6 +3958,14 @@ pub fn lookup_item_type(cx: ctxt,
         || csearch::get_type(cx, did))
 }
 
+pub fn lookup_impl_vtables(cx: ctxt,
+                           did: ast::def_id)
+                     -> typeck::impl_res {
+    lookup_locally_or_in_crate_store(
+        "impl_vtables", did, cx.impl_vtables,
+        || csearch::get_impl_vtables(cx, did) )
+}
+
 /// Given the did of a trait, returns its canonical trait ref.
 pub fn lookup_trait_def(cx: ctxt, did: ast::def_id) -> @ty::TraitDef {
     match cx.trait_defs.find(&did) {
@@ -4339,9 +4349,9 @@ pub fn determine_inherited_purity(parent: (ast::purity, ast::node_id),
 // relation on the supertraits from each bounded trait's constraint
 // list.
 pub fn each_bound_trait_and_supertraits(tcx: ctxt,
-                                        bounds: &ParamBounds,
+                                        bounds: &[@TraitRef],
                                         f: &fn(@TraitRef) -> bool) -> bool {
-    for bounds.trait_bounds.iter().advance |&bound_trait_ref| {
+    for bounds.iter().advance |&bound_trait_ref| {
         let mut supertrait_set = HashMap::new();
         let mut trait_refs = ~[];
         let mut i = 0;
@@ -4383,38 +4393,14 @@ pub fn count_traits_and_supertraits(tcx: ctxt,
                                     type_param_defs: &[TypeParameterDef]) -> uint {
     let mut total = 0;
     for type_param_defs.iter().advance |type_param_def| {
-        for each_bound_trait_and_supertraits(tcx, type_param_def.bounds) |_| {
+        for each_bound_trait_and_supertraits(
+            tcx, type_param_def.bounds.trait_bounds) |_| {
             total += 1;
         }
     }
     return total;
 }
 
-// Given a trait and a type, returns the impl of that type.
-// This is broken, of course, by parametric impls. This used to use
-// a table specifically for this mapping, but I removed that table.
-// This is only used when calling a supertrait method from a default method,
-// and should go away once I fix how that works. -sully
-pub fn bogus_get_impl_id_from_ty(tcx: ctxt,
-                                 trait_id: def_id, self_ty: t) -> def_id {
-    match tcx.trait_impls.find(&trait_id) {
-        Some(ty_to_impl) => {
-            for ty_to_impl.iter().advance |imp| {
-                let impl_ty = tcx.tcache.get_copy(&imp.did);
-                if impl_ty.ty == self_ty { return imp.did; }
-            }
-            // try autoderef!
-            match deref(tcx, self_ty, false) {
-                Some(some_ty) =>
-                  bogus_get_impl_id_from_ty(tcx, trait_id, some_ty.ty),
-                None => tcx.sess.bug("get_impl_id: no impl of trait for \
-                                      this type")
-            }
-        },
-        None => tcx.sess.bug("get_impl_id: trait isn't in trait_impls")
-    }
-}
-
 pub fn get_tydesc_ty(tcx: ctxt) -> Result<t, ~str> {
     do tcx.lang_items.require(TyDescStructLangItem).map |tydesc_lang_item| {
         tcx.intrinsic_defs.find_copy(tydesc_lang_item)
diff --git a/src/librustc/middle/typeck/check/method.rs b/src/librustc/middle/typeck/check/method.rs
index 8d546366846..fd2ef337261 100644
--- a/src/librustc/middle/typeck/check/method.rs
+++ b/src/librustc/middle/typeck/check/method.rs
@@ -90,7 +90,8 @@ use middle::typeck::check::vtable;
 use middle::typeck::check;
 use middle::typeck::infer;
 use middle::typeck::{method_map_entry, method_origin, method_param};
-use middle::typeck::{method_self, method_static, method_trait, method_super};
+use middle::typeck::{method_static, method_trait};
+use middle::typeck::{param_numbered, param_self, param_index};
 use middle::typeck::check::regionmanip::replace_bound_regions_in_fn_sig;
 use util::common::indenter;
 
@@ -328,64 +329,6 @@ impl<'self> LookupContext<'self> {
         }
     }
 
-    pub fn push_inherent_candidates_from_param(&self,
-                                               rcvr_ty: ty::t,
-                                               param_ty: param_ty) {
-        debug!("push_inherent_candidates_from_param(param_ty=%?)",
-               param_ty);
-        let _indenter = indenter();
-
-        let tcx = self.tcx();
-        let mut next_bound_idx = 0; // count only trait bounds
-        let type_param_def = match tcx.ty_param_defs.find(&param_ty.def_id.node) {
-            Some(t) => t,
-            None => {
-                tcx.sess.span_bug(
-                    self.expr.span,
-                    fmt!("No param def for %?", param_ty));
-            }
-        };
-
-        for ty::each_bound_trait_and_supertraits(tcx, type_param_def.bounds)
-            |bound_trait_ref|
-        {
-            let this_bound_idx = next_bound_idx;
-            next_bound_idx += 1;
-
-            let trait_methods = ty::trait_methods(tcx, bound_trait_ref.def_id);
-            let pos = {
-                match trait_methods.iter().position(|m| {
-                    m.explicit_self != ast::sty_static &&
-                        m.ident == self.m_name })
-                {
-                    Some(pos) => pos,
-                    None => {
-                        debug!("trait doesn't contain method: %?",
-                               bound_trait_ref.def_id);
-                        loop; // check next trait or bound
-                    }
-                }
-            };
-            let method = trait_methods[pos];
-
-            let cand = Candidate {
-                rcvr_ty: rcvr_ty,
-                rcvr_substs: bound_trait_ref.substs.clone(),
-                method_ty: method,
-                origin: method_param(
-                    method_param {
-                        trait_id: bound_trait_ref.def_id,
-                        method_num: pos,
-                        param_num: param_ty.idx,
-                        bound_num: this_bound_idx,
-                    })
-            };
-
-            debug!("pushing inherent candidate for param: %?", cand);
-            self.inherent_candidates.push(cand);
-        }
-    }
-
     pub fn push_inherent_candidates_from_trait(&self,
                                                self_ty: ty::t,
                                                did: def_id,
@@ -438,69 +381,87 @@ impl<'self> LookupContext<'self> {
         });
     }
 
+    pub fn push_inherent_candidates_from_param(&self,
+                                               rcvr_ty: ty::t,
+                                               param_ty: param_ty) {
+        debug!("push_inherent_candidates_from_param(param_ty=%?)",
+               param_ty);
+        let _indenter = indenter();
+
+        let tcx = self.tcx();
+        let type_param_def = match tcx.ty_param_defs.find(&param_ty.def_id.node) {
+            Some(t) => t,
+            None => {
+                tcx.sess.span_bug(
+                    self.expr.span,
+                    fmt!("No param def for %?", param_ty));
+            }
+        };
+
+        self.push_inherent_candidates_from_bounds(
+            rcvr_ty, type_param_def.bounds.trait_bounds,
+            param_numbered(param_ty.idx));
+    }
+
+
     pub fn push_inherent_candidates_from_self(&self,
                                               self_ty: ty::t,
                                               did: def_id) {
-        struct MethodInfo {
-            method_ty: @ty::Method,
-            trait_def_id: ast::def_id,
-            index: uint,
-            trait_ref: @ty::TraitRef
-        }
+        let tcx = self.tcx();
+
+        let trait_ref = ty::lookup_trait_def(tcx, did).trait_ref;
+        self.push_inherent_candidates_from_bounds(
+            self_ty, &[trait_ref], param_self);
+    }
 
+    pub fn push_inherent_candidates_from_bounds(&self,
+                                                self_ty: ty::t,
+                                                bounds: &[@TraitRef],
+                                                param: param_index) {
         let tcx = self.tcx();
-        // First, try self methods
-        let mut method_info: Option<MethodInfo> = None;
-        let methods = ty::trait_methods(tcx, did);
-        match methods.iter().position(|m| m.ident == self.m_name) {
-            Some(i) => {
-                method_info = Some(MethodInfo {
-                    method_ty: methods[i],
-                    index: i,
-                    trait_def_id: did,
-                    trait_ref: ty::lookup_trait_def(tcx, did).trait_ref
-                });
-            }
-            None => ()
-        }
-        // No method found yet? Check each supertrait
-        if method_info.is_none() {
-            for ty::trait_supertraits(tcx, did).iter().advance |trait_ref| {
-                let supertrait_methods =
-                    ty::trait_methods(tcx, trait_ref.def_id);
-                match supertrait_methods.iter().position(|m| m.ident == self.m_name) {
-                    Some(i) => {
-                        method_info = Some(MethodInfo {
-                            method_ty: supertrait_methods[i],
-                            index: i,
-                            trait_def_id: trait_ref.def_id,
-                            trait_ref: *trait_ref
-                        });
-                        break;
+        let mut next_bound_idx = 0; // count only trait bounds
+
+        for ty::each_bound_trait_and_supertraits(tcx, bounds)
+            |bound_trait_ref|
+        {
+            let this_bound_idx = next_bound_idx;
+            next_bound_idx += 1;
+
+            let trait_methods = ty::trait_methods(tcx, bound_trait_ref.def_id);
+            let pos = {
+                match trait_methods.iter().position(|m| {
+                    m.explicit_self != ast::sty_static &&
+                        m.ident == self.m_name })
+                {
+                    Some(pos) => pos,
+                    None => {
+                        debug!("trait doesn't contain method: %?",
+                               bound_trait_ref.def_id);
+                        loop; // check next trait or bound
                     }
-                    None => ()
                 }
-            }
-        }
-        match method_info {
-            Some(ref info) => {
-                // We've found a method -- return it
-                let origin = if did == info.trait_def_id {
-                    method_self(info.trait_def_id, info.index)
-                } else {
-                    method_super(info.trait_def_id, info.index)
-                };
-                self.inherent_candidates.push(Candidate {
-                    rcvr_ty: self_ty,
-                    rcvr_substs: info.trait_ref.substs.clone(),
-                    method_ty: info.method_ty,
-                    origin: origin
-                });
-            }
-            _ => return
+            };
+            let method = trait_methods[pos];
+
+            let cand = Candidate {
+                rcvr_ty: self_ty,
+                rcvr_substs: bound_trait_ref.substs.clone(),
+                method_ty: method,
+                origin: method_param(
+                    method_param {
+                        trait_id: bound_trait_ref.def_id,
+                        method_num: pos,
+                        param_num: param,
+                        bound_num: this_bound_idx,
+                    })
+            };
+
+            debug!("pushing inherent candidate for param: %?", cand);
+            self.inherent_candidates.push(cand);
         }
     }
 
+
     pub fn push_inherent_impl_candidates_for_type(&self, did: def_id) {
         let opt_impl_infos = self.tcx().inherent_impls.find(&did);
         for opt_impl_infos.iter().advance |impl_infos| {
@@ -1005,14 +966,13 @@ impl<'self> LookupContext<'self> {
         /*!
          *
          * There are some limitations to calling functions through a
-         * traint instance, because (a) the self type is not known
+         * trait instance, because (a) the self type is not known
          * (that's the whole point of a trait instance, after all, to
          * obscure the self type) and (b) the call must go through a
          * vtable and hence cannot be monomorphized. */
 
         match candidate.origin {
-            method_static(*) | method_param(*) |
-                method_self(*) | method_super(*) => {
+            method_static(*) | method_param(*) => {
                 return; // not a call to a trait instance
             }
             method_trait(*) => {}
@@ -1036,10 +996,11 @@ impl<'self> LookupContext<'self> {
         // No code can call the finalize method explicitly.
         let bad;
         match candidate.origin {
-            method_static(method_id) | method_self(method_id, _)
-                | method_super(method_id, _) => {
+            method_static(method_id) => {
                 bad = self.tcx().destructors.contains(&method_id);
             }
+            // XXX: does this properly enforce this on everything now
+            // that self has been merged in? -sully
             method_param(method_param { trait_id: trait_id, _ }) |
             method_trait(trait_id, _, _) => {
                 bad = self.tcx().destructor_for_type.contains_key(&trait_id);
@@ -1158,8 +1119,7 @@ impl<'self> LookupContext<'self> {
             method_param(ref mp) => {
                 type_of_trait_method(self.tcx(), mp.trait_id, mp.method_num)
             }
-            method_trait(did, idx, _) | method_self(did, idx) |
-                method_super(did, idx) => {
+            method_trait(did, idx, _) => {
                 type_of_trait_method(self.tcx(), did, idx)
             }
         };
@@ -1180,8 +1140,7 @@ impl<'self> LookupContext<'self> {
             method_param(ref mp) => {
                 self.report_param_candidate(idx, (*mp).trait_id)
             }
-            method_trait(trait_did, _, _) | method_self(trait_did, _)
-                | method_super(trait_did, _) => {
+            method_trait(trait_did, _, _) => {
                 self.report_trait_candidate(idx, trait_did)
             }
         }
diff --git a/src/librustc/middle/typeck/check/vtable.rs b/src/librustc/middle/typeck/check/vtable.rs
index da09f79d031..50f7f18b0a6 100644
--- a/src/librustc/middle/typeck/check/vtable.rs
+++ b/src/librustc/middle/typeck/check/vtable.rs
@@ -16,11 +16,11 @@ use middle::typeck::check::{structurally_resolved_type};
 use middle::typeck::infer::fixup_err_to_str;
 use middle::typeck::infer::{resolve_and_force_all_but_regions, resolve_type};
 use middle::typeck::infer;
-use middle::typeck::{CrateCtxt, vtable_origin, vtable_res};
-use middle::typeck::{vtable_static, vtable_param, vtable_self};
+use middle::typeck::{CrateCtxt, vtable_origin, vtable_res, vtable_param_res};
+use middle::typeck::{vtable_static, vtable_param, impl_res};
+use middle::typeck::{param_numbered, param_self, param_index};
 use middle::subst::Subst;
 use util::common::indenter;
-use util::ppaux::tys_to_str;
 use util::ppaux;
 
 use std::hashmap::HashSet;
@@ -46,6 +46,16 @@ use syntax::visit;
 // *fully* resolved. (We could be less restrictive than that, but it
 // would require much more care, and this seems to work decently in
 // practice.)
+//
+// While resolution on a single type requires the type to be fully
+// resolved, when resolving a substitution against a list of bounds,
+// we do not require all of the types to be resolved in advance.
+// Furthermore, we process substitutions in reverse order, which
+// allows resolution on later parameters to give information on
+// earlier params referenced by the typeclass bounds.
+// It may be better to do something more clever, like processing fully
+// resolved types first.
+
 
 /// Location info records the span and ID of the expression or item that is
 /// responsible for this vtable instantiation. (This may not be an expression
@@ -84,42 +94,19 @@ fn lookup_vtables(vcx: &VtableContext,
            substs.repr(vcx.tcx()));
     let _i = indenter();
 
-    let tcx = vcx.tcx();
-    let mut result = ~[];
-    let mut i = 0u;
-    for substs.tps.iter().advance |ty| {
-        // ty is the value supplied for the type parameter A...
-        let mut param_result = ~[];
-
-        for ty::each_bound_trait_and_supertraits(
-            tcx, type_param_defs[i].bounds) |trait_ref|
-        {
-            // ...and here trait_ref is each bound that was declared on A,
-            // expressed in terms of the type parameters.
-
-            debug!("about to subst: %s, %s", trait_ref.repr(tcx), substs.repr(tcx));
-
-            // Substitute the values of the type parameters that may
-            // appear in the bound.
-            let trait_ref = trait_ref.subst(tcx, substs);
-
-            debug!("after subst: %s", trait_ref.repr(tcx));
-
-            match lookup_vtable(vcx, location_info, *ty, trait_ref, is_early) {
-                Some(vtable) => param_result.push(vtable),
-                None => {
-                    vcx.tcx().sess.span_fatal(
-                        location_info.span,
-                        fmt!("failed to find an implementation of \
-                              trait %s for %s",
-                             vcx.infcx.trait_ref_to_str(trait_ref),
-                             vcx.infcx.ty_to_str(*ty)));
-                }
-            }
-        }
-        result.push(@param_result);
-        i += 1u;
-    }
+
+    // We do this backwards for reasons discussed above.
+    assert_eq!(substs.tps.len(), type_param_defs.len());
+    let mut result =
+        substs.tps.rev_iter()
+        .zip(type_param_defs.rev_iter())
+        .transform(|(ty, def)|
+                   lookup_vtables_for_param(vcx, location_info, Some(substs),
+                                            &*def.bounds, *ty, is_early))
+        .to_owned_vec();
+    result.reverse();
+
+    assert_eq!(substs.tps.len(), result.len());
     debug!("lookup_vtables result(\
             location_info=%?, \
             type_param_defs=%s, \
@@ -132,25 +119,58 @@ fn lookup_vtables(vcx: &VtableContext,
     @result
 }
 
-fn fixup_substs(vcx: &VtableContext,
-                location_info: &LocationInfo,
-                id: ast::def_id,
-                substs: ty::substs,
-                is_early: bool)
-                -> Option<ty::substs> {
+fn lookup_vtables_for_param(vcx: &VtableContext,
+                            location_info: &LocationInfo,
+                            // None for substs means the identity
+                            substs: Option<&ty::substs>,
+                            type_param_bounds: &ty::ParamBounds,
+                            ty: ty::t,
+                            is_early: bool) -> vtable_param_res {
     let tcx = vcx.tcx();
-    // use a dummy type just to package up the substs that need fixing up
-    let t = ty::mk_trait(tcx,
-                         id, substs,
-                         ty::RegionTraitStore(ty::re_static),
-                         ast::m_imm,
-                         ty::EmptyBuiltinBounds());
-    do fixup_ty(vcx, location_info, t, is_early).map |t_f| {
-        match ty::get(*t_f).sty {
-          ty::ty_trait(_, ref substs_f, _, _, _) => (*substs_f).clone(),
-          _ => fail!("t_f should be a trait")
+
+    // ty is the value supplied for the type parameter A...
+    let mut param_result = ~[];
+
+    for ty::each_bound_trait_and_supertraits(
+        tcx, type_param_bounds.trait_bounds) |trait_ref|
+    {
+        // ...and here trait_ref is each bound that was declared on A,
+        // expressed in terms of the type parameters.
+
+        // Substitute the values of the type parameters that may
+        // appear in the bound.
+        let trait_ref = substs.map_default(trait_ref, |substs| {
+            debug!("about to subst: %s, %s",
+                   trait_ref.repr(tcx), substs.repr(tcx));
+            trait_ref.subst(tcx, *substs)
+        });
+
+        debug!("after subst: %s", trait_ref.repr(tcx));
+
+        match lookup_vtable(vcx, location_info, ty, trait_ref, is_early) {
+            Some(vtable) => param_result.push(vtable),
+            None => {
+                vcx.tcx().sess.span_fatal(
+                    location_info.span,
+                    fmt!("failed to find an implementation of \
+                          trait %s for %s",
+                         vcx.infcx.trait_ref_to_str(trait_ref),
+                         vcx.infcx.ty_to_str(ty)));
+            }
         }
     }
+
+    debug!("lookup_vtables_for_param result(\
+            location_info=%?, \
+            type_param_bounds=%s, \
+            ty=%s, \
+            result=%s)",
+           location_info,
+           type_param_bounds.repr(vcx.tcx()),
+           ty.repr(vcx.tcx()),
+           param_result.repr(vcx.tcx()));
+
+    return @param_result;
 }
 
 fn relate_trait_refs(vcx: &VtableContext,
@@ -173,10 +193,15 @@ fn relate_trait_refs(vcx: &VtableContext,
     {
         result::Ok(()) => {} // Ok.
         result::Err(ref err) => {
+            // There is an error, but we need to do some work to make
+            // the message good.
+            // Resolve any type vars in the trait refs
             let r_act_trait_ref =
                 vcx.infcx.resolve_type_vars_in_trait_ref_if_possible(act_trait_ref);
             let r_exp_trait_ref =
                 vcx.infcx.resolve_type_vars_in_trait_ref_if_possible(exp_trait_ref);
+            // Only print the message if there aren't any previous type errors
+            // inside the types.
             if !ty::trait_ref_contains_error(&r_act_trait_ref) &&
                 !ty::trait_ref_contains_error(&r_exp_trait_ref)
             {
@@ -192,8 +217,7 @@ fn relate_trait_refs(vcx: &VtableContext,
     }
 }
 
-// Look up the vtable to use when treating an item of type `t` as if it has
-// type `trait_ty`
+// Look up the vtable implementing the trait `trait_ref` at type `t`
 fn lookup_vtable(vcx: &VtableContext,
                  location_info: &LocationInfo,
                  ty: ty::t,
@@ -216,220 +240,247 @@ fn lookup_vtable(vcx: &VtableContext,
             // The type has unconstrained type variables in it, so we can't
             // do early resolution on it. Return some completely bogus vtable
             // information: we aren't storing it anyways.
-            return Some(vtable_param(0, 0));
+            return Some(vtable_param(param_self, 0));
         }
     };
 
-    match ty::get(ty).sty {
+    // If the type is self or a param, we look at the trait/supertrait
+    // bounds to see if they include the trait we are looking for.
+    let vtable_opt = match ty::get(ty).sty {
         ty::ty_param(param_ty {idx: n, def_id: did}) => {
-            let mut n_bound = 0;
             let type_param_def = tcx.ty_param_defs.get(&did.node);
-            for ty::each_bound_trait_and_supertraits(
-                tcx, type_param_def.bounds) |bound_trait_ref|
-            {
-                debug!("checking bounds trait %s", bound_trait_ref.repr(vcx.tcx()));
-
-                if bound_trait_ref.def_id == trait_ref.def_id {
-                    relate_trait_refs(vcx,
-                                      location_info,
-                                      bound_trait_ref,
-                                      trait_ref);
-                    let vtable = vtable_param(n, n_bound);
-                    debug!("found param vtable: %?",
-                           vtable);
-                    return Some(vtable);
-                }
-
-                n_bound += 1;
-            }
+            lookup_vtable_from_bounds(vcx, location_info,
+                                      type_param_def.bounds.trait_bounds,
+                                      param_numbered(n),
+                                      trait_ref)
         }
 
         ty::ty_self(trait_id) => {
-            debug!("trying to find %? vtable for type %?",
-                   trait_ref.def_id, trait_id);
+            let self_trait_ref = ty::lookup_trait_def(tcx, trait_id).trait_ref;
+            lookup_vtable_from_bounds(vcx, location_info,
+                                      &[self_trait_ref],
+                                      param_self,
+                                      trait_ref)
+        }
 
-            if trait_id == trait_ref.def_id {
-                let vtable = vtable_self(trait_id);
-                debug!("found self vtable: %?", vtable);
-                return Some(vtable);
-            }
+        // Default case just falls through
+        _ => None
+    };
+
+    if vtable_opt.is_some() { return vtable_opt; }
+
+    // If we aren't a self type or param, or it was, but we didn't find it,
+    // do a search.
+    return search_for_vtable(vcx, location_info,
+                             ty, trait_ref, is_early)
+}
+
+// Given a list of bounds on a type, search those bounds to see if any
+// of them are the vtable we are looking for.
+fn lookup_vtable_from_bounds(vcx: &VtableContext,
+                             location_info: &LocationInfo,
+                             bounds: &[@ty::TraitRef],
+                             param: param_index,
+                             trait_ref: @ty::TraitRef)
+    -> Option<vtable_origin> {
+    let tcx = vcx.tcx();
+
+    let mut n_bound = 0;
+    for ty::each_bound_trait_and_supertraits(tcx, bounds) |bound_trait_ref| {
+        debug!("checking bounds trait %s",
+               bound_trait_ref.repr(vcx.tcx()));
+
+        if bound_trait_ref.def_id == trait_ref.def_id {
+            relate_trait_refs(vcx,
+                              location_info,
+                              bound_trait_ref,
+                              trait_ref);
+            let vtable = vtable_param(param, n_bound);
+            debug!("found param vtable: %?",
+                   vtable);
+            return Some(vtable);
         }
 
-        _ => {
-            let mut found = ~[];
+        n_bound += 1;
+    }
 
-            let mut impls_seen = HashSet::new();
+    return None;
+}
 
-            match tcx.trait_impls.find(&trait_ref.def_id) {
-                None => {
-                    // Nothing found. Continue.
-                }
-                Some(implementations) => {
-                    // implementations is the list of all impls in scope for
-                    // trait_ref. (Usually, there's just one.)
-                    for implementations.iter().advance |im| {
-                        // im is one specific impl of trait_ref.
-
-                        // First, ensure we haven't processed this impl yet.
-                        if impls_seen.contains(&im.did) {
-                            loop;
-                        }
-                        impls_seen.insert(im.did);
-
-                        // ty::impl_traits gives us the trait im implements,
-                        // if there is one (there's either zero or one).
-                        //
-                        // If foo implements a trait t, and if t is the
-                        // same trait as trait_ref, we need to
-                        // unify it with trait_ref in order to get all
-                        // the ty vars sorted out.
-                        let r = ty::impl_trait_ref(tcx, im.did);
-                        for r.iter().advance |&of_trait_ref| {
-                            if of_trait_ref.def_id != trait_ref.def_id { loop; }
-
-                            // At this point, we know that of_trait_ref is
-                            // the same trait as trait_ref, but
-                            // possibly applied to different substs.
-                            //
-                            // Next, we check whether the "for" ty in
-                            // the impl is compatible with the type
-                            // that we're casting to a trait. That is,
-                            // if im is:
-                            //
-                            // impl<T> self_ty<T>: some_trait<T> { ... }
-                            //
-                            // we check whether self_ty<T> is the type
-                            // of the thing that we're trying to cast
-                            // to some_trait.  If not, then we try the next
-                            // impl.
-                            //
-                            // FIXME(#5781) this should be mk_eqty not mk_subty
-                            let ty::ty_param_substs_and_ty {
-                                substs: substs,
-                                ty: for_ty
-                            } = impl_self_ty(vcx, location_info, im.did);
-                            match infer::mk_subty(vcx.infcx,
-                                                  false,
-                                                  infer::RelateSelfType(
-                                                      location_info.span),
-                                                  ty,
-                                                  for_ty) {
-                                result::Err(_) => loop,
-                                result::Ok(()) => ()
-                            }
-
-                            // Now, in the previous example, for_ty is
-                            // bound to the type self_ty, and substs
-                            // is bound to [T].
-                            debug!("The self ty is %s and its substs are %s",
-                                   vcx.infcx.ty_to_str(for_ty),
-                                   tys_to_str(vcx.tcx(), substs.tps));
-
-                            // Next, we unify trait_ref -- the type
-                            // that we want to cast to -- with of_trait_ref
-                            // -- the trait that im implements. At
-                            // this point, we require that they be
-                            // unifiable with each other -- that's
-                            // what relate_trait_refs does.
-                            //
-                            // For example, in the above example,
-                            // of_trait_ref would be some_trait<T>, so we
-                            // would be unifying trait_ref<U> (for some
-                            // value of U) with some_trait<T>. This
-                            // would fail if T and U weren't
-                            // compatible.
-
-                            debug!("(checking vtable) @2 relating trait \
-                                    ty %s to of_trait_ref %s",
-                                   vcx.infcx.trait_ref_to_str(trait_ref),
-                                   vcx.infcx.trait_ref_to_str(of_trait_ref));
-
-                            let of_trait_ref = of_trait_ref.subst(tcx, &substs);
-                            relate_trait_refs(
-                                vcx, location_info,
-                                of_trait_ref, trait_ref);
-
-                            // Recall that trait_ref -- the trait type
-                            // we're casting to -- is the trait with
-                            // id trait_ref.def_id applied to the substs
-                            // trait_ref.substs. Now we extract out the
-                            // types themselves from trait_ref.substs.
-
-                            // Recall that substs is the impl self
-                            // type's list of substitutions. That is,
-                            // if this is an impl of some trait for
-                            // foo<T, U>, then substs is [T,
-                            // U]. substs might contain type
-                            // variables, so we call fixup_substs to
-                            // resolve them.
-
-                            let substs_f = match fixup_substs(vcx,
-                                                              location_info,
-                                                              trait_ref.def_id,
-                                                              substs,
-                                                              is_early) {
-                                Some(ref substs) => (*substs).clone(),
-                                None => {
-                                    assert!(is_early);
-                                    // Bail out with a bogus answer
-                                    return Some(vtable_param(0, 0));
-                                }
-                            };
-
-                            debug!("The fixed-up substs are %s - \
-                                    they will be unified with the bounds for \
-                                    the target ty, %s",
-                                   tys_to_str(vcx.tcx(), substs_f.tps),
-                                   vcx.infcx.trait_ref_to_str(trait_ref));
-
-                            // Next, we unify the fixed-up
-                            // substitutions for the impl self ty with
-                            // the substitutions from the trait type
-                            // that we're trying to cast
-                            // to. connect_trait_tps requires these
-                            // lists of types to unify pairwise.
-
-                            let im_generics =
-                                ty::lookup_item_type(tcx, im.did).generics;
-                            connect_trait_tps(vcx,
-                                              location_info,
-                                              &substs_f,
-                                              trait_ref,
-                                              im.did);
-                            let subres = lookup_vtables(
-                                vcx, location_info,
-                                *im_generics.type_param_defs, &substs_f,
-                                is_early);
-
-                            // Finally, we register that we found a
-                            // matching impl, and record the def ID of
-                            // the impl as well as the resolved list
-                            // of type substitutions for the target
-                            // trait.
-                            found.push(vtable_static(im.did,
-                                                     substs_f.tps.clone(),
-                                                     subres));
-                        }
-                    }
-                }
+fn search_for_vtable(vcx: &VtableContext,
+                     location_info: &LocationInfo,
+                     ty: ty::t,
+                     trait_ref: @ty::TraitRef,
+                     is_early: bool)
+    -> Option<vtable_origin>
+{
+    let tcx = vcx.tcx();
+
+    let mut found = ~[];
+    let mut impls_seen = HashSet::new();
+
+    // XXX: this is a bad way to do this, since we do
+    // pointless allocations.
+    let impls = tcx.trait_impls.find(&trait_ref.def_id)
+        .map_default(@mut ~[], |x| **x);
+    // impls is the list of all impls in scope for trait_ref.
+    for impls.iter().advance |im| {
+        // im is one specific impl of trait_ref.
+
+        // First, ensure we haven't processed this impl yet.
+        if impls_seen.contains(&im.did) {
+            loop;
+        }
+        impls_seen.insert(im.did);
+
+        // ty::impl_traits gives us the trait im implements.
+        //
+        // If foo implements a trait t, and if t is the same trait as
+        // trait_ref, we need to unify it with trait_ref in order to
+        // get all the ty vars sorted out.
+        let r = ty::impl_trait_ref(tcx, im.did);
+        let of_trait_ref = r.expect("trait_ref missing on trait impl");
+        if of_trait_ref.def_id != trait_ref.def_id { loop; }
+
+        // At this point, we know that of_trait_ref is the same trait
+        // as trait_ref, but possibly applied to different substs.
+        //
+        // Next, we check whether the "for" ty in the impl is
+        // compatible with the type that we're casting to a
+        // trait. That is, if im is:
+        //
+        // impl<T> some_trait<T> for self_ty<T> { ... }
+        //
+        // we check whether self_ty<T> is the type of the thing that
+        // we're trying to cast to some_trait.  If not, then we try
+        // the next impl.
+        //
+        // XXX: document a bit more what this means
+        //
+        // FIXME(#5781) this should be mk_eqty not mk_subty
+        let ty::ty_param_substs_and_ty {
+            substs: substs,
+            ty: for_ty
+        } = impl_self_ty(vcx, location_info, im.did);
+        match infer::mk_subty(vcx.infcx,
+                              false,
+                              infer::RelateSelfType(
+                                  location_info.span),
+                              ty,
+                              for_ty) {
+            result::Err(_) => loop,
+            result::Ok(()) => ()
+        }
+
+        // Now, in the previous example, for_ty is bound to
+        // the type self_ty, and substs is bound to [T].
+        debug!("The self ty is %s and its substs are %s",
+               vcx.infcx.ty_to_str(for_ty),
+               vcx.infcx.tys_to_str(substs.tps));
+
+        // Next, we unify trait_ref -- the type that we want to cast
+        // to -- with of_trait_ref -- the trait that im implements. At
+        // this point, we require that they be unifiable with each
+        // other -- that's what relate_trait_refs does.
+        //
+        // For example, in the above example, of_trait_ref would be
+        // some_trait<T>, so we would be unifying trait_ref<U> (for
+        // some value of U) with some_trait<T>. This would fail if T
+        // and U weren't compatible.
+
+        debug!("(checking vtable) @2 relating trait \
+                ty %s to of_trait_ref %s",
+               vcx.infcx.trait_ref_to_str(trait_ref),
+               vcx.infcx.trait_ref_to_str(of_trait_ref));
+
+        let of_trait_ref = of_trait_ref.subst(tcx, &substs);
+        relate_trait_refs(vcx, location_info, of_trait_ref, trait_ref);
+
+
+        // Recall that trait_ref -- the trait type we're casting to --
+        // is the trait with id trait_ref.def_id applied to the substs
+        // trait_ref.substs.
+
+        // Resolve any sub bounds. Note that there still may be free
+        // type variables in substs. This might still be OK: the
+        // process of looking up bounds might constrain some of them.
+        let im_generics =
+            ty::lookup_item_type(tcx, im.did).generics;
+        let subres = lookup_vtables(vcx, location_info,
+                                    *im_generics.type_param_defs, &substs,
+                                    is_early);
+
+
+        // substs might contain type variables, so we call
+        // fixup_substs to resolve them.
+        let substs_f = match fixup_substs(vcx,
+                                          location_info,
+                                          trait_ref.def_id,
+                                          substs,
+                                          is_early) {
+            Some(ref substs) => (*substs).clone(),
+            None => {
+                assert!(is_early);
+                // Bail out with a bogus answer
+                return Some(vtable_param(param_self, 0));
             }
+        };
+
+        debug!("The fixed-up substs are %s - \
+                they will be unified with the bounds for \
+                the target ty, %s",
+               vcx.infcx.tys_to_str(substs_f.tps),
+               vcx.infcx.trait_ref_to_str(trait_ref));
+
+        // Next, we unify the fixed-up substitutions for the impl self
+        // ty with the substitutions from the trait type that we're
+        // trying to cast to. connect_trait_tps requires these lists
+        // of types to unify pairwise.
+        // I am a little confused about this, since it seems to be
+        // very similar to the relate_trait_refs we already do,
+        // but problems crop up if it is removed, so... -sully
+        connect_trait_tps(vcx, location_info, &substs_f, trait_ref, im.did);
+
+        // Finally, we register that we found a matching impl, and
+        // record the def ID of the impl as well as the resolved list
+        // of type substitutions for the target trait.
+        found.push(vtable_static(im.did, substs_f.tps.clone(), subres));
+    }
 
-            match found.len() {
-                0 => { /* fallthrough */ }
-                1 => return Some(found[0].clone()),
-                _ => {
-                    if !is_early {
-                        vcx.tcx().sess.span_err(
-                            location_info.span,
-                            "multiple applicable methods in scope");
-                    }
-                    return Some(found[0].clone());
-                }
+    match found.len() {
+        0 => { return None }
+        1 => return Some(found[0].clone()),
+        _ => {
+            if !is_early {
+                vcx.tcx().sess.span_err(
+                    location_info.span,
+                    "multiple applicable methods in scope");
             }
+            return Some(found[0].clone());
         }
     }
+}
 
-    return None;
+
+fn fixup_substs(vcx: &VtableContext,
+                location_info: &LocationInfo,
+                id: ast::def_id,
+                substs: ty::substs,
+                is_early: bool)
+                -> Option<ty::substs> {
+    let tcx = vcx.tcx();
+    // use a dummy type just to package up the substs that need fixing up
+    let t = ty::mk_trait(tcx,
+                         id, substs,
+                         ty::RegionTraitStore(ty::re_static),
+                         ast::m_imm,
+                         ty::EmptyBuiltinBounds());
+    do fixup_ty(vcx, location_info, t, is_early).map |t_f| {
+        match ty::get(*t_f).sty {
+          ty::ty_trait(_, ref substs_f, _, _, _) => (*substs_f).clone(),
+          _ => fail!("t_f should be a trait")
+        }
+    }
 }
 
 fn fixup_ty(vcx: &VtableContext,
@@ -682,16 +733,39 @@ pub fn resolve_impl(ccx: @mut CrateCtxt, impl_item: @ast::item) {
         Some(trait_ref) => {
             let infcx = infer::new_infer_ctxt(ccx.tcx);
             let vcx = VtableContext { ccx: ccx, infcx: infcx };
-            let trait_def = ty::lookup_trait_def(ccx.tcx, trait_ref.def_id);
+            let loc_info = location_info_for_item(impl_item);
 
+            // First, check that the impl implements any trait bounds
+            // on the trait.
+            let trait_def = ty::lookup_trait_def(ccx.tcx, trait_ref.def_id);
             let vtbls = lookup_vtables(&vcx,
-                                       &location_info_for_item(impl_item),
+                                       &loc_info,
                                        *trait_def.generics.type_param_defs,
                                        &trait_ref.substs,
                                        false);
 
-            // FIXME(#7450): Doesn't work cross crate
-            ccx.vtable_map.insert(impl_item.id, vtbls);
+            // Now, locate the vtable for the impl itself. The real
+            // purpose of this is to check for supertrait impls,
+            // but that falls out of doing this.
+            let param_bounds = ty::ParamBounds {
+                builtin_bounds: ty::EmptyBuiltinBounds(),
+                trait_bounds: ~[trait_ref]
+            };
+            let t = ty::node_id_to_type(ccx.tcx, impl_item.id);
+            debug!("=== Doing a self lookup now.");
+            // Right now, we don't have any place to store this.
+            // We will need to make one so we can use this information
+            // for compiling default methods that refer to supertraits.
+            let self_vtable_res =
+                lookup_vtables_for_param(&vcx, &loc_info, None,
+                                         &param_bounds, t, false);
+
+
+            let res = impl_res {
+                trait_vtables: vtbls,
+                self_vtables: self_vtable_res
+            };
+            ccx.tcx.impl_vtables.insert(def_id, res);
         }
     }
 }
diff --git a/src/librustc/middle/typeck/check/writeback.rs b/src/librustc/middle/typeck/check/writeback.rs
index 4d437d83f2a..a7319d4b008 100644
--- a/src/librustc/middle/typeck/check/writeback.rs
+++ b/src/librustc/middle/typeck/check/writeback.rs
@@ -20,7 +20,7 @@ use middle::typeck::infer::{force_all, resolve_all, resolve_region};
 use middle::typeck::infer::resolve_type;
 use middle::typeck::infer;
 use middle::typeck::{vtable_res, vtable_origin};
-use middle::typeck::{vtable_static, vtable_param, vtable_self};
+use middle::typeck::{vtable_static, vtable_param};
 use middle::typeck::method_map_entry;
 use middle::typeck::write_substs_to_tcx;
 use middle::typeck::write_ty_to_tcx;
@@ -109,9 +109,6 @@ fn resolve_vtable_map_entry(fcx: @mut FnCtxt, sp: span, id: ast::node_id) {
             &vtable_param(n, b) => {
                 vtable_param(n, b)
             }
-            &vtable_self(def_id) => {
-                vtable_self(def_id)
-            }
         }
     }
 }
diff --git a/src/librustc/middle/typeck/infer/mod.rs b/src/librustc/middle/typeck/infer/mod.rs
index 1f0fb135762..eb32f4e59f0 100644
--- a/src/librustc/middle/typeck/infer/mod.rs
+++ b/src/librustc/middle/typeck/infer/mod.rs
@@ -653,6 +653,11 @@ impl InferCtxt {
                   self.resolve_type_vars_if_possible(t))
     }
 
+    pub fn tys_to_str(@mut self, ts: &[ty::t]) -> ~str {
+        let tstrs = ts.map(|t| self.ty_to_str(*t));
+        fmt!("(%s)", tstrs.connect(", "))
+    }
+
     pub fn trait_ref_to_str(@mut self, t: &ty::TraitRef) -> ~str {
         let t = self.resolve_type_vars_in_trait_ref_if_possible(t);
         trait_ref_to_str(self.tcx, &t)
diff --git a/src/librustc/middle/typeck/mod.rs b/src/librustc/middle/typeck/mod.rs
index 81b18e746b2..0ea00e15863 100644
--- a/src/librustc/middle/typeck/mod.rs
+++ b/src/librustc/middle/typeck/mod.rs
@@ -75,14 +75,14 @@ pub mod infer;
 pub mod collect;
 pub mod coherence;
 
+#[deriving(Clone, Encodable, Decodable, Eq, Ord)]
+pub enum param_index {
+    param_numbered(uint),
+    param_self
+}
+
 #[deriving(Clone, Encodable, Decodable)]
 pub enum method_origin {
-    // supertrait method invoked on "self" inside a default method
-    // first field is supertrait ID;
-    // second field is method index (relative to the *supertrait*
-    // method list)
-    method_super(ast::def_id, uint),
-
     // fully statically resolved method
     method_static(ast::def_id),
 
@@ -92,9 +92,6 @@ pub enum method_origin {
     // method invoked on a trait instance
     method_trait(ast::def_id, uint, ty::TraitStore),
 
-    // method invoked on "self" inside a default method
-    method_self(ast::def_id, uint)
-
 }
 
 // details for a method invoked with a receiver whose type is a type parameter
@@ -109,7 +106,7 @@ pub struct method_param {
 
     // index of the type parameter (from those that are in scope) that is
     // the type of the receiver
-    param_num: uint,
+    param_num: param_index,
 
     // index of the bound for this type parameter which specifies the trait
     bound_num: uint,
@@ -153,15 +150,10 @@ pub enum vtable_origin {
       fn foo<T:quux,baz,bar>(a: T) -- a's vtable would have a
       vtable_param origin
 
-      The first uint is the param number (identifying T in the example),
+      The first argument is the param index (identifying T in the example),
       and the second is the bound number (identifying baz)
      */
-    vtable_param(uint, uint),
-
-    /*
-     Dynamic vtable, comes from self.
-    */
-    vtable_self(ast::def_id)
+    vtable_param(param_index, uint),
 }
 
 impl Repr for vtable_origin {
@@ -178,15 +170,34 @@ impl Repr for vtable_origin {
             vtable_param(x, y) => {
                 fmt!("vtable_param(%?, %?)", x, y)
             }
-            vtable_self(def_id) => {
-                fmt!("vtable_self(%?)", def_id)
-            }
         }
     }
 }
 
 pub type vtable_map = @mut HashMap<ast::node_id, vtable_res>;
 
+
+// Information about the vtable resolutions for for a trait impl.
+// Mostly the information is important for implementing default
+// methods.
+#[deriving(Clone)]
+pub struct impl_res {
+    // resolutions for any bounded params on the trait definition
+    trait_vtables: vtable_res,
+    // resolutions for the trait /itself/ (and for supertraits)
+    self_vtables: vtable_param_res
+}
+
+impl Repr for impl_res {
+    fn repr(&self, tcx: ty::ctxt) -> ~str {
+        fmt!("impl_res {trait_vtables=%s, self_vtables=%s}",
+             self.trait_vtables.repr(tcx),
+             self.self_vtables.repr(tcx))
+    }
+}
+
+pub type impl_vtable_map = @mut HashMap<ast::def_id, impl_res>;
+
 pub struct CrateCtxt {
     // A mapping from method call sites to traits that have that method.
     trait_map: resolve::TraitMap,
diff --git a/src/librustc/util/ppaux.rs b/src/librustc/util/ppaux.rs
index 32ac5e72928..932648d4f9b 100644
--- a/src/librustc/util/ppaux.rs
+++ b/src/librustc/util/ppaux.rs
@@ -715,10 +715,6 @@ impl Repr for typeck::method_map_entry {
 impl Repr for typeck::method_origin {
     fn repr(&self, tcx: ctxt) -> ~str {
         match self {
-            &typeck::method_super(def_id, n) => {
-                fmt!("method_super(%s, %?)",
-                     def_id.repr(tcx), n)
-            }
             &typeck::method_static(def_id) => {
                 fmt!("method_static(%s)", def_id.repr(tcx))
             }
@@ -729,9 +725,6 @@ impl Repr for typeck::method_origin {
                 fmt!("method_trait(%s, %?, %s)", def_id.repr(tcx), n,
                      st.repr(tcx))
             }
-            &typeck::method_self(def_id, n) => {
-                fmt!("method_self(%s, %?)", def_id.repr(tcx), n)
-            }
         }
     }
 }
diff --git a/src/libstd/cmp.rs b/src/libstd/cmp.rs
index 8a13cab28c3..eee786524f5 100644
--- a/src/libstd/cmp.rs
+++ b/src/libstd/cmp.rs
@@ -86,6 +86,12 @@ pub trait TotalOrd: TotalEq {
     fn cmp(&self, other: &Self) -> Ordering;
 }
 
+impl TotalEq for Ordering {
+    #[inline]
+    fn equals(&self, other: &Ordering) -> bool {
+        *self == *other
+    }
+}
 impl TotalOrd for Ordering {
     #[inline]
     fn cmp(&self, other: &Ordering) -> Ordering {
diff --git a/src/libstd/iterator.rs b/src/libstd/iterator.rs
index 0c2a7bb7b40..5ea7585a3df 100644
--- a/src/libstd/iterator.rs
+++ b/src/libstd/iterator.rs
@@ -96,7 +96,7 @@ impl<A, T: DoubleEndedIterator<A>> Iterator<A> for InvertIterator<A, T> {
     fn size_hint(&self) -> (uint, Option<uint>) { self.iter.size_hint() }
 }
 
-impl<A, T: Iterator<A>> DoubleEndedIterator<A> for InvertIterator<A, T> {
+impl<A, T: DoubleEndedIterator<A>> DoubleEndedIterator<A> for InvertIterator<A, T> {
     #[inline]
     fn next_back(&mut self) -> Option<A> { self.iter.next() }
 }
@@ -343,6 +343,18 @@ pub trait IteratorUtil<A> {
     /// ~~~
     fn collect<B: FromIterator<A, Self>>(&mut self) -> B;
 
+    /// Loops through the entire iterator, collecting all of the elements into
+    /// a unique vector. This is simply collect() specialized for vectors.
+    ///
+    /// # Example
+    ///
+    /// ~~~ {.rust}
+    /// let a = [1, 2, 3, 4, 5];
+    /// let b: ~[int] = a.iter().transform(|&x| x).to_owned_vec();
+    /// assert!(a == b);
+    /// ~~~
+    fn to_owned_vec(&mut self) -> ~[A];
+
     /// Loops through `n` iterations, returning the `n`th element of the
     /// iterator.
     ///
@@ -539,6 +551,11 @@ impl<A, T: Iterator<A>> IteratorUtil<A> for T {
         FromIterator::from_iterator(self)
     }
 
+    #[inline]
+    fn to_owned_vec(&mut self) -> ~[A] {
+        self.collect()
+    }
+
     /// Return the `n`th item yielded by an iterator.
     #[inline]
     fn nth(&mut self, mut n: uint) -> Option<A> {
diff --git a/src/test/auxiliary/issue_3979_traits.rs b/src/test/auxiliary/issue_3979_traits.rs
index 1e56dab1559..eb10553f19c 100644
--- a/src/test/auxiliary/issue_3979_traits.rs
+++ b/src/test/auxiliary/issue_3979_traits.rs
@@ -14,12 +14,13 @@
 #[crate_type = "lib"];
 
 trait Positioned {
-  fn SetX(&self, int);
+  fn SetX(&mut self, int);
   fn X(&self) -> int;
 }
 
 trait Movable: Positioned {
-  fn translate(&self, dx: int) {
-    self.SetX(self.X() + dx);
+  fn translate(&mut self, dx: int) {
+    let x = self.X() + dx;
+    self.SetX(x);
   }
 }
diff --git a/src/test/run-pass/default-method-supertrait-vtable.rs b/src/test/run-pass/default-method-supertrait-vtable.rs
new file mode 100644
index 00000000000..90a2b914021
--- /dev/null
+++ b/src/test/run-pass/default-method-supertrait-vtable.rs
@@ -0,0 +1,36 @@
+// Copyright 2013 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.
+
+
+// Tests that we can call a function bounded over a supertrait from
+// a default method
+
+fn require_y<T: Y>(x: T) -> int { x.y() }
+
+trait Y {
+    fn y(self) -> int;
+}
+
+
+trait Z: Y {
+    fn x(self) -> int {
+        require_y(self)
+    }
+}
+
+impl Y for int {
+    fn y(self) -> int { self }
+}
+
+impl Z for int;
+
+fn main() {
+    assert_eq!(12.x(), 12);
+}
diff --git a/src/test/run-pass/issue-3979-2.rs b/src/test/run-pass/issue-3979-2.rs
index 9a8b90db185..39e9f5dcd2d 100644
--- a/src/test/run-pass/issue-3979-2.rs
+++ b/src/test/run-pass/issue-3979-2.rs
@@ -8,8 +8,6 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-// xfail-test
-
 trait A {
     fn a_method(&self);
 }
diff --git a/src/test/run-pass/issue-3979-generics.rs b/src/test/run-pass/issue-3979-generics.rs
index 2a1ded96827..867301121da 100644
--- a/src/test/run-pass/issue-3979-generics.rs
+++ b/src/test/run-pass/issue-3979-generics.rs
@@ -8,15 +8,15 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-// xfail-test FIXME #5946
 trait Positioned<S> {
   fn SetX(&mut self, S);
   fn X(&self) -> S;
 }
 
-trait Movable<S, T>: Positioned<T> {
-  fn translate(&self, dx: T) {
-    self.SetX(self.X() + dx);
+trait Movable<S: Add<S, S>>: Positioned<S> {
+  fn translate(&mut self, dx: S) {
+    let x = self.X() + dx;
+    self.SetX(x);
   }
 }
 
@@ -31,10 +31,10 @@ impl Positioned<int> for Point {
     }
 }
 
-impl Movable<int, int> for Point;
+impl Movable<int> for Point;
 
 pub fn main() {
-    let p = Point{ x: 1, y: 2};
+    let mut p = Point{ x: 1, y: 2};
     p.translate(3);
     assert_eq!(p.X(), 4);
 }
diff --git a/src/test/run-pass/issue-3979-xcrate.rs b/src/test/run-pass/issue-3979-xcrate.rs
index 4bde414c4ac..caf6d202316 100644
--- a/src/test/run-pass/issue-3979-xcrate.rs
+++ b/src/test/run-pass/issue-3979-xcrate.rs
@@ -8,7 +8,7 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-// xfail-test // tjc: ???
+// xfail-fast
 // aux-build:issue_3979_traits.rs
 extern mod issue_3979_traits;
 use issue_3979_traits::*;
diff --git a/src/test/run-pass/issue-3979.rs b/src/test/run-pass/issue-3979.rs
index fe10dd5af53..2e53fb5d3f9 100644
--- a/src/test/run-pass/issue-3979.rs
+++ b/src/test/run-pass/issue-3979.rs
@@ -1,5 +1,3 @@
-// xfail-test
-// Reason: ICE with explicit self
 
 // Copyright 2012 The Rust Project Developers. See the COPYRIGHT
 // file at the top-level directory of this distribution and at
diff --git a/src/test/run-pass/supertrait-default-generics.rs b/src/test/run-pass/supertrait-default-generics.rs
new file mode 100644
index 00000000000..ae7e18d532b
--- /dev/null
+++ b/src/test/run-pass/supertrait-default-generics.rs
@@ -0,0 +1,42 @@
+// 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.
+
+// There is some other borrowck bug, so we make the stuff not mut.
+
+trait Positioned<S> {
+  fn SetX(&mut self, S);
+  fn X(&self) -> S;
+}
+
+trait Movable<S: Add<S, S>>: Positioned<S> {
+  fn translate(&mut self, dx: S) {
+    let x = self.X() + dx;
+    self.SetX(x);
+  }
+}
+
+struct Point<S> { x: S, y: S }
+
+impl<S: Clone> Positioned<S> for Point<S> {
+    fn SetX(&mut self, x: S) {
+        self.x = x;
+    }
+    fn X(&self) -> S {
+        self.x.clone()
+    }
+}
+
+impl<S: Clone + Add<S, S>> Movable<S> for Point<S>;
+
+pub fn main() {
+    let mut p = Point{ x: 1, y: 2};
+    p.translate(3);
+    assert_eq!(p.X(), 4);
+}